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}