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