Skip to main content

rkyv/niche/
niching.rs

1//! [`Niching`] implementors for [`NicheInto`].
2//!
3//! [`NicheInto`]: crate::with::NicheInto
4
5use crate::Place;
6
7/// A type that can be used to niche a value with [`NicheInto`].
8///
9/// # Example
10///
11/// ```
12/// use rkyv::{
13///     niche::niching::Niching, primitive::ArchivedU32, with::NicheInto,
14///     Archive, Archived, Place, Serialize,
15/// };
16///
17/// // Let's niche `Option<u32>` by using odd values
18/// struct NeverOdd;
19///
20/// impl Niching<ArchivedU32> for NeverOdd {
21///     unsafe fn is_niched(niched: *const ArchivedU32) -> bool {
22///         // Interprete odd values as "niched"
23///         unsafe { *niched % 2 == 1 }
24///     }
25///
26///     fn resolve_niched(out: Place<ArchivedU32>) {
27///         // To niche, we use the value `1`
28///         out.write(ArchivedU32::from_native(1))
29///     }
30/// }
31///
32/// #[derive(Archive)]
33/// struct Basic {
34///     field: Option<u32>,
35/// }
36///
37/// #[derive(Archive, Serialize)]
38/// struct Niched {
39///     #[rkyv(with = NicheInto<NeverOdd>)]
40///     field: Option<u32>,
41/// }
42///
43/// # fn main() -> Result<(), rkyv::rancor::Error> {
44/// // Indeed, we have a smaller archived representation
45/// assert!(size_of::<ArchivedNiched>() < size_of::<ArchivedBasic>());
46///
47/// let values: Vec<Niched> =
48///     (0..4).map(|n| Niched { field: Some(n) }).collect();
49///
50/// let bytes = rkyv::to_bytes(&values)?;
51/// let archived = rkyv::access::<Archived<Vec<Niched>>, _>(&bytes)?;
52/// assert_eq!(archived[0].field.as_ref(), Some(&0.into()));
53/// assert_eq!(archived[1].field.as_ref(), None);
54/// assert_eq!(archived[2].field.as_ref(), Some(&2.into()));
55/// assert_eq!(archived[3].field.as_ref(), None);
56/// # Ok(()) }
57/// ```
58///
59/// [`NicheInto`]: crate::with::NicheInto
60pub trait Niching<T> {
61    /// Returns whether the given value has been niched.
62    ///
63    /// While `niched` is guaranteed to point to bytes which are all valid to
64    /// read, the value it points to is not guaranteed to be a valid instance of
65    /// `T`.
66    ///
67    /// # Safety
68    ///
69    /// `niched` must be non-null, properly-aligned, and safe for reads. It does
70    /// not have to point to a valid `T`.
71    unsafe fn is_niched(niched: *const T) -> bool;
72
73    /// Writes data to `out` indicating that a `T` is niched.
74    fn resolve_niched(out: Place<T>);
75}
76
77/// Trait to allow `NichedOption<Self, N1>` to be niched further by `N2`.
78///
79/// # Safety
80///
81/// Implementors must ensure that the memory regions within `Self` that are used
82/// for [`Niching`] impls of `N1` and `N2` are mutually exclusive.
83pub unsafe trait SharedNiching<N1, N2> {}
84
85/// Default [`Niching`] for various types.
86///
87/// Also serves as with-wrapper by being shorthand for
88/// `NicheInto<DefaultNiche>`.
89pub struct DefaultNiche;
90
91/// [`Niching`] for zero-niched values.
92pub struct Zero;
93
94/// [`Niching`] for NaN-niched values.
95pub struct NaN;
96
97/// [`Niching`] for null-pointer-niched values.
98pub struct Null;
99
100/// [`Niching`] for booleans.
101pub struct Bool;