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