1mod email;
2mod non_empty_string;
3mod telephone;
4mod date_time;
5mod date;
6mod time;
7mod accept;
8
9pub use email::*;
10pub use non_empty_string::*;
11pub use telephone::*;
12pub use date_time::*;
13pub use date::*;
14pub use time::*;
15pub use accept::*;
16
17use num_bigint::BigInt;
18use num_rational::BigRational;
19
20use leptos::*;
21use std::error::Error;
22use std::fmt::{Debug, Display};
23use std::rc::Rc;
24use std::str::FromStr;
25
26#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
28pub struct Optional<T>(Option<T>);
29
30impl<T> FromStr for Optional<T>
31where
32 T: FromStr,
33{
34 type Err = <T as FromStr>::Err;
35
36 fn from_str(s: &str) -> Result<Self, Self::Err> {
37 if s.is_empty() {
38 return Ok(Optional(None));
39 }
40 Ok(Optional(T::from_str(s).ok()))
41 }
42}
43
44impl<T> Display for Optional<T>
45where
46 T: Display,
47{
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 if let Some(value) = &self.0 {
50 write!(f, "{}", value)
51 } else {
52 write!(f, "")
53 }
54 }
55}
56
57macro_rules! impl_direct_datatypes {
58 ( $( $t:ty where $($name:literal $( : $val:literal)? ),* $(,)? );* $(;)? ) => {
59 $(
60 impl Datatype for $t {
61 type Inner = $t;
62 type Error = <$t as FromStr>::Err;
63
64 fn validate(input: $t) -> Result<Self, <$t as FromStr>::Err> {
65 Ok(input)
66 }
67
68 fn attributes() -> Vec<(&'static str, Attribute)> {
69 vec![ $( ($name, {
70 #[allow(unused)]
71 let mut v = Attribute::Bool(true);
72 $( v = Attribute::String(Oco::Borrowed($val)); )?
73 v
74 }) ),* ]
75 }
76 }
77 )*
78 };
79}
80
81impl_direct_datatypes! {
82 u8 where "type": "number", "step": "1", "min": "0", "max": "255", "required";
83 Optional<u8> where "type": "number", "step": "1", "min": "0", "max": "255";
84 u16 where "type": "number", "step": "1", "min": "0", "max": "65535", "required";
85 Optional<u16> where "type": "number", "step": "1", "min": "0", "max": "65535";
86 u32 where "type": "number", "step": "1", "min": "0", "max": "4294967295", "required";
87 Optional<u32> where "type": "number", "step": "1", "min": "0", "max": "4294967295";
88 u64 where "type": "number", "step": "1", "min": "0", "max": "18446744073709551615", "required";
89 Optional<u64> where "type": "number", "step": "1", "min": "0", "max": "18446744073709551615";
90 u128 where "type": "number", "step": "1", "min": "0", "max": "340282366920938463463374607431768211455", "required";
91 Optional<u128> where "type": "number", "step": "1", "min": "0", "max": "340282366920938463463374607431768211455";
92 i8 where "type": "number", "step": "1", "min": "-128", "max": "127", "required";
93 Optional<i8> where "type": "number", "step": "1", "min": "-128", "max": "127";
94 i16 where "type": "number", "step": "1", "min": "-32768", "max": "32767", "required";
95 Optional<i16> where "type": "number", "step": "1", "min": "-32768", "max": "32767";
96 i32 where "type": "number", "step": "1", "min": "-2147483648", "max": "2147483647", "required";
97 Optional<i32> where "type": "number", "step": "1", "min": "-2147483648", "max": "2147483647";
98 i64 where "type": "number", "step": "1", "min": "-9223372036854775808", "max": "9223372036854775807", "required";
99 Optional<i64> where "type": "number", "step": "1", "min": "-9223372036854775808", "max": "9223372036854775807";
100 i128 where "type": "number", "step": "1", "min": "-170141183460469231731687303715884105728", "max": "170141183460469231731687303715884105727", "required";
101 Optional<i128> where "type": "number", "step": "1", "min": "-170141183460469231731687303715884105728", "max": "170141183460469231731687303715884105727";
102 String where "type": "text";
103 BigInt where "type": "number", "step": "1", "required";
104 Optional<BigInt> where "type": "number", "step": "1";
105 BigRational where "type": "number", "required";
106 Optional<BigRational> where "type": "number";
107 DateTime where "type": "datetime-local", "required";
108 Optional<DateTime> where "type": "datetime-local";
109 Date where "type": "date", "required";
110 Optional<Date> where "type": "date";
111 Time where "type": "time", "required";
112 Optional<Time> where "type": "time";
113 bool where "type": "checkbox";
114}
115
116#[macro_export]
118macro_rules! impl_datatype {
119 ($this:ty) => {
120 impl std::fmt::Display for $this {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 write!(f, "{}", self.0)
123 }
124 }
125
126 impl std::ops::Deref for $this {
127 type Target = <$this as $crate::Datatype>::Inner;
128
129 fn deref(&self) -> &Self::Target {
130 &self.0
131 }
132 }
133
134 impl Into<<$this as $crate::Datatype>::Inner> for $this {
135 fn into(self) -> <$this as $crate::Datatype>::Inner {
136 self.0
137 }
138 }
139
140 impl std::str::FromStr for $this {
141 type Err = <$this as $crate::Datatype>::Error;
142
143 fn from_str(s: &str) -> Result<Self, Self::Err> {
144 <$this as $crate::Datatype>::validate(<$this as $crate::Datatype>::Inner::from_str(s).map_err(<$this as $crate::Datatype>::Error::from)?)
145 }
146 }
147
148 impl<'de> serde::Deserialize<'de> for $this {
149 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
150 where
151 D: serde::Deserializer<'de>,
152 {
153 let value = <$this as $crate::Datatype>::Inner::deserialize(deserializer)?;
154 <$this as $crate::Datatype>::validate(value).map_err(serde::de::Error::custom)
155 }
156 }
157 };
158}
159
160pub trait Datatype: Clone + Display + Debug + Default + FromStr<Err = Self::Error> + Into<Self::Inner> + PartialEq + 'static {
163 type Inner: Datatype;
164 type Error: From<<Self::Inner as Datatype>::Error> + Error + Clone + PartialEq + 'static;
165
166 fn validate(input: Self::Inner) -> Result<Self, Self::Error>
168 where
169 Self: Sized;
170
171 fn attributes() -> Vec<(&'static str, Attribute)>;
173}
174
175#[derive(Clone)]
178pub(crate) struct TranslationProvider<T>(Rc<dyn Fn(T) -> TextProp>);
179
180
181pub fn provide_translation<F, T>(f: F)
184where
185 T: Clone + 'static,
186 F: Fn(T) -> TextProp + 'static,
187{
188 provide_context(TranslationProvider(Rc::new(f)));
189}
190
191pub fn expect_translation<T, F>(value: F) -> TextProp
192where
193 F: Into<MaybeSignal<T>>,
194 T: Clone + 'static,
195{
196 let value = value.into();
197 let translation_provider = expect_context::<TranslationProvider<T>>();
198 (move || translation_provider.0(value.get()).get()).into()
199}
200
201pub fn use_translation<T, F>(value: F) -> TextProp
202where
203 F: Into<MaybeSignal<T>>,
204 T: Clone + Display + 'static,
205{
206 let value = value.into();
207 let translation_provider: Option<TranslationProvider<T>> = use_context::<TranslationProvider<T>>();
208 if let Some(translation_provider) = translation_provider {
209 (move || translation_provider.0(value.get()).get()).into()
210 } else {
211 (move || format!("{}", value.get())).into()
212 }
213
214}