• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

facet-rs / facet / 18681380540

21 Oct 2025 10:48AM UTC coverage: 54.052%. First build
18681380540

push

github

fasterthanlime
use a more descriptive ReflectError variant

2 of 12 new or added lines in 1 file covered. (16.67%)

4762 of 8810 relevant lines covered (54.05%)

40.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

35.19
/facet-reflect/src/peek/value.rs
1
use core::{cmp::Ordering, marker::PhantomData, ptr::NonNull};
2
use facet_core::{
3
    Def, Facet, PointerType, PtrConst, Shape, StructKind, Type, TypeNameOpts, UserType, ValueVTable,
4
};
5

6
use crate::{PeekNdArray, PeekSet, ReflectError, ScalarType};
7

8
use super::{
9
    ListLikeDef, PeekEnum, PeekList, PeekListLike, PeekMap, PeekOption, PeekPointer, PeekStruct,
10
    PeekTuple, tuple::TupleType,
11
};
12

13
/// A unique identifier for a peek value
14
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
15
pub struct ValueId {
16
    pub(crate) shape: &'static Shape,
17
    pub(crate) ptr: *const u8,
18
}
19

20
impl ValueId {
21
    #[inline]
22
    pub(crate) fn new(shape: &'static Shape, ptr: *const u8) -> Self {
×
23
        Self { shape, ptr }
×
24
    }
×
25
}
26

27
impl 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

33
impl 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
/// Lets you read from a value (implements read-only [`ValueVTable`] proxies)
40
///
41
/// If the value is a struct, you can read its fields, if the value is an enum,
42
/// you can find out which variant is selected, if it's a scalar you can check
43
/// against known types and get a concrete value out of it, etc.
44
#[derive(Clone, Copy)]
45
pub struct Peek<'mem, 'facet> {
46
    /// Underlying data
47
    pub(crate) data: PtrConst<'mem>,
48

49
    /// Shape of the value
50
    pub(crate) shape: &'static Shape,
51

52
    invariant: PhantomData<fn(&'facet ()) -> &'facet ()>,
53
}
54

55
impl<'mem, 'facet> Peek<'mem, 'facet> {
56
    /// Returns a read-only view over a `T` value.
57
    pub fn new<T: Facet<'facet> + ?Sized>(t: &'mem T) -> Self {
64✔
58
        Self {
64✔
59
            data: PtrConst::new(NonNull::from(t)),
64✔
60
            shape: T::SHAPE,
64✔
61
            invariant: PhantomData,
64✔
62
        }
64✔
63
    }
64✔
64

65
    /// Returns a read-only view over a value (given its shape), trusting you
66
    /// that those two match.
67
    ///
68
    /// # Safety
69
    ///
70
    /// This function is unsafe because it doesn't check if the provided data
71
    /// and shape are compatible. The caller must ensure that the data is valid
72
    /// for the given shape.
73
    pub unsafe fn unchecked_new(data: PtrConst<'mem>, shape: &'static Shape) -> Self {
46✔
74
        Self {
46✔
75
            data,
46✔
76
            shape,
46✔
77
            invariant: PhantomData,
46✔
78
        }
46✔
79
    }
46✔
80

81
    /// Returns the vtable
82
    #[inline(always)]
83
    pub fn vtable(&self) -> &'static ValueVTable {
17✔
84
        &self.shape.vtable
17✔
85
    }
17✔
86

87
    /// Returns a unique identifier for this value, usable for cycle detection
88
    #[inline]
89
    pub fn id(&self) -> ValueId {
×
90
        ValueId::new(self.shape, self.data.as_byte_ptr())
×
91
    }
×
92

93
    /// Returns true if the two values are pointer-equal
94
    #[inline]
95
    pub fn ptr_eq(&self, other: &Peek<'_, '_>) -> bool {
×
96
        self.data.as_byte_ptr() == other.data.as_byte_ptr()
×
97
    }
×
98

99
    /// Returns true if this scalar is equal to the other scalar
100
    ///
101
    /// # Returns
102
    ///
103
    /// `false` if equality comparison is not supported for this scalar type
