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