1use core::{cmp::Ordering, marker::PhantomData};
2use facet_core::{
3 Def, Facet, PointerType, PtrConst, PtrMut, Shape, StructKind, Type, TypeNameOpts, UserType,
4 ValueVTable,
5};
6
7use crate::{ReflectError, ScalarType};
8
9use super::{
10 ListLikeDef, PeekEnum, PeekList, PeekListLike, PeekMap, PeekSmartPointer, PeekStruct,
11 PeekTuple, tuple::TupleType,
12};
13
14#[derive(Clone, Copy, PartialEq, Eq, Hash)]
16pub struct ValueId<'shape> {
17 pub(crate) shape: &'shape Shape<'shape>,
18 pub(crate) ptr: *const u8,
19}
20
21impl<'shape> ValueId<'shape> {
22 pub(crate) fn new(shape: &'shape Shape<'shape>, ptr: *const u8) -> Self {
23 Self { shape, ptr }
24 }
25}
26
27impl core::fmt::Display for ValueId<'_> {
28 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
29 write!(f, "{}@{:p}", self.shape, self.ptr)
30 }
31}
32
33impl core::fmt::Debug for ValueId<'_> {
34 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
35 core::fmt::Display::fmt(self, f)
36 }
37}
38
39#[derive(Clone, Copy)]
41pub struct Peek<'mem, 'facet, 'shape> {
42 pub(crate) data: PtrConst<'mem>,
44
45 pub(crate) shape: &'shape Shape<'shape>,
47
48 invariant: PhantomData<fn(&'facet ()) -> &'facet ()>,
49}
50
51impl<'mem, 'facet, 'shape> Peek<'mem, 'facet, 'shape> {
52 pub fn new<T: Facet<'facet>>(t: &'mem T) -> Self {
54 Self {
55 data: PtrConst::new(t as *const T),
56 shape: T::SHAPE,
57 invariant: PhantomData,
58 }
59 }
60
61 pub unsafe fn unchecked_new(data: PtrConst<'mem>, shape: &'shape Shape<'shape>) -> Self {
69 Self {
70 data,
71 shape,
72 invariant: PhantomData,
73 }
74 }
75
76 #[inline(always)]
78 pub fn vtable(&self) -> &'shape ValueVTable {
79 self.shape.vtable
80 }
81
82 pub fn id(&self) -> ValueId<'shape> {
84 ValueId::new(self.shape, self.data.as_byte_ptr())
85 }
86
87 #[inline]
89 pub fn ptr_eq(&self, other: &Peek<'_, '_, '_>) -> bool {
90 self.data.as_byte_ptr() == other.data.as_byte_ptr()
91 }
92
93 #[inline]
99 pub fn partial_eq(&self, other: &Peek<'_, '_, '_>) -> Option<bool> {
100 unsafe { (self.shape.vtable.partial_eq)().map(|eq_fn| eq_fn(self.data, other.data)) }
101 }
102
103 #[inline]
109 pub fn partial_cmp(&self, other: &Peek<'_, '_, '_>) -> Option<Ordering> {
110 unsafe {
111 (self.shape.vtable.partial_ord)()
112 .and_then(|partial_ord_fn| partial_ord_fn(self.data, other.data))
113 }
114 }
115
116 #[inline(always)]
122 pub fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) -> bool {
123 unsafe {
124 if let Some(hash_fn) = (self.shape.vtable.hash)() {
125 let hasher_opaque = PtrMut::new(hasher);
126 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
127 opaque.as_mut::<H>().write(bytes)
128 });
129 true
130 } else {
131 false
132 }
133 }
134 }
135
136 #[inline(always)]
147 pub fn type_name(
148 &self,
149 f: &mut core::fmt::Formatter<'_>,
150 opts: TypeNameOpts,
151 ) -> core::fmt::Result {
152 (self.shape.vtable.type_name)(f, opts)
153 }
154
155 #[inline(always)]
157 pub const fn shape(&self) -> &'shape Shape<'shape> {
158 self.shape
159 }
160
161 #[inline(always)]
163 pub const fn data(&self) -> PtrConst<'mem> {
164 self.data
165 }
166
167 pub fn scalar_type(&self) -> Option<ScalarType> {
169 ScalarType::try_from_shape(self.shape)
170 }
171
172 pub fn get<T: Facet<'facet>>(&self) -> Result<&T, ReflectError<'shape>> {
178 if self.shape != T::SHAPE {
179 Err(ReflectError::WrongShape {
180 expected: self.shape,
181 actual: T::SHAPE,
182 })
183 } else {
184 Ok(unsafe { self.data.get::<T>() })
185 }
186 }
187
188 pub fn as_str(&self) -> Option<&'mem str> {
191 let peek = self.innermost_peek();
192 if let Some(ScalarType::Str) = peek.scalar_type() {
193 unsafe { Some(peek.data.get::<&str>()) }
194 } else if let Some(ScalarType::String) = peek.scalar_type() {
195 unsafe { Some(peek.data.get::<alloc::string::String>().as_str()) }
196 } else if let Type::Pointer(PointerType::Reference(vpt)) = peek.shape.ty {
197 let target_shape = (vpt.target)();
198 if let Some(ScalarType::Str) = ScalarType::try_from_shape(target_shape) {
199 unsafe { Some(peek.data.get::<&str>()) }
200 } else {
201 None
202 }
203 } else {
204 None
205 }
206 }
207
208 pub fn as_bytes(&self) -> Option<&'mem [u8]> {
211 if let Type::Pointer(PointerType::Reference(vpt)) = self.shape.ty {
213 let target_shape = (vpt.target)();
214 if let Def::Slice(sd) = target_shape.def {
215 if sd.t().is_type::<u8>() {
216 unsafe { return Some(self.data.get::<&[u8]>()) }
217 }
218 }
219 }
220 None
221 }
222
223 pub fn into_struct(self) -> Result<PeekStruct<'mem, 'facet, 'shape>, ReflectError<'shape>> {
225 if let Type::User(UserType::Struct(ty)) = self.shape.ty {
226 Ok(PeekStruct { value: self, ty })
227 } else {
228 Err(ReflectError::WasNotA {
229 expected: "struct",
230 actual: self.shape,
231 })
232 }
233 }
234
235 pub fn into_enum(self) -> Result<PeekEnum<'mem, 'facet, 'shape>, ReflectError<'shape>> {
237 if let Type::User(UserType::Enum(ty)) = self.shape.ty {
238 Ok(PeekEnum { value: self, ty })
239 } else {
240 Err(ReflectError::WasNotA {
241 expected: "enum",
242 actual: self.shape,
243 })
244 }
245 }
246
247 pub fn into_map(self) -> Result<PeekMap<'mem, 'facet, 'shape>, ReflectError<'shape>> {
249 if let Def::Map(def) = self.shape.def {
250 Ok(PeekMap { value: self, def })
251 } else {
252 Err(ReflectError::WasNotA {
253 expected: "map",
254 actual: self.shape,
255 })
256 }
257 }
258
259 pub fn into_list(self) -> Result<PeekList<'mem, 'facet, 'shape>, ReflectError<'shape>> {
261 if let Def::List(def) = self.shape.def {
262 return Ok(PeekList { value: self, def });
263 }
264
265 Err(ReflectError::WasNotA {
266 expected: "list",
267 actual: self.shape,
268 })
269 }
270
271 pub fn into_list_like(
273 self,
274 ) -> Result<PeekListLike<'mem, 'facet, 'shape>, ReflectError<'shape>> {
275 match self.shape.def {
276 Def::List(def) => Ok(PeekListLike::new(self, ListLikeDef::List(def))),
277 Def::Array(def) => Ok(PeekListLike::new(self, ListLikeDef::Array(def))),
278 _ => {
279 match self.shape.ty {
281 Type::Pointer(ptr) => match ptr {
282 PointerType::Reference(vpt) | PointerType::Raw(vpt) => {
283 let target = (vpt.target)();
284 match target.def {
285 Def::Slice(def) => {
286 return Ok(PeekListLike::new(self, ListLikeDef::Slice(def)));
287 }
288 _ => {
289 }
291 }
292 }
293 PointerType::Function(_) => {
294 }
296 },
297 _ => {
298 }
300 }
301
302 Err(ReflectError::WasNotA {
303 expected: "list, array or slice",
304 actual: self.shape,
305 })
306 }
307 }
308 }
309
310 pub fn into_smart_pointer(
312 self,
313 ) -> Result<PeekSmartPointer<'mem, 'facet, 'shape>, ReflectError<'shape>> {
314 if let Def::SmartPointer(def) = self.shape.def {
315 Ok(PeekSmartPointer { value: self, def })
316 } else {
317 Err(ReflectError::WasNotA {
318 expected: "smart pointer",
319 actual: self.shape,
320 })
321 }
322 }
323
324 pub fn into_option(
326 self,
327 ) -> Result<super::PeekOption<'mem, 'facet, 'shape>, ReflectError<'shape>> {
328 if let Def::Option(def) = self.shape.def {
329 Ok(super::PeekOption { value: self, def })
330 } else {
331 Err(ReflectError::WasNotA {
332 expected: "option",
333 actual: self.shape,
334 })
335 }
336 }
337
338 pub fn into_tuple(self) -> Result<PeekTuple<'mem, 'facet, 'shape>, ReflectError<'shape>> {
340 if let Type::User(UserType::Struct(struct_type)) = self.shape.ty {
341 if struct_type.kind == StructKind::Tuple {
342 Ok(PeekTuple {
343 value: self,
344 ty: TupleType {
345 fields: struct_type.fields,
346 },
347 })
348 } else {
349 Err(ReflectError::WasNotA {
350 expected: "tuple",
351 actual: self.shape,
352 })
353 }
354 } else {
355 Err(ReflectError::WasNotA {
356 expected: "tuple",
357 actual: self.shape,
358 })
359 }
360 }
361
362 pub fn innermost_peek(self) -> Self {
368 let mut current_peek = self;
369 while let (Some(try_borrow_inner_fn), Some(inner_shape)) = (
370 (current_peek.shape.vtable.try_borrow_inner)(),
371 current_peek.shape.inner,
372 ) {
373 unsafe {
374 let inner_data = try_borrow_inner_fn(current_peek.data).unwrap_or_else(|e| {
375 panic!("innermost_peek: try_borrow_inner returned an error! was trying to go from {} to {}. error: {e}", current_peek.shape,
376 inner_shape())
377 });
378
379 current_peek = Peek {
380 data: inner_data,
381 shape: inner_shape(),
382 invariant: PhantomData,
383 };
384 }
385 }
386 current_peek
387 }
388}
389
390impl<'mem, 'facet, 'shape> core::fmt::Display for Peek<'mem, 'facet, 'shape> {
391 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
392 if let Some(display_fn) = (self.vtable().display)() {
393 unsafe { display_fn(self.data, f) }
394 } else {
395 write!(f, "⟨{}⟩", self.shape)
396 }
397 }
398}
399
400impl<'mem, 'facet, 'shape> core::fmt::Debug for Peek<'mem, 'facet, 'shape> {
401 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
402 if let Some(debug_fn) = (self.vtable().debug)() {
403 unsafe { debug_fn(self.data, f) }
404 } else {
405 write!(f, "⟨{}⟩", self.shape)
406 }
407 }
408}
409
410impl<'mem, 'facet, 'shape> core::cmp::PartialEq for Peek<'mem, 'facet, 'shape> {
411 fn eq(&self, other: &Self) -> bool {
412 if self.shape != other.shape {
413 return false;
414 }
415 let eq_fn = match (self.shape.vtable.partial_eq)() {
416 Some(eq_fn) => eq_fn,
417 None => return false,
418 };
419 unsafe { eq_fn(self.data, other.data) }
420 }
421}
422
423impl<'mem, 'facet, 'shape> core::cmp::PartialOrd for Peek<'mem, 'facet, 'shape> {
424 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
425 if self.shape != other.shape {
426 return None;
427 }
428 let partial_ord_fn = (self.shape.vtable.partial_ord)()?;
429 unsafe { partial_ord_fn(self.data, other.data) }
430 }
431}
432
433impl<'mem, 'facet, 'shape> core::hash::Hash for Peek<'mem, 'facet, 'shape> {
434 fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
435 if let Some(hash_fn) = (self.shape.vtable.hash)() {
436 let hasher_opaque = PtrMut::new(hasher);
437 unsafe {
438 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
439 opaque.as_mut::<H>().write(bytes)
440 })
441 };
442 } else {
443 panic!("Hashing is not supported for this shape");
444 }
445 }
446}