pdk_classy/extract/
from_context.rs

1// Copyright (c) 2025, Salesforce, Inc.,
2// All rights reserved.
3// For full license text, see the LICENSE.txt file
4
5use std::convert::Infallible;
6
7use crate::{all_the_tuples, BoxError};
8
9use self::extractability::{Direct, Extractability};
10
11mod private {
12    pub trait Sealed {}
13}
14
15/// Trait that defines the extractability of a type.
16pub mod extractability {
17    use super::private::Sealed;
18
19    /// Trait that defines the extractability of a type.
20    pub trait Extractability: Sealed {}
21
22    /// The type can be extracted from the context directly.
23    pub enum Direct {}
24    impl Sealed for Direct {}
25    impl Extractability for Direct {}
26
27    /// The type can be extracted in a context from contexts of higher hierarchy.
28    pub enum Transitive {}
29    impl Sealed for Transitive {}
30    impl Extractability for Transitive {}
31}
32
33/// Extract data from the given context.
34pub trait FromContext<C, E: Extractability = Direct>: Sized {
35    type Error: Into<BoxError>;
36
37    fn from_context(context: &C) -> Result<Self, Self::Error>;
38
39    fn from_context_always(context: &C) -> Self
40    where
41        Self: FromContext<C, E, Error = Infallible>,
42    {
43        // Infallible never fails
44        Self::from_context(context).unwrap()
45    }
46}
47
48pub trait Extract<T> {
49    type Error;
50
51    fn extract(&self) -> Result<T, Self::Error>;
52
53    fn extract_always(&self) -> T
54    where
55        Self: Extract<T, Error = Infallible>,
56    {
57        self.extract().unwrap()
58    }
59}
60
61impl<C, T> Extract<T> for C
62where
63    T: FromContext<C>,
64{
65    type Error = T::Error;
66
67    fn extract(&self) -> Result<T, Self::Error> {
68        T::from_context(self)
69    }
70}
71
72impl<T, C> FromContext<C> for Option<T>
73where
74    T: FromContext<C>,
75{
76    type Error = Infallible;
77
78    fn from_context(context: &C) -> Result<Self, Self::Error> {
79        Ok(T::from_context(context).ok())
80    }
81}
82
83impl<T, C> FromContext<C> for Result<T, T::Error>
84where
85    T: FromContext<C>,
86{
87    type Error = Infallible;
88
89    fn from_context(context: &C) -> Result<Self, Self::Error> {
90        Ok(T::from_context(context))
91    }
92}
93
94impl<C> FromContext<C> for () {
95    type Error = Infallible;
96
97    fn from_context(_: &C) -> Result<Self, Self::Error> {
98        Ok(())
99    }
100}
101
102macro_rules! impl_from_context {
103    (
104        $($ty:ident),*
105    ) => {
106        #[allow(non_snake_case)]
107        impl<C, $($ty, )* > FromContext<C> for ($($ty,)*)
108        where
109            $( $ty: FromContext<C>, )*
110        {
111            type Error = BoxError;
112
113            fn from_context(context: &C) -> Result<Self, Self::Error> {
114                $(
115                    let $ty = $ty::from_context(context).map_err(|err| err.into())?;
116                )*
117
118                Ok(($($ty,)*))
119            }
120        }
121    }
122}
123
124all_the_tuples!(impl_from_context);