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;