1 //! Structured values. 2 3 use std::fmt; 4 5 mod internal; 6 mod impls; 7 8 #[cfg(test)] 9 pub(in kv) mod test; 10 11 pub use kv::Error; 12 13 use self::internal::{Inner, Visitor, Primitive}; 14 15 /// A type that can be converted into a [`Value`](struct.Value.html). 16 pub trait ToValue { 17 /// Perform the conversion. to_value(&self) -> Value18 fn to_value(&self) -> Value; 19 } 20 21 impl<'a, T> ToValue for &'a T 22 where 23 T: ToValue + ?Sized, 24 { to_value(&self) -> Value25 fn to_value(&self) -> Value { 26 (**self).to_value() 27 } 28 } 29 30 impl<'v> ToValue for Value<'v> { to_value(&self) -> Value31 fn to_value(&self) -> Value { 32 Value { 33 inner: self.inner, 34 } 35 } 36 } 37 38 /// A type that requires extra work to convert into a [`Value`](struct.Value.html). 39 /// 40 /// This trait is a more advanced initialization API than [`ToValue`](trait.ToValue.html). 41 /// It's intended for erased values coming from other logging frameworks that may need 42 /// to perform extra work to determine the concrete type to use. 43 pub trait Fill { 44 /// Fill a value. fill(&self, slot: &mut Slot) -> Result<(), Error>45 fn fill(&self, slot: &mut Slot) -> Result<(), Error>; 46 } 47 48 impl<'a, T> Fill for &'a T 49 where 50 T: Fill + ?Sized, 51 { fill(&self, slot: &mut Slot) -> Result<(), Error>52 fn fill(&self, slot: &mut Slot) -> Result<(), Error> { 53 (**self).fill(slot) 54 } 55 } 56 57 /// A value slot to fill using the [`Fill`](trait.Fill.html) trait. 58 pub struct Slot<'a> { 59 filled: bool, 60 visitor: &'a mut Visitor, 61 } 62 63 impl<'a> fmt::Debug for Slot<'a> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result64 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 65 f.debug_struct("Slot").finish() 66 } 67 } 68 69 impl<'a> Slot<'a> { new(visitor: &'a mut Visitor) -> Self70 fn new(visitor: &'a mut Visitor) -> Self { 71 Slot { 72 visitor, 73 filled: false, 74 } 75 } 76 77 /// Fill the slot with a value. 78 /// 79 /// The given value doesn't need to satisfy any particular lifetime constraints. 80 /// 81 /// # Panics 82 /// 83 /// Calling `fill` more than once will panic. fill(&mut self, value: Value) -> Result<(), Error>84 pub fn fill(&mut self, value: Value) -> Result<(), Error> { 85 assert!(!self.filled, "the slot has already been filled"); 86 self.filled = true; 87 88 value.visit(self.visitor) 89 } 90 } 91 92 /// A value in a structured key-value pair. 93 pub struct Value<'v> { 94 inner: Inner<'v>, 95 } 96 97 impl<'v> Value<'v> { 98 /// Get a value from an internal `Visit`. from_primitive(value: Primitive<'v>) -> Self99 fn from_primitive(value: Primitive<'v>) -> Self { 100 Value { 101 inner: Inner::Primitive(value), 102 } 103 } 104 105 /// Get a value from a fillable slot. from_fill<T>(value: &'v T) -> Self where T: Fill,106 pub fn from_fill<T>(value: &'v T) -> Self 107 where 108 T: Fill, 109 { 110 Value { 111 inner: Inner::Fill(value), 112 } 113 } 114 visit(&self, visitor: &mut Visitor) -> Result<(), Error>115 fn visit(&self, visitor: &mut Visitor) -> Result<(), Error> { 116 self.inner.visit(visitor) 117 } 118 } 119 120 #[cfg(test)] 121 mod tests { 122 use super::*; 123 124 #[test] fill_value()125 fn fill_value() { 126 struct TestFill; 127 128 impl Fill for TestFill { 129 fn fill(&self, slot: &mut Slot) -> Result<(), Error> { 130 let dbg: &fmt::Debug = &1; 131 132 slot.fill(Value::from_debug(&dbg)) 133 } 134 } 135 136 assert_eq!("1", Value::from_fill(&TestFill).to_string()); 137 } 138 139 #[test] 140 #[should_panic] fill_multiple_times_panics()141 fn fill_multiple_times_panics() { 142 struct BadFill; 143 144 impl Fill for BadFill { 145 fn fill(&self, slot: &mut Slot) -> Result<(), Error> { 146 slot.fill(42.into())?; 147 slot.fill(6789.into())?; 148 149 Ok(()) 150 } 151 } 152 153 let _ = Value::from_fill(&BadFill).to_string(); 154 } 155 } 156