facet_reflect/peek/
mod.rs

1//! Allows peeking (reading from) shapes
2
3#[cfg(feature = "alloc")]
4extern crate alloc;
5
6use facet_core::{Facet, TypeNameOpts};
7
8mod value;
9pub use value::*;
10
11mod struct_;
12pub use struct_::*;
13
14mod enum_;
15pub use enum_::*;
16
17mod list;
18pub use list::*;
19
20mod map;
21pub use map::*;
22
23mod option;
24pub use option::*;
25
26use facet_core::{Def, OpaqueConst, Shape};
27
28/// Lets you peek at the innards of a value
29///
30/// It's possible (in some cases..) to escape the borrow checker by setting `'mem` to `'static`,
31/// in which case, you're entirely on your own.
32#[derive(Clone, Copy)]
33#[non_exhaustive]
34pub enum Peek<'mem> {
35    /// cf. [`PeekValue`]
36    Value(PeekValue<'mem>),
37
38    /// cf. [`PeekList`]
39    List(PeekList<'mem>),
40
41    /// cf. [`PeekMap`]
42    Map(PeekMap<'mem>),
43
44    /// cf. [`PeekStruct`]
45    Struct(PeekStruct<'mem>),
46
47    /// cf. [`PeekEnum`]
48    Enum(PeekEnum<'mem>),
49
50    /// cf. [`PeekOption`]
51    Option(PeekOption<'mem>),
52}
53
54impl<'mem> core::ops::Deref for Peek<'mem> {
55    type Target = PeekValue<'mem>;
56
57    fn deref(&self) -> &Self::Target {
58        match self {
59            Peek::Value(value) => value,
60            Peek::List(list) => list,
61            Peek::Map(map) => map,
62            Peek::Struct(struct_) => struct_,
63            Peek::Enum(enum_) => enum_,
64            Peek::Option(option) => option,
65        }
66    }
67}
68
69impl<'mem> Peek<'mem> {
70    /// Creates a new peek from a reference to some initialized value that implements `Facet`
71    pub fn new<S: Facet>(s: &'mem S) -> Self {
72        // This is safe because we're creating an Opaque pointer to read-only data
73        // The pointer will be valid for the lifetime 'mem
74        let data = OpaqueConst::new(s);
75        unsafe { Self::unchecked_new(data, S::SHAPE) }
76    }
77
78    /// Creates a new peek, for easy manipulation of some opaque data.
79    ///
80    /// # Safety
81    ///
82    /// `data` must be initialized and well-aligned, and point to a value
83    /// of the type described by `shape`.
84    pub unsafe fn unchecked_new(data: OpaqueConst<'mem>, shape: &'static Shape) -> Self {
85        let value = unsafe { PeekValue::unchecked_new(data, shape) };
86        match shape.def {
87            Def::Struct(def) => Peek::Struct(PeekStruct::new(value, def)),
88            Def::Map(def) => Peek::Map(PeekMap::new(value, def)),
89            Def::List(def) => Peek::List(PeekList::new(value, def)),
90            Def::Scalar { .. } => Peek::Value(value),
91            Def::Enum(def) => Peek::Enum(PeekEnum::new(value, def)),
92            Def::Option(def) => Peek::Option(PeekOption::new(value, def)),
93            _ => todo!("unsupported def: {:?}", shape.def),
94        }
95    }
96
97    /// Coerce this to a value so we can use display, debug, etc.
98    pub fn as_value(self) -> PeekValue<'mem> {
99        match self {
100            Self::Value(v) => v,
101            Self::List(l) => *l,
102            Self::Map(m) => *m,
103            Self::Struct(s) => *s,
104            Self::Enum(e) => *e,
105            Self::Option(o) => *o,
106        }
107    }
108}
109
110impl core::fmt::Debug for Peek<'_> {
111    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
112        let value = self.as_value();
113        if value.debug(f).is_none() {
114            value.type_name(f, TypeNameOpts::infinite())?;
115            write!(f, "(⋯)")?;
116        }
117        Ok(())
118    }
119}
120
121impl core::fmt::Display for Peek<'_> {
122    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
123        let value = self.as_value();
124        if value.display(f).is_none() {
125            value.type_name(f, TypeNameOpts::infinite())?;
126            write!(f, "(⋯)")?;
127        }
128        Ok(())
129    }
130}