1use core::cmp::Ordering;
2use facet_core::{Def, Facet, PtrConst, PtrMut, Shape, TypeNameOpts, ValueVTable};
3
4use crate::{ReflectError, ScalarType};
5
6use super::{PeekEnum, PeekList, PeekMap, PeekSmartPointer, PeekStruct};
7
8#[derive(Clone, Copy, PartialEq, Eq, Hash)]
10pub struct ValueId {
11 pub(crate) shape: &'static Shape,
12 pub(crate) ptr: *const u8,
13}
14
15impl ValueId {
16 pub(crate) fn new(shape: &'static Shape, ptr: *const u8) -> Self {
17 Self { shape, ptr }
18 }
19}
20
21impl core::fmt::Display for ValueId {
22 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
23 write!(f, "{}@{:p}", self.shape, self.ptr)
24 }
25}
26
27impl core::fmt::Debug for ValueId {
28 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
29 core::fmt::Display::fmt(self, f)
30 }
31}
32
33#[derive(Clone, Copy)]
35pub struct Peek<'mem> {
36 pub(crate) data: PtrConst<'mem>,
38
39 pub(crate) shape: &'static Shape,
41}
42
43impl<'mem> Peek<'mem> {
44 pub fn new<T: Facet + 'mem>(t: &'mem T) -> Self {
46 Self {
47 data: PtrConst::new(t as *const T),
48 shape: T::SHAPE,
49 }
50 }
51
52 pub unsafe fn unchecked_new(data: PtrConst<'mem>, shape: &'static Shape) -> Self {
60 Self { data, shape }
61 }
62
63 #[inline(always)]
65 fn vtable(&self) -> &'static ValueVTable {
66 self.shape.vtable
67 }
68
69 pub fn id(&self) -> ValueId {
71 ValueId::new(self.shape, self.data.as_byte_ptr())
72 }
73
74 #[inline]
76 pub fn ptr_eq(&self, other: &Peek<'_>) -> bool {
77 self.data.as_byte_ptr() == other.data.as_byte_ptr()
78 }
79
80 #[inline]
86 pub fn eq(&self, other: &Peek<'_>) -> Option<bool> {
87 unsafe {
88 self.shape
89 .vtable
90 .eq
91 .map(|eq_fn| eq_fn(self.data, other.data))
92 }
93 }
94
95 #[inline]
101 pub fn partial_cmp(&self, other: &Peek<'_>) -> Option<Ordering> {
102 unsafe {
103 self.shape
104 .vtable
105 .partial_ord
106 .and_then(|partial_ord_fn| partial_ord_fn(self.data, other.data))
107 }
108 }
109
110 #[inline(always)]
116 pub fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) -> bool {
117 unsafe {
118 if let Some(hash_fn) = self.shape.vtable.hash {
119 let hasher_opaque = PtrMut::new(hasher);
120 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
121 opaque.as_mut::<H>().write(bytes)
122 });
123 true
124 } else {
125 false
126 }
127 }
128 }
129
130 #[inline(always)]
141 pub fn type_name(
142 &self,
143 f: &mut core::fmt::Formatter<'_>,
144 opts: TypeNameOpts,
145 ) -> core::fmt::Result {
146 (self.shape.vtable.type_name)(f, opts)
147 }
148
149 #[inline(always)]
151 pub const fn shape(&self) -> &'static Shape {
152 self.shape
153 }
154
155 #[inline(always)]
157 pub const fn data(&self) -> PtrConst<'mem> {
158 self.data
159 }
160
161 pub fn scalar_type(&self) -> Option<ScalarType> {
163 ScalarType::try_from_shape(self.shape)
164 }
165
166 pub fn get<T: Facet>(&self) -> Result<&T, ReflectError> {
172 if self.shape != T::SHAPE {
173 Err(ReflectError::WrongShape {
174 expected: self.shape,
175 actual: T::SHAPE,
176 })
177 } else {
178 Ok(unsafe { self.data.get::<T>() })
179 }
180 }
181
182 pub fn into_struct(self) -> Result<PeekStruct<'mem>, ReflectError> {
184 if let Def::Struct(def) = self.shape.def {
185 Ok(PeekStruct { value: self, def })
186 } else {
187 Err(ReflectError::WasNotA {
188 expected: "struct",
189 actual: self.shape,
190 })
191 }
192 }
193
194 pub fn into_enum(self) -> Result<PeekEnum<'mem>, ReflectError> {
196 if let Def::Enum(def) = self.shape.def {
197 Ok(PeekEnum { value: self, def })
198 } else {
199 Err(ReflectError::WasNotA {
200 expected: "enum",
201 actual: self.shape,
202 })
203 }
204 }
205
206 pub fn into_map(self) -> Result<PeekMap<'mem>, ReflectError> {
208 if let Def::Map(def) = self.shape.def {
209 Ok(PeekMap { value: self, def })
210 } else {
211 Err(ReflectError::WasNotA {
212 expected: "map",
213 actual: self.shape,
214 })
215 }
216 }
217
218 pub fn into_list(self) -> Result<PeekList<'mem>, ReflectError> {
220 if let Def::List(def) = self.shape.def {
221 Ok(PeekList { value: self, def })
222 } else {
223 Err(ReflectError::WasNotA {
224 expected: "list",
225 actual: self.shape,
226 })
227 }
228 }
229
230 pub fn into_smart_pointer(self) -> Result<PeekSmartPointer<'mem>, ReflectError> {
232 if let Def::SmartPointer(def) = self.shape.def {
233 Ok(PeekSmartPointer { value: self, def })
234 } else {
235 Err(ReflectError::WasNotA {
236 expected: "smart pointer",
237 actual: self.shape,
238 })
239 }
240 }
241
242 pub fn into_option(self) -> Result<super::PeekOption<'mem>, ReflectError> {
244 if let Def::Option(def) = self.shape.def {
245 Ok(super::PeekOption { value: self, def })
246 } else {
247 Err(ReflectError::WasNotA {
248 expected: "option",
249 actual: self.shape,
250 })
251 }
252 }
253}
254
255impl core::fmt::Display for Peek<'_> {
256 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
257 if let Some(display_fn) = self.vtable().display {
258 unsafe { display_fn(self.data, f) }
259 } else {
260 write!(f, "⟨{}⟩", self.shape)
261 }
262 }
263}
264
265impl core::fmt::Debug for Peek<'_> {
266 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
267 if let Some(debug_fn) = self.vtable().debug {
268 unsafe { debug_fn(self.data, f) }
269 } else {
270 write!(f, "⟨{}⟩", self.shape)
271 }
272 }
273}
274
275impl core::cmp::PartialEq for Peek<'_> {
276 fn eq(&self, other: &Self) -> bool {
277 if self.shape != other.shape {
278 return false;
279 }
280 let eq_fn = match self.shape.vtable.eq {
281 Some(eq_fn) => eq_fn,
282 None => return false,
283 };
284 unsafe { eq_fn(self.data, other.data) }
285 }
286}
287
288impl core::cmp::PartialOrd for Peek<'_> {
289 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
290 if self.shape != other.shape {
291 return None;
292 }
293 let partial_ord_fn = self.shape.vtable.partial_ord?;
294 unsafe { partial_ord_fn(self.data, other.data) }
295 }
296}
297
298impl core::hash::Hash for Peek<'_> {
299 fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
300 if let Some(hash_fn) = self.shape.vtable.hash {
301 let hasher_opaque = PtrMut::new(hasher);
302 unsafe {
303 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
304 opaque.as_mut::<H>().write(bytes)
305 })
306 };
307 } else {
308 panic!("Hashing is not supported for this shape");
309 }
310 }
311}