valuable/tuplable.rs
1use crate::{Valuable, Value, Visit};
2
3use core::fmt;
4
5/// A tuple-like [`Valuable`] sub-type.
6///
7/// Implemented by [`Valuable`] types that have a tuple-like shape. Fields are
8/// always unnamed. Values that implement `Tuplable` must return
9/// [`Value::Tuplable`] from their [`Valuable::as_value`] implementation.
10///
11/// It is uncommon for users to implement this type as the crate provides
12/// implementations of `Tuplable` for Rust tuples.
13///
14/// # Inspecting
15///
16/// Inspecting fields contained by a `Tuplable` instance is done by visiting the
17/// tuple. When visiting a `Tuple`, the `visit_unnamed_fields()` method is
18/// called. When the tuple is statically defined, `visit_unnamed_fields()` is
19/// called once with the values of all the fields. A dynamic tuple
20/// implementation may call `visit_unnamed_fields()` multiple times.
21pub trait Tuplable: Valuable {
22 /// Returns the tuple's definition.
23 ///
24 /// See [`TupleDef`] documentation for more details.
25 ///
26 /// # Examples
27 ///
28 /// ```
29 /// use valuable::{Tuplable, TupleDef};
30 ///
31 /// let tuple = (123, "hello");
32 ///
33 /// if let TupleDef::Static { fields, .. } = tuple.definition() {
34 /// assert_eq!(2, fields);
35 /// }
36 /// ```
37 fn definition(&self) -> TupleDef;
38}
39
40/// The number of fields and other tuple-level information.
41///
42/// Returned by [`Tuplable::definition()`], `TupleDef` provides the caller with
43/// information about the tuple's definition.
44///
45/// This includes the number of fields contained by the tuple.
46#[derive(Debug)]
47#[non_exhaustive]
48pub enum TupleDef {
49 /// The tuple is statically-defined, all fields are known ahead of time.
50 ///
51 /// Static tuple implementations are provided by the crate.
52 ///
53 /// # Examples
54 ///
55 /// A statically defined tuple.
56 ///
57 /// ```
58 /// use valuable::{Tuplable, TupleDef};
59 ///
60 /// let tuple = (123, "hello");
61 ///
62 /// match tuple.definition() {
63 /// TupleDef::Static { fields, .. } => {
64 /// assert_eq!(2, fields);
65 /// }
66 /// _ => unreachable!(),
67 /// };
68 /// ```
69 #[non_exhaustive]
70 Static {
71 /// The number of fields contained by the tuple.
72 fields: usize,
73 },
74 /// The tuple is dynamically-defined, not all fields are known ahead of
75 /// time.
76 ///
77 /// # Examples
78 ///
79 /// ```
80 /// use valuable::{Tuplable, TupleDef, Valuable, Value, Visit};
81 ///
82 /// struct MyTuple;
83 ///
84 /// impl Valuable for MyTuple {
85 /// fn as_value(&self) -> Value<'_> {
86 /// Value::Tuplable(self)
87 /// }
88 ///
89 /// fn visit(&self, visit: &mut dyn Visit) {
90 /// visit.visit_unnamed_fields(&[Value::I32(123)]);
91 /// visit.visit_unnamed_fields(&[Value::String("hello world")]);
92 /// }
93 /// }
94 ///
95 /// impl Tuplable for MyTuple {
96 /// fn definition(&self) -> TupleDef {
97 /// TupleDef::new_dynamic((1, Some(3)))
98 /// }
99 /// }
100 /// ```
101 #[non_exhaustive]
102 Dynamic {
103 /// Returns the bounds on the number of tuple fields.
104 ///
105 /// Specifically, the first element is the lower bound, and the second
106 /// element is the upper bound.
107 fields: (usize, Option<usize>),
108 },
109}
110
111macro_rules! deref {
112 (
113 $(
114 $(#[$attrs:meta])*
115 $ty:ty,
116 )*
117 ) => {
118 $(
119 $(#[$attrs])*
120 impl<T: ?Sized + Tuplable> Tuplable for $ty {
121 fn definition(&self) -> TupleDef {
122 T::definition(&**self)
123 }
124 }
125 )*
126 };
127}
128
129deref! {
130 &T,
131 &mut T,
132 #[cfg(feature = "alloc")]
133 alloc::boxed::Box<T>,
134 #[cfg(feature = "alloc")]
135 alloc::rc::Rc<T>,
136 #[cfg(not(valuable_no_atomic_cas))]
137 #[cfg(feature = "alloc")]
138 alloc::sync::Arc<T>,
139}
140
141impl Tuplable for () {
142 fn definition(&self) -> TupleDef {
143 TupleDef::Static { fields: 0 }
144 }
145}
146
147macro_rules! tuple_impls {
148 (
149 $( $len:expr => ( $($n:tt $name:ident)+ ) )+
150 ) => {
151 $(
152 impl<$($name),+> Valuable for ($($name,)+)
153 where
154 $($name: Valuable,)+
155 {
156 fn as_value(&self) -> Value<'_> {
157 Value::Tuplable(self)
158 }
159
160 fn visit(&self, visit: &mut dyn Visit) {
161 visit.visit_unnamed_fields(&[
162 $(
163 self.$n.as_value(),
164 )+
165 ]);
166 }
167 }
168
169 impl<$($name),+> Tuplable for ($($name,)+)
170 where
171 $($name: Valuable,)+
172 {
173 fn definition(&self) -> TupleDef {
174 TupleDef::Static { fields: $len }
175 }
176 }
177 )+
178 }
179}
180
181tuple_impls! {
182 1 => (0 T0)
183 2 => (0 T0 1 T1)
184 3 => (0 T0 1 T1 2 T2)
185 4 => (0 T0 1 T1 2 T2 3 T3)
186 5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
187 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
188 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
189 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
190 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
191 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
192 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
193 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
194 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12)
195 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13)
196 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14)
197 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15)
198}
199
200impl fmt::Debug for dyn Tuplable + '_ {
201 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
202 if self.definition().is_unit() {
203 ().fmt(fmt)
204 } else {
205 struct DebugTuple<'a, 'b> {
206 fmt: fmt::DebugTuple<'a, 'b>,
207 }
208
209 impl Visit for DebugTuple<'_, '_> {
210 fn visit_unnamed_fields(&mut self, values: &[Value<'_>]) {
211 for value in values {
212 self.fmt.field(value);
213 }
214 }
215
216 fn visit_value(&mut self, _: Value<'_>) {
217 unimplemented!()
218 }
219 }
220
221 let mut debug = DebugTuple {
222 fmt: fmt.debug_tuple(""),
223 };
224
225 self.visit(&mut debug);
226 debug.fmt.finish()
227 }
228 }
229}
230
231impl TupleDef {
232 /// Create a new [`TupleDef::Static`] instance
233 ///
234 /// This should be used when the tuple's fields are fixed and known ahead of time.
235 ///
236 /// # Examples
237 ///
238 /// ```
239 /// use valuable::TupleDef;
240 ///
241 /// let def = TupleDef::new_static(2);
242 /// ```
243 pub const fn new_static(fields: usize) -> TupleDef {
244 TupleDef::Static { fields }
245 }
246
247 /// Create a new [`TupleDef::Dynamic`] instance.
248 ///
249 /// This is used when the tuple's fields may vary at runtime.
250 ///
251 /// # Examples
252 ///
253 /// ```
254 /// use valuable::TupleDef;
255 ///
256 /// let def = TupleDef::new_dynamic((2, Some(10)));
257 /// ```
258 pub const fn new_dynamic(fields: (usize, Option<usize>)) -> TupleDef {
259 TupleDef::Dynamic { fields }
260 }
261
262 /// Returns `true` if `self` represents the [unit][primitive@unit] tuple.
263 ///
264 /// # Examples
265 ///
266 /// With the unit tuple
267 ///
268 /// ```
269 /// use valuable::Tuplable;
270 ///
271 /// let tuple: &dyn Tuplable = &();
272 /// assert!(tuple.definition().is_unit());
273 /// ```
274 ///
275 /// When not the unit tuple.
276 ///
277 /// ```
278 /// use valuable::Tuplable;
279 ///
280 /// let tuple: &dyn Tuplable = &(123,456);
281 /// assert!(!tuple.definition().is_unit());
282 /// ```
283 pub fn is_unit(&self) -> bool {
284 match *self {
285 TupleDef::Static { fields } => fields == 0,
286 TupleDef::Dynamic { fields } => fields == (0, Some(0)),
287 }
288 }
289
290 /// Returns `true` if the tuple is [statically defined](TupleDef::Static).
291 ///
292 /// # Examples
293 ///
294 /// With a static tuple
295 ///
296 /// ```
297 /// use valuable::TupleDef;
298 ///
299 /// let def = TupleDef::new_static(2);
300 /// assert!(def.is_static());
301 /// ```
302 ///
303 /// With a dynamic tuple
304 ///
305 /// ```
306 /// use valuable::TupleDef;
307 ///
308 /// let def = TupleDef::new_dynamic((2, None));
309 /// assert!(!def.is_static());
310 /// ```
311 pub fn is_static(&self) -> bool {
312 matches!(self, TupleDef::Static { .. })
313 }
314
315 /// Returns `true` if the tuple is [dynamically defined](TupleDef::Dynamic).
316 ///
317 /// # Examples
318 ///
319 /// With a static tuple
320 ///
321 /// ```
322 /// use valuable::TupleDef;
323 ///
324 /// let def = TupleDef::new_static(2);
325 /// assert!(!def.is_dynamic());
326 /// ```
327 ///
328 /// With a dynamic tuple
329 ///
330 /// ```
331 /// use valuable::TupleDef;
332 ///
333 /// let def = TupleDef::new_dynamic((2, None));
334 /// assert!(def.is_dynamic());
335 /// ```
336 pub fn is_dynamic(&self) -> bool {
337 matches!(self, TupleDef::Dynamic { .. })
338 }
339}