1use anyhow::Result;
2
3use crate::guard::Guard;
4
5pub trait Validator: 'static + Copy {
6 type Item;
7 type Error;
8 fn validate(item: &Self::Item) -> Result<(), Self::Error>;
9}
10
11#[derive(
12 Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
13)]
14#[repr(transparent)]
15pub struct View<T: 'static, E, U: Validator<Item = T, Error = E>>(T, std::marker::PhantomData<U>);
16
17impl<T: std::fmt::Debug, E, U: Validator<Item = T, Error = E>> std::fmt::Debug for View<T, E, U> {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 f.debug_tuple("View").field(&self.0).finish()
20 }
21}
22
23impl<T, E, U: Validator<Item = T, Error = E>> std::ops::Deref for View<T, E, U> {
24 type Target = T;
25
26 #[inline(always)]
27 fn deref(&self) -> &Self::Target {
28 self.as_ref()
29 }
30}
31
32impl<T, E, U: Validator<Item = T, Error = E>> AsRef<T> for View<T, E, U> {
33 #[inline(always)]
34 fn as_ref(&self) -> &T {
35 &self.0
36 }
37}
38
39impl<T, E, U: Validator<Item = T, Error = E>> View<T, E, U> {
40 #[inline(always)]
41 pub fn new(item: T) -> Self {
42 Self(item, std::marker::PhantomData)
43 }
44
45 #[inline(always)]
46 pub fn with_validator(item: T, _: U) -> Self {
47 Self(item, std::marker::PhantomData)
48 }
49
50 #[inline(always)]
51 pub fn into_inner(self) -> T {
52 self.0
53 }
54
55 #[inline(always)]
56 #[must_use]
57 pub fn modify<'a>(&'a mut self) -> Guard<'a, T, E, U> {
58 Guard::new(&mut self.0)
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_view() -> Result<()> {
68 #[derive(Clone, Copy)]
69 struct TestValidator;
70
71 impl Validator for TestValidator {
72 type Item = i32;
73 type Error = anyhow::Error;
74
75 fn validate(item: &Self::Item) -> Result<()> {
76 if *item < 0 {
77 Err(anyhow::anyhow!("Value must be positive"))
78 } else if *item % 2 == 0 && *item != 0 && *item <= 10 {
79 Err(anyhow::anyhow!(
80 "Value must be odd, or zero, or greater than 10"
81 ))
82 } else if *item == 7 {
83 Err(anyhow::anyhow!("Value must not be 7"))
84 } else {
85 Ok(())
86 }
87 }
88 }
89
90 let mut item = View::with_validator(0, TestValidator);
91 let mut g = item.modify();
92
93 *g = 1;
94 assert_eq!(*g, 1);
95 assert!(g.check().is_ok());
96
97 *g = -1;
98 assert_eq!(*g, -1);
99 assert!(g.check().is_err());
100
101 *g = 12;
102 assert_eq!(*g, 12);
103 assert!(g.check().is_ok());
104
105 *g = 7;
106 assert_eq!(*g, 7);
107
108 let mut g = match g.commit() {
109 Ok(_) => panic!("Expected error"),
110 Err(g) => g,
111 };
112
113 assert_eq!(*g, 7);
115
116 *g = 100;
117 assert!(g.commit().is_ok());
118
119 assert_eq!(&*item, &100);
122
123 Ok(())
124 }
125}