structural_typing/
extract.rs

1//! Extract selected fields from structs, returning the selected fields and remainder.
2//!
3//! Use `extract()` when extraction always succeeds (e.g., `Present` → `Optional`).
4//! Use `try_extract()` when extraction may fail (e.g., `Optional` → `Present` can fail if `None`).
5
6use core::marker::PhantomData;
7
8use crate::access::Access;
9
10/// Trait for compile-time checked extraction from one access type to another.
11///
12/// Returns both the extracted value (in target access type) and the remainder.
13pub trait Extract<A: Access<T>, T>: Access<T> + Sized {
14    /// Extract a value into target type and remainder parts.
15    fn extract(self) -> (A, <A as Access<T>>::RemainderFrom<Self>);
16}
17
18/// Trait for runtime checked extraction that may fail.
19///
20/// Returns Ok with (extracted, remainder) on success, or Err with original value on failure.
21///
22/// Most conversions delegate to `Extract` and always succeed; only `Option<T>` → `T` can fail when the value is `None`.
23pub trait TryExtract<A: Access<T>, T>: Access<T> + Sized {
24    /// Try to extract a value into target type and remainder parts.
25    ///
26    /// # Errors
27    ///
28    /// Returns `Err` with the original value if the extraction cannot be performed
29    /// (e.g., when trying to convert `Option<T>` to `T` but the value is `None`).
30    fn try_extract(self) -> Result<(A, <A as Access<T>>::RemainderFrom<Self>), Self>;
31}
32
33impl<T, A: Access<T>> Extract<PhantomData<T>, T> for A {
34    fn extract(
35        self,
36    ) -> (
37        PhantomData<T>,
38        <PhantomData<T> as Access<T>>::RemainderFrom<Self>,
39    ) {
40        (PhantomData, self)
41    }
42}
43
44impl<T, A: Access<T>> Extract<Option<T>, T> for A {
45    fn extract(self) -> (Option<T>, <Option<T> as Access<T>>::RemainderFrom<Self>) {
46        (self.into_option(), PhantomData)
47    }
48}
49
50impl<T> Extract<T, T> for T {
51    fn extract(self) -> (T, <T as Access<T>>::RemainderFrom<Self>) {
52        (self, PhantomData)
53    }
54}
55
56impl<T, A: Access<T>> TryExtract<PhantomData<T>, T> for A {
57    fn try_extract(
58        self,
59    ) -> Result<
60        (
61            PhantomData<T>,
62            <PhantomData<T> as Access<T>>::RemainderFrom<Self>,
63        ),
64        Self,
65    >
66    where
67        PhantomData<T>: Access<T>,
68    {
69        Ok(self.extract())
70    }
71}
72
73impl<T, A: Access<T>> TryExtract<Option<T>, T> for A {
74    fn try_extract(self) -> Result<(Option<T>, <Option<T> as Access<T>>::RemainderFrom<Self>), Self>
75    where
76        Option<T>: Access<T>,
77    {
78        Ok(self.extract())
79    }
80}
81
82impl<T> TryExtract<T, T> for T {
83    fn try_extract(self) -> Result<(T, <T as Access<T>>::RemainderFrom<Self>), Self> {
84        Ok(self.extract())
85    }
86}
87
88impl<T> TryExtract<T, T> for Option<T> {
89    fn try_extract(self) -> Result<(T, <T as Access<T>>::RemainderFrom<Self>), Self> {
90        match self {
91            Some(v) => Ok((v, PhantomData)),
92            None => Err(None),
93        }
94    }
95}