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 + TryExtract<A, T> {
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
34where
35    Self: TryExtract<PhantomData<T>, T>,
36{
37    fn extract(
38        self,
39    ) -> (
40        PhantomData<T>,
41        <PhantomData<T> as Access<T>>::RemainderFrom<Self>,
42    ) {
43        (PhantomData, self)
44    }
45}
46
47impl<T, A: Access<T>> Extract<Option<T>, T> for A
48where
49    Self: TryExtract<Option<T>, T>,
50{
51    fn extract(self) -> (Option<T>, <Option<T> as Access<T>>::RemainderFrom<Self>) {
52        (self.into_option(), PhantomData)
53    }
54}
55
56impl<T> Extract<T, T> for T {
57    fn extract(self) -> (T, <T as Access<T>>::RemainderFrom<Self>) {
58        (self, PhantomData)
59    }
60}
61
62impl<T, A: Access<T>> TryExtract<A, T> for Option<T> {
63    fn try_extract(self) -> Result<(A, <A as Access<T>>::RemainderFrom<Self>), Self> {
64        A::try_from_option(self)
65    }
66}
67
68impl<T, A: Access<T>> TryExtract<A, T> for T {
69    fn try_extract(self) -> Result<(A, <A as Access<T>>::RemainderFrom<Self>), Self> {
70        Ok(A::from_value(self))
71    }
72}
73
74impl<T> TryExtract<Option<T>, T> for PhantomData<T> {
75    fn try_extract(
76        self,
77    ) -> Result<(Option<T>, <Option<T> as Access<T>>::RemainderFrom<Self>), Self> {
78        Ok((None, self))
79    }
80}
81
82impl<T> TryExtract<PhantomData<T>, T> for PhantomData<T> {
83    fn try_extract(
84        self,
85    ) -> Result<
86        (
87            PhantomData<T>,
88            <PhantomData<T> as Access<T>>::RemainderFrom<Self>,
89        ),
90        Self,
91    > {
92        Ok((PhantomData, self))
93    }
94}