1use core::{cmp::Ordering, marker::PhantomData};
2use facet_core::{Def, Facet, PtrConst, PtrMut, Shape, TypeNameOpts, ValueVTable};
3
4use crate::{ReflectError, ScalarType};
5
6use super::{ListLikeDef, PeekEnum, PeekList, PeekListLike, 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_list_like(self) -> Result<PeekListLike<'mem, 'facet_lifetime>, ReflectError> {
239 match self.shape.def {
240 Def::List(def) => Ok(PeekListLike::new(self, ListLikeDef::List(def))),
241 Def::Array(def) => Ok(PeekListLike::new(self, ListLikeDef::Array(def))),
242 Def::Slice(def) => Ok(PeekListLike::new(self, ListLikeDef::Slice(def))),
243 _ => Err(ReflectError::WasNotA {
244 expected: "list, array or slice",
245 actual: self.shape,
246 }),
247 }
248 }
249
250 pub fn into_smart_pointer(
252 self,
253 ) -> Result<PeekSmartPointer<'mem, 'facet_lifetime>, ReflectError> {
254 if let Def::SmartPointer(def) = self.shape.def {
255 Ok(PeekSmartPointer { value: self, def })
256 } else {
257 Err(ReflectError::WasNotA {
258 expected: "smart pointer",
259 actual: self.shape,
260 })
261 }
262 }
263
264 pub fn into_option(self) -> Result<super::PeekOption<'mem, 'facet_lifetime>, ReflectError> {
266 if let Def::Option(def) = self.shape.def {
267 Ok(super::PeekOption { value: self, def })
268 } else {
269 Err(ReflectError::WasNotA {
270 expected: "option",
271 actual: self.shape,
272 })
273 }
274 }
275
276 pub fn innermost_peek(self) -> Self {
282 let mut current_peek = self;
283 while let (Some(try_borrow_inner_fn), Some(inner_shape)) = (
284 current_peek.shape.vtable.try_borrow_inner,
285 current_peek.shape.inner,
286 ) {
287 unsafe {
288 let inner_data = try_borrow_inner_fn(current_peek.data)
289 .expect("innermost_peek: try_borrow_inner returned an error");
290
291 current_peek = Peek {
292 data: inner_data,
293 shape: inner_shape(),
294 invariant: PhantomData,
295 };
296 }
297 }
298 current_peek
299 }
300}
301
302impl core::fmt::Display for Peek<'_, '_> {
303 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
304 if let Some(display_fn) = self.vtable().display {
305 unsafe { display_fn(self.data, f) }
306 } else {
307 write!(f, "⟨{}⟩", self.shape)
308 }
309 }
310}
311
312impl core::fmt::Debug for Peek<'_, '_> {
313 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
314 if let Some(debug_fn) = self.vtable().debug {
315 unsafe { debug_fn(self.data, f) }
316 } else {
317 write!(f, "⟨{}⟩", self.shape)
318 }
319 }
320}
321
322impl core::cmp::PartialEq for Peek<'_, '_> {
323 fn eq(&self, other: &Self) -> bool {
324 if self.shape != other.shape {
325 return false;
326 }
327 let eq_fn = match self.shape.vtable.eq {
328 Some(eq_fn) => eq_fn,
329 None => return false,
330 };
331 unsafe { eq_fn(self.data, other.data) }
332 }
333}
334
335impl core::cmp::PartialOrd for Peek<'_, '_> {
336 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
337 if self.shape != other.shape {
338 return None;
339 }
340 let partial_ord_fn = self.shape.vtable.partial_ord?;
341 unsafe { partial_ord_fn(self.data, other.data) }
342 }
343}
344
345impl core::hash::Hash for Peek<'_, '_> {
346 fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
347 if let Some(hash_fn) = self.shape.vtable.hash {
348 let hasher_opaque = PtrMut::new(hasher);
349 unsafe {
350 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
351 opaque.as_mut::<H>().write(bytes)
352 })
353 };
354 } else {
355 panic!("Hashing is not supported for this shape");
356 }
357 }
358}