1use core::marker::PhantomData;
2
3use facet_core::{Def, Facet, PtrConst, PtrMut, Shape, StructKind, Type, UserType, Variance};
4use facet_path::{Path, PathAccessError, PathStep};
5
6use crate::{
7 ReflectError, ReflectErrorKind,
8 peek::{ListLikeDef, TupleType, VariantError},
9};
10
11use super::{
12 PokeDynamicValue, PokeList, PokeListLike, PokeMap, PokeNdArray, PokeOption, PokePointer,
13 PokeResult, PokeSet, PokeStruct, PokeTuple,
14};
15
16pub struct Poke<'mem, 'facet> {
54 pub(crate) data: PtrMut,
56
57 pub(crate) shape: &'static Shape,
59
60 #[allow(clippy::type_complexity)]
63 _marker: PhantomData<(&'mem mut (), fn(&'facet ()) -> &'facet ())>,
64}
65
66impl<'mem, 'facet> Poke<'mem, 'facet> {
67 pub fn new<T: Facet<'facet>>(t: &'mem mut T) -> Self {
72 Self {
73 data: PtrMut::new(t as *mut T as *mut u8),
74 shape: T::SHAPE,
75 _marker: PhantomData,
76 }
77 }
78
79 pub unsafe fn from_raw_parts(data: PtrMut, shape: &'static Shape) -> Self {
86 Self {
87 data,
88 shape,
89 _marker: PhantomData,
90 }
91 }
92
93 #[inline(always)]
95 pub const fn shape(&self) -> &'static Shape {
96 self.shape
97 }
98
99 #[inline(always)]
101 pub const fn data(&self) -> PtrConst {
102 self.data.as_const()
103 }
104
105 #[inline]
107 pub(crate) fn err(&self, kind: ReflectErrorKind) -> ReflectError {
108 ReflectError::new(kind, Path::new(self.shape))
109 }
110
111 #[inline(always)]
113 pub const fn data_mut(&mut self) -> PtrMut {
114 self.data
115 }
116
117 #[inline]
119 pub fn variance(&self) -> Variance {
120 self.shape.computed_variance()
121 }
122
123 #[inline]
131 pub fn try_reborrow<'shorter>(&mut self) -> Option<Poke<'_, 'shorter>>
132 where
133 'facet: 'shorter,
134 {
135 if self.variance().can_shrink() {
136 Some(Poke {
137 data: self.data,
138 shape: self.shape,
139 _marker: PhantomData,
140 })
141 } else {
142 None
143 }
144 }
145
146 #[inline]
148 pub const fn is_struct(&self) -> bool {
149 matches!(self.shape.ty, Type::User(UserType::Struct(_)))
150 }
151
152 #[inline]
154 pub const fn is_enum(&self) -> bool {
155 matches!(self.shape.ty, Type::User(UserType::Enum(_)))
156 }
157
158 #[inline]
160 pub const fn is_scalar(&self) -> bool {
161 matches!(self.shape.def, Def::Scalar)
162 }
163
164 #[inline]
169 pub const fn is_tuple(&self) -> bool {
170 matches!(
171 self.shape.ty,
172 Type::User(UserType::Struct(s)) if matches!(s.kind, StructKind::Tuple)
173 )
174 }
175
176 #[inline]
178 pub const fn is_list(&self) -> bool {
179 matches!(self.shape.def, Def::List(_))
180 }
181
182 #[inline]
184 pub const fn is_array(&self) -> bool {
185 matches!(self.shape.def, Def::Array(_))
186 }
187
188 #[inline]
190 pub const fn is_slice(&self) -> bool {
191 matches!(self.shape.def, Def::Slice(_))
192 }
193
194 #[inline]
197 pub const fn is_list_like(&self) -> bool {
198 matches!(self.shape.def, Def::List(_) | Def::Array(_) | Def::Slice(_))
199 }
200
201 #[inline]
203 pub const fn is_map(&self) -> bool {
204 matches!(self.shape.def, Def::Map(_))
205 }
206
207 #[inline]
209 pub const fn is_set(&self) -> bool {
210 matches!(self.shape.def, Def::Set(_))
211 }
212
213 #[inline]
215 pub const fn is_option(&self) -> bool {
216 matches!(self.shape.def, Def::Option(_))
217 }
218
219 #[inline]
221 pub const fn is_result(&self) -> bool {
222 matches!(self.shape.def, Def::Result(_))
223 }
224
225 #[inline]
227 pub const fn is_pointer(&self) -> bool {
228 matches!(self.shape.def, Def::Pointer(_))
229 }
230
231 #[inline]
233 pub const fn is_ndarray(&self) -> bool {
234 matches!(self.shape.def, Def::NdArray(_))
235 }
236
237 #[inline]
240 pub const fn is_dynamic_value(&self) -> bool {
241 matches!(self.shape.def, Def::DynamicValue(_))
242 }
243
244 pub fn into_struct(self) -> Result<PokeStruct<'mem, 'facet>, ReflectError> {
246 match self.shape.ty {
247 Type::User(UserType::Struct(struct_type)) => Ok(PokeStruct {
248 value: self,
249 ty: struct_type,
250 }),
251 _ => Err(self.err(ReflectErrorKind::WasNotA {
252 expected: "struct",
253 actual: self.shape,
254 })),
255 }
256 }
257
258 pub fn into_enum(self) -> Result<super::PokeEnum<'mem, 'facet>, ReflectError> {
260 match self.shape.ty {
261 Type::User(UserType::Enum(enum_type)) => Ok(super::PokeEnum {
262 value: self,
263 ty: enum_type,
264 }),
265 _ => Err(self.err(ReflectErrorKind::WasNotA {
266 expected: "enum",
267 actual: self.shape,
268 })),
269 }
270 }
271
272 #[inline]
274 pub fn into_list(self) -> Result<PokeList<'mem, 'facet>, ReflectError> {
275 if let Def::List(def) = self.shape.def {
276 return Ok(unsafe { PokeList::new(self, def) });
280 }
281
282 Err(self.err(ReflectErrorKind::WasNotA {
283 expected: "list",
284 actual: self.shape,
285 }))
286 }
287
288 #[inline]
290 pub fn into_list_like(self) -> Result<PokeListLike<'mem, 'facet>, ReflectError> {
291 match self.shape.def {
292 Def::List(def) => Ok(unsafe { PokeListLike::new(self, ListLikeDef::List(def)) }),
295 Def::Array(def) => Ok(unsafe { PokeListLike::new(self, ListLikeDef::Array(def)) }),
296 Def::Slice(def) => Ok(unsafe { PokeListLike::new(self, ListLikeDef::Slice(def)) }),
297 _ => Err(self.err(ReflectErrorKind::WasNotA {
298 expected: "list, array or slice",
299 actual: self.shape,
300 })),
301 }
302 }
303
304 #[inline]
306 pub fn into_map(self) -> Result<PokeMap<'mem, 'facet>, ReflectError> {
307 if let Def::Map(def) = self.shape.def {
308 return Ok(unsafe { PokeMap::new(self, def) });
309 }
310
311 Err(self.err(ReflectErrorKind::WasNotA {
312 expected: "map",
313 actual: self.shape,
314 }))
315 }
316
317 #[inline]
319 pub fn into_set(self) -> Result<PokeSet<'mem, 'facet>, ReflectError> {
320 if let Def::Set(def) = self.shape.def {
321 return Ok(unsafe { PokeSet::new(self, def) });
322 }
323
324 Err(self.err(ReflectErrorKind::WasNotA {
325 expected: "set",
326 actual: self.shape,
327 }))
328 }
329
330 #[inline]
332 pub fn into_option(self) -> Result<PokeOption<'mem, 'facet>, ReflectError> {
333 if let Def::Option(def) = self.shape.def {
334 return Ok(unsafe { PokeOption::new(self, def) });
335 }
336
337 Err(self.err(ReflectErrorKind::WasNotA {
338 expected: "option",
339 actual: self.shape,
340 }))
341 }
342
343 #[inline]
345 pub fn into_result(self) -> Result<PokeResult<'mem, 'facet>, ReflectError> {
346 if let Def::Result(def) = self.shape.def {
347 return Ok(unsafe { PokeResult::new(self, def) });
348 }
349
350 Err(self.err(ReflectErrorKind::WasNotA {
351 expected: "result",
352 actual: self.shape,
353 }))
354 }
355
356 #[inline]
358 pub fn into_tuple(self) -> Result<PokeTuple<'mem, 'facet>, ReflectError> {
359 if let Type::User(UserType::Struct(struct_type)) = self.shape.ty
360 && struct_type.kind == StructKind::Tuple
361 {
362 return Ok(PokeTuple {
363 value: self,
364 ty: TupleType {
365 fields: struct_type.fields,
366 },
367 });
368 }
369
370 Err(self.err(ReflectErrorKind::WasNotA {
371 expected: "tuple",
372 actual: self.shape,
373 }))
374 }
375
376 #[inline]
378 pub fn into_pointer(self) -> Result<PokePointer<'mem, 'facet>, ReflectError> {
379 if let Def::Pointer(def) = self.shape.def {
380 return Ok(PokePointer { value: self, def });
381 }
382
383 Err(self.err(ReflectErrorKind::WasNotA {
384 expected: "smart pointer",
385 actual: self.shape,
386 }))
387 }
388
389 #[inline]
391 pub fn into_ndarray(self) -> Result<PokeNdArray<'mem, 'facet>, ReflectError> {
392 if let Def::NdArray(def) = self.shape.def {
393 return Ok(unsafe { PokeNdArray::new(self, def) });
394 }
395
396 Err(self.err(ReflectErrorKind::WasNotA {
397 expected: "ndarray",
398 actual: self.shape,
399 }))
400 }
401
402 #[inline]
404 pub fn into_dynamic_value(self) -> Result<PokeDynamicValue<'mem, 'facet>, ReflectError> {
405 if let Def::DynamicValue(def) = self.shape.def {
406 return Ok(PokeDynamicValue { value: self, def });
407 }
408
409 Err(self.err(ReflectErrorKind::WasNotA {
410 expected: "dynamic value",
411 actual: self.shape,
412 }))
413 }
414
415 pub fn get<T: Facet<'facet>>(&self) -> Result<&T, ReflectError> {
419 if self.shape != T::SHAPE {
420 return Err(self.err(ReflectErrorKind::WrongShape {
421 expected: self.shape,
422 actual: T::SHAPE,
423 }));
424 }
425 Ok(unsafe { self.data.as_const().get::<T>() })
426 }
427
428 pub fn get_mut<T: Facet<'facet>>(&mut self) -> Result<&mut T, ReflectError> {
432 if self.shape != T::SHAPE {
433 return Err(self.err(ReflectErrorKind::WrongShape {
434 expected: self.shape,
435 actual: T::SHAPE,
436 }));
437 }
438 Ok(unsafe { self.data.as_mut::<T>() })
439 }
440
441 pub fn set<T: Facet<'facet>>(&mut self, value: T) -> Result<(), ReflectError> {
445 if self.shape != T::SHAPE {
446 return Err(self.err(ReflectErrorKind::WrongShape {
447 expected: self.shape,
448 actual: T::SHAPE,
449 }));
450 }
451 unsafe {
452 self.shape.call_drop_in_place(self.data);
454 core::ptr::write(self.data.as_mut_byte_ptr() as *mut T, value);
455 }
456 Ok(())
457 }
458
459 #[inline]
461 pub fn as_peek(&self) -> crate::Peek<'_, 'facet> {
462 unsafe { crate::Peek::unchecked_new(self.data.as_const(), self.shape) }
463 }
464
465 #[inline]
467 pub fn into_peek(self) -> crate::Peek<'mem, 'facet> {
468 unsafe { crate::Peek::unchecked_new(self.data.as_const(), self.shape) }
469 }
470
471 pub fn at_path_mut(self, path: &Path) -> Result<Poke<'mem, 'facet>, PathAccessError> {
496 if self.shape != path.shape {
497 return Err(PathAccessError::RootShapeMismatch {
498 expected: path.shape,
499 actual: self.shape,
500 });
501 }
502
503 let mut data = self.data;
504 let mut shape: &'static Shape = self.shape;
505
506 for (step_index, step) in path.steps().iter().enumerate() {
507 let (new_data, new_shape) = apply_step_mut(data, shape, *step, step_index)?;
508 data = new_data;
509 shape = new_shape;
510 }
511
512 Ok(unsafe { Poke::from_raw_parts(data, shape) })
513 }
514}
515
516fn apply_step_mut(
521 data: PtrMut,
522 shape: &'static Shape,
523 step: PathStep,
524 step_index: usize,
525) -> Result<(PtrMut, &'static Shape), PathAccessError> {
526 match step {
527 PathStep::Field(idx) => {
528 let idx = idx as usize;
529 match shape.ty {
530 Type::User(UserType::Struct(sd)) => {
531 if idx >= sd.fields.len() {
532 return Err(PathAccessError::IndexOutOfBounds {
533 step,
534 step_index,
535 shape,
536 index: idx,
537 bound: sd.fields.len(),
538 });
539 }
540 let field = &sd.fields[idx];
541 let field_data = unsafe { data.field(field.offset) };
542 Ok((field_data, field.shape()))
543 }
544 Type::User(UserType::Enum(enum_type)) => {
545 let variant_idx = variant_index_from_raw(data.as_const(), shape, enum_type)
547 .map_err(|_| PathAccessError::WrongStepKind {
548 step,
549 step_index,
550 shape,
551 })?;
552 let variant = &enum_type.variants[variant_idx];
553 if idx >= variant.data.fields.len() {
554 return Err(PathAccessError::IndexOutOfBounds {
555 step,
556 step_index,
557 shape,
558 index: idx,
559 bound: variant.data.fields.len(),
560 });
561 }
562 let field = &variant.data.fields[idx];
563 let field_data = unsafe { data.field(field.offset) };
564 Ok((field_data, field.shape()))
565 }
566 _ => Err(PathAccessError::WrongStepKind {
567 step,
568 step_index,
569 shape,
570 }),
571 }
572 }
573
574 PathStep::Variant(expected_idx) => {
575 let expected_idx = expected_idx as usize;
576 let enum_type = match shape.ty {
577 Type::User(UserType::Enum(et)) => et,
578 _ => {
579 return Err(PathAccessError::WrongStepKind {
580 step,
581 step_index,
582 shape,
583 });
584 }
585 };
586
587 if expected_idx >= enum_type.variants.len() {
588 return Err(PathAccessError::IndexOutOfBounds {
589 step,
590 step_index,
591 shape,
592 index: expected_idx,
593 bound: enum_type.variants.len(),
594 });
595 }
596
597 let actual_idx =
598 variant_index_from_raw(data.as_const(), shape, enum_type).map_err(|_| {
599 PathAccessError::WrongStepKind {
600 step,
601 step_index,
602 shape,
603 }
604 })?;
605
606 if actual_idx != expected_idx {
607 return Err(PathAccessError::VariantMismatch {
608 step_index,
609 shape,
610 expected_variant: expected_idx,
611 actual_variant: actual_idx,
612 });
613 }
614
615 Ok((data, shape))
617 }
618
619 PathStep::Index(idx) => {
620 let idx = idx as usize;
621 match shape.def {
622 Def::List(def) => {
623 let get_mut_fn = def.vtable.get_mut.ok_or(PathAccessError::WrongStepKind {
624 step,
625 step_index,
626 shape,
627 })?;
628 let len = unsafe { (def.vtable.len)(data.as_const()) };
629 let item = unsafe { get_mut_fn(data, idx, shape) };
630 item.map(|ptr| (ptr, def.t()))
631 .ok_or(PathAccessError::IndexOutOfBounds {
632 step,
633 step_index,
634 shape,
635 index: idx,
636 bound: len,
637 })
638 }
639 Def::Array(def) => {
640 let elem_shape = def.t();
642 let layout = elem_shape.layout.sized_layout().map_err(|_| {
643 PathAccessError::WrongStepKind {
644 step,
645 step_index,
646 shape,
647 }
648 })?;
649 let len = def.n;
650 if idx >= len {
651 return Err(PathAccessError::IndexOutOfBounds {
652 step,
653 step_index,
654 shape,
655 index: idx,
656 bound: len,
657 });
658 }
659 let elem_data = unsafe { data.field(layout.size() * idx) };
660 Ok((elem_data, elem_shape))
661 }
662 _ => Err(PathAccessError::WrongStepKind {
663 step,
664 step_index,
665 shape,
666 }),
667 }
668 }
669
670 PathStep::OptionSome => {
671 if let Def::Option(option_def) = shape.def {
672 let is_some = unsafe { (option_def.vtable.is_some)(data.as_const()) };
674 if !is_some {
675 return Err(PathAccessError::OptionIsNone { step_index, shape });
676 }
677 let inner_raw_ptr = unsafe { (option_def.vtable.get_value)(data.as_const()) };
681 assert!(
682 !inner_raw_ptr.is_null(),
683 "is_some was true but get_value returned null"
684 );
685 let inner_ptr_const = facet_core::PtrConst::new_sized(inner_raw_ptr);
686 let offset = unsafe {
688 inner_ptr_const
689 .as_byte_ptr()
690 .offset_from(data.as_const().as_byte_ptr())
691 } as usize;
692 let inner_data = unsafe { data.field(offset) };
693 Ok((inner_data, option_def.t()))
694 } else {
695 Err(PathAccessError::WrongStepKind {
696 step,
697 step_index,
698 shape,
699 })
700 }
701 }
702
703 PathStep::MapKey(_) | PathStep::MapValue(_) => {
704 if matches!(shape.def, Def::Map(_)) {
705 Err(PathAccessError::MissingTarget {
706 step,
707 step_index,
708 shape,
709 })
710 } else {
711 Err(PathAccessError::WrongStepKind {
712 step,
713 step_index,
714 shape,
715 })
716 }
717 }
718
719 PathStep::Deref => {
720 if matches!(shape.def, Def::Pointer(_)) {
721 Err(PathAccessError::MissingTarget {
722 step,
723 step_index,
724 shape,
725 })
726 } else {
727 Err(PathAccessError::WrongStepKind {
728 step,
729 step_index,
730 shape,
731 })
732 }
733 }
734
735 PathStep::Inner => Err(PathAccessError::MissingTarget {
736 step,
737 step_index,
738 shape,
739 }),
740
741 PathStep::Proxy => Err(PathAccessError::MissingTarget {
742 step,
743 step_index,
744 shape,
745 }),
746 }
747}
748
749fn variant_index_from_raw(
752 data: PtrConst,
753 shape: &'static Shape,
754 enum_type: facet_core::EnumType,
755) -> Result<usize, VariantError> {
756 use facet_core::EnumRepr;
757
758 if let Def::Option(option_def) = shape.def {
760 let is_some = unsafe { (option_def.vtable.is_some)(data) };
761 return Ok(enum_type
762 .variants
763 .iter()
764 .position(|variant| {
765 let has_fields = !variant.data.fields.is_empty();
766 has_fields == is_some
767 })
768 .expect("No variant found matching Option state"));
769 }
770
771 if enum_type.enum_repr == EnumRepr::RustNPO {
772 let layout = shape
773 .layout
774 .sized_layout()
775 .map_err(|_| VariantError::Unsized)?;
776 let slice = unsafe { core::slice::from_raw_parts(data.as_byte_ptr(), layout.size()) };
777 let all_zero = slice.iter().all(|v| *v == 0);
778
779 Ok(enum_type
780 .variants
781 .iter()
782 .position(|variant| {
783 let mut max_offset = 0;
784 for field in variant.data.fields {
785 let offset = field.offset
786 + field
787 .shape()
788 .layout
789 .sized_layout()
790 .map(|v| v.size())
791 .unwrap_or(0);
792 max_offset = core::cmp::max(max_offset, offset);
793 }
794 if all_zero {
795 max_offset == 0
796 } else {
797 max_offset != 0
798 }
799 })
800 .expect("No variant found with matching discriminant"))
801 } else {
802 let discriminant = match enum_type.enum_repr {
803 EnumRepr::Rust => {
804 panic!("cannot read discriminant from Rust enum with unspecified layout")
805 }
806 EnumRepr::RustNPO => 0,
807 EnumRepr::U8 => unsafe { data.read::<u8>() as i64 },
808 EnumRepr::U16 => unsafe { data.read::<u16>() as i64 },
809 EnumRepr::U32 => unsafe { data.read::<u32>() as i64 },
810 EnumRepr::U64 => unsafe { data.read::<u64>() as i64 },
811 EnumRepr::USize => unsafe { data.read::<usize>() as i64 },
812 EnumRepr::I8 => unsafe { data.read::<i8>() as i64 },
813 EnumRepr::I16 => unsafe { data.read::<i16>() as i64 },
814 EnumRepr::I32 => unsafe { data.read::<i32>() as i64 },
815 EnumRepr::I64 => unsafe { data.read::<i64>() },
816 EnumRepr::ISize => unsafe { data.read::<isize>() as i64 },
817 };
818
819 Ok(enum_type
820 .variants
821 .iter()
822 .position(|variant| variant.discriminant == Some(discriminant))
823 .expect("No variant found with matching discriminant"))
824 }
825}
826
827impl core::fmt::Debug for Poke<'_, '_> {
828 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
829 write!(f, "Poke<{}>", self.shape)
830 }
831}
832
833#[cfg(test)]
834mod tests {
835 use super::*;
836
837 #[test]
838 fn poke_primitive_get_set() {
839 let mut x: i32 = 42;
840 let mut poke = Poke::new(&mut x);
841
842 assert_eq!(*poke.get::<i32>().unwrap(), 42);
843
844 poke.set(100i32).unwrap();
845 assert_eq!(x, 100);
846 }
847
848 #[test]
849 fn poke_primitive_get_mut() {
850 let mut x: i32 = 42;
851 let mut poke = Poke::new(&mut x);
852
853 *poke.get_mut::<i32>().unwrap() = 99;
854 assert_eq!(x, 99);
855 }
856
857 #[test]
858 fn poke_wrong_type_fails() {
859 let mut x: i32 = 42;
860 let poke = Poke::new(&mut x);
861
862 let result = poke.get::<u32>();
863 assert!(matches!(
864 result,
865 Err(ReflectError {
866 kind: ReflectErrorKind::WrongShape { .. },
867 ..
868 })
869 ));
870 }
871
872 #[test]
873 fn poke_set_wrong_type_fails() {
874 let mut x: i32 = 42;
875 let mut poke = Poke::new(&mut x);
876
877 let result = poke.set(42u32);
878 assert!(matches!(
879 result,
880 Err(ReflectError {
881 kind: ReflectErrorKind::WrongShape { .. },
882 ..
883 })
884 ));
885 }
886
887 #[test]
888 fn poke_string_drop_and_replace() {
889 let mut s = String::from("hello");
891 let mut poke = Poke::new(&mut s);
892
893 poke.set(String::from("world")).unwrap();
894 assert_eq!(s, "world");
895 }
896
897 #[test]
898 fn poke_is_predicates() {
899 let mut v: alloc::vec::Vec<i32> = alloc::vec![1, 2, 3];
900 let poke = Poke::new(&mut v);
901 assert!(poke.is_list());
902 assert!(poke.is_list_like());
903 assert!(!poke.is_map());
904 assert!(!poke.is_set());
905 assert!(!poke.is_option());
906 assert!(!poke.is_result());
907 assert!(!poke.is_tuple());
908 assert!(!poke.is_scalar());
909
910 let mut x: Option<i32> = Some(1);
911 let poke = Poke::new(&mut x);
912 assert!(poke.is_option());
913 assert!(!poke.is_list());
914
915 let mut r: Result<i32, i32> = Ok(1);
916 let poke = Poke::new(&mut r);
917 assert!(poke.is_result());
918
919 let mut t: (i32, i32) = (1, 2);
920 let poke = Poke::new(&mut t);
921 assert!(poke.is_tuple());
922
923 let mut n: i32 = 42;
924 let poke = Poke::new(&mut n);
925 assert!(poke.is_scalar());
926
927 let mut a: [i32; 3] = [1, 2, 3];
928 let poke = Poke::new(&mut a);
929 assert!(poke.is_array());
930 assert!(poke.is_list_like());
931 }
932}