104
    #[inline]
105
    pub fn partial_eq(&self, other: &Peek<'_, '_>) -> Result<bool, ReflectError> {
1✔
106
        if let Some(f) = (self.vtable().partial_eq)() {
1✔
107
            if self.shape == other.shape {
1✔
108
                return Ok(unsafe { f(self.data, other.data) });
1✔
109
            } else {
NEW
110
                return Err(ReflectError::WrongShape {
×
NEW
111
                    expected: self.shape,
×
NEW
112
                    actual: other.shape,
×
NEW
113
                });
×
114
            }
115
        }
×
116

117
        Err(ReflectError::OperationFailed {
×
118
            shape: self.shape(),
×
119
            operation: "partial_eq",
×
120
        })
×
121
    }
1✔
122

123
    /// Compares this scalar with another and returns their ordering
124
    ///
125
    /// # Returns
126
    ///
127
    /// `None` if comparison is not supported for this scalar type
128
    #[inline]
129
    pub fn partial_cmp(&self, other: &Peek<'_, '_>) -> Result<Option<Ordering>, ReflectError> {
×
NEW
130
        if let Some(f) = (self.vtable().partial_ord)() {
×
NEW
131
            if self.shape == other.shape {
×
132
                return Ok(unsafe { f(self.data, other.data) });
×
133
            } else {
NEW
134
                return Err(ReflectError::WrongShape {
×
NEW
135
                    expected: self.shape,
×
NEW
136
                    actual: other.shape,
×
NEW
137
                });
×
138
            }
139
        }
×
140

141
        Err(ReflectError::OperationFailed {
×
142
            shape: self.shape(),
×
143
            operation: "partial_cmp",
×
144
        })
×
145
    }
×
146
    /// Hashes this scalar
147
    ///
148
    /// # Returns
149
    ///
150
    /// `Err` if hashing is not supported for this scalar type, `Ok` otherwise
151
    #[inline(always)]
152
    pub fn hash(&self, hasher: &mut dyn core::hash::Hasher) -> Result<(), ReflectError> {
1✔
153
        if let Some(hash_fn) = (self.vtable().hash)() {
1✔
154
            unsafe {
155
                hash_fn(self.data, hasher);
1✔
156
                return Ok(());
1✔
157
            };
158
        }
×
159

160
        Err(ReflectError::OperationFailed {
×
161
            shape: self.shape(),
×
162
            operation: "hash",
×
163
        })
×
164
    }
1✔
165

166
    /// Returns the type name of this scalar
167
    ///
168
    /// # Arguments
169
    ///
170
    /// * `f` - A mutable reference to a `core::fmt::Formatter`
171
    /// * `opts` - The `TypeNameOpts` to use for formatting
172
    ///
173
    /// # Returns
174
    ///
175
    /// The result of the type name formatting
176
    #[inline(always)]
177
    pub fn type_name(
×
178
        &self,
×
179
        f: &mut core::fmt::Formatter<'_>,
×
180
        opts: TypeNameOpts,
×
181
    ) -> core::fmt::Result {
×
182
        (self.shape.vtable.type_name())(f, opts)
×
183
    }
×
184

185
    /// Returns the shape
186
    #[inline(always)]
187
    pub const fn shape(&self) -> &'static Shape {
×
188
        self.shape
×
189
    }
×
190

191
    /// Returns the data
192
    #[inline(always)]
193
    pub const fn data(&self) -> PtrConst<'mem> {
115✔
194
        self.data
115✔
195
    }
115✔
196

197
    /// Get the scalar type if set.
198
    #[inline]
199
    pub fn scalar_type(&self) -> Option<ScalarType> {
×
200
        ScalarType::try_from_shape(self.shape)
×
201
    }
×
202

203
    /// Read the value from memory into a Rust value.
204
    ///
205
    /// # Panics
206
    ///
207
    /// Panics if the shape doesn't match the type `T`.
208
    #[inline]
209
    pub fn get<T: Facet<'facet> + ?Sized>(&self) -> Result<&T, ReflectError> {
