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 {
16 pub(crate) shape: &'static Shape,
17 pub(crate) ptr: *const u8,
18}
19
20impl ValueId {
21 pub(crate) fn new(shape: &'static 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_lifetime> {
41 pub(crate) data: PtrConst<'mem>,
43
44 pub(crate) shape: &'static Shape,
46
47 invariant: PhantomData<fn(&'facet_lifetime ()) -> &'facet_lifetime ()>,
48}
49
50impl<'mem, 'facet_lifetime> Peek<'mem, 'facet_lifetime> {
51 pub fn new<T: Facet<'facet_lifetime>>(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: &'static Shape) -> Self {
68 Self {
69 data,
70 shape,
71 invariant: PhantomData,
72 }
73 }
74
75 #[inline(always)]
77 pub fn vtable(&self) -> &'static ValueVTable {
78 self.shape.vtable
79 }
80
81 pub fn id(&self) -> ValueId {
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) -> &'static 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_lifetime>>(&self) -> Result<&T, ReflectError> {
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<&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_lifetime>, ReflectError> {
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_lifetime>, ReflectError> {
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_lifetime>, ReflectError> {
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_lifetime>, ReflectError> {
252 if let Def::List(def) = self.shape.def {
253 Ok(PeekList { value: self, def })
254 } else {
255 Err(ReflectError::WasNotA {
256 expected: "list",
257 actual: self.shape,
258 })
259 }
260 }
261
262 pub fn into_list_like(self) -> Result<PeekListLike<'mem, 'facet_lifetime>, ReflectError> {
264 match self.shape.def {
265 Def::List(def) => Ok(PeekListLike::new(self, ListLikeDef::List(def))),
266 Def::Array(def) => Ok(PeekListLike::new(self, ListLikeDef::Array(def))),
267 _ => {
268 match self.shape.ty {
270 Type::Pointer(ptr) => match ptr {
271 PointerType::Reference(vpt) | PointerType::Raw(vpt) => {
272 let target = (vpt.target)();
273 match target.def {
274 Def::Slice(def) => {
275 return Ok(PeekListLike::new(self, ListLikeDef::Slice(def)));
276 }
277 _ => {
278 }
280 }
281 }
282 PointerType::Function(_) => {
283 }
285 },
286 _ => {
287 }
289 }
290
291 Err(ReflectError::WasNotA {
292 expected: "list, array or slice",
293 actual: self.shape,
294 })
295 }
296 }
297 }
298
299 pub fn into_smart_pointer(
301 self,
302 ) -> Result<PeekSmartPointer<'mem, 'facet_lifetime>, ReflectError> {
303 if let Def::SmartPointer(def) = self.shape.def {
304 Ok(PeekSmartPointer { value: self, def })
305 } else {
306 Err(ReflectError::WasNotA {
307 expected: "smart pointer",
308 actual: self.shape,
309 })
310 }
311 }
312
313 pub fn into_option(self) -> Result<super::PeekOption<'mem, 'facet_lifetime>, ReflectError> {
315 if let Def::Option(def) = self.shape.def {
316 Ok(super::PeekOption { value: self, def })
317 } else {
318 Err(ReflectError::WasNotA {
319 expected: "option",
320 actual: self.shape,
321 })
322 }
323 }
324
325 pub fn into_tuple(self) -> Result<PeekTuple<'mem, 'facet_lifetime>, ReflectError> {
327 if let Type::Sequence(SequenceType::Tuple(ty)) = self.shape.ty {
328 Ok(PeekTuple { value: self, ty })
329 } else {
330 Err(ReflectError::WasNotA {
331 expected: "tuple",
332 actual: self.shape,
333 })
334 }
335 }
336
337 pub fn innermost_peek(self) -> Self {
343 let mut current_peek = self;
344 while let (Some(try_borrow_inner_fn), Some(inner_shape)) = (
345 current_peek.shape.vtable.try_borrow_inner,
346 current_peek.shape.inner,
347 ) {
348 unsafe {
349 let inner_data = try_borrow_inner_fn(current_peek.data).unwrap_or_else(|e| {
350 panic!("innermost_peek: try_borrow_inner returned an error! was trying to go from {} to {}. error: {e}", current_peek.shape,
351 inner_shape())
352 });
353
354 current_peek = Peek {
355 data: inner_data,
356 shape: inner_shape(),
357 invariant: PhantomData,
358 };
359 }
360 }
361 current_peek
362 }
363}
364
365impl core::fmt::Display for Peek<'_, '_> {
366 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
367 if let Some(display_fn) = self.vtable().display {
368 unsafe { display_fn(self.data, f) }
369 } else {
370 write!(f, "⟨{}⟩", self.shape)
371 }
372 }
373}
374
375impl core::fmt::Debug for Peek<'_, '_> {
376 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
377 if let Some(debug_fn) = self.vtable().debug {
378 unsafe { debug_fn(self.data, f) }
379 } else {
380 write!(f, "⟨{}⟩", self.shape)
381 }
382 }
383}
384
385impl core::cmp::PartialEq for Peek<'_, '_> {
386 fn eq(&self, other: &Self) -> bool {
387 if self.shape != other.shape {
388 return false;
389 }
390 let eq_fn = match self.shape.vtable.eq {
391 Some(eq_fn) => eq_fn,
392 None => return false,
393 };
394 unsafe { eq_fn(self.data, other.data) }
395 }
396}
397
398impl core::cmp::PartialOrd for Peek<'_, '_> {
399 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
400 if self.shape != other.shape {
401 return None;
402 }
403 let partial_ord_fn = self.shape.vtable.partial_ord?;
404 unsafe { partial_ord_fn(self.data, other.data) }
405 }
406}
407
408impl core::hash::Hash for Peek<'_, '_> {
409 fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
410 if let Some(hash_fn) = self.shape.vtable.hash {
411 let hasher_opaque = PtrMut::new(hasher);
412 unsafe {
413 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
414 opaque.as_mut::<H>().write(bytes)
415 })
416 };
417 } else {
418 panic!("Hashing is not supported for this shape");
419 }
420 }
421}