1use core::{cmp::Ordering, marker::PhantomData};
2use facet_core::{
3 Def, Facet, PointerType, PtrConst, PtrMut, SequenceType, Shape, Type, TypeNameOpts, UserType,
4 ValueVTable,
5};
6
7use crate::{ReflectError, ScalarType};
8
9use super::{
10 ListLikeDef, PeekEnum, PeekList, PeekListLike, PeekMap, PeekSmartPointer, PeekStruct, PeekTuple,
11};
12
13#[derive(Clone, Copy, PartialEq, Eq, Hash)]
15pub struct ValueId<'shape> {
16 pub(crate) shape: &'shape Shape<'shape>,
17 pub(crate) ptr: *const u8,
18}
19
20impl<'shape> ValueId<'shape> {
21 pub(crate) fn new(shape: &'shape Shape<'shape>, ptr: *const u8) -> Self {
22 Self { shape, ptr }
23 }
24}
25
26impl core::fmt::Display for ValueId<'_> {
27 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
28 write!(f, "{}@{:p}", self.shape, self.ptr)
29 }
30}
31
32impl core::fmt::Debug for ValueId<'_> {
33 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
34 core::fmt::Display::fmt(self, f)
35 }
36}
37
38#[derive(Clone, Copy)]
40pub struct Peek<'mem, 'facet, 'shape> {
41 pub(crate) data: PtrConst<'mem>,
43
44 pub(crate) shape: &'shape Shape<'shape>,
46
47 invariant: PhantomData<fn(&'facet ()) -> &'facet ()>,
48}
49
50impl<'mem, 'facet, 'shape> Peek<'mem, 'facet, 'shape> {
51 pub fn new<T: Facet<'facet>>(t: &'mem T) -> Self {
53 Self {
54 data: PtrConst::new(t as *const T),
55 shape: T::SHAPE,
56 invariant: PhantomData,
57 }
58 }
59
60 pub unsafe fn unchecked_new(data: PtrConst<'mem>, shape: &'shape Shape<'shape>) -> Self {
68 Self {
69 data,
70 shape,
71 invariant: PhantomData,
72 }
73 }
74
75 #[inline(always)]
77 pub fn vtable(&self) -> &'shape ValueVTable {
78 self.shape.vtable
79 }
80
81 pub fn id(&self) -> ValueId<'shape> {
83 ValueId::new(self.shape, self.data.as_byte_ptr())
84 }
85
86 #[inline]
88 pub fn ptr_eq(&self, other: &Peek<'_, '_, '_>) -> bool {
89 self.data.as_byte_ptr() == other.data.as_byte_ptr()
90 }
91
92 #[inline]
98 pub fn eq(&self, other: &Peek<'_, '_, '_>) -> Option<bool> {
99 unsafe {
100 self.shape
101 .vtable
102 .eq
103 .map(|eq_fn| eq_fn(self.data, other.data))
104 }
105 }
106
107 #[inline]
113 pub fn partial_cmp(&self, other: &Peek<'_, '_, '_>) -> Option<Ordering> {
114 unsafe {
115 self.shape
116 .vtable
117 .partial_ord
118 .and_then(|partial_ord_fn| partial_ord_fn(self.data, other.data))
119 }
120 }
121
122 #[inline(always)]
128 pub fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) -> bool {
129 unsafe {
130 if let Some(hash_fn) = self.shape.vtable.hash {
131 let hasher_opaque = PtrMut::new(hasher);
132 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
133 opaque.as_mut::<H>().write(bytes)
134 });
135 true
136 } else {
137 false
138 }
139 }
140 }
141
142 #[inline(always)]
153 pub fn type_name(
154 &self,
155 f: &mut core::fmt::Formatter<'_>,
156 opts: TypeNameOpts,
157 ) -> core::fmt::Result {
158 (self.shape.vtable.type_name)(f, opts)
159 }
160
161 #[inline(always)]
163 pub const fn shape(&self) -> &'shape Shape<'shape> {
164 self.shape
165 }
166
167 #[inline(always)]
169 pub const fn data(&self) -> PtrConst<'mem> {
170 self.data
171 }
172
173 pub fn scalar_type(&self) -> Option<ScalarType> {
175 ScalarType::try_from_shape(self.shape)
176 }
177
178 pub fn get<T: Facet<'facet>>(&self) -> Result<&T, ReflectError<'shape>> {
184 if self.shape != T::SHAPE {
185 Err(ReflectError::WrongShape {
186 expected: self.shape,
187 actual: T::SHAPE,
188 })
189 } else {
190 Ok(unsafe { self.data.get::<T>() })
191 }
192 }
193
194 pub fn as_str(&self) -> Option<&'mem str> {
197 let peek = self.innermost_peek();
198 if let Some(ScalarType::Str) = peek.scalar_type() {
199 unsafe { Some(peek.data.get::<&str>()) }
200 } else if let Some(ScalarType::String) = peek.scalar_type() {
201 unsafe { Some(peek.data.get::<alloc::string::String>().as_str()) }
202 } else if let Type::Pointer(PointerType::Reference(vpt)) = peek.shape.ty {
203 let target_shape = (vpt.target)();
204 if let Some(ScalarType::Str) = ScalarType::try_from_shape(target_shape) {
205 unsafe { Some(peek.data.get::<&str>()) }
206 } else {
207 None
208 }
209 } else {
210 None
211 }
212 }
213
214 pub fn into_struct(self) -> Result<PeekStruct<'mem, 'facet, 'shape>, ReflectError<'shape>> {
216 if let Type::User(UserType::Struct(ty)) = self.shape.ty {
217 Ok(PeekStruct { value: self, ty })
218 } else {
219 Err(ReflectError::WasNotA {
220 expected: "struct",
221 actual: self.shape,
222 })
223 }
224 }
225
226 pub fn into_enum(self) -> Result<PeekEnum<'mem, 'facet, 'shape>, ReflectError<'shape>> {
228 if let Type::User(UserType::Enum(ty)) = self.shape.ty {
229 Ok(PeekEnum { value: self, ty })
230 } else {
231 Err(ReflectError::WasNotA {
232 expected: "enum",
233 actual: self.shape,
234 })
235 }
236 }
237
238 pub fn into_map(self) -> Result<PeekMap<'mem, 'facet, 'shape>, ReflectError<'shape>> {
240 if let Def::Map(def) = self.shape.def {
241 Ok(PeekMap { value: self, def })
242 } else {
243 Err(ReflectError::WasNotA {
244 expected: "map",
245 actual: self.shape,
246 })
247 }
248 }
249
250 pub fn into_list(self) -> Result<PeekList<'mem, 'facet, 'shape>, ReflectError<'shape>> {
252 if let Def::List(def) = self.shape.def {
253 return Ok(PeekList { value: self, def });
254 }
255
256 Err(ReflectError::WasNotA {
257 expected: "list",
258 actual: self.shape,
259 })
260 }
261
262 pub fn into_list_like(
264 self,
265 ) -> Result<PeekListLike<'mem, 'facet, 'shape>, ReflectError<'shape>> {
266 match self.shape.def {
267 Def::List(def) => Ok(PeekListLike::new(self, ListLikeDef::List(def))),
268 Def::Array(def) => Ok(PeekListLike::new(self, ListLikeDef::Array(def))),
269 _ => {
270 match self.shape.ty {
272 Type::Pointer(ptr) => match ptr {
273 PointerType::Reference(vpt) | PointerType::Raw(vpt) => {
274 let target = (vpt.target)();
275 match target.def {
276 Def::Slice(def) => {
277 return Ok(PeekListLike::new(self, ListLikeDef::Slice(def)));
278 }
279 _ => {
280 }
282 }
283 }
284 PointerType::Function(_) => {
285 }
287 },
288 _ => {
289 }
291 }
292
293 Err(ReflectError::WasNotA {
294 expected: "list, array or slice",
295 actual: self.shape,
296 })
297 }
298 }
299 }
300
301 pub fn into_smart_pointer(
303 self,
304 ) -> Result<PeekSmartPointer<'mem, 'facet, 'shape>, ReflectError<'shape>> {
305 if let Def::SmartPointer(def) = self.shape.def {
306 Ok(PeekSmartPointer { value: self, def })
307 } else {
308 Err(ReflectError::WasNotA {
309 expected: "smart pointer",
310 actual: self.shape,
311 })
312 }
313 }
314
315 pub fn into_option(
317 self,
318 ) -> Result<super::PeekOption<'mem, 'facet, 'shape>, ReflectError<'shape>> {
319 if let Def::Option(def) = self.shape.def {
320 Ok(super::PeekOption { value: self, def })
321 } else {
322 Err(ReflectError::WasNotA {
323 expected: "option",
324 actual: self.shape,
325 })
326 }
327 }
328
329 pub fn into_tuple(self) -> Result<PeekTuple<'mem, 'facet, 'shape>, ReflectError<'shape>> {
331 if let Type::Sequence(SequenceType::Tuple(ty)) = self.shape.ty {
332 Ok(PeekTuple { value: self, ty })
333 } else {
334 Err(ReflectError::WasNotA {
335 expected: "tuple",
336 actual: self.shape,
337 })
338 }
339 }
340
341 pub fn innermost_peek(self) -> Self {
347 let mut current_peek = self;
348 while let (Some(try_borrow_inner_fn), Some(inner_shape)) = (
349 current_peek.shape.vtable.try_borrow_inner,
350 current_peek.shape.inner,
351 ) {
352 unsafe {
353 let inner_data = try_borrow_inner_fn(current_peek.data).unwrap_or_else(|e| {
354 panic!("innermost_peek: try_borrow_inner returned an error! was trying to go from {} to {}. error: {e}", current_peek.shape,
355 inner_shape())
356 });
357
358 current_peek = Peek {
359 data: inner_data,
360 shape: inner_shape(),
361 invariant: PhantomData,
362 };
363 }
364 }
365 current_peek
366 }
367}
368
369impl<'mem, 'facet, 'shape> core::fmt::Display for Peek<'mem, 'facet, 'shape> {
370 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
371 if let Some(display_fn) = self.vtable().display {
372 unsafe { display_fn(self.data, f) }
373 } else {
374 write!(f, "⟨{}⟩", self.shape)
375 }
376 }
377}
378
379impl<'mem, 'facet, 'shape> core::fmt::Debug for Peek<'mem, 'facet, 'shape> {
380 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
381 if let Some(debug_fn) = self.vtable().debug {
382 unsafe { debug_fn(self.data, f) }
383 } else {
384 write!(f, "⟨{}⟩", self.shape)
385 }
386 }
387}
388
389impl<'mem, 'facet, 'shape> core::cmp::PartialEq for Peek<'mem, 'facet, 'shape> {
390 fn eq(&self, other: &Self) -> bool {
391 if self.shape != other.shape {
392 return false;
393 }
394 let eq_fn = match self.shape.vtable.eq {
395 Some(eq_fn) => eq_fn,
396 None => return false,
397 };
398 unsafe { eq_fn(self.data, other.data) }
399 }
400}
401
402impl<'mem, 'facet, 'shape> core::cmp::PartialOrd for Peek<'mem, 'facet, 'shape> {
403 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
404 if self.shape != other.shape {
405 return None;
406 }
407 let partial_ord_fn = self.shape.vtable.partial_ord?;
408 unsafe { partial_ord_fn(self.data, other.data) }
409 }
410}
411
412impl<'mem, 'facet, 'shape> core::hash::Hash for Peek<'mem, 'facet, 'shape> {
413 fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
414 if let Some(hash_fn) = self.shape.vtable.hash {
415 let hasher_opaque = PtrMut::new(hasher);
416 unsafe {
417 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
418 opaque.as_mut::<H>().write(bytes)
419 })
420 };
421 } else {
422 panic!("Hashing is not supported for this shape");
423 }
424 }
425}