41✔
210
        if self.shape != T::SHAPE {
41✔
211
            Err(ReflectError::WrongShape {
×
212
                expected: self.shape,
×
213
                actual: T::SHAPE,
×
214
            })
×
215
        } else {
216
            Ok(unsafe { self.data.get::<T>() })
41✔
217
        }
218
    }
41✔
219

220
    /// Try to get the value as a string if it's a string type
221
    /// Returns None if the value is not a string or couldn't be extracted
222
    pub fn as_str(&self) -> Option<&'mem str> {
×
223
        let peek = self.innermost_peek();
×
224
        if let Some(ScalarType::Str) = peek.scalar_type() {
×
225
            unsafe { Some(peek.data.get::<&str>()) }
×
226
        } else if let Some(ScalarType::String) = peek.scalar_type() {
×
227
            unsafe { Some(peek.data.get::<alloc::string::String>().as_str()) }
×
228
        } else if let Type::Pointer(PointerType::Reference(vpt)) = peek.shape.ty {
×
229
            let target_shape = (vpt.target)();
×
230
            if let Some(ScalarType::Str) = ScalarType::try_from_shape(target_shape) {
×
231
                unsafe { Some(peek.data.get::<&str>()) }
×
232
            } else {
233
                None
×
234
            }
235
        } else {
236
            None
×
237
        }
238
    }
×
239

240
    /// Try to get the value as a byte slice if it's a &[u8] type
241
    /// Returns None if the value is not a byte slice or couldn't be extracted
242
    #[inline]
243
    pub fn as_bytes(&self) -> Option<&'mem [u8]> {
×
244
        // Check if it's a direct &[u8]
245
        if let Type::Pointer(PointerType::Reference(vpt)) = self.shape.ty {
×
246
            let target_shape = (vpt.target)();
×
247
            if let Def::Slice(sd) = target_shape.def {
×
248
                if sd.t().is_type::<u8>() {
×
249
                    unsafe { return Some(self.data.get::<&[u8]>()) }
×
250
                }
×
251
            }
×
252
        }
×
253
        None
×
254
    }
×
255

256
    /// Tries to identify this value as a struct
257
    #[inline]
258
    pub fn into_struct(self) -> Result<PeekStruct<'mem, 'facet>, ReflectError> {
2✔
259
        if let Type::User(UserType::Struct(ty)) = self.shape.ty {
2✔
260
            Ok(PeekStruct { value: self, ty })
2✔
261
        } else {
262
            Err(ReflectError::WasNotA {
×
263
                expected: "struct",
×
264
                actual: self.shape,
×
265
            })
×
266
        }
267
    }
2✔
268

269
    /// Tries to identify this value as an enum
270
    #[inline]
271
    pub fn into_enum(self) -> Result<PeekEnum<'mem, 'facet>, ReflectError> {
5✔
272
        if let Type::User(UserType::Enum(ty)) = self.shape.ty {
5✔
273
            Ok(PeekEnum { value: self, ty })
5✔
274
        } else {
275
            Err(ReflectError::WasNotA {
×
276
                expected: "enum",
×
277
                actual: self.shape,
×
278
            })
×
279
        }
280
    }
5✔
281

282
    /// Tries to identify this value as a map
283
    #[inline]
284
    pub fn into_map(self) -> Result<PeekMap<'mem, 'facet>, ReflectError> {
4✔
285
        if let Def::Map(def) = self.shape.def {
4✔
286
            Ok(PeekMap { value: self, def })
4✔
287
        } else {
288
            Err(ReflectError::WasNotA {
×
289
                expected: "map",
×
290
                actual: self.shape,
×
291
            })
×
292
        }
293
    }
4✔
294

295
    /// Tries to identify this value as a set
296
    #[inline]
297
    pub fn into_set(self) -> Result<PeekSet<'mem, 'facet>, ReflectError> {
2✔
298
        if let Def::Set(def) = self.shape.def {
2✔
299
            Ok(PeekSet { value: self, def })
2✔
300
        } else {
301
            Err(ReflectError::WasNotA {
×
302
                expected: "set",
×
303
                actual: self.shape,
×
304
            })
×
305
        }
306
    }
