Skip to main content

structural_typing/
access.rs

1//! Runtime field access for structural types.
2use core::marker::PhantomData;
3
4use crate::presence::InferPresence;
5
6/// Uniform field access for Present, Optional, or Absent.
7pub trait Access<T>: InferPresence<T> {
8    /// Compile-time constant indicating if this field is absent.
9    const IS_ABSENT: bool;
10
11    /// Remainder type when extracting Self from Source.
12    type RemainderFrom<Source: Access<T>>: Access<T>;
13
14    /// Get field reference if present.
15    fn get(&self) -> Option<&T>;
16    /// Get mutable field reference if present.
17    fn get_mut(&mut self) -> Option<&mut T>;
18    /// Consume and convert to Option.
19    fn into_option(self) -> Option<T>;
20
21    /// Construct from a value.
22    fn from_value(value: T) -> (Self, Self::RemainderFrom<T>)
23    where
24        Self: Sized;
25
26    /// Try to construct from an option.
27    ///
28    /// # Errors
29    ///
30    /// Returns `Err` with the original `Option<T>` if the conversion cannot be performed.
31    #[allow(clippy::type_complexity)]
32    fn try_from_option(
33        value: Option<T>,
34    ) -> Result<(Self, Self::RemainderFrom<Option<T>>), Option<T>>
35    where
36        Self: Sized;
37}
38
39/// Helper function to check if a field is absent (used by serde).
40pub fn is_absent<A: Access<T>, T>(_value: &A) -> bool {
41    A::IS_ABSENT
42}
43
44impl<T> Access<T> for PhantomData<T> {
45    const IS_ABSENT: bool = true;
46
47    type RemainderFrom<Source: Access<T>> = Source;
48
49    #[inline]
50    fn get(&self) -> Option<&T> {
51        None
52    }
53    #[inline]
54    fn get_mut(&mut self) -> Option<&mut T> {
55        None
56    }
57    #[inline]
58    fn into_option(self) -> Option<T> {
59        None
60    }
61
62    #[inline]
63    fn from_value(value: T) -> (Self, Self::RemainderFrom<T>) {
64        (PhantomData, value)
65    }
66
67    #[inline]
68    fn try_from_option(
69        value: Option<T>,
70    ) -> Result<(Self, Self::RemainderFrom<Option<T>>), Option<T>> {
71        Ok((PhantomData, value))
72    }
73}
74
75impl<T: Sized> Access<T> for T {
76    const IS_ABSENT: bool = false;
77
78    type RemainderFrom<Source: Access<T>> = PhantomData<T>;
79
80    #[inline]
81    fn get(&self) -> Option<&T> {
82        Some(self)
83    }
84    #[inline]
85    fn get_mut(&mut self) -> Option<&mut T> {
86        Some(self)
87    }
88    #[inline]
89    fn into_option(self) -> Option<T> {
90        Some(self)
91    }
92
93    #[inline]
94    fn from_value(value: T) -> (Self, Self::RemainderFrom<T>) {
95        (value, PhantomData)
96    }
97
98    #[inline]
99    fn try_from_option(
100        value: Option<T>,
101    ) -> Result<(Self, Self::RemainderFrom<Option<T>>), Option<T>> {
102        match value {
103            Some(v) => Ok((v, PhantomData)),
104            None => Err(None),
105        }
106    }
107}
108
109impl<T> Access<T> for Option<T> {
110    const IS_ABSENT: bool = false;
111
112    type RemainderFrom<Source: Access<T>> = PhantomData<T>;
113
114    #[inline]
115    fn get(&self) -> Option<&T> {
116        self.as_ref()
117    }
118    #[inline]
119    fn get_mut(&mut self) -> Option<&mut T> {
120        self.as_mut()
121    }
122    #[inline]
123    fn into_option(self) -> Option<T> {
124        self
125    }
126
127    #[inline]
128    fn from_value(value: T) -> (Self, Self::RemainderFrom<T>) {
129        (Some(value), PhantomData)
130    }
131
132    #[inline]
133    fn try_from_option(
134        value: Option<T>,
135    ) -> Result<(Self, Self::RemainderFrom<Option<T>>), Option<T>> {
136        Ok((value, PhantomData))
137    }
138}