1use core::{cmp::Ordering, marker::PhantomData};
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, 'facet_lifetime> {
36 pub(crate) data: PtrConst<'mem>,
38
39 pub(crate) shape: &'static Shape,
41
42 invariant: PhantomData<fn(&'facet_lifetime ()) -> &'facet_lifetime ()>,
43}
44
45impl<'mem, 'facet_lifetime> Peek<'mem, 'facet_lifetime> {
46 pub fn new<T: Facet<'facet_lifetime>>(t: &'mem T) -> Self {
48 Self {
49 data: PtrConst::new(t as *const T),
50 shape: T::SHAPE,
51 invariant: PhantomData,
52 }
53 }
54
55 pub unsafe fn unchecked_new(data: PtrConst<'mem>, shape: &'static Shape) -> Self {
63 Self {
64 data,
65 shape,
66 invariant: PhantomData,
67 }
68 }
69
70 #[inline(always)]
72 pub fn vtable(&self) -> &'static ValueVTable {
73 self.shape.vtable
74 }
75
76 pub fn id(&self) -> ValueId {
78 ValueId::new(self.shape, self.data.as_byte_ptr())
79 }
80
81 #[inline]
83 pub fn ptr_eq(&self, other: &Peek<'_, '_>) -> bool {
84 self.data.as_byte_ptr() == other.data.as_byte_ptr()
85 }
86
87 #[inline]
93 pub fn eq(&self, other: &Peek<'_, '_>) -> Option<bool> {
94 unsafe {
95 self.shape
96 .vtable
97 .eq
98 .map(|eq_fn| eq_fn(self.data, other.data))
99 }
100 }
101
102 #[inline]
108 pub fn partial_cmp(&self, other: &Peek<'_, '_>) -> Option<Ordering> {
109 unsafe {
110 self.shape
111 .vtable
112 .partial_ord
113 .and_then(|partial_ord_fn| partial_ord_fn(self.data, other.data))
114 }
115 }
116
117 #[inline(always)]
123 pub fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) -> bool {
124 unsafe {
125 if let Some(hash_fn) = self.shape.vtable.hash {
126 let hasher_opaque = PtrMut::new(hasher);
127 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
128 opaque.as_mut::<H>().write(bytes)
129 });
130 true
131 } else {
132 false
133 }
134 }
135 }
136
137 #[inline(always)]
148 pub fn type_name(
149 &self,
150 f: &mut core::fmt::Formatter<'_>,
151 opts: TypeNameOpts,
152 ) -> core::fmt::Result {
153 (self.shape.vtable.type_name)(f, opts)
154 }
155
156 #[inline(always)]
158 pub const fn shape(&self) -> &'static Shape {
159 self.shape
160 }
161
162 #[inline(always)]
164 pub const fn data(&self) -> PtrConst<'mem> {
165 self.data
166 }
167
168 pub fn scalar_type(&self) -> Option<ScalarType> {
170 ScalarType::try_from_shape(self.shape)
171 }
172
173 pub fn get<T: Facet<'facet_lifetime>>(&self) -> Result<&T, ReflectError> {
179 if self.shape != T::SHAPE {
180 Err(ReflectError::WrongShape {
181 expected: self.shape,
182 actual: T::SHAPE,
183 })
184 } else {
185 Ok(unsafe { self.data.get::<T>() })
186 }
187 }
188
189 pub fn into_struct(self) -> Result<PeekStruct<'mem, 'facet_lifetime>, ReflectError> {
191 if let Def::Struct(def) = self.shape.def {
192 Ok(PeekStruct { value: self, def })
193 } else {
194 Err(ReflectError::WasNotA {
195 expected: "struct",
196 actual: self.shape,
197 })
198 }
199 }
200
201 pub fn into_enum(self) -> Result<PeekEnum<'mem, 'facet_lifetime>, ReflectError> {
203 if let Def::Enum(def) = self.shape.def {
204 Ok(PeekEnum { value: self, def })
205 } else {
206 Err(ReflectError::WasNotA {
207 expected: "enum",
208 actual: self.shape,
209 })
210 }
211 }
212
213 pub fn into_map(self) -> Result<PeekMap<'mem, 'facet_lifetime>, ReflectError> {
215 if let Def::Map(def) = self.shape.def {
216 Ok(PeekMap { value: self, def })
217 } else {
218 Err(ReflectError::WasNotA {
219 expected: "map",
220 actual: self.shape,
221 })
222 }
223 }
224
225 pub fn into_list(self) -> Result<PeekList<'mem, 'facet_lifetime>, ReflectError> {
227 if let Def::List(def) = self.shape.def {
228 Ok(PeekList { value: self, def })
229 } else {
230 Err(ReflectError::WasNotA {
231 expected: "list",
232 actual: self.shape,
233 })
234 }
235 }
236
237 pub fn into_smart_pointer(
239 self,
240 ) -> Result<PeekSmartPointer<'mem, 'facet_lifetime>, ReflectError> {
241 if let Def::SmartPointer(def) = self.shape.def {
242 Ok(PeekSmartPointer { value: self, def })
243 } else {
244 Err(ReflectError::WasNotA {
245 expected: "smart pointer",
246 actual: self.shape,
247 })
248 }
249 }
250
251 pub fn into_option(self) -> Result<super::PeekOption<'mem, 'facet_lifetime>, ReflectError> {
253 if let Def::Option(def) = self.shape.def {
254 Ok(super::PeekOption { value: self, def })
255 } else {
256 Err(ReflectError::WasNotA {
257 expected: "option",
258 actual: self.shape,
259 })
260 }
261 }
262
263 pub fn innermost_peek(self) -> Self {
269 let mut current_peek = self;
270 while let (Some(try_borrow_inner_fn), Some(inner_shape)) = (
271 current_peek.shape.vtable.try_borrow_inner,
272 current_peek.shape.inner,
273 ) {
274 unsafe {
275 let inner_data = try_borrow_inner_fn(current_peek.data)
276 .expect("innermost_peek: try_borrow_inner returned an error");
277
278 current_peek = Peek {
279 data: inner_data,
280 shape: inner_shape(),
281 invariant: PhantomData,
282 };
283 }
284 }
285 current_peek
286 }
287}
288
289impl core::fmt::Display for Peek<'_, '_> {
290 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
291 if let Some(display_fn) = self.vtable().display {
292 unsafe { display_fn(self.data, f) }
293 } else {
294 write!(f, "⟨{}⟩", self.shape)
295 }
296 }
297}
298
299impl core::fmt::Debug for Peek<'_, '_> {
300 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
301 if let Some(debug_fn) = self.vtable().debug {
302 unsafe { debug_fn(self.data, f) }
303 } else {
304 write!(f, "⟨{}⟩", self.shape)
305 }
306 }
307}
308
309impl core::cmp::PartialEq for Peek<'_, '_> {
310 fn eq(&self, other: &Self) -> bool {
311 if self.shape != other.shape {
312 return false;
313 }
314 let eq_fn = match self.shape.vtable.eq {
315 Some(eq_fn) => eq_fn,
316 None => return false,
317 };
318 unsafe { eq_fn(self.data, other.data) }
319 }
320}
321
322impl core::cmp::PartialOrd for Peek<'_, '_> {
323 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
324 if self.shape != other.shape {
325 return None;
326 }
327 let partial_ord_fn = self.shape.vtable.partial_ord?;
328 unsafe { partial_ord_fn(self.data, other.data) }
329 }
330}
331
332impl core::hash::Hash for Peek<'_, '_> {
333 fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
334 if let Some(hash_fn) = self.shape.vtable.hash {
335 let hasher_opaque = PtrMut::new(hasher);
336 unsafe {
337 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
338 opaque.as_mut::<H>().write(bytes)
339 })
340 };
341 } else {
342 panic!("Hashing is not supported for this shape");
343 }
344 }
345}