2✔
307

308
    /// Tries to identify this value as a list
309
    #[inline]
310
    pub fn into_list(self) -> Result<PeekList<'mem, 'facet>, ReflectError> {
2✔
311
        if let Def::List(def) = self.shape.def {
2✔
312
            return Ok(PeekList { value: self, def });
2✔
313
        }
×
314

315
        Err(ReflectError::WasNotA {
×
316
            expected: "list",
×
317
            actual: self.shape,
×
318
        })
×
319
    }
2✔
320

321
    /// Tries to identify this value as a ndarray
322
    #[inline]
323
    pub fn into_ndarray(self) -> Result<PeekNdArray<'mem, 'facet>, ReflectError> {
1✔
324
        if let Def::NdArray(def) = self.shape.def {
1✔
325
            return Ok(PeekNdArray { value: self, def });
1✔
326
        }
×
327

328
        Err(ReflectError::WasNotA {
×
329
            expected: "ndarray",
×
330
            actual: self.shape,
×
331
        })
×
332
    }
1✔
333

334
    /// Tries to identify this value as a list, array or slice
335
    #[inline]
336
    pub fn into_list_like(self) -> Result<PeekListLike<'mem, 'facet>, ReflectError> {
3✔
337
        match self.shape.def {
3✔
338
            Def::List(def) => Ok(PeekListLike::new(self, ListLikeDef::List(def))),
1✔
339
            Def::Array(def) => Ok(PeekListLike::new(self, ListLikeDef::Array(def))),
1✔
340
            Def::Slice(def) => {
×
341
                // When we have a bare slice shape with a wide pointer,
342
                // it means we have a reference to a slice (e.g., from Arc<[T]>::borrow_inner)
343
                Ok(PeekListLike::new(self, ListLikeDef::Slice(def)))
×
344
            }
345
            _ => {
346
                // &[i32] is actually a _pointer_ to a slice.
347
                match self.shape.ty {
1✔
348
                    Type::Pointer(ptr) => match ptr {
1✔
349
                        PointerType::Reference(vpt) | PointerType::Raw(vpt) => {
1✔
350
                            let target = (vpt.target)();
1✔
351
                            match target.def {
1✔
352
                                Def::Slice(def) => {
1✔
353
                                    let ptr = unsafe { self.data.as_ptr::<*const [()]>() };
1✔
354
                                    let ptr = PtrConst::new(unsafe {
1✔
355
                                        NonNull::new_unchecked((*ptr) as *mut [()])
1✔
356
                                    });
357
                                    let peek = unsafe { Peek::unchecked_new(ptr, def.t) };
1✔
358

359
                                    return Ok(PeekListLike::new(peek, ListLikeDef::Slice(def)));
1✔
360
                                }
361
                                _ => {
×
362
                                    // well it's not list-like then
×
363
                                }
×
364
                            }
365
                        }
366
                        PointerType::Function(_) => {
×
367
                            // well that's not a list-like
×
368
                        }
×
369
                    },
370
                    _ => {
×
371
                        // well that's not a list-like either
×
372
                    }
×
373
                }
374

375
                Err(ReflectError::WasNotA {
×
376
                    expected: "list, array or slice",
×
377
                    actual: self.shape,
×
378
                })
×
379
            }
380
        }
381
    }
3✔
382

383
    /// Tries to identify this value as a pointer
384
    #[inline]
385
    pub fn into_pointer(self) -> Result<PeekPointer<'mem, 'facet>, ReflectError> {
9✔
386
        if let Def::Pointer(def) = self.shape.def {
9✔
387
            Ok(PeekPointer { value: self, def })
9✔
388
        } else {
389
            Err(ReflectError::WasNotA {
×
390
                expected: "smart pointer",
×
391
                actual: self.shape,
×
392
            })
×
393
        }
394
    }
9✔
395

396
    /// Tries to identify this value as an option
397
    #[inline]
