srt_protocol/options/
validation.rs

1use std::ops::Deref;
2
3pub trait Validation: Sized {
4    type Error;
5
6    fn is_valid(&self) -> Result<(), Self::Error>;
7
8    fn try_validate(self) -> Result<Valid<Self>, Self::Error> {
9        self.is_valid()?;
10        Ok(Valid(self))
11    }
12}
13
14pub trait CompositeValidation: Validation {
15    fn is_valid_composite(&self) -> Result<(), <Self as Validation>::Error>;
16}
17
18pub trait OptionsOf<C>: CompositeValidation {
19    fn set_options(&mut self, value: C);
20}
21
22impl<C> OptionsOf<C> for C
23where
24    C: CompositeValidation,
25{
26    fn set_options(&mut self, value: C) {
27        *self = value;
28    }
29}
30
31#[derive(Debug, Default, Clone, Eq, PartialEq)]
32pub struct Valid<T: Validation>(T);
33
34impl<T: Validation> Deref for Valid<T> {
35    type Target = T;
36
37    fn deref(&self) -> &Self::Target {
38        &self.0
39    }
40}
41
42impl<T: Validation> Valid<T> {
43    pub fn into_value(self) -> T {
44        self.0
45    }
46
47    pub fn set(self, set_fn: impl FnOnce(&mut T)) -> Result<Self, <T as Validation>::Error> {
48        let mut inner = self.0;
49        set_fn(&mut inner);
50        inner.try_validate()
51    }
52
53    pub fn with<F>(self, options: F) -> Result<Self, <T as Validation>::Error>
54    where
55        T: OptionsOf<F>,
56        F: Validation<Error = <T as Validation>::Error>,
57    {
58        let mut inner = self.0;
59        inner.set_options(options.try_validate()?.0);
60        inner.is_valid_composite()?;
61        Ok(Self(inner))
62    }
63
64    pub fn with2<F1, F2>(self, options1: F1, options2: F2) -> Result<Self, <T as Validation>::Error>
65    where
66        T: OptionsOf<F1> + OptionsOf<F2>,
67        F1: Validation<Error = <T as Validation>::Error>,
68        F2: Validation<Error = <T as Validation>::Error>,
69    {
70        let mut inner = self.0;
71        inner.set_options(options1.try_validate()?.0);
72        inner.set_options(options2.try_validate()?.0);
73        inner.is_valid_composite()?;
74        Ok(Self(inner))
75    }
76
77    pub fn with3<F1, F2, F3>(
78        self,
79        options1: F1,
80        options2: F2,
81        options3: F3,
82    ) -> Result<Self, <T as Validation>::Error>
83    where
84        T: OptionsOf<F1> + OptionsOf<F2> + OptionsOf<F3>,
85        F1: Validation<Error = <T as Validation>::Error>,
86        F2: Validation<Error = <T as Validation>::Error>,
87        F3: Validation<Error = <T as Validation>::Error>,
88    {
89        let mut inner = self.0;
90        inner.set_options(options1.try_validate()?.0);
91        inner.set_options(options2.try_validate()?.0);
92        inner.set_options(options3.try_validate()?.0);
93        inner.is_valid_composite()?;
94        Ok(Self(inner))
95    }
96}
97
98#[cfg(test)]
99mod test {
100    use super::*;
101
102    #[derive(Debug, Default, Clone, Eq, PartialEq)]
103    struct Test {
104        pub field: u32,
105    }
106
107    #[derive(Debug, Default, Clone, Eq, PartialEq)]
108    struct Test2 {
109        pub field: u32,
110    }
111
112    #[derive(Debug, Default, Clone, Eq, PartialEq)]
113    struct Test3 {
114        pub field: u32,
115    }
116
117    #[derive(Debug, Clone, Eq, PartialEq)]
118    enum TestError {
119        Test(Test),
120        Test2(Test2),
121        Test3(Test3),
122        TestParent(TestParent),
123    }
124
125    #[derive(Debug, Default, Clone, Eq, PartialEq)]
126    struct TestParent {
127        pub child: Test,
128        pub child2: Test2,
129        pub child3: Test3,
130    }
131
132    impl OptionsOf<Test> for TestParent {
133        fn set_options(&mut self, value: Test) {
134            self.child = value;
135        }
136    }
137
138    impl OptionsOf<Test2> for TestParent {
139        fn set_options(&mut self, value: Test2) {
140            self.child2 = value;
141        }
142    }
143
144    impl OptionsOf<Test3> for TestParent {
145        fn set_options(&mut self, value: Test3) {
146            self.child3 = value;
147        }
148    }
149
150    impl Validation for Test {
151        type Error = TestError;
152
153        fn is_valid(&self) -> Result<(), Self::Error> {
154            if self.field > 10 {
155                Ok(())
156            } else {
157                Err(TestError::Test(self.clone()))
158            }
159        }
160    }
161
162    impl Validation for Test2 {
163        type Error = TestError;
164
165        fn is_valid(&self) -> Result<(), Self::Error> {
166            if self.field > 20 {
167                Ok(())
168            } else {
169                Err(TestError::Test2(self.clone()))
170            }
171        }
172    }
173
174    impl Validation for Test3 {
175        type Error = TestError;
176
177        fn is_valid(&self) -> Result<(), Self::Error> {
178            if self.field > 20 {
179                Ok(())
180            } else {
181                Err(TestError::Test3(self.clone()))
182            }
183        }
184    }
185
186    impl CompositeValidation for TestParent {
187        fn is_valid_composite(&self) -> Result<(), Self::Error> {
188            if self.child.field == self.child2.field {
189                Ok(())
190            } else {
191                Err(TestError::TestParent(self.clone()))
192            }
193        }
194    }
195
196    impl Validation for TestParent {
197        type Error = TestError;
198
199        fn is_valid(&self) -> Result<(), Self::Error> {
200            self.child.is_valid()?;
201            self.child2.is_valid()?;
202            self.child3.is_valid()?;
203            self.is_valid_composite()
204        }
205    }
206
207    struct TestBuilder(Valid<TestParent>);
208    impl TestBuilder {
209        pub fn new() -> Self {
210            Self(Default::default())
211        }
212
213        pub fn with2<F1, F2>(
214            mut self,
215            options1: F1,
216            options2: F2,
217        ) -> Result<Self, <TestParent as Validation>::Error>
218        where
219            TestParent: OptionsOf<F1> + OptionsOf<F2>,
220            F1: Validation<Error = <TestParent as Validation>::Error>,
221            F2: Validation<Error = <TestParent as Validation>::Error>,
222        {
223            self.0 = self.0.with2(options1, options2)?;
224            Ok(self)
225        }
226
227        pub fn build(self) -> Valid<TestParent> {
228            self.0
229        }
230    }
231
232    #[test]
233    fn test_validation() {
234        let test = Test { field: 40 };
235        let test2 = Test2 { field: 40 };
236        let test3 = Test3 { field: 40 };
237        let parent: Valid<TestParent> = TestParent {
238            child: Test { field: 30 },
239            child2: Test2 { field: 30 },
240            child3: Test3 { field: 30 },
241        }
242        .try_validate()
243        .unwrap()
244        .set(|p| p.child3.field = 120)
245        .unwrap();
246
247        let parent = parent.with2(test.clone(), test2.clone()).unwrap();
248
249        let parent = parent.with3(test.clone(), test2, test3).unwrap();
250
251        assert_eq!(
252            parent.child.field, test.field,
253            "{} != {}",
254            parent.child.field, test.field
255        );
256
257        let fail = parent.with(Test { field: 1234 });
258        assert_eq!(
259            fail,
260            Err(TestError::TestParent(TestParent {
261                child: Test { field: 1234 },
262                child2: Test2 { field: 40 },
263                child3: Test3 { field: 40 }
264            }))
265        );
266
267        let parent = TestBuilder::new()
268            .with2(Test { field: 100 }, Test2 { field: 100 })
269            .unwrap()
270            .build();
271        assert_ne!(
272            parent.child.field, test.field,
273            "{} == {}",
274            parent.child.field, test.field
275        );
276    }
277}