1use crate::{Error, FixedDecimal, Interval, Passive, Result, Value};
2use anyhow::Context;
3use quote::ToTokens;
4use rust_decimal::{Decimal, prelude::FromPrimitive};
5use std::{
6 any, array,
7 borrow::Cow,
8 cell::{Cell, RefCell},
9 collections::{BTreeMap, HashMap, LinkedList, VecDeque},
10 hash::Hash,
11 rc::Rc,
12 sync::{Arc, RwLock},
13 vec,
14};
15use time::macros::format_description;
16
17pub trait AsValue {
18 fn as_empty_value() -> Value;
19 fn as_value(self) -> Value;
20 fn try_from_value(value: Value) -> Result<Self>
21 where
22 Self: Sized;
23}
24
25impl<T: AsValue> From<T> for Value {
26 fn from(value: T) -> Self {
27 value.as_value()
28 }
29}
30
31impl From<&'static str> for Value {
32 fn from(value: &'static str) -> Self {
33 Value::Varchar(Some(value.into()))
34 }
35}
36
37macro_rules! impl_as_value {
38 ($source:ty, $value:path => $expr:expr $(, $pat_rest:path => $expr_rest:expr)* $(,)?) => {
39 impl AsValue for $source {
40 fn as_empty_value() -> Value {
41 $value(None)
42 }
43 fn as_value(self) -> Value {
44 $value(Some(self.into()))
45 }
46 fn try_from_value(value: Value) -> Result<Self> {
47 match value {
48 $value(Some(v), ..) => $expr(v),
49 #[allow(unreachable_patterns)]
50 Value::Int64(Some(v), ..) => if v as $source as i64 == v {
51 Ok(v as $source)
52 } else {
53 Err(Error::msg(format!(
54 "Cannot convert `{:?}` into {}, the value is out of bounds",
55 v,
56 stringify!($source),
57 )))
58 }
59 #[allow(unreachable_patterns)]
60 $($pat_rest(Some(v), ..) => $expr_rest(v),)*
61 _ => Err(Error::msg(format!(
62 "Cannot convert `{:?}` into `{}`",
63 value,
64 stringify!($source),
65 ))),
66 }
67 }
68 }
69 };
70}
71impl_as_value!(
72 i8,
73 Value::Int8 => |v| Ok(v),
74 Value::UInt8 => |v| Ok(v as i8),
75);
76impl_as_value!(
77 i16,
78 Value::Int16 => |v| Ok(v),
79 Value::Int8 => |v| Ok(v as i16),
80 Value::UInt16 => |v| Ok(v as i16),
81 Value::UInt8 => |v| Ok(v as i16),
82);
83impl_as_value!(
84 i32,
85 Value::Int32 => |v| Ok(v),
86 Value::Int16 => |v| Ok(v as i32),
87 Value::Int8 => |v| Ok(v as i32),
88 Value::UInt32 => |v| Ok(v as i32),
89 Value::UInt16 => |v| Ok(v as i32),
90 Value::UInt8 => |v| Ok(v as i32),
91);
92impl_as_value!(
93 i64,
94 Value::Int64 => |v| Ok(v),
95 Value::Int32 => |v| Ok(v as i64),
96 Value::Int16 => |v| Ok(v as i64),
97 Value::Int8 => |v| Ok(v as i64),
98 Value::UInt64 => |v| Ok(v as i64),
99 Value::UInt32 => |v| Ok(v as i64),
100 Value::UInt16 => |v| Ok(v as i64),
101 Value::UInt8 => |v| Ok(v as i64),
102);
103impl_as_value!(
104 i128,
105 Value::Int128 => |v| Ok(v),
106 Value::Int64 => |v| Ok(v as i128),
107 Value::Int32 => |v| Ok(v as i128),
108 Value::Int16 => |v| Ok(v as i128),
109 Value::Int8 => |v| Ok(v as i128),
110 Value::UInt128 => |v| Ok(v as i128),
111 Value::UInt64 => |v| Ok(v as i128),
112 Value::UInt32 => |v| Ok(v as i128),
113 Value::UInt16 => |v| Ok(v as i128),
114 Value::UInt8 => |v| Ok(v as i128),
115);
116impl_as_value!(u8, Value::UInt8 => |v| Ok(v));
117impl_as_value!(
118 u16,
119 Value::UInt16 => |v| Ok(v),
120 Value::UInt8 => |v| Ok(v as u16),
121);
122impl_as_value!(
123 u32,
124 Value::UInt32 => |v| Ok(v),
125 Value::UInt16 => |v| Ok(v as u32),
126 Value::UInt8 => |v| Ok(v as u32),
127);
128impl_as_value!(
129 u64,
130 Value::UInt64 => |v| Ok(v),
131 Value::UInt32 => |v| Ok(v as u64),
132 Value::UInt16 => |v| Ok(v as u64),
133 Value::UInt8 => |v| Ok(v as u64),
134);
135impl_as_value!(
136 u128,
137 Value::UInt128 => |v| Ok(v),
138 Value::UInt64 => |v| Ok(v as u128),
139 Value::UInt32 => |v| Ok(v as u128),
140 Value::UInt16 => |v| Ok(v as u128),
141 Value::UInt8 => |v| Ok(v as u128),
142);
143
144macro_rules! impl_as_value {
145 ($source:ty, $value:path => $expr:expr $(, $pat_rest:path => $expr_rest:expr)* $(,)?) => {
146 impl AsValue for $source {
147 fn as_empty_value() -> Value {
148 $value(None)
149 }
150 fn as_value(self) -> Value {
151 $value(Some(self.into()))
152 }
153 fn try_from_value(value: Value) -> Result<Self> {
154 match value {
155 $value(Some(v), ..) => $expr(v),
156 $($pat_rest(Some(v), ..) => $expr_rest(v),)*
157 _ => Err(Error::msg(format!(
158 "Cannot convert `{:?}` into `{}`",
159 value,
160 stringify!($source),
161 ))),
162 }
163 }
164 }
165 };
166}
167impl_as_value!(
168 bool,
169 Value::Boolean => |v| Ok(v),
170 Value::Int8 => |v| Ok(v != 0),
171 Value::Int16 => |v| Ok(v != 0),
172 Value::Int32 => |v| Ok(v != 0),
173 Value::Int64 => |v| Ok(v != 0),
174 Value::Int128 => |v| Ok(v != 0),
175 Value::UInt8 => |v| Ok(v != 0),
176 Value::UInt16 => |v| Ok(v != 0),
177 Value::UInt32 => |v| Ok(v != 0),
178 Value::UInt64 => |v| Ok(v != 0),
179 Value::UInt128 => |v| Ok(v != 0),
180);
181impl_as_value!(
182 f32,
183 Value::Float32 => |v| Ok(v),
184 Value::Float64 => |v| Ok(v as f32),
185 Value::Decimal => |v: Decimal| Ok(v.try_into()?),
186);
187impl_as_value!(
188 f64,
189 Value::Float64 => |v| Ok(v),
190 Value::Float32 => |v| Ok(v as f64),
191 Value::Decimal => |v: Decimal| Ok(v.try_into()?),
192);
193impl_as_value!(char,
194 Value::Char => |v| Ok(v),
195 Value::Varchar => |v: String| {
196 if v.len() != 1 {
197 Err(Error::msg("Cannot convert Value::Varchar containing more then one character into a char."))
198 } else {
199 Ok(v.chars().next().unwrap())
200 }
201 }
202);
203impl_as_value!(
204 String,
205 Value::Varchar => |v| Ok(v),
206 Value::Char => |v: char| Ok(v.into()),
207);
208impl<'a> AsValue for Cow<'a, str> {
209 fn as_empty_value() -> Value {
210 Value::Varchar(None)
211 }
212 fn as_value(self) -> Value {
213 Value::Varchar(Some(self.into()))
214 }
215 fn try_from_value(value: Value) -> Result<Self>
216 where
217 Self: Sized,
218 {
219 let Value::Varchar(Some(value)) = value else {
220 return Err(Error::msg(format!(
221 "Cannot convert `{}` into `Cow<'a, str>`",
222 value.to_token_stream().to_string(),
223 )));
224 };
225 Ok(value.into())
226 }
227}
228impl_as_value!(Box<[u8]>, Value::Blob => |v| Ok(v));
229impl_as_value!(
230 time::Date,
231 Value::Date => |v| Ok(v),
232 Value::Varchar => |v: String| Ok(
233 time::Date::parse(
234 &v,
235 format_description!("[year]-[month]-[day]")
236 )
237 .with_context(|| format!("Cannot convert '{}' to time::Time", v))
238 ?),
239);
240impl_as_value!(
241 time::Time,
242 Value::Time => |v| Ok(v),
243 Value::Varchar => |v: String| {
244 time::Time::parse(
245 &v,
246 format_description!("[hour]:[minute]:[second].[subsecond]"),
247 )
248 .or(time::Time::parse(
249 &v,
250 format_description!("[hour]:[minute]:[second]"),
251 ))
252 .or(time::Time::parse(
253 &v,
254 format_description!("[hour]:[minute]"),
255 ))
256 .with_context(|| format!("Cannot convert '{}' to time::Time", v))
257 .map_err(Into::into)
258 },
259);
260impl_as_value!(
261 time::PrimitiveDateTime,
262 Value::Timestamp => |v| Ok(v),
263 Value::Varchar => |v: String| {
264 time::PrimitiveDateTime::parse(
265 &v,
266 format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond]")
267 )
268 .or(time::PrimitiveDateTime::parse(
269 &v,
270 format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]")
271 ))
272 .or(time::PrimitiveDateTime::parse(
273 &v,
274 format_description!("[year]-[month]-[day]T[hour]:[minute]")
275 ))
276 .or(time::PrimitiveDateTime::parse(
277 &v,
278 format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]")
279 ))
280 .or(time::PrimitiveDateTime::parse(
281 &v,
282 format_description!("[year]-[month]-[day] [hour]:[minute]:[second]")
283 ))
284 .or(time::PrimitiveDateTime::parse(
285 &v,
286 format_description!("[year]-[month]-[day] [hour]:[minute]")
287 ))
288 .with_context(|| format!("Cannot convert '{}' to time::PrimitiveDateTime", v))
289 .map_err(Into::into)
290 },
291);
292impl_as_value!(
293 time::OffsetDateTime,
294 Value::TimestampWithTimezone => |v| Ok(v),
295 Value::Varchar => |v: String| {
296 time::OffsetDateTime::parse(
297 &v,
298 format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond][offset_hour sign:mandatory]:[offset_minute]")
299 )
300 .or(time::OffsetDateTime::parse(
301 &v,
302 format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond][offset_hour sign:mandatory]")
303 ))
304 .or(time::OffsetDateTime::parse(
305 &v,
306 format_description!("[year]-[month]-[day]T[hour]:[minute]:[second][offset_hour sign:mandatory]:[offset_minute]")
307 ))
308 .or(time::OffsetDateTime::parse(
309 &v,
310 format_description!("[year]-[month]-[day]T[hour]:[minute]:[second][offset_hour sign:mandatory]")
311 ))
312 .or(time::OffsetDateTime::parse(
313 &v,
314 format_description!("[year]-[month]-[day]T[hour]:[minute][offset_hour sign:mandatory]:[offset_minute]")
315 ))
316 .or(time::OffsetDateTime::parse(
317 &v,
318 format_description!("[year]-[month]-[day]T[hour]:[minute][offset_hour sign:mandatory]")
319 ))
320 .with_context(|| format!("Cannot convert '{}' to time::OffsetDateTime", v))
321 .map_err(Into::into)
322 }
323);
324impl_as_value!(std::time::Duration, Value::Interval => |v: Interval| Ok(v.into()));
325impl_as_value!(Interval, Value::Interval => |v| Ok(v));
326impl_as_value!(time::Duration, Value::Interval => |v: Interval| Ok(v.into()));
327impl_as_value!(
328 uuid::Uuid,
329 Value::Uuid => |v| Ok(v),
330 Value::Varchar => |v: String| Ok(uuid::Uuid::parse_str(&v)?),
331);
332
333impl AsValue for Decimal {
334 fn as_empty_value() -> Value {
335 Value::Decimal(None, 0, 0)
336 }
337 fn as_value(self) -> Value {
338 Value::Decimal(Some(self), 0, self.scale() as _)
339 }
340 fn try_from_value(value: Value) -> Result<Self> {
341 match value {
342 Value::Decimal(Some(v), ..) => Ok(v),
343 Value::Int8(Some(v), ..) => Ok(Decimal::new(v as i64, 0)),
344 Value::Int16(Some(v), ..) => Ok(Decimal::new(v as i64, 0)),
345 Value::Int32(Some(v), ..) => Ok(Decimal::new(v as i64, 0)),
346 Value::Int64(Some(v), ..) => Ok(Decimal::new(v, 0)),
347 Value::UInt8(Some(v), ..) => Ok(Decimal::new(v as i64, 0)),
348 Value::UInt16(Some(v), ..) => Ok(Decimal::new(v as i64, 0)),
349 Value::UInt32(Some(v), ..) => Ok(Decimal::new(v as i64, 0)),
350 Value::UInt64(Some(v), ..) => Ok(Decimal::new(v as i64, 0)),
351 Value::Float32(Some(v), ..) => Ok(Decimal::from_f32(v)
352 .ok_or(Error::msg("Could not convert the Float32 into Decimal"))?),
353 Value::Float64(Some(v), ..) => Ok(Decimal::from_f64(v)
354 .ok_or(Error::msg("Could not convert the Float64 into Decimal"))?),
355 _ => Err(Error::msg(format!(
356 "Cannot convert `{:?}` into `rust_decimal::Decimal`",
357 value,
358 ))),
359 }
360 }
361}
362
363impl<const W: u8, const S: u8> AsValue for FixedDecimal<W, S> {
364 fn as_empty_value() -> Value {
365 Decimal::as_empty_value()
366 }
367 fn as_value(self) -> Value {
368 Value::Decimal(Some(self.0), W, S)
369 }
370 fn try_from_value(value: Value) -> Result<Self>
371 where
372 Self: Sized,
373 {
374 Ok(Self(Decimal::try_from_value(value)?))
375 }
376}
377
378impl<T: AsValue, const N: usize> AsValue for [T; N] {
379 fn as_empty_value() -> Value {
380 Value::Array(None, Box::new(T::as_empty_value()), N as u32)
381 }
382 fn as_value(self) -> Value {
383 Value::Array(
384 Some(self.into_iter().map(AsValue::as_value).collect()),
385 Box::new(T::as_empty_value()),
386 N as u32,
387 )
388 }
389 fn try_from_value(value: Value) -> Result<Self> {
390 let from_iter = |mut it: vec::IntoIter<Value>| {
391 let len = it.len();
392 array::try_from_fn(|_| {
393 T::try_from_value(it.next().ok_or_else(|| {
394 Error::msg(format!(
395 "Cannot convert a container of {} elements to array {}",
396 len,
397 any::type_name::<Self>()
398 ))
399 })?)
400 })
401 };
402 match value {
403 Value::List(Some(v), ..) if v.len() == N => from_iter(v.into_iter()),
404 Value::Array(Some(v), ..) => from_iter(v.into_iter()),
405 _ => Err(Error::msg(format!(
406 "Cannot convert `{:?}` into array `{}`",
407 value,
408 any::type_name::<Self>()
409 ))),
410 }
411 }
412}
413
414macro_rules! impl_as_value {
415 ($list:ident) => {
416 impl<T: AsValue> AsValue for $list<T> {
417 fn as_empty_value() -> Value {
418 Value::List(None, Box::new(T::as_empty_value()))
419 }
420 fn as_value(self) -> Value {
421 Value::List(
422 Some(self.into_iter().map(AsValue::as_value).collect()),
423 Box::new(T::as_empty_value()),
424 )
425 }
426 fn try_from_value(value: Value) -> Result<Self> {
427 match value {
428 Value::List(Some(v), ..) => Ok(v
429 .into_iter()
430 .map(|v| Ok::<_, Error>(<T as AsValue>::try_from_value(v)?))
431 .collect::<Result<_>>()?),
432 Value::List(None, ..) => Ok($list::<T>::new()),
433 Value::Array(Some(v), ..) => Ok(v
434 .into_iter()
435 .map(|v| Ok::<_, Error>(<T as AsValue>::try_from_value(v)?))
436 .collect::<Result<_>>()?),
437 _ => Err(Error::msg(format!(
438 "Cannot convert `{:?}` into list-like `{}`",
439 value,
440 stringify!($list<T>),
441 ))),
442 }
443 }
444 }
445 };
446}
447impl_as_value!(Vec);
448impl_as_value!(VecDeque);
449impl_as_value!(LinkedList);
450
451macro_rules! impl_as_value {
452 ($map:ident, $($key_trait:ident),+) => {
453 impl<K: AsValue $(+ $key_trait)+, V: AsValue> AsValue for $map<K, V> {
454 fn as_empty_value() -> Value {
455 Value::Map(None, K::as_empty_value().into(), V::as_empty_value().into())
456 }
457 fn as_value(self) -> Value {
458 Value::Map(
459 Some(
460 self.into_iter()
461 .map(|(k, v)| (k.as_value(), v.as_value()))
462 .collect(),
463 ),
464 K::as_empty_value().into(),
465 V::as_empty_value().into(),
466 )
467 }
468 fn try_from_value(value: Value) -> Result<Self> {
469 if let Value::Map(Some(v), ..) = value {
470 Ok(v.into_iter()
471 .map(|(k, v)| {
472 Ok((
473 <K as AsValue>::try_from_value(k)?,
474 <V as AsValue>::try_from_value(v)?,
475 ))
476 })
477 .collect::<Result<_>>()?)
478 } else {
479 Err(Error::msg(format!(
480 "Cannot convert `{:?}` into map `{}`",
481 value,
482 stringify!($map<K, V>),
483 )))
484 }
485 }
486 }
487 }
488}
489impl_as_value!(BTreeMap, Ord);
490impl_as_value!(HashMap, Eq, Hash);
491
492impl<T: AsValue> AsValue for Passive<T> {
493 fn as_empty_value() -> Value {
494 T::as_empty_value()
495 }
496 fn as_value(self) -> Value {
497 match self {
498 Passive::Set(v) => v.as_value(),
499 Passive::NotSet => T::as_empty_value(),
500 }
501 }
502 fn try_from_value(value: Value) -> Result<Self> {
503 Ok(Passive::Set(<T as AsValue>::try_from_value(value)?))
504 }
505}
506
507impl<T: AsValue> AsValue for Option<T> {
508 fn as_empty_value() -> Value {
509 T::as_empty_value()
510 }
511 fn as_value(self) -> Value {
512 match self {
513 Some(v) => v.as_value(),
514 None => T::as_empty_value(),
515 }
516 }
517 fn try_from_value(value: Value) -> Result<Self> {
518 Ok(if value.is_null() {
519 None
520 } else {
521 Some(<T as AsValue>::try_from_value(value)?)
522 })
523 }
524}
525
526impl<T: AsValue> AsValue for Box<T> {
528 fn as_empty_value() -> Value {
529 T::as_empty_value()
530 }
531 fn as_value(self) -> Value {
532 (*self).as_value()
533 }
534 fn try_from_value(value: Value) -> Result<Self> {
535 Ok(Box::new(<T as AsValue>::try_from_value(value)?))
536 }
537}
538
539macro_rules! impl_as_value {
540 ($wrapper:ident) => {
541 impl<T: AsValue + ToOwned<Owned = impl AsValue>> AsValue for $wrapper<T> {
542 fn as_empty_value() -> Value {
543 T::as_empty_value()
544 }
545 fn as_value(self) -> Value {
546 $wrapper::<T>::into_inner(self).as_value()
547 }
548 fn try_from_value(value: Value) -> Result<Self> {
549 Ok($wrapper::new(<T as AsValue>::try_from_value(value)?))
550 }
551 }
552 };
553}
554impl_as_value!(Cell);
555impl_as_value!(RefCell);
556
557impl<T: AsValue> AsValue for RwLock<T> {
558 fn as_empty_value() -> Value {
559 T::as_empty_value()
560 }
561 fn as_value(self) -> Value {
562 self.into_inner()
563 .expect("Error occurred while trying to take the content of the RwLock")
564 .as_value()
565 }
566 fn try_from_value(value: Value) -> Result<Self> {
567 Ok(RwLock::new(<T as AsValue>::try_from_value(value)?))
568 }
569}
570
571macro_rules! impl_as_value {
572 ($wrapper:ident) => {
573 impl<T: AsValue + ToOwned<Owned = impl AsValue>> AsValue for $wrapper<T> {
574 fn as_empty_value() -> Value {
575 T::as_empty_value()
576 }
577 fn as_value(self) -> Value {
578 $wrapper::try_unwrap(self)
579 .map(|v| v.as_value())
580 .unwrap_or_else(|v| v.as_ref().to_owned().as_value())
581 }
582 fn try_from_value(value: Value) -> Result<Self> {
583 Ok($wrapper::new(<T as AsValue>::try_from_value(value)?))
584 }
585 }
586 };
587}
588impl_as_value!(Arc);
589impl_as_value!(Rc);