398
    pub fn into_option(self) -> Result<PeekOption<'mem, 'facet>, ReflectError> {
2✔
399
        if let Def::Option(def) = self.shape.def {
2✔
400
            Ok(PeekOption { value: self, def })
2✔
401
        } else {
402
            Err(ReflectError::WasNotA {
×
403
                expected: "option",
×
404
                actual: self.shape,
×
405
            })
×
406
        }
407
    }
2✔
408

409
    /// Tries to identify this value as a tuple
410
    #[inline]
411
    pub fn into_tuple(self) -> Result<PeekTuple<'mem, 'facet>, ReflectError> {
×
412
        if let Type::User(UserType::Struct(struct_type)) = self.shape.ty {
×
413
            if struct_type.kind == StructKind::Tuple {
×
414
                Ok(PeekTuple {
×
415
                    value: self,
×
416
                    ty: TupleType {
×
417
                        fields: struct_type.fields,
×
418
                    },
×
419
                })
×
420
            } else {
421
                Err(ReflectError::WasNotA {
×
422
                    expected: "tuple",
×
423
                    actual: self.shape,
×
424
                })
×
425
            }
426
        } else {
427
            Err(ReflectError::WasNotA {
×
428
                expected: "tuple",
×
429
                actual: self.shape,
×
430
            })
×
431
        }
432
    }
×
433

434
    /// Tries to return the innermost value — useful for serialization. For example, we serialize a `NonZero<u8>` the same
435
    /// as a `u8`. Similarly, we serialize a `Utf8PathBuf` the same as a `String.
436
    ///
437
    /// Returns a `Peek` to the innermost value, unwrapping transparent wrappers recursively.
438
    /// For example, this will peel through newtype wrappers or smart pointers that have an `inner`.
439
    pub fn innermost_peek(self) -> Self {
×
440
        let mut current_peek = self;
×
441
        while let (Some(try_borrow_inner_fn), Some(inner_shape)) = (
×
442
            (current_peek.shape.vtable.try_borrow_inner)(),
×
443
            current_peek.shape.inner,
×
444
        ) {
445
            unsafe {
446
                let inner_data = try_borrow_inner_fn(current_peek.data).unwrap_or_else(|e| {
×
447
                    panic!("innermost_peek: try_borrow_inner returned an error! was trying to go from {} to {}. error: {e}", current_peek.shape,
×
448
                        inner_shape())
×
449
                });
450

451
                current_peek = Peek {
×
452
                    data: inner_data,
×
453
                    shape: inner_shape(),
×
454
                    invariant: PhantomData,
×
455
                };
×
456
            }
457
        }
458
        current_peek
×
459
    }
×
460
}
461

462
impl<'mem, 'facet> core::fmt::Display for Peek<'mem, 'facet> {
463
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
12✔
464
        if let Some(display_fn) = (self.vtable().display)() {
12✔
465
            return unsafe { display_fn(self.data, f) };
11✔
466
        }
1✔
467
        write!(f, "⟨{}⟩", self.shape)
1✔
468
    }
12✔
469
}
470

471
impl<'mem, 'facet> core::fmt::Debug for Peek<'mem, 'facet> {
472
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
3✔
473
        if let Some(debug_fn) = (self.vtable().debug)() {
3✔
474
            return unsafe { debug_fn(self.data, f) };
3✔
475
        }
×
476

477
        write!(f, "⟨{}⟩", self.shape)
×
478
    }
3✔
479
}
480

481
impl<'mem, 'facet> core::cmp::PartialEq for Peek<'mem, 'facet> {
482
    #[inline]
483
    fn eq(&self, other: &Self) -> bool {
1✔
484
        self.partial_eq(other).unwrap_or(false)
1✔
485
    }
1✔
486
}
487

488
impl<'mem, 'facet> core::cmp::PartialOrd for Peek<'mem, 'facet> {
489
    #[inline]
490
    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
×
491
        self.partial_cmp(other).unwrap_or(None)
×
492
    }
×
493
}
494

495
impl<'mem, 'facet> core::hash::Hash for Peek<'mem, 'facet> {
496
    fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
×
497
        self.hash(hasher)
×
498
            .expect("Hashing is not supported for this shape");
×
499
    }
×
500
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc