1use core::{
4 error::Error,
5 fmt::{Debug, Display},
6 ops::Range,
7};
8
9use alloc::string::{String, ToString};
10use nami::{Binding, SignalExt};
11use regex::Regex;
12use waterui_core::View;
13use waterui_layout::stack::vstack;
14use waterui_text::text;
15
16macro_rules! impl_error {
17 ($ident:ident,$message:expr) => {
18 #[derive(Debug, Clone, Copy)]
19 #[doc = $message]
20 pub struct $ident;
21
22 impl core::fmt::Display for $ident {
23 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
24 write!(f, $message)
25 }
26 }
27
28 impl core::error::Error for $ident {}
29 };
30}
31
32pub trait Validatable: View + Sized {
36 type Value;
38 fn validable(&mut self) -> &mut Binding<Self::Value>;
42}
43
44pub trait Validator<T>: Clone + 'static {
49 type Err: Error;
51 fn validate(&self, value: T) -> Result<(), Self::Err>;
61
62 fn and<V>(self, other: V) -> And<Self, V>
69 where
70 Self: Sized,
71 V: Validator<T>,
72 {
73 And(self, other)
74 }
75 fn or<V>(self, other: V) -> Or<Self, V>
81 where
82 Self: Sized,
83 V: Validator<T>,
84 {
85 Or(self, other)
86 }
87}
88
89#[derive(Debug, Clone)]
93pub struct ValidatableView<V, T> {
94 view: V,
95 validator: T,
96}
97
98impl<V, T> View for ValidatableView<V, T>
99where
100 T: Validator<V::Value>,
101 V: Validatable<Value: Clone>,
102{
103 fn body(mut self, _env: &waterui_core::Environment) -> impl View {
104 let value = {
105 let value = self.view.validable();
106 let validator = self.validator.clone();
107 let new_binding = value.filter(move |v| validator.validate(v.clone()).is_ok());
108
109 *value = new_binding;
110 value.clone()
111 };
112 vstack((
113 self.view,
114 text(value.map(move |v| {
115 if let Err(reason) = self.validator.validate(v) {
116 reason.to_string()
117 } else {
118 String::new()
119 }
120 })),
121 ))
122 }
123}
124
125#[derive(Debug, Clone)]
127pub struct OutOfRange<T>(pub Range<T>);
128
129impl<T: Display> Display for OutOfRange<T> {
130 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
131 write!(
132 f,
133 "Value is out of range: {} - {}.",
134 self.0.start, self.0.end
135 )
136 }
137}
138
139impl<T: Display + Debug> Error for OutOfRange<T> {}
140
141impl<T: Display + Debug + Ord + Clone + 'static> Validator<T> for Range<T> {
142 type Err = OutOfRange<T>;
143 fn validate(&self, value: T) -> Result<(), Self::Err> {
144 self.contains(&value)
145 .then_some(())
146 .ok_or(OutOfRange(self.clone()))
147 }
148}
149
150impl<V: Validatable, T> ValidatableView<V, T> {
151 pub const fn new(view: V, validator: T) -> Self {
157 Self { view, validator }
158 }
159}
160impl_error!(NotMatch, "Value does not match the required pattern.");
161
162impl<T> Validator<T> for Regex
163where
164 T: AsRef<str>,
165{
166 type Err = NotMatch;
167 fn validate(&self, value: T) -> Result<(), Self::Err> {
168 self.is_match(value.as_ref()).then_some(()).ok_or(NotMatch)
169 }
170}
171
172#[derive(Debug, Clone)]
175pub struct And<A, B>(A, B);
176
177#[derive(Debug, Clone)]
179pub enum AndError<A, B> {
180 A(A),
182 B(B),
184}
185
186impl<A, B> Display for AndError<A, B>
187where
188 A: Display,
189 B: Display,
190{
191 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
192 match self {
193 Self::A(a) => write!(f, "{a}"),
194 Self::B(b) => write!(f, "{b}"),
195 }
196 }
197}
198
199impl<A, B> Error for AndError<A, B>
200where
201 A: Error,
202 B: Error,
203{
204}
205
206impl<T, A, B> Validator<T> for And<A, B>
207where
208 T: Clone,
209 A: Validator<T>,
210 B: Validator<T>,
211{
212 type Err = AndError<A::Err, B::Err>;
213 fn validate(&self, value: T) -> Result<(), Self::Err> {
214 self.0.validate(value.clone()).map_err(AndError::A)?;
215 self.1.validate(value).map_err(AndError::B)
216 }
217}
218
219#[derive(Debug, Clone)]
223pub struct Or<A, B>(A, B);
224
225#[derive(Debug, Clone)]
227pub struct OrError<A, B>(pub A, pub B);
228
229impl<A, B> Display for OrError<A, B>
230where
231 A: Display,
232 B: Display,
233{
234 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
235 write!(
236 f,
237 "At least one of the following errors occurred:\n1. {}\n2. {}",
238 self.0, self.1
239 )
240 }
241}
242
243impl<A, B> Error for OrError<A, B>
244where
245 A: Error,
246 B: Error,
247{
248}
249
250impl<T, A, B> Validator<T> for Or<A, B>
251where
252 T: Clone,
253 A: Validator<T>,
254 B: Validator<T>,
255{
256 type Err = OrError<A::Err, B::Err>;
257 fn validate(&self, value: T) -> Result<(), Self::Err> {
258 self.0
259 .validate(value.clone())
260 .or_else(|e1| self.1.validate(value).map_err(|e2| OrError(e1, e2)))
261 }
262}
263
264#[derive(Debug, Clone, Copy)]
266pub struct Required;
267
268impl_error!(RequiredError, "Value is required.");
269
270impl<T> Validator<Option<T>> for Required {
271 type Err = RequiredError;
272 fn validate(&self, value: Option<T>) -> Result<(), Self::Err> {
273 value.is_some().then_some(()).ok_or(RequiredError)
274 }
275}
276
277impl<'a> Validator<&'a str> for Required {
278 type Err = RequiredError;
279
280 fn validate(&self, value: &'a str) -> Result<(), Self::Err> {
281 value.trim().is_empty().then_some(()).ok_or(RequiredError)
283 }
284}