Skip to main content

pdk_classy/extract/
from_context.rs

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