/rust/registry/src/index.crates.io-1949cf8c6b5b557f/value-bag-1.12.0/src/fill.rs
Line | Count | Source |
1 | | //! Deferred value initialization. |
2 | | //! |
3 | | //! The [`Fill`] trait is a way to bridge APIs that may not be directly |
4 | | //! compatible with other constructor methods. |
5 | | //! |
6 | | //! The `Fill` trait is automatically implemented for closures, so can usually |
7 | | //! be used in libraries that can't implement the trait themselves. |
8 | | //! |
9 | | //! ``` |
10 | | //! use value_bag::{ValueBag, fill::Slot}; |
11 | | //! |
12 | | //! let value = ValueBag::from_fill(&|slot: Slot| { |
13 | | //! #[derive(Debug)] |
14 | | //! struct MyShortLivedValue; |
15 | | //! |
16 | | //! slot.fill_debug(&MyShortLivedValue) |
17 | | //! }); |
18 | | //! |
19 | | //! assert_eq!("MyShortLivedValue", format!("{:?}", value)); |
20 | | //! ``` |
21 | | //! |
22 | | //! The trait can also be implemented manually: |
23 | | //! |
24 | | //! ``` |
25 | | //! # use std::fmt::Debug; |
26 | | //! use value_bag::{ValueBag, Error, fill::{Slot, Fill}}; |
27 | | //! |
28 | | //! struct FillDebug; |
29 | | //! |
30 | | //! impl Fill for FillDebug { |
31 | | //! fn fill(&self, slot: Slot) -> Result<(), Error> { |
32 | | //! slot.fill_debug(&42i64 as &dyn Debug) |
33 | | //! } |
34 | | //! } |
35 | | //! |
36 | | //! let value = ValueBag::from_fill(&FillDebug); |
37 | | //! |
38 | | //! assert_eq!(None, value.to_i64()); |
39 | | //! ``` |
40 | | |
41 | | use crate::std::fmt; |
42 | | |
43 | | use super::internal::{Internal, InternalVisitor}; |
44 | | use super::{Error, ValueBag}; |
45 | | |
46 | | impl<'v> ValueBag<'v> { |
47 | | /// Get a value from a fillable slot. |
48 | 0 | pub const fn from_fill<T>(value: &'v T) -> Self |
49 | 0 | where |
50 | 0 | T: Fill, |
51 | | { |
52 | 0 | ValueBag { |
53 | 0 | inner: Internal::Fill(value), |
54 | 0 | } |
55 | 0 | } |
56 | | } |
57 | | |
58 | | /// A type that requires extra work to convert into a [`ValueBag`](../struct.ValueBag.html). |
59 | | /// |
60 | | /// This trait is an advanced initialization API. |
61 | | /// It's intended for erased values coming from other logging frameworks that may need |
62 | | /// to perform extra work to determine the concrete type to use. |
63 | | pub trait Fill { |
64 | | /// Fill a value. |
65 | | fn fill(&self, slot: Slot) -> Result<(), Error>; |
66 | | } |
67 | | |
68 | | impl<F> Fill for F |
69 | | where |
70 | | F: Fn(Slot) -> Result<(), Error>, |
71 | | { |
72 | 0 | fn fill(&self, slot: Slot) -> Result<(), Error> { |
73 | 0 | (self)(slot) |
74 | 0 | } |
75 | | } |
76 | | |
77 | | /// A value slot to fill using the [`Fill`](trait.Fill.html) trait. |
78 | | pub struct Slot<'s, 'f> { |
79 | | visitor: &'s mut dyn InternalVisitor<'f>, |
80 | | } |
81 | | |
82 | | impl<'s, 'f> fmt::Debug for Slot<'s, 'f> { |
83 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
84 | 0 | f.debug_struct("Slot").finish() |
85 | 0 | } |
86 | | } |
87 | | |
88 | | impl<'s, 'f> Slot<'s, 'f> { |
89 | 0 | pub(crate) fn new(visitor: &'s mut dyn InternalVisitor<'f>) -> Self { |
90 | 0 | Slot { visitor } |
91 | 0 | } |
92 | | |
93 | 0 | pub(crate) fn fill<F>(self, f: F) -> Result<(), Error> |
94 | 0 | where |
95 | 0 | F: FnOnce(&mut dyn InternalVisitor<'f>) -> Result<(), Error>, |
96 | | { |
97 | 0 | f(self.visitor) |
98 | 0 | } |
99 | | |
100 | | /// Fill the slot with a value. |
101 | | /// |
102 | | /// The given value doesn't need to satisfy any particular lifetime constraints. |
103 | 0 | pub fn fill_any<T>(self, value: T) -> Result<(), Error> |
104 | 0 | where |
105 | 0 | T: Into<ValueBag<'f>>, |
106 | | { |
107 | 0 | self.fill(|visitor| value.into().inner.internal_visit(visitor)) |
108 | 0 | } |
109 | | } |
110 | | |
111 | | #[cfg(test)] |
112 | | mod tests { |
113 | | #[cfg(target_arch = "wasm32")] |
114 | | use wasm_bindgen_test::*; |
115 | | |
116 | | use super::*; |
117 | | use crate::std::string::ToString; |
118 | | |
119 | | #[test] |
120 | | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] |
121 | | fn fill_value_borrowed() { |
122 | | struct TestFill; |
123 | | |
124 | | impl Fill for TestFill { |
125 | | fn fill(&self, slot: Slot) -> Result<(), Error> { |
126 | | let dbg = &1 as &dyn fmt::Debug; |
127 | | |
128 | | slot.fill_debug(dbg) |
129 | | } |
130 | | } |
131 | | |
132 | | assert_eq!("1", ValueBag::from_fill(&TestFill).to_string()); |
133 | | } |
134 | | |
135 | | #[test] |
136 | | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] |
137 | | fn fill_cast() { |
138 | | struct TestFill; |
139 | | |
140 | | impl Fill for TestFill { |
141 | | fn fill(&self, slot: Slot) -> Result<(), Error> { |
142 | | slot.fill_any("a string") |
143 | | } |
144 | | } |
145 | | |
146 | | assert_eq!( |
147 | | "a string", |
148 | | ValueBag::from_fill(&TestFill) |
149 | | .to_borrowed_str() |
150 | | .expect("invalid value") |
151 | | ); |
152 | | } |
153 | | |
154 | | #[test] |
155 | | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] |
156 | | fn fill_fn_cast() { |
157 | | assert_eq!( |
158 | | 42u64, |
159 | | ValueBag::from_fill(&|slot: Slot| slot.fill_any(42u64)) |
160 | | .to_u64() |
161 | | .unwrap() |
162 | | ); |
163 | | } |
164 | | |
165 | | #[test] |
166 | | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] |
167 | | fn fill_fn_borrowed() { |
168 | | #[derive(Debug)] |
169 | | struct MyValue; |
170 | | |
171 | | let value = MyValue; |
172 | | assert_eq!( |
173 | | format!("{:?}", value), |
174 | | format!( |
175 | | "{:?}", |
176 | | ValueBag::from_fill(&|slot: Slot| slot.fill_debug(&value)) |
177 | | ) |
178 | | ); |
179 | | } |
180 | | } |