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