facet_reflect/peek/
struct_.rs

1use facet_core::{Field, FieldAttribute, FieldError, FieldFlags, StructDef};
2
3use crate::Peek;
4
5/// Lets you read from a struct (implements read-only struct operations)
6#[derive(Clone, Copy)]
7pub struct PeekStruct<'mem, 'facet_lifetime> {
8    /// the underlying value
9    pub(crate) value: Peek<'mem, 'facet_lifetime>,
10
11    /// the definition of the struct!
12    pub(crate) def: StructDef,
13}
14
15impl<'mem, 'facet_lifetime> PeekStruct<'mem, 'facet_lifetime> {
16    /// Returns the struct definition
17    #[inline(always)]
18    pub fn def(&self) -> &StructDef {
19        &self.def
20    }
21
22    /// Returns the number of fields in this struct
23    #[inline(always)]
24    pub fn field_count(&self) -> usize {
25        self.def.fields.len()
26    }
27
28    /// Returns the value of the field at the given index
29    #[inline(always)]
30    pub fn field(&self, index: usize) -> Result<Peek<'mem, 'facet_lifetime>, FieldError> {
31        self.def
32            .fields
33            .get(index)
34            .map(|field| unsafe {
35                let field_data = self.value.data().field(field.offset);
36                Peek::unchecked_new(field_data, field.shape())
37            })
38            .ok_or(FieldError::IndexOutOfBounds)
39    }
40
41    /// Gets the value of the field with the given name
42    #[inline]
43    pub fn field_by_name(&self, name: &str) -> Result<Peek<'mem, 'facet_lifetime>, FieldError> {
44        for (i, field) in self.def.fields.iter().enumerate() {
45            if field.name == name {
46                return self.field(i);
47            }
48        }
49        Err(FieldError::NoSuchField)
50    }
51
52    /// Iterates over all fields in this struct, providing both name and value
53    #[inline]
54    pub fn fields(
55        &self,
56    ) -> impl Iterator<Item = (&'static Field, Peek<'mem, 'facet_lifetime>)> + '_ {
57        (0..self.field_count()).filter_map(|i| {
58            let field = self.def.fields.get(i)?;
59            let value = self.field(i).ok()?;
60            Some((field, value))
61        })
62    }
63
64    /// Iterates over fields in this struct that should be included when it is serialized.
65    #[inline]
66    pub fn fields_for_serialize(
67        &self,
68    ) -> impl Iterator<Item = (&'static Field, Peek<'mem, 'facet_lifetime>)> + '_ {
69        self.fields().filter(|(field, peek)| {
70            if field.flags.contains(FieldFlags::SKIP_SERIALIZING) {
71                return false;
72            }
73
74            for attr in field.attributes {
75                if let FieldAttribute::SkipSerializingIf(fn_ptr) = attr {
76                    if unsafe { fn_ptr(peek.data()) } {
77                        return false;
78                    }
79                }
80            }
81            true
82        })
83    }
84}