facet_reflect/poke/
value.rs1use core::marker::PhantomData;
2
3use facet_core::{Def, Facet, PtrConst, PtrMut, Shape, Type, UserType};
4
5use crate::ReflectError;
6
7use super::PokeStruct;
8
9pub struct Poke<'mem, 'facet> {
47 pub(crate) data: PtrMut,
49
50 pub(crate) shape: &'static Shape,
52
53 #[allow(clippy::type_complexity)]
56 _marker: PhantomData<(&'mem mut (), fn(&'facet ()) -> &'facet ())>,
57}
58
59impl<'mem, 'facet> Poke<'mem, 'facet> {
60 pub fn new<T: Facet<'facet>>(t: &'mem mut T) -> Self {
65 Self {
66 data: PtrMut::new(t as *mut T as *mut u8),
67 shape: T::SHAPE,
68 _marker: PhantomData,
69 }
70 }
71
72 pub unsafe fn from_raw_parts(data: PtrMut, shape: &'static Shape) -> Self {
79 Self {
80 data,
81 shape,
82 _marker: PhantomData,
83 }
84 }
85
86 #[inline(always)]
88 pub fn shape(&self) -> &'static Shape {
89 self.shape
90 }
91
92 #[inline(always)]
94 pub fn data(&self) -> PtrConst {
95 self.data.as_const()
96 }
97
98 #[inline(always)]
100 pub fn data_mut(&mut self) -> PtrMut {
101 self.data
102 }
103
104 #[inline]
106 pub fn is_struct(&self) -> bool {
107 matches!(self.shape.ty, Type::User(UserType::Struct(_)))
108 }
109
110 #[inline]
112 pub fn is_enum(&self) -> bool {
113 matches!(self.shape.ty, Type::User(UserType::Enum(_)))
114 }
115
116 #[inline]
118 pub fn is_scalar(&self) -> bool {
119 matches!(self.shape.def, Def::Scalar)
120 }
121
122 pub fn into_struct(self) -> Result<PokeStruct<'mem, 'facet>, ReflectError> {
124 match self.shape.ty {
125 Type::User(UserType::Struct(struct_type)) => Ok(PokeStruct {
126 value: self,
127 ty: struct_type,
128 }),
129 _ => Err(ReflectError::WasNotA {
130 expected: "struct",
131 actual: self.shape,
132 }),
133 }
134 }
135
136 pub fn into_enum(self) -> Result<super::PokeEnum<'mem, 'facet>, ReflectError> {
138 match self.shape.ty {
139 Type::User(UserType::Enum(enum_type)) => Ok(super::PokeEnum {
140 value: self,
141 ty: enum_type,
142 }),
143 _ => Err(ReflectError::WasNotA {
144 expected: "enum",
145 actual: self.shape,
146 }),
147 }
148 }
149
150 pub fn get<T: Facet<'facet>>(&self) -> Result<&T, ReflectError> {
154 if self.shape != T::SHAPE {
155 return Err(ReflectError::WrongShape {
156 expected: self.shape,
157 actual: T::SHAPE,
158 });
159 }
160 Ok(unsafe { self.data.as_const().get::<T>() })
161 }
162
163 pub fn get_mut<T: Facet<'facet>>(&mut self) -> Result<&mut T, ReflectError> {
167 if self.shape != T::SHAPE {
168 return Err(ReflectError::WrongShape {
169 expected: self.shape,
170 actual: T::SHAPE,
171 });
172 }
173 Ok(unsafe { self.data.as_mut::<T>() })
174 }
175
176 pub fn set<T: Facet<'facet>>(&mut self, value: T) -> Result<(), ReflectError> {
180 if self.shape != T::SHAPE {
181 return Err(ReflectError::WrongShape {
182 expected: self.shape,
183 actual: T::SHAPE,
184 });
185 }
186 unsafe {
187 self.shape.call_drop_in_place(self.data);
189 core::ptr::write(self.data.as_mut_byte_ptr() as *mut T, value);
190 }
191 Ok(())
192 }
193
194 #[inline]
196 pub fn as_peek(&self) -> crate::Peek<'_, 'facet> {
197 unsafe { crate::Peek::unchecked_new(self.data.as_const(), self.shape) }
198 }
199}
200
201impl core::fmt::Debug for Poke<'_, '_> {
202 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
203 write!(f, "Poke<{}>", self.shape)
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210
211 #[test]
212 fn poke_primitive_get_set() {
213 let mut x: i32 = 42;
214 let mut poke = Poke::new(&mut x);
215
216 assert_eq!(*poke.get::<i32>().unwrap(), 42);
217
218 poke.set(100i32).unwrap();
219 assert_eq!(x, 100);
220 }
221
222 #[test]
223 fn poke_primitive_get_mut() {
224 let mut x: i32 = 42;
225 let mut poke = Poke::new(&mut x);
226
227 *poke.get_mut::<i32>().unwrap() = 99;
228 assert_eq!(x, 99);
229 }
230
231 #[test]
232 fn poke_wrong_type_fails() {
233 let mut x: i32 = 42;
234 let poke = Poke::new(&mut x);
235
236 let result = poke.get::<u32>();
237 assert!(matches!(result, Err(ReflectError::WrongShape { .. })));
238 }
239
240 #[test]
241 fn poke_set_wrong_type_fails() {
242 let mut x: i32 = 42;
243 let mut poke = Poke::new(&mut x);
244
245 let result = poke.set(42u32);
246 assert!(matches!(result, Err(ReflectError::WrongShape { .. })));
247 }
248
249 #[test]
250 fn poke_string_drop_and_replace() {
251 let mut s = String::from("hello");
253 let mut poke = Poke::new(&mut s);
254
255 poke.set(String::from("world")).unwrap();
256 assert_eq!(s, "world");
257 }
258}