1use core::{cmp::Ordering, marker::PhantomData, ptr::NonNull};
2use facet_core::{
3 Def, Facet, PointerType, PtrConst, Shape, StructKind, Type, TypeNameOpts, UserType, ValueVTable,
4};
5#[cfg(feature = "alloc")]
6use facet_core::{Field, FieldAttribute};
7
8use crate::{PeekNdArray, PeekSet, ReflectError, ScalarType};
9
10use super::{
11 ListLikeDef, PeekEnum, PeekList, PeekListLike, PeekMap, PeekOption, PeekPointer, PeekStruct,
12 PeekTuple, tuple::TupleType,
13};
14
15#[cfg(feature = "alloc")]
16use super::OwnedPeek;
17
18#[derive(Clone, Copy, PartialEq, Eq, Hash)]
20pub struct ValueId {
21 pub(crate) shape: &'static Shape,
22 pub(crate) ptr: *const u8,
23}
24
25impl ValueId {
26 #[inline]
27 pub(crate) fn new(shape: &'static Shape, ptr: *const u8) -> Self {
28 Self { shape, ptr }
29 }
30}
31
32impl core::fmt::Display for ValueId {
33 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
34 write!(f, "{}@{:p}", self.shape, self.ptr)
35 }
36}
37
38impl core::fmt::Debug for ValueId {
39 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
40 core::fmt::Display::fmt(self, f)
41 }
42}
43
44#[derive(Clone, Copy)]
50pub struct Peek<'mem, 'facet> {
51 pub(crate) data: PtrConst<'mem>,
53
54 pub(crate) shape: &'static Shape,
56
57 invariant: PhantomData<fn(&'facet ()) -> &'facet ()>,
58}
59
60impl<'mem, 'facet> Peek<'mem, 'facet> {
61 pub fn new<T: Facet<'facet> + ?Sized>(t: &'mem T) -> Self {
63 Self {
64 data: PtrConst::new(NonNull::from(t)),
65 shape: T::SHAPE,
66 invariant: PhantomData,
67 }
68 }
69
70 pub unsafe fn unchecked_new(data: PtrConst<'mem>, shape: &'static Shape) -> Self {
79 Self {
80 data,
81 shape,
82 invariant: PhantomData,
83 }
84 }
85
86 #[inline(always)]
88 pub fn vtable(&self) -> &'static ValueVTable {
89 &self.shape.vtable
90 }
91
92 #[inline]
94 pub fn id(&self) -> ValueId {
95 ValueId::new(self.shape, self.data.as_byte_ptr())
96 }
97
98 #[inline]
100 pub fn ptr_eq(&self, other: &Peek<'_, '_>) -> bool {
101 self.data.as_byte_ptr() == other.data.as_byte_ptr()
102 }
103
104 #[inline]
110 pub fn partial_eq(&self, other: &Peek<'_, '_>) -> Result<bool, ReflectError> {
111 if let Some(f) = self.vtable().partial_eq {
112 if self.shape == other.shape {
113 return Ok(unsafe { f(self.data, other.data) });
114 } else {
115 return Err(ReflectError::WrongShape {
116 expected: self.shape,
117 actual: other.shape,
118 });
119 }
120 }
121
122 Err(ReflectError::OperationFailed {
123 shape: self.shape(),
124 operation: "partial_eq",
125 })
126 }
127
128 #[inline]
134 pub fn partial_cmp(&self, other: &Peek<'_, '_>) -> Result<Option<Ordering>, ReflectError> {
135 if let Some(f) = self.vtable().partial_ord {
136 if self.shape == other.shape {
137 return Ok(unsafe { f(self.data, other.data) });
138 } else {
139 return Err(ReflectError::WrongShape {
140 expected: self.shape,
141 actual: other.shape,
142 });
143 }
144 }
145
146 Err(ReflectError::OperationFailed {
147 shape: self.shape(),
148 operation: "partial_cmp",
149 })
150 }
151 #[inline(always)]
157 pub fn hash(&self, hasher: &mut dyn core::hash::Hasher) -> Result<(), ReflectError> {
158 if let Some(hash_fn) = self.vtable().hash {
159 unsafe {
160 hash_fn(self.data, hasher);
161 return Ok(());
162 };
163 }
164
165 Err(ReflectError::OperationFailed {
166 shape: self.shape(),
167 operation: "hash",
168 })
169 }
170
171 #[inline(always)]
182 pub fn type_name(
183 &self,
184 f: &mut core::fmt::Formatter<'_>,
185 opts: TypeNameOpts,
186 ) -> core::fmt::Result {
187 self.shape.vtable.type_name()(f, opts)
188 }
189
190 #[inline(always)]
192 pub const fn shape(&self) -> &'static Shape {
193 self.shape
194 }
195
196 #[inline(always)]
198 pub const fn data(&self) -> PtrConst<'mem> {
199 self.data
200 }
201
202 #[inline]
204 pub fn scalar_type(&self) -> Option<ScalarType> {
205 ScalarType::try_from_shape(self.shape)
206 }
207
208 #[inline]
214 pub fn get<T: Facet<'facet> + ?Sized>(&self) -> Result<&T, ReflectError> {
215 if self.shape != T::SHAPE {
216 Err(ReflectError::WrongShape {
217 expected: self.shape,
218 actual: T::SHAPE,
219 })
220 } else {
221 Ok(unsafe { self.data.get::<T>() })
222 }
223 }
224
225 pub fn as_str(&self) -> Option<&'mem str> {
228 let peek = self.innermost_peek();
229 if let Some(ScalarType::Str) = peek.scalar_type() {
230 unsafe { Some(peek.data.get::<&str>()) }
231 } else if let Some(ScalarType::String) = peek.scalar_type() {
232 unsafe { Some(peek.data.get::<alloc::string::String>().as_str()) }
233 } else if let Type::Pointer(PointerType::Reference(vpt)) = peek.shape.ty {
234 let target_shape = vpt.target;
235 if let Some(ScalarType::Str) = ScalarType::try_from_shape(target_shape) {
236 unsafe { Some(peek.data.get::<&str>()) }
237 } else {
238 None
239 }
240 } else {
241 None
242 }
243 }
244
245 #[inline]
248 pub fn as_bytes(&self) -> Option<&'mem [u8]> {
249 if let Type::Pointer(PointerType::Reference(vpt)) = self.shape.ty {
251 let target_shape = vpt.target;
252 if let Def::Slice(sd) = target_shape.def {
253 if sd.t().is_type::<u8>() {
254 unsafe { return Some(self.data.get::<&[u8]>()) }
255 }
256 }
257 }
258 None
259 }
260
261 #[inline]
263 pub fn into_struct(self) -> Result<PeekStruct<'mem, 'facet>, ReflectError> {
264 if let Type::User(UserType::Struct(ty)) = self.shape.ty {
265 Ok(PeekStruct { value: self, ty })
266 } else {
267 Err(ReflectError::WasNotA {
268 expected: "struct",
269 actual: self.shape,
270 })
271 }
272 }
273
274 #[inline]
276 pub fn into_enum(self) -> Result<PeekEnum<'mem, 'facet>, ReflectError> {
277 if let Type::User(UserType::Enum(ty)) = self.shape.ty {
278 Ok(PeekEnum { value: self, ty })
279 } else {
280 Err(ReflectError::WasNotA {
281 expected: "enum",
282 actual: self.shape,
283 })
284 }
285 }
286
287 #[inline]
289 pub fn into_map(self) -> Result<PeekMap<'mem, 'facet>, ReflectError> {
290 if let Def::Map(def) = self.shape.def {
291 Ok(PeekMap { value: self, def })
292 } else {
293 Err(ReflectError::WasNotA {
294 expected: "map",
295 actual: self.shape,
296 })
297 }
298 }
299
300 #[inline]
302 pub fn into_set(self) -> Result<PeekSet<'mem, 'facet>, ReflectError> {
303 if let Def::Set(def) = self.shape.def {
304 Ok(PeekSet { value: self, def })
305 } else {
306 Err(ReflectError::WasNotA {
307 expected: "set",
308 actual: self.shape,
309 })
310 }
311 }
312
313 #[inline]
315 pub fn into_list(self) -> Result<PeekList<'mem, 'facet>, ReflectError> {
316 if let Def::List(def) = self.shape.def {
317 return Ok(PeekList { value: self, def });
318 }
319
320 Err(ReflectError::WasNotA {
321 expected: "list",
322 actual: self.shape,
323 })
324 }
325
326 #[inline]
328 pub fn into_ndarray(self) -> Result<PeekNdArray<'mem, 'facet>, ReflectError> {
329 if let Def::NdArray(def) = self.shape.def {
330 return Ok(PeekNdArray { value: self, def });
331 }
332
333 Err(ReflectError::WasNotA {
334 expected: "ndarray",
335 actual: self.shape,
336 })
337 }
338
339 #[inline]
341 pub fn into_list_like(self) -> Result<PeekListLike<'mem, 'facet>, ReflectError> {
342 match self.shape.def {
343 Def::List(def) => Ok(PeekListLike::new(self, ListLikeDef::List(def))),
344 Def::Array(def) => Ok(PeekListLike::new(self, ListLikeDef::Array(def))),
345 Def::Slice(def) => {
346 Ok(PeekListLike::new(self, ListLikeDef::Slice(def)))
349 }
350 _ => {
351 match self.shape.ty {
353 Type::Pointer(ptr) => match ptr {
354 PointerType::Reference(vpt) | PointerType::Raw(vpt) => {
355 let target = vpt.target;
356 match target.def {
357 Def::Slice(def) => {
358 let ptr = unsafe { self.data.as_ptr::<*const [()]>() };
359 let ptr = PtrConst::new(unsafe {
360 NonNull::new_unchecked((*ptr) as *mut [()])
361 });
362 let peek = unsafe { Peek::unchecked_new(ptr, def.t) };
363
364 return Ok(PeekListLike::new(peek, ListLikeDef::Slice(def)));
365 }
366 _ => {
367 }
369 }
370 }
371 PointerType::Function(_) => {
372 }
374 },
375 _ => {
376 }
378 }
379
380 Err(ReflectError::WasNotA {
381 expected: "list, array or slice",
382 actual: self.shape,
383 })
384 }
385 }
386 }
387
388 #[inline]
390 pub fn into_pointer(self) -> Result<PeekPointer<'mem, 'facet>, ReflectError> {
391 if let Def::Pointer(def) = self.shape.def {
392 Ok(PeekPointer { value: self, def })
393 } else {
394 Err(ReflectError::WasNotA {
395 expected: "smart pointer",
396 actual: self.shape,
397 })
398 }
399 }
400
401 #[inline]
403 pub fn into_option(self) -> Result<PeekOption<'mem, 'facet>, ReflectError> {
404 if let Def::Option(def) = self.shape.def {
405 Ok(PeekOption { value: self, def })
406 } else {
407 Err(ReflectError::WasNotA {
408 expected: "option",
409 actual: self.shape,
410 })
411 }
412 }
413
414 #[inline]
416 pub fn into_tuple(self) -> Result<PeekTuple<'mem, 'facet>, ReflectError> {
417 if let Type::User(UserType::Struct(struct_type)) = self.shape.ty {
418 if struct_type.kind == StructKind::Tuple {
419 Ok(PeekTuple {
420 value: self,
421 ty: TupleType {
422 fields: struct_type.fields,
423 },
424 })
425 } else {
426 Err(ReflectError::WasNotA {
427 expected: "tuple",
428 actual: self.shape,
429 })
430 }
431 } else {
432 Err(ReflectError::WasNotA {
433 expected: "tuple",
434 actual: self.shape,
435 })
436 }
437 }
438
439 pub fn innermost_peek(self) -> Self {
445 let mut current_peek = self;
446 while let (Some(try_borrow_inner_fn), Some(inner_shape)) = (
447 current_peek.shape.vtable.try_borrow_inner,
448 current_peek.shape.inner,
449 ) {
450 unsafe {
451 let inner_data = try_borrow_inner_fn(current_peek.data).unwrap_or_else(|e| {
452 panic!("innermost_peek: try_borrow_inner returned an error! was trying to go from {} to {}. error: {e}", current_peek.shape,
453 inner_shape)
454 });
455
456 current_peek = Peek {
457 data: inner_data,
458 shape: inner_shape,
459 invariant: PhantomData,
460 };
461 }
462 }
463 current_peek
464 }
465
466 #[cfg(feature = "alloc")]
471 pub fn custom_serialization(&self, field: Field) -> Result<OwnedPeek<'mem>, ReflectError> {
472 if let Some(serialize_with) = field.vtable.serialize_with {
473 let Some(&FieldAttribute::SerializeInto(target_shape)) = field
474 .attributes
475 .iter()
476 .find(|&p| matches!(p, FieldAttribute::SerializeInto(_)))
477 else {
478 panic!("expected field attribute to be present with deserialize_with");
479 };
480 let tptr = target_shape.allocate().map_err(|_| ReflectError::Unsized {
481 shape: target_shape,
482 operation: "Not a Sized type",
483 })?;
484 let ser_res = unsafe { serialize_with(self.data(), tptr) };
485 let err = match ser_res {
486 Ok(rptr) => {
487 if rptr.as_uninit() != tptr {
488 ReflectError::CustomSerializationError {
489 message: "serialize_with did not return the expected pointer".into(),
490 src_shape: self.shape,
491 dst_shape: target_shape,
492 }
493 } else {
494 return Ok(OwnedPeek {
495 shape: target_shape,
496 data: rptr,
497 });
498 }
499 }
500 Err(message) => ReflectError::CustomSerializationError {
501 message,
502 src_shape: self.shape,
503 dst_shape: target_shape,
504 },
505 };
506 unsafe {
508 target_shape.deallocate_uninit(tptr).unwrap()
510 };
511 Err(err)
512 } else {
513 Err(ReflectError::OperationFailed {
514 shape: self.shape,
515 operation: "field does not have a serialize_with function",
516 })
517 }
518 }
519}
520
521impl<'mem, 'facet> core::fmt::Display for Peek<'mem, 'facet> {
522 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
523 if let Some(display_fn) = self.vtable().display {
524 return unsafe { display_fn(self.data, f) };
525 }
526 write!(f, "⟨{}⟩", self.shape)
527 }
528}
529
530impl<'mem, 'facet> core::fmt::Debug for Peek<'mem, 'facet> {
531 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
532 if let Some(debug_fn) = self.vtable().debug {
533 return unsafe { debug_fn(self.data, f) };
534 }
535
536 write!(f, "⟨{}⟩", self.shape)
537 }
538}
539
540impl<'mem, 'facet> core::cmp::PartialEq for Peek<'mem, 'facet> {
541 #[inline]
542 fn eq(&self, other: &Self) -> bool {
543 self.partial_eq(other).unwrap_or(false)
544 }
545}
546
547impl<'mem, 'facet> core::cmp::PartialOrd for Peek<'mem, 'facet> {
548 #[inline]
549 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
550 self.partial_cmp(other).unwrap_or(None)
551 }
552}
553
554impl<'mem, 'facet> core::hash::Hash for Peek<'mem, 'facet> {
555 fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
556 self.hash(hasher)
557 .expect("Hashing is not supported for this shape");
558 }
559}