|
1 | 1 | #![doc = include_str!("../README.md")] |
2 | | -use derive_more::Display; |
3 | | -use std::error::Error; |
4 | | -use std::fmt::{Debug, Display}; |
5 | | -use std::hash::{Hash, Hasher}; |
6 | | -use std::marker::PhantomData; |
7 | | -use std::ops::Deref; |
8 | | -use std::str::FromStr; |
9 | 2 | pub mod infallible; |
10 | 3 | pub use infallible::*; |
11 | 4 | pub mod via_string; |
12 | 5 | pub use via_string::*; |
13 | | - |
14 | | -#[derive(Debug)] |
15 | | -pub struct Tagged<Rep, Tag>(Rep, PhantomData<Tag>); |
16 | | - |
17 | | -pub trait Refine<Rep>: Sized { |
18 | | - type RefineError; |
19 | | - |
20 | | - fn refine(rep: Rep) -> Result<Rep, Self::RefineError> { |
21 | | - Ok(rep) |
22 | | - } |
23 | | -} |
24 | | - |
25 | | -impl<Rep, Tag> Tagged<Rep, Tag> { |
26 | | - pub fn new(rep: Rep) -> Result<Self, Tag::RefineError> |
27 | | - where |
28 | | - Tag: Refine<Rep>, |
29 | | - { |
30 | | - Tag::refine(rep).map(|rep| Tagged(rep, PhantomData)) |
31 | | - } |
32 | | - pub fn rep(&self) -> &Rep { |
33 | | - &self.0 |
34 | | - } |
35 | | -} |
36 | | - |
37 | | -impl<Rep: Eq, Tag> Eq for Tagged<Rep, Tag> {} |
38 | | - |
39 | | -impl<Rep: PartialEq, Tag> PartialEq for Tagged<Rep, Tag> { |
40 | | - fn eq(&self, other: &Self) -> bool { |
41 | | - self.rep() == other.rep() |
42 | | - } |
43 | | -} |
44 | | - |
45 | | -impl<Rep: Ord, Tag> Ord for Tagged<Rep, Tag> { |
46 | | - fn cmp(&self, other: &Self) -> std::cmp::Ordering { |
47 | | - self.rep().cmp(other.rep()) |
48 | | - } |
49 | | -} |
50 | | - |
51 | | -impl<Rep: PartialOrd, Tag> PartialOrd for Tagged<Rep, Tag> { |
52 | | - fn partial_cmp( |
53 | | - &self, |
54 | | - other: &Self, |
55 | | - ) -> Option<std::cmp::Ordering> { |
56 | | - self.rep().partial_cmp(other.rep()) |
57 | | - } |
58 | | -} |
59 | | - |
60 | | -impl<Rep: Clone, Tag> Clone for Tagged<Rep, Tag> { |
61 | | - fn clone(&self) -> Self { |
62 | | - Tagged(self.rep().clone(), PhantomData) |
63 | | - } |
64 | | -} |
65 | | - |
66 | | -impl<Rep: Display, Tag> Display for Tagged<Rep, Tag> { |
67 | | - fn fmt( |
68 | | - &self, |
69 | | - f: &mut std::fmt::Formatter<'_>, |
70 | | - ) -> std::fmt::Result { |
71 | | - self.rep().fmt(f) |
72 | | - } |
73 | | -} |
74 | | - |
75 | | -impl<Rep: Hash, Tag> Hash for Tagged<Rep, Tag> { |
76 | | - fn hash<H: Hasher>(&self, state: &mut H) { |
77 | | - self.rep().hash(state); |
78 | | - } |
79 | | -} |
80 | | - |
81 | | -impl<Rep, Tag> Deref for Tagged<Rep, Tag> { |
82 | | - type Target = Rep; |
83 | | - |
84 | | - fn deref(&self) -> &Self::Target { |
85 | | - self.rep() |
86 | | - } |
87 | | -} |
88 | | - |
89 | | -#[derive(Debug, Display)] |
90 | | -pub enum ParseError<Rep, Tag> |
91 | | -where |
92 | | - Rep: FromStr, |
93 | | - Tag: Refine<Rep>, |
94 | | -{ |
95 | | - Decode(Rep::Err), |
96 | | - Refine(Tag::RefineError), |
97 | | -} |
98 | | - |
99 | | -impl<Rep, Tag> Error for ParseError<Rep, Tag> |
100 | | -where |
101 | | - Rep: Debug + FromStr, |
102 | | - Tag: Debug + Refine<Rep>, |
103 | | - Rep::Err: Debug + Display, |
104 | | - Tag::RefineError: Debug + Display, |
105 | | -{ |
106 | | -} |
107 | | - |
108 | | -impl<Rep, Tag> Eq for ParseError<Rep, Tag> |
109 | | -where |
110 | | - Rep: FromStr, |
111 | | - Tag: Refine<Rep>, |
112 | | - Rep::Err: Eq, |
113 | | - Tag::RefineError: Eq, |
114 | | -{ |
115 | | -} |
116 | | - |
117 | | -impl<Rep, Tag> PartialEq for ParseError<Rep, Tag> |
118 | | -where |
119 | | - Rep: FromStr, |
120 | | - Tag: Refine<Rep>, |
121 | | - Rep::Err: PartialEq, |
122 | | - Tag::RefineError: PartialEq, |
123 | | -{ |
124 | | - fn eq(&self, other: &Self) -> bool { |
125 | | - match (self, other) { |
126 | | - ( |
127 | | - ParseError::Decode(a), |
128 | | - ParseError::Decode(b), |
129 | | - ) => a == b, |
130 | | - ( |
131 | | - ParseError::Refine(a), |
132 | | - ParseError::Refine(b), |
133 | | - ) => a == b, |
134 | | - _ => false, |
135 | | - } |
136 | | - } |
137 | | -} |
138 | | - |
139 | | -impl<Rep, Tag> Clone for ParseError<Rep, Tag> |
140 | | -where |
141 | | - Rep: FromStr, |
142 | | - Tag: Refine<Rep>, |
143 | | - Rep::Err: Clone, |
144 | | - Tag::RefineError: Clone, |
145 | | -{ |
146 | | - fn clone(&self) -> Self { |
147 | | - match self { |
148 | | - ParseError::Decode(err) => { |
149 | | - ParseError::Decode(err.clone()) |
150 | | - } |
151 | | - ParseError::Refine(err) => { |
152 | | - ParseError::Refine(err.clone()) |
153 | | - } |
154 | | - } |
155 | | - } |
156 | | -} |
157 | | - |
158 | | -impl<Rep, Tag> FromStr for Tagged<Rep, Tag> |
159 | | -where |
160 | | - Rep: FromStr, |
161 | | - Tag: Refine<Rep>, |
162 | | -{ |
163 | | - type Err = ParseError<Rep, Tag>; |
164 | | - fn from_str(s: &str) -> Result<Self, Self::Err> { |
165 | | - Tagged::new( |
166 | | - Rep::from_str(s).map_err(ParseError::Decode)?, |
167 | | - ) |
168 | | - .map_err(ParseError::Refine) |
169 | | - } |
170 | | -} |
171 | | - |
172 | | -#[cfg(feature = "serde")] |
173 | | -use serde::{Deserialize, Serialize}; |
174 | | - |
175 | | -#[cfg(feature = "serde")] |
176 | | -impl<Rep: Serialize, Tag> Serialize for Tagged<Rep, Tag> { |
177 | | - fn serialize<S>( |
178 | | - &self, |
179 | | - serializer: S, |
180 | | - ) -> Result<S::Ok, S::Error> |
181 | | - where |
182 | | - S: serde::Serializer, |
183 | | - { |
184 | | - self.rep().serialize(serializer) |
185 | | - } |
186 | | -} |
187 | | - |
188 | | -#[cfg(feature = "serde")] |
189 | | -impl<'de, Rep, Tag> Deserialize<'de> for Tagged<Rep, Tag> |
190 | | -where |
191 | | - Rep: Deserialize<'de>, |
192 | | - Tag: Refine<Rep>, |
193 | | - Tag::RefineError: Display, |
194 | | -{ |
195 | | - fn deserialize<D>( |
196 | | - deserializer: D, |
197 | | - ) -> Result<Self, D::Error> |
198 | | - where |
199 | | - D: serde::Deserializer<'de>, |
200 | | - { |
201 | | - Rep::deserialize(deserializer).and_then(|rep| { |
202 | | - Tagged::new(rep) |
203 | | - .map_err(serde::de::Error::custom) |
204 | | - }) |
205 | | - } |
206 | | -} |
207 | | - |
208 | | -#[cfg(feature = "diesel")] |
209 | | -mod diesel_impl { |
210 | | - use crate::*; |
211 | | - use diesel::Queryable; |
212 | | - use diesel::backend::Backend; |
213 | | - use diesel::deserialize::FromSql; |
214 | | - use diesel::expression::AsExpression; |
215 | | - use diesel::serialize::{Output, ToSql}; |
216 | | - use diesel::sql_types::SingleValue; |
217 | | - use std::error::Error; |
218 | | - |
219 | | - impl<Rep, Tag, ST> AsExpression<ST> for Tagged<Rep, Tag> |
220 | | - where |
221 | | - Rep: Clone + AsExpression<ST>, |
222 | | - ST: SingleValue, |
223 | | - { |
224 | | - type Expression = Rep::Expression; |
225 | | - fn as_expression(self) -> Self::Expression { |
226 | | - self.rep().clone().as_expression() |
227 | | - } |
228 | | - } |
229 | | - |
230 | | - impl<Rep, Tag, ST> AsExpression<ST> for &Tagged<Rep, Tag> |
231 | | - where |
232 | | - Rep: Clone + AsExpression<ST>, |
233 | | - ST: SingleValue, |
234 | | - { |
235 | | - type Expression = Rep::Expression; |
236 | | - fn as_expression(self) -> Self::Expression { |
237 | | - self.rep().clone().as_expression() |
238 | | - } |
239 | | - } |
240 | | - |
241 | | - impl<DB, Rep, Tag, ST> ToSql<ST, DB> for Tagged<Rep, Tag> |
242 | | - where |
243 | | - Rep: ToSql<ST, DB>, |
244 | | - DB: Backend, |
245 | | - Tag: Debug, |
246 | | - { |
247 | | - fn to_sql<'a>( |
248 | | - &'a self, |
249 | | - out: &mut Output<'a, '_, DB>, |
250 | | - ) -> diesel::serialize::Result { |
251 | | - self.rep().to_sql(out) |
252 | | - } |
253 | | - } |
254 | | - |
255 | | - impl<DB, Rep, Tag, ST> FromSql<ST, DB> for Tagged<Rep, Tag> |
256 | | - where |
257 | | - Rep: FromSql<ST, DB>, |
258 | | - Tag: Refine<Rep>, |
259 | | - Tag::RefineError: 'static + Error + Send + Sync, |
260 | | - DB: Backend, |
261 | | - { |
262 | | - fn from_sql( |
263 | | - bytes: DB::RawValue<'_>, |
264 | | - ) -> diesel::deserialize::Result<Self> { |
265 | | - let rep = Rep::from_sql(bytes)?; |
266 | | - Ok(Tagged::new(rep).map_err(Box::new)?) |
267 | | - } |
268 | | - } |
269 | | - |
270 | | - impl<Rep, Tag, ST, DB> Queryable<ST, DB> |
271 | | - for Tagged<Rep, Tag> |
272 | | - where |
273 | | - Rep: Queryable<ST, DB>, |
274 | | - Tag: Refine<Rep>, |
275 | | - Tag::RefineError: 'static + Error + Send + Sync, |
276 | | - DB: Backend, |
277 | | - { |
278 | | - type Row = Rep::Row; |
279 | | - fn build( |
280 | | - row: Self::Row, |
281 | | - ) -> diesel::deserialize::Result<Self> { |
282 | | - let rep = Queryable::build(row)?; |
283 | | - Ok(Tagged::new(rep).map_err(Box::new)?) |
284 | | - } |
285 | | - } |
286 | | -} |
| 6 | +pub mod parse_error; |
| 7 | +pub use parse_error::*; |
| 8 | +pub mod refine; |
| 9 | +pub use refine::*; |
| 10 | +pub mod tagged; |
| 11 | +pub use tagged::*; |
0 commit comments