facet_peek/
lib.rs

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