fields_iter/
lib.rs

1//! A crate macro that allows you inspecting the fields of structs.
2//!
3//! See the docs on [`FieldsInspect`] for more.
4//!
5//! # no-std support
6//!
7//! This crate is no-std compatible.
8
9#![no_std]
10#![forbid(unsafe_op_in_unsafe_fn, rust_2018_idioms)]
11#![warn(missing_docs)]
12#![cfg_attr(docsrs, feature(doc_cfg))]
13
14use core::any::Any;
15use core::iter::FusedIterator;
16use core::marker::PhantomData;
17use core::panic::UnwindSafe;
18
19pub use fields_iter_macros::FieldsInspect;
20
21// FIXME: We're forced to use a second trait because `*mut Self` cannot be the `self` pointer
22// without `arbitrary_self_types`. When it is stabilized, remove this trait.
23#[doc(hidden)]
24pub trait FieldsInspectImpl {
25    fn struct_name() -> &'static str;
26    fn fields_count() -> u32;
27    fn field_name(n: u32) -> &'static str;
28    fn field(&self, n: u32) -> &dyn Any;
29    /// # Safety
30    ///
31    /// You should call this only with `this` pointing to a valid `FieldsInspectImpl`-implementing
32    /// type (this is not a reference because this runs into issues with Stacked Borrows for
33    /// `FieldsIterMut`). You should use the resulting reference only for the lifetime of `this`,
34    /// and not create an overlapping reference (references from the same `n`) during this region.
35    unsafe fn field_mut(this: *mut (), n: u32) -> &'static mut dyn Any;
36}
37
38impl<'a, T: ?Sized + FieldsInspectImpl + 'a> FieldsInspectImpl for &'a mut T {
39    fn struct_name() -> &'static str {
40        T::struct_name()
41    }
42    fn fields_count() -> u32 {
43        T::fields_count()
44    }
45    fn field_name(n: u32) -> &'static str {
46        T::field_name(n)
47    }
48    fn field(&self, n: u32) -> &dyn Any {
49        T::field(*self, n)
50    }
51    unsafe fn field_mut(this: *mut (), n: u32) -> &'static mut dyn Any {
52        // SAFETY: Precondition.
53        unsafe { T::field_mut((*this.cast::<Self>()) as *mut T as *mut (), n) }
54    }
55}
56
57#[doc(hidden)]
58pub struct FieldsIterMutVtable {
59    field_name: fn(u32) -> &'static str,
60    field_mut: unsafe fn(*mut (), n: u32) -> &'static mut dyn Any,
61}
62
63/// A trait that allows iterating over over struct's fields, getting their name and a mutable/shared
64/// reference to them.
65///
66/// [You need to derive this trait](derive@FieldsInspect) (actually, it the derive creates an impl
67/// for a hidden trait this trait has a blanket implementation to).
68///
69/// # Examples
70///
71/// Printing the values of all field whose name starts with "a" and are strings:
72/// ```
73/// use fields_iter::{FieldsInspect, FieldsIter};
74///
75/// fn print_starts_with_a(v: &dyn FieldsInspect) {
76///     for (name, value) in FieldsIter::new(v) {
77///         if !name.starts_with('a') { continue };
78///         let Some(value) = value.downcast_ref::<String>() else { continue };
79///         println!("{name}={value}");
80///     }
81/// }
82/// ```
83///
84/// Adding one to the field `add_here`:
85/// ```
86/// use fields_iter::{FieldsInspect, FieldsIterMut};
87///
88/// # #[derive(FieldsInspect)]
89/// # struct Type { add_here: i32 }
90/// # let mut original = Type { add_here: 0 };
91/// let v: &mut dyn FieldsInspect;
92/// # let v: &mut dyn FieldsInspect = &mut original;
93/// let field = FieldsIterMut::new(v)
94///     .find(|&(name, _)| name == "add_here")
95///     .expect("no `add_here` field")
96///     .1
97///     .downcast_mut::<i32>()
98///     .expect("field `add_here` is not of type `i32`");
99/// *field += 1;
100/// # assert_eq!(original.add_here, 1);
101/// ```
102pub trait FieldsInspect {
103    /// The struct name.
104    ///
105    /// This takes `&self` to make `FieldsIter` object safe.
106    fn struct_name(&self) -> &'static str;
107
108    /// The numbers of fields.
109    ///
110    /// This allows you to iterate over the fields without allocating a `Box` and in `no_std` mode.
111    ///
112    /// This takes `&self` to make `FieldsIter` object safe.
113    ///
114    /// # Example
115    ///
116    /// ```
117    /// # use fields_iter::FieldsInspect;
118    /// #[derive(FieldsInspect)]
119    /// struct HasFieldsInspect {
120    ///     a: i32,
121    ///     b: String,
122    /// }
123    ///
124    /// let v = HasFieldsInspect { a: 0, b: String::new() };
125    /// assert_eq!(v.fields_count(), 2);
126    /// ```
127    ///
128    /// This takes `&self` to make `FieldsIter` object safe.
129    fn fields_count(&self) -> u32;
130
131    /// The name of the nth field.
132    ///
133    /// Named fields return their name; tuple fields return their index (e.g. "1", "2").
134    ///
135    /// This allows you to iterate over the fields without allocating a `Box` and in `no_std` mode.
136    ///
137    /// This takes `&self` to make `FieldsIter` object safe.
138    ///
139    /// # Example
140    ///
141    /// ```
142    /// # use fields_iter::FieldsInspect;
143    /// #[derive(FieldsInspect)]
144    /// struct HasFieldsInspect {
145    ///     a: i32,
146    ///     b: String,
147    /// }
148    ///
149    /// let v = HasFieldsInspect { a: 0, b: String::new() };
150    /// assert_eq!(v.field_name(0), "a");
151    /// assert_eq!(v.field_name(1), "b");
152    /// ```
153    ///
154    /// # Panics
155    ///
156    /// This panics if given an out of bounds field index.
157    fn field_name(&self, n: u32) -> &'static str;
158
159    /// The value of the nth field.
160    ///
161    /// This allows you to iterate over the fields without allocating a `Box` and in `no_std` mode.
162    ///
163    /// # Example
164    ///
165    /// ```
166    /// # use fields_iter::FieldsInspect;
167    /// #[derive(FieldsInspect)]
168    /// struct HasFieldsInspect {
169    ///     a: i32,
170    ///     b: String,
171    /// }
172    ///
173    /// let v = HasFieldsInspect { a: 0, b: String::new() };
174    /// assert!(std::ptr::eq(v.field(0), &v.a));
175    /// assert!(std::ptr::eq(v.field(1), &v.b));
176    /// ```
177    ///
178    /// # Panics
179    ///
180    /// This panics if given an out of bounds field index.
181    fn field(&self, n: u32) -> &dyn Any;
182
183    /// The value of the nth field.
184    ///
185    /// This allows you to iterate over the fields without allocating a `Box` and in `no_std` mode.
186    ///
187    /// # Example
188    ///
189    /// ```
190    /// # use fields_iter::FieldsInspect;
191    /// #[derive(FieldsInspect)]
192    /// struct HasFieldsInspect {
193    ///     a: i32,
194    ///     b: String,
195    /// }
196    ///
197    /// let mut v = HasFieldsInspect { a: 0, b: String::new() };
198    /// *v.field_mut(0).downcast_mut::<i32>().unwrap() += 5;
199    /// assert_eq!(v.a, 5);
200    /// ```
201    ///
202    /// # Panics
203    ///
204    /// This panics if given an out of bounds field index.
205    fn field_mut(&mut self, n: u32) -> &mut dyn Any;
206
207    #[doc(hidden)]
208    fn __fields_mut_iter_vtable(&self) -> &'static FieldsIterMutVtable;
209}
210
211impl<T: ?Sized + FieldsInspectImpl> FieldsInspect for T {
212    fn struct_name(&self) -> &'static str {
213        <T as FieldsInspectImpl>::struct_name()
214    }
215    fn fields_count(&self) -> u32 {
216        <T as FieldsInspectImpl>::fields_count()
217    }
218    fn field_name(&self, n: u32) -> &'static str {
219        <T as FieldsInspectImpl>::field_name(n)
220    }
221    fn field(&self, n: u32) -> &dyn Any {
222        <T as FieldsInspectImpl>::field(self, n)
223    }
224    fn field_mut(&mut self, n: u32) -> &mut dyn Any {
225        // SAFETY: We derive the pointer from reference and return a reference with the same lifetime.
226        unsafe { <T as FieldsInspectImpl>::field_mut(self as *mut Self as *mut (), n) }
227    }
228    #[doc(hidden)]
229    fn __fields_mut_iter_vtable(&self) -> &'static FieldsIterMutVtable {
230        &FieldsIterMutVtable {
231            field_name: <Self as FieldsInspectImpl>::field_name,
232            field_mut: <Self as FieldsInspectImpl>::field_mut,
233        }
234    }
235}
236
237/// An iterator over the names and shared references to a type implementing `FieldsInspect`.
238///
239/// # Example
240///
241/// ```
242/// # use std::any::Any;
243/// # use fields_iter::{FieldsInspect, FieldsIter};
244/// fn find_field<'a>(v: &'a dyn FieldsInspect, name: &str) -> Option<&'a dyn Any> {
245///     FieldsIter::new(v).find_map(|(n, v)| (n == name).then_some(v))
246/// }
247///
248/// #[derive(FieldsInspect)]
249/// struct HasFieldsInspect {
250///     a: i32,
251///     b: String,
252/// }
253/// let v = HasFieldsInspect { a: 0, b: String::new() };
254/// assert!(std::ptr::eq(&v.b, find_field(&v, "b").unwrap().downcast_ref::<String>().unwrap()));
255/// ```
256pub struct FieldsIter<'a, T: ?Sized = dyn FieldsInspect> {
257    fields_count: u32,
258    next_field_idx: u32,
259    value: &'a T,
260}
261
262impl<'a, T: ?Sized + FieldsInspect> FieldsIter<'a, T> {
263    /// Creates a new `FieldsIter`.
264    pub fn new(v: &'a T) -> Self {
265        Self { fields_count: v.fields_count(), next_field_idx: 0, value: v }
266    }
267}
268
269impl<'a, T: ?Sized + FieldsInspect> Iterator for FieldsIter<'a, T> {
270    type Item = (&'static str, &'a dyn Any);
271
272    fn next(&mut self) -> Option<Self::Item> {
273        if self.next_field_idx >= self.fields_count {
274            return None;
275        }
276        let name = self.value.field_name(self.next_field_idx);
277        let value = self.value.field(self.next_field_idx);
278        self.next_field_idx += 1;
279        Some((name, value))
280    }
281
282    fn size_hint(&self) -> (usize, Option<usize>) {
283        let result = self.len();
284        (result, Some(result))
285    }
286}
287
288impl<'a, T: ?Sized + FieldsInspect> ExactSizeIterator for FieldsIter<'a, T> {
289    fn len(&self) -> usize {
290        (self.fields_count - self.next_field_idx) as usize
291    }
292}
293
294impl<'a, T: ?Sized + FieldsInspect> FusedIterator for FieldsIter<'a, T> {}
295
296impl<'a, T: ?Sized + FieldsInspect> DoubleEndedIterator for FieldsIter<'a, T> {
297    fn next_back(&mut self) -> Option<Self::Item> {
298        if self.fields_count == self.next_field_idx {
299            return None;
300        }
301        self.fields_count -= 1;
302        let name = self.value.field_name(self.fields_count);
303        let value = self.value.field(self.fields_count);
304        Some((name, value))
305    }
306}
307
308/// An iterator over the names and mutable references to a type implementing `FieldsInspect`.
309///
310/// # Example
311///
312/// ```
313/// # use std::any::Any;
314/// # use fields_iter::{FieldsInspect, FieldsIterMut};
315/// fn find_field<'a>(v: &'a mut dyn FieldsInspect, name: &str) -> Option<&'a mut dyn Any> {
316///     FieldsIterMut::new(v).find_map(|(n, v)| (n == name).then_some(v))
317/// }
318///
319/// #[derive(FieldsInspect)]
320/// struct HasFieldsInspect {
321///     a: i32,
322///     b: String,
323/// }
324/// let mut v = HasFieldsInspect { a: 0, b: String::new() };
325/// *find_field(&mut v, "a").unwrap().downcast_mut::<i32>().unwrap() = 123;
326/// assert_eq!(v.a, 123);
327/// ```
328pub struct FieldsIterMut<'a, T: ?Sized = dyn FieldsInspect> {
329    fields_count: u32,
330    next_field_idx: u32,
331    value: *mut (),
332    vtable: &'static FieldsIterMutVtable,
333    _marker: PhantomData<&'a mut T>,
334}
335
336impl<'a, T: ?Sized + FieldsInspect> FieldsIterMut<'a, T> {
337    /// Creates a new `FieldsIter`.
338    pub fn new(v: &'a mut T) -> Self {
339        Self {
340            fields_count: v.fields_count(),
341            next_field_idx: 0,
342            value: v as *mut T as *mut (),
343            vtable: v.__fields_mut_iter_vtable(),
344            _marker: PhantomData,
345        }
346    }
347}
348
349impl<'a, T: ?Sized + FieldsInspect> Iterator for FieldsIterMut<'a, T> {
350    type Item = (&'static str, &'a mut dyn Any);
351
352    fn next(&mut self) -> Option<Self::Item> {
353        if self.next_field_idx >= self.fields_count {
354            return None;
355        }
356        let name = (self.vtable.field_name)(self.next_field_idx);
357        // The pointer is created from reference by `new()`, we return a reference with the same
358        // lifetime, and we only borrow disjoint fields.
359        let value = unsafe { (self.vtable.field_mut)(self.value, self.next_field_idx) };
360        self.next_field_idx += 1;
361        Some((name, value))
362    }
363
364    fn size_hint(&self) -> (usize, Option<usize>) {
365        let result = self.len();
366        (result, Some(result))
367    }
368}
369
370impl<'a, T: ?Sized + FieldsInspect> ExactSizeIterator for FieldsIterMut<'a, T> {
371    fn len(&self) -> usize {
372        (self.fields_count - self.next_field_idx) as usize
373    }
374}
375
376impl<'a, T: ?Sized + FieldsInspect> FusedIterator for FieldsIterMut<'a, T> {}
377
378impl<'a, T: ?Sized + FieldsInspect> DoubleEndedIterator for FieldsIterMut<'a, T> {
379    fn next_back(&mut self) -> Option<Self::Item> {
380        if self.fields_count == self.next_field_idx {
381            return None;
382        }
383        self.fields_count -= 1;
384        let name = (self.vtable.field_name)(self.fields_count);
385        // The pointer is created from reference by `new()`, we return a reference with the same
386        // lifetime, and we only borrow disjoint fields.
387        let value = unsafe { (self.vtable.field_mut)(self.value, self.fields_count) };
388        Some((name, value))
389    }
390}
391
392// SAFETY: We use the pointer, our only non-`Send`/`Sync` data, in a uniquely owned manner.
393unsafe impl<'a, T: ?Sized + FieldsInspect + Send> Send for FieldsIterMut<'a, T> {}
394unsafe impl<'a, T: ?Sized + FieldsInspect + Sync> Sync for FieldsIterMut<'a, T> {}
395impl<'a, T: ?Sized + FieldsInspect + UnwindSafe> UnwindSafe for FieldsIterMut<'a, T> {}
396
397#[cold]
398#[doc(hidden)]
399#[track_caller]
400pub fn field_out_of_bounds(struct_name: &str, field: u32) -> ! {
401    panic!("field index {field} is out of bounds for struct `{struct_name}`")
402}
403
404#[doc(hidden)]
405pub use core::ptr::addr_of_mut;