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 partial_eq(&self, other: &Peek<'_, '_, '_>) -> Option<bool> {
99 unsafe { (self.shape.vtable.partial_eq)().map(|eq_fn| eq_fn(self.data, other.data)) }
100 }
101
102 #[inline]
108 pub fn partial_cmp(&self, other: &Peek<'_, '_, '_>) -> Option<Ordering> {
109 unsafe {
110 (self.shape.vtable.partial_ord)()
111 .and_then(|partial_ord_fn| partial_ord_fn(self.data, other.data))
112 }
113 }
114
115 #[inline(always)]
121 pub fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) -> bool {
122 unsafe {
123 if let Some(hash_fn) = (self.shape.vtable.hash)() {
124 let hasher_opaque = PtrMut::new(hasher);
125 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
126 opaque.as_mut::<H>().write(bytes)
127 });
128 true
129 } else {
130 false
131 }
132 }
133 }
134
135 #[inline(always)]
146 pub fn type_name(
147 &self,
148 f: &mut core::fmt::Formatter<'_>,
149 opts: TypeNameOpts,
150 ) -> core::fmt::Result {
151 (self.shape.vtable.type_name)(f, opts)
152 }
153
154 #[inline(always)]
156 pub const fn shape(&self) -> &'shape Shape<'shape> {
157 self.shape
158 }
159
160 #[inline(always)]
162 pub const fn data(&self) -> PtrConst<'mem> {
163 self.data
164 }
165
166 pub fn scalar_type(&self) -> Option<ScalarType> {
168 ScalarType::try_from_shape(self.shape)
169 }
170
171 pub fn get<T: Facet<'facet>>(&self) -> Result<&T, ReflectError<'shape>> {
177 if self.shape != T::SHAPE {
178 Err(ReflectError::WrongShape {
179 expected: self.shape,
180 actual: T::SHAPE,
181 })
182 } else {
183 Ok(unsafe { self.data.get::<T>() })
184 }
185 }
186
187 pub fn as_str(&self) -> Option<&'mem str> {
190 let peek = self.innermost_peek();
191 if let Some(ScalarType::Str) = peek.scalar_type() {
192 unsafe { Some(peek.data.get::<&str>()) }
193 } else if let Some(ScalarType::String) = peek.scalar_type() {
194 unsafe { Some(peek.data.get::<alloc::string::String>().as_str()) }
195 } else if let Type::Pointer(PointerType::Reference(vpt)) = peek.shape.ty {
196 let target_shape = (vpt.target)();
197 if let Some(ScalarType::Str) = ScalarType::try_from_shape(target_shape) {
198 unsafe { Some(peek.data.get::<&str>()) }
199 } else {
200 None
201 }
202 } else {
203 None
204 }
205 }
206
207 pub fn into_struct(self) -> Result<PeekStruct<'mem, 'facet, 'shape>, ReflectError<'shape>> {
209 if let Type::User(UserType::Struct(ty)) = self.shape.ty {
210 Ok(PeekStruct { value: self, ty })
211 } else {
212 Err(ReflectError::WasNotA {
213 expected: "struct",
214 actual: self.shape,
215 })
216 }
217 }
218
219 pub fn into_enum(self) -> Result<PeekEnum<'mem, 'facet, 'shape>, ReflectError<'shape>> {
221 if let Type::User(UserType::Enum(ty)) = self.shape.ty {
222 Ok(PeekEnum { value: self, ty })
223 } else {
224 Err(ReflectError::WasNotA {
225 expected: "enum",
226 actual: self.shape,
227 })
228 }
229 }
230
231 pub fn into_map(self) -> Result<PeekMap<'mem, 'facet, 'shape>, ReflectError<'shape>> {
233 if let Def::Map(def) = self.shape.def {
234 Ok(PeekMap { value: self, def })
235 } else {
236 Err(ReflectError::WasNotA {
237 expected: "map",
238 actual: self.shape,
239 })
240 }
241 }
242
243 pub fn into_list(self) -> Result<PeekList<'mem, 'facet, 'shape>, ReflectError<'shape>> {
245 if let Def::List(def) = self.shape.def {
246 return Ok(PeekList { value: self, def });
247 }
248
249 Err(ReflectError::WasNotA {
250 expected: "list",
251 actual: self.shape,
252 })
253 }
254
255 pub fn into_list_like(
257 self,
258 ) -> Result<PeekListLike<'mem, 'facet, 'shape>, ReflectError<'shape>> {
259 match self.shape.def {
260 Def::List(def) => Ok(PeekListLike::new(self, ListLikeDef::List(def))),
261 Def::Array(def) => Ok(PeekListLike::new(self, ListLikeDef::Array(def))),
262 _ => {
263 match self.shape.ty {
265 Type::Pointer(ptr) => match ptr {
266 PointerType::Reference(vpt) | PointerType::Raw(vpt) => {
267 let target = (vpt.target)();
268 match target.def {
269 Def::Slice(def) => {
270 return Ok(PeekListLike::new(self, ListLikeDef::Slice(def)));
271 }
272 _ => {
273 }
275 }
276 }
277 PointerType::Function(_) => {
278 }
280 },
281 _ => {
282 }
284 }
285
286 Err(ReflectError::WasNotA {
287 expected: "list, array or slice",
288 actual: self.shape,
289 })
290 }
291 }
292 }
293
294 pub fn into_smart_pointer(
296 self,
297 ) -> Result<PeekSmartPointer<'mem, 'facet, 'shape>, ReflectError<'shape>> {
298 if let Def::SmartPointer(def) = self.shape.def {
299 Ok(PeekSmartPointer { value: self, def })
300 } else {
301 Err(ReflectError::WasNotA {
302 expected: "smart pointer",
303 actual: self.shape,
304 })
305 }
306 }
307
308 pub fn into_option(
310 self,
311 ) -> Result<super::PeekOption<'mem, 'facet, 'shape>, ReflectError<'shape>> {
312 if let Def::Option(def) = self.shape.def {
313 Ok(super::PeekOption { value: self, def })
314 } else {
315 Err(ReflectError::WasNotA {
316 expected: "option",
317 actual: self.shape,
318 })
319 }
320 }
321
322 pub fn into_tuple(self) -> Result<PeekTuple<'mem, 'facet, 'shape>, ReflectError<'shape>> {
324 if let Type::Sequence(SequenceType::Tuple(ty)) = self.shape.ty {
325 Ok(PeekTuple { value: self, ty })
326 } else {
327 Err(ReflectError::WasNotA {
328 expected: "tuple",
329 actual: self.shape,
330 })
331 }
332 }
333
334 pub fn innermost_peek(self) -> Self {
340 let mut current_peek = self;
341 while let (Some(try_borrow_inner_fn), Some(inner_shape)) = (
342 (current_peek.shape.vtable.try_borrow_inner)(),
343 current_peek.shape.inner,
344 ) {
345 unsafe {
346 let inner_data = try_borrow_inner_fn(current_peek.data).unwrap_or_else(|e| {
347 panic!("innermost_peek: try_borrow_inner returned an error! was trying to go from {} to {}. error: {e}", current_peek.shape,
348 inner_shape())
349 });
350
351 current_peek = Peek {
352 data: inner_data,
353 shape: inner_shape(),
354 invariant: PhantomData,
355 };
356 }
357 }
358 current_peek
359 }
360}
361
362impl<'mem, 'facet, 'shape> core::fmt::Display for Peek<'mem, 'facet, 'shape> {
363 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
364 if let Some(display_fn) = (self.vtable().display)() {
365 unsafe { display_fn(self.data, f) }
366 } else {
367 write!(f, "⟨{}⟩", self.shape)
368 }
369 }
370}
371
372impl<'mem, 'facet, 'shape> core::fmt::Debug for Peek<'mem, 'facet, 'shape> {
373 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
374 if let Some(debug_fn) = (self.vtable().debug)() {
375 unsafe { debug_fn(self.data, f) }
376 } else {
377 write!(f, "⟨{}⟩", self.shape)
378 }
379 }
380}
381
382impl<'mem, 'facet, 'shape> core::cmp::PartialEq for Peek<'mem, 'facet, 'shape> {
383 fn eq(&self, other: &Self) -> bool {
384 if self.shape != other.shape {
385 return false;
386 }
387 let eq_fn = match (self.shape.vtable.partial_eq)() {
388 Some(eq_fn) => eq_fn,
389 None => return false,
390 };
391 unsafe { eq_fn(self.data, other.data) }
392 }
393}
394
395impl<'mem, 'facet, 'shape> core::cmp::PartialOrd for Peek<'mem, 'facet, 'shape> {
396 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
397 if self.shape != other.shape {
398 return None;
399 }
400 let partial_ord_fn = (self.shape.vtable.partial_ord)()?;
401 unsafe { partial_ord_fn(self.data, other.data) }
402 }
403}
404
405impl<'mem, 'facet, 'shape> core::hash::Hash for Peek<'mem, 'facet, 'shape> {
406 fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
407 if let Some(hash_fn) = (self.shape.vtable.hash)() {
408 let hasher_opaque = PtrMut::new(hasher);
409 unsafe {
410 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
411 opaque.as_mut::<H>().write(bytes)
412 })
413 };
414 } else {
415 panic!("Hashing is not supported for this shape");
416 }
417 }
418}