facet_peek/
lib.rs

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