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;