mysql_common/value/convert/
mod.rs

1// Copyright (c) 2017 Anatoly Ikorsky
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9use btoi::{btoi, btou};
10use num_traits::ToPrimitive;
11use regex::bytes::Regex;
12
13use std::{
14    any::type_name,
15    borrow::Cow,
16    convert::{TryFrom, TryInto},
17    rc::Rc,
18    str::from_utf8,
19    sync::{Arc, LazyLock},
20    time::Duration,
21};
22
23use crate::value::Value;
24
25pub mod bigdecimal;
26pub mod bigint;
27pub mod chrono;
28pub mod decimal;
29pub mod time;
30pub mod uuid;
31
32#[cfg(feature = "chrono")]
33static DATETIME_RE_YMD: LazyLock<Regex> =
34    LazyLock::new(|| Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap());
35#[cfg(feature = "chrono")]
36static DATETIME_RE_YMD_HMS: LazyLock<Regex> =
37    LazyLock::new(|| Regex::new(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$").unwrap());
38#[cfg(feature = "chrono")]
39static DATETIME_RE_YMD_HMS_NS: LazyLock<Regex> =
40    LazyLock::new(|| Regex::new(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{1,6}$").unwrap());
41static TIME_RE_HH_MM_SS: LazyLock<Regex> =
42    LazyLock::new(|| Regex::new(r"^\d{2}:[0-5]\d:[0-5]\d$").unwrap());
43static TIME_RE_HH_MM_SS_MS: LazyLock<Regex> =
44    LazyLock::new(|| Regex::new(r"^\d{2}:[0-5]\d:[0-5]\d\.\d{1,6}$").unwrap());
45static TIME_RE_HHH_MM_SS: LazyLock<Regex> =
46    LazyLock::new(|| Regex::new(r"^[0-8]\d\d:[0-5]\d:[0-5]\d$").unwrap());
47static TIME_RE_HHH_MM_SS_MS: LazyLock<Regex> =
48    LazyLock::new(|| Regex::new(r"^[0-8]\d\d:[0-5]\d:[0-5]\d\.\d{1,6}$").unwrap());
49
50/// Returns (year, month, day, hour, minute, second, micros)
51#[cfg(feature = "chrono")]
52fn parse_mysql_datetime_string(bytes: &[u8]) -> Option<(u32, u32, u32, u32, u32, u32, u32)> {
53    let len = bytes.len();
54
55    #[derive(PartialEq, Eq, PartialOrd, Ord)]
56    #[repr(u8)]
57    enum DateTimeKind {
58        Ymd = 0,
59        YmdHms,
60        YmdHmsMs,
61    }
62
63    let kind = if len == 10 && DATETIME_RE_YMD.is_match(bytes) {
64        DateTimeKind::Ymd
65    } else if len == 19 && DATETIME_RE_YMD_HMS.is_match(bytes) {
66        DateTimeKind::YmdHms
67    } else if 20 < len && len < 27 && DATETIME_RE_YMD_HMS_NS.is_match(bytes) {
68        DateTimeKind::YmdHmsMs
69    } else {
70        return None;
71    };
72
73    let (year, month, day, hour, minute, second, micros) = match kind {
74        DateTimeKind::Ymd => (..4, 5..7, 8..10, None, None, None, None),
75        DateTimeKind::YmdHms => (
76            ..4,
77            5..7,
78            8..10,
79            Some(11..13),
80            Some(14..16),
81            Some(17..19),
82            None,
83        ),
84        DateTimeKind::YmdHmsMs => (
85            ..4,
86            5..7,
87            8..10,
88            Some(11..13),
89            Some(14..16),
90            Some(17..19),
91            Some(20..),
92        ),
93    };
94
95    Some((
96        btou(&bytes[year]).unwrap(),
97        btou(&bytes[month]).unwrap(),
98        btou(&bytes[day]).unwrap(),
99        hour.map(|pos| btou(&bytes[pos]).unwrap()).unwrap_or(0),
100        minute.map(|pos| btou(&bytes[pos]).unwrap()).unwrap_or(0),
101        second.map(|pos| btou(&bytes[pos]).unwrap()).unwrap_or(0),
102        micros.map(|pos| parse_micros(&bytes[pos])).unwrap_or(0),
103    ))
104}
105
106/// `FromValue` conversion error.
107#[derive(Debug, Clone, PartialEq, thiserror::Error)]
108#[error("Couldn't convert the value `{:?}` to a desired type", _0)]
109pub struct FromValueError(pub Value);
110
111/// Implement this trait to convert a value to some type.
112///
113/// The `FromRow` trait requires an ability to rollback this conversion to an original `Value`
114/// instance. Thats the reason why there is the `Intermediate` type – consider implementing
115/// `Into<Value>` for your `Intermediate` type if you want `FromRow` to work with your type.
116pub trait FromValue: Sized {
117    type Intermediate: TryFrom<Value, Error = FromValueError> + Into<Self>;
118
119    /// Will panic if could not convert `v` to `Self`.
120    fn from_value(v: Value) -> Self {
121        match Self::from_value_opt(v) {
122            Ok(this) => this,
123            Err(e) => panic!("Could not retrieve `{}`: {e}", type_name::<Self>(),),
124        }
125    }
126
127    /// Will return `Err(Error::FromValueError(v))` if could not convert `v` to `Self`.
128    fn from_value_opt(v: Value) -> Result<Self, FromValueError> {
129        Self::Intermediate::try_from(v).map(Into::into)
130    }
131
132    /// Will return `Err(Error::FromValueError(v))` if `v` is not convertible to `Self`.
133    fn get_intermediate(v: Value) -> Result<Self::Intermediate, FromValueError> {
134        Self::Intermediate::try_from(v)
135    }
136}
137
138/// Intermediate result for a type that requires parsing.
139#[derive(Debug, Clone, PartialEq)]
140pub struct ParseIr<T>(pub T, pub Value);
141
142impl<T> ParseIr<T> {
143    pub fn commit(self) -> T {
144        self.0
145    }
146
147    pub fn rollback(self) -> Value {
148        self.1
149    }
150}
151
152/// Intermediate result for a type that optionally requires parsing.
153#[derive(Debug, Clone, PartialEq)]
154pub enum ParseIrOpt<T> {
155    /// Type instance is ready without parsing.
156    Ready(T),
157    /// Type instance is successfully parsed from this value.
158    Parsed(T, Value),
159}
160
161impl<T> ParseIrOpt<T> {
162    pub fn commit(self) -> T {
163        match self {
164            ParseIrOpt::Ready(t) | ParseIrOpt::Parsed(t, _) => t,
165        }
166    }
167
168    pub fn rollback(self) -> Value
169    where
170        T: Into<Value>,
171    {
172        match self {
173            ParseIrOpt::Ready(t) => t.into(),
174            ParseIrOpt::Parsed(_, v) => v,
175        }
176    }
177}
178
179macro_rules! impl_from_value_num {
180    ($ty:ident) => {
181        impl TryFrom<Value> for ParseIrOpt<$ty> {
182            type Error = FromValueError;
183
184            fn try_from(v: Value) -> Result<Self, Self::Error> {
185                match v {
186                    Value::Int(x) => $ty::try_from(x)
187                        .map(ParseIrOpt::Ready)
188                        .map_err(|_| FromValueError(Value::Int(x))),
189                    Value::UInt(x) => $ty::try_from(x)
190                        .map(ParseIrOpt::Ready)
191                        .map_err(|_| FromValueError(Value::UInt(x))),
192                    Value::Bytes(bytes) => match btoi(&*bytes) {
193                        Ok(x) => Ok(ParseIrOpt::Parsed(x, Value::Bytes(bytes))),
194                        _ => Err(FromValueError(Value::Bytes(bytes))),
195                    },
196                    v => Err(FromValueError(v)),
197                }
198            }
199        }
200
201        impl From<ParseIrOpt<$ty>> for $ty {
202            fn from(value: ParseIrOpt<$ty>) -> Self {
203                value.commit()
204            }
205        }
206
207        impl From<ParseIrOpt<$ty>> for Value {
208            fn from(value: ParseIrOpt<$ty>) -> Self {
209                value.rollback()
210            }
211        }
212
213        impl FromValue for $ty {
214            type Intermediate = ParseIrOpt<$ty>;
215        }
216    };
217}
218
219impl_from_value_num!(i8);
220impl_from_value_num!(u8);
221impl_from_value_num!(i16);
222impl_from_value_num!(u16);
223impl_from_value_num!(i32);
224impl_from_value_num!(u32);
225impl_from_value_num!(i64);
226impl_from_value_num!(u64);
227impl_from_value_num!(isize);
228impl_from_value_num!(usize);
229impl_from_value_num!(i128);
230impl_from_value_num!(u128);
231
232impl TryFrom<Value> for ParseIrOpt<bool> {
233    type Error = FromValueError;
234
235    fn try_from(v: Value) -> Result<Self, Self::Error> {
236        match v {
237            Value::Int(0) | Value::UInt(0) => Ok(ParseIrOpt::Ready(false)),
238            Value::Int(_) | Value::UInt(_) => Ok(ParseIrOpt::Ready(true)),
239            Value::Bytes(ref bytes) => match bytes.as_slice() {
240                [b'0'] => Ok(ParseIrOpt::Parsed(false, v)),
241                [b'1'] => Ok(ParseIrOpt::Parsed(true, v)),
242                _ => Err(FromValueError(v)),
243            },
244            v => Err(FromValueError(v)),
245        }
246    }
247}
248
249impl From<ParseIrOpt<bool>> for bool {
250    fn from(value: ParseIrOpt<bool>) -> Self {
251        value.commit()
252    }
253}
254
255impl From<ParseIrOpt<bool>> for Value {
256    fn from(value: ParseIrOpt<bool>) -> Self {
257        value.rollback()
258    }
259}
260
261impl FromValue for bool {
262    type Intermediate = ParseIrOpt<bool>;
263}
264
265impl TryFrom<Value> for ParseIrOpt<f32> {
266    type Error = FromValueError;
267
268    fn try_from(v: Value) -> Result<Self, Self::Error> {
269        match v {
270            Value::Float(x) => Ok(ParseIrOpt::Ready(x)),
271            Value::Bytes(bytes) => match from_utf8(&bytes) {
272                Ok(f) => match f.parse::<f32>() {
273                    Ok(x) => Ok(ParseIrOpt::Parsed(x, Value::Bytes(bytes))),
274                    _ => Err(FromValueError(Value::Bytes(bytes))),
275                },
276                _ => Err(FromValueError(Value::Bytes(bytes))),
277            },
278            v => Err(FromValueError(v)),
279        }
280    }
281}
282
283impl From<ParseIrOpt<f32>> for f32 {
284    fn from(value: ParseIrOpt<f32>) -> Self {
285        value.commit()
286    }
287}
288
289impl From<ParseIrOpt<f32>> for Value {
290    fn from(value: ParseIrOpt<f32>) -> Self {
291        value.rollback()
292    }
293}
294
295impl FromValue for f32 {
296    type Intermediate = ParseIrOpt<f32>;
297}
298
299impl TryFrom<Value> for ParseIrOpt<f64> {
300    type Error = FromValueError;
301
302    fn try_from(v: Value) -> Result<Self, Self::Error> {
303        match v {
304            Value::Double(x) => Ok(ParseIrOpt::Ready(x)),
305            Value::Float(x) => Ok(ParseIrOpt::Ready(x.into())),
306            Value::Bytes(bytes) => match from_utf8(&bytes) {
307                Ok(f) => match f.parse::<f64>() {
308                    Ok(x) => Ok(ParseIrOpt::Parsed(x, Value::Bytes(bytes))),
309                    _ => Err(FromValueError(Value::Bytes(bytes))),
310                },
311                _ => Err(FromValueError(Value::Bytes(bytes))),
312            },
313            v => Err(FromValueError(v)),
314        }
315    }
316}
317
318impl From<ParseIrOpt<f64>> for f64 {
319    fn from(value: ParseIrOpt<f64>) -> Self {
320        value.commit()
321    }
322}
323
324impl From<ParseIrOpt<f64>> for Value {
325    fn from(value: ParseIrOpt<f64>) -> Self {
326        value.rollback()
327    }
328}
329
330impl FromValue for f64 {
331    type Intermediate = ParseIrOpt<f64>;
332}
333
334fn mysql_time_to_duration(
335    days: u32,
336    hours: u8,
337    minutes: u8,
338    seconds: u8,
339    microseconds: u32,
340) -> Duration {
341    let nanos = (microseconds) * 1000;
342    let secs = u64::from(seconds)
343        + u64::from(minutes) * 60
344        + u64::from(hours) * 60 * 60
345        + u64::from(days) * 60 * 60 * 24;
346    Duration::new(secs, nanos)
347}
348
349impl TryFrom<Value> for ParseIrOpt<Duration> {
350    type Error = FromValueError;
351
352    fn try_from(v: Value) -> Result<Self, Self::Error> {
353        match v {
354            Value::Time(false, days, hours, minutes, seconds, microseconds) => {
355                let duration = mysql_time_to_duration(days, hours, minutes, seconds, microseconds);
356                Ok(ParseIrOpt::Parsed(duration, v))
357            }
358            Value::Bytes(ref val_bytes) => {
359                let duration = match parse_mysql_time_string(val_bytes) {
360                    Some((false, hours, minutes, seconds, microseconds)) => {
361                        let days = hours / 24;
362                        let hours = (hours % 24) as u8;
363                        mysql_time_to_duration(days, hours, minutes, seconds, microseconds)
364                    }
365                    _ => return Err(FromValueError(v)),
366                };
367                Ok(ParseIrOpt::Parsed(duration, v))
368            }
369            v => Err(FromValueError(v)),
370        }
371    }
372}
373
374impl From<ParseIrOpt<Duration>> for Duration {
375    fn from(value: ParseIrOpt<Duration>) -> Self {
376        value.commit()
377    }
378}
379
380impl From<ParseIrOpt<Duration>> for Value {
381    fn from(value: ParseIrOpt<Duration>) -> Self {
382        value.rollback()
383    }
384}
385
386impl FromValue for Duration {
387    type Intermediate = ParseIrOpt<Duration>;
388}
389
390impl TryFrom<Value> for String {
391    type Error = FromValueError;
392
393    fn try_from(v: Value) -> Result<Self, Self::Error> {
394        match v {
395            Value::Bytes(bytes) => match String::from_utf8(bytes) {
396                Ok(x) => Ok(x),
397                Err(e) => Err(FromValueError(Value::Bytes(e.into_bytes()))),
398            },
399            v => Err(FromValueError(v)),
400        }
401    }
402}
403
404impl FromValue for String {
405    type Intermediate = String;
406}
407
408impl TryFrom<Value> for Vec<u8> {
409    type Error = FromValueError;
410
411    fn try_from(v: Value) -> Result<Self, Self::Error> {
412        match v {
413            Value::Bytes(bytes) => Ok(bytes),
414            v => Err(FromValueError(v)),
415        }
416    }
417}
418
419impl FromValue for Vec<u8> {
420    type Intermediate = Vec<u8>;
421}
422
423impl TryFrom<Value> for Arc<[u8]> {
424    type Error = FromValueError;
425
426    fn try_from(v: Value) -> Result<Self, Self::Error> {
427        match v {
428            Value::Bytes(bytes) => Ok(bytes.into()),
429            v => Err(FromValueError(v)),
430        }
431    }
432}
433
434impl FromValue for Arc<[u8]> {
435    type Intermediate = Arc<[u8]>;
436}
437
438impl TryFrom<Value> for Rc<[u8]> {
439    type Error = FromValueError;
440
441    fn try_from(v: Value) -> Result<Self, Self::Error> {
442        match v {
443            Value::Bytes(bytes) => Ok(bytes.into()),
444            v => Err(FromValueError(v)),
445        }
446    }
447}
448
449impl FromValue for Rc<[u8]> {
450    type Intermediate = Rc<[u8]>;
451}
452
453impl TryFrom<Value> for Box<[u8]> {
454    type Error = FromValueError;
455
456    fn try_from(v: Value) -> Result<Self, Self::Error> {
457        match v {
458            Value::Bytes(bytes) => Ok(bytes.into()),
459            v => Err(FromValueError(v)),
460        }
461    }
462}
463
464impl FromValue for Box<[u8]> {
465    type Intermediate = Box<[u8]>;
466}
467
468impl TryFrom<Value> for Arc<str> {
469    type Error = FromValueError;
470
471    fn try_from(v: Value) -> Result<Self, Self::Error> {
472        match v {
473            Value::Bytes(bytes) => match String::from_utf8(bytes) {
474                Ok(x) => Ok(x.into()),
475                Err(e) => Err(FromValueError(Value::Bytes(e.into_bytes()))),
476            },
477            v => Err(FromValueError(v)),
478        }
479    }
480}
481
482impl FromValue for Arc<str> {
483    type Intermediate = Arc<str>;
484}
485
486impl TryFrom<Value> for Rc<str> {
487    type Error = FromValueError;
488
489    fn try_from(v: Value) -> Result<Self, Self::Error> {
490        match v {
491            Value::Bytes(bytes) => match String::from_utf8(bytes) {
492                Ok(x) => Ok(x.into()),
493                Err(e) => Err(FromValueError(Value::Bytes(e.into_bytes()))),
494            },
495            v => Err(FromValueError(v)),
496        }
497    }
498}
499
500impl FromValue for Rc<str> {
501    type Intermediate = Rc<str>;
502}
503
504impl TryFrom<Value> for Box<str> {
505    type Error = FromValueError;
506
507    fn try_from(v: Value) -> Result<Self, Self::Error> {
508        match v {
509            Value::Bytes(bytes) => match String::from_utf8(bytes) {
510                Ok(x) => Ok(x.into()),
511                Err(e) => Err(FromValueError(Value::Bytes(e.into_bytes()))),
512            },
513            v => Err(FromValueError(v)),
514        }
515    }
516}
517
518impl FromValue for Box<str> {
519    type Intermediate = Box<str>;
520}
521
522/// Intermediate result of a `Value`-to-`Option<T>` conversion.
523#[derive(Debug, Clone, PartialEq)]
524pub enum OptionIr2<T: FromValue> {
525    None,
526    Some(T::Intermediate),
527}
528
529impl<T: FromValue> TryFrom<Value> for OptionIr2<T> {
530    type Error = <<T as FromValue>::Intermediate as TryFrom<Value>>::Error;
531
532    fn try_from(value: Value) -> Result<Self, Self::Error> {
533        match value {
534            Value::NULL => Ok(Self::None),
535            v => <T as FromValue>::Intermediate::try_from(v).map(Self::Some),
536        }
537    }
538}
539
540impl<T: FromValue> From<OptionIr2<T>> for Option<T> {
541    fn from(ir: OptionIr2<T>) -> Self {
542        match ir {
543            OptionIr2::None => None,
544            OptionIr2::Some(ir) => Some(ir.into()),
545        }
546    }
547}
548
549impl<T: FromValue> From<OptionIr2<T>> for Value
550where
551    <T as FromValue>::Intermediate: Into<Value>,
552{
553    fn from(ir: OptionIr2<T>) -> Self {
554        match ir {
555            OptionIr2::None => Value::NULL,
556            OptionIr2::Some(ir) => ir.into(),
557        }
558    }
559}
560
561impl<T: FromValue> FromValue for Option<T> {
562    type Intermediate = OptionIr2<T>;
563}
564
565// TODO: rustc is unable to conclude that Infallible equals FromValueError
566#[derive(Debug, Clone, PartialEq, PartialOrd)]
567#[repr(transparent)]
568pub struct ValueIr(pub Value);
569
570impl TryFrom<Value> for ValueIr {
571    type Error = FromValueError;
572
573    fn try_from(value: Value) -> Result<Self, Self::Error> {
574        Ok(ValueIr(value))
575    }
576}
577
578impl From<ValueIr> for Value {
579    fn from(value: ValueIr) -> Self {
580        value.0
581    }
582}
583
584impl FromValue for Value {
585    type Intermediate = ValueIr;
586}
587
588/// Will panic if could not convert `v` to `T`
589pub fn from_value<T: FromValue>(v: Value) -> T {
590    FromValue::from_value(v)
591}
592
593/// Will return `Err(FromValueError(v))` if could not convert `v` to `T`
594pub fn from_value_opt<T: FromValue>(v: Value) -> Result<T, FromValueError> {
595    FromValue::from_value_opt(v)
596}
597
598impl TryFrom<Value> for Cow<'static, str> {
599    type Error = FromValueError;
600
601    fn try_from(v: Value) -> Result<Self, Self::Error> {
602        match v {
603            Value::Bytes(bytes) => match String::from_utf8(bytes) {
604                Ok(x) => Ok(Cow::Owned(x)),
605                Err(e) => Err(FromValueError(Value::Bytes(e.into_bytes()))),
606            },
607            v => Err(FromValueError(v)),
608        }
609    }
610}
611
612impl FromValue for Cow<'static, str> {
613    type Intermediate = String;
614}
615
616impl TryFrom<Value> for Cow<'static, [u8]> {
617    type Error = FromValueError;
618
619    fn try_from(v: Value) -> Result<Self, Self::Error> {
620        match v {
621            Value::Bytes(x) => Ok(Cow::Owned(x)),
622            v => Err(FromValueError(v)),
623        }
624    }
625}
626
627impl FromValue for Cow<'static, [u8]> {
628    type Intermediate = Cow<'static, [u8]>;
629}
630
631impl<const N: usize> TryFrom<Value> for [u8; N] {
632    type Error = FromValueError;
633
634    fn try_from(v: Value) -> Result<Self, Self::Error> {
635        match v {
636            Value::Bytes(bytes) => bytes
637                .try_into()
638                .map_err(|x| FromValueError(Value::Bytes(x))),
639            v => Err(FromValueError(v)),
640        }
641    }
642}
643
644impl<const N: usize> FromValue for [u8; N] {
645    type Intermediate = [u8; N];
646}
647
648fn parse_micros(micros_bytes: &[u8]) -> u32 {
649    let mut micros = btou(micros_bytes).unwrap();
650
651    let mut pad_zero_cnt = 0;
652    for b in micros_bytes.iter() {
653        if *b == b'0' {
654            pad_zero_cnt += 1;
655        } else {
656            break;
657        }
658    }
659
660    for _ in 0..(6 - pad_zero_cnt - (micros_bytes.len() - pad_zero_cnt)) {
661        micros *= 10;
662    }
663    micros
664}
665
666/// Returns (is_neg, hours, minutes, seconds, microseconds)
667fn parse_mysql_time_string(mut bytes: &[u8]) -> Option<(bool, u32, u8, u8, u32)> {
668    #[derive(PartialEq, Eq, PartialOrd, Ord)]
669    #[repr(u8)]
670    enum TimeKind {
671        HhMmSs = 0,
672        HhhMmSs,
673        HhMmSsMs,
674        HhhMmSsMs,
675    }
676
677    if bytes.len() < 8 {
678        return None;
679    }
680
681    let is_neg = bytes[0] == b'-';
682    if is_neg {
683        bytes = &bytes[1..];
684    }
685
686    let len = bytes.len();
687
688    let kind = if len == 8 && TIME_RE_HH_MM_SS.is_match(bytes) {
689        TimeKind::HhMmSs
690    } else if len == 9 && TIME_RE_HHH_MM_SS.is_match(bytes) {
691        TimeKind::HhhMmSs
692    } else if TIME_RE_HH_MM_SS_MS.is_match(bytes) {
693        TimeKind::HhMmSsMs
694    } else if TIME_RE_HHH_MM_SS_MS.is_match(bytes) {
695        TimeKind::HhhMmSsMs
696    } else {
697        return None;
698    };
699
700    let (hour_pos, min_pos, sec_pos, micros_pos) = match kind {
701        TimeKind::HhMmSs => (..2, 3..5, 6..8, None),
702        TimeKind::HhMmSsMs => (..2, 3..5, 6..8, Some(9..)),
703        TimeKind::HhhMmSs => (..3, 4..6, 7..9, None),
704        TimeKind::HhhMmSsMs => (..3, 4..6, 7..9, Some(10..)),
705    };
706
707    Some((
708        is_neg,
709        btou(&bytes[hour_pos]).unwrap(),
710        btou(&bytes[min_pos]).unwrap(),
711        btou(&bytes[sec_pos]).unwrap(),
712        micros_pos.map(|pos| parse_micros(&bytes[pos])).unwrap_or(0),
713    ))
714}
715
716impl From<Duration> for Value {
717    fn from(x: Duration) -> Value {
718        let mut secs_total = x.as_secs();
719        let micros = (f64::from(x.subsec_nanos()) / 1000_f64).round() as u32;
720        let seconds = (secs_total % 60) as u8;
721        secs_total -= u64::from(seconds);
722        let minutes = ((secs_total % (60 * 60)) / 60) as u8;
723        secs_total -= u64::from(minutes) * 60;
724        let hours = ((secs_total % (60 * 60 * 24)) / (60 * 60)) as u8;
725        secs_total -= u64::from(hours) * 60 * 60;
726        Value::Time(
727            false,
728            (secs_total / (60 * 60 * 24)) as u32,
729            hours,
730            minutes,
731            seconds,
732            micros,
733        )
734    }
735}
736
737pub trait ToValue {
738    fn to_value(&self) -> Value;
739}
740
741impl<T: Into<Value> + Clone> ToValue for T {
742    fn to_value(&self) -> Value {
743        self.clone().into()
744    }
745}
746
747impl<'a, T: ToValue> From<&'a T> for Value {
748    fn from(x: &'a T) -> Value {
749        x.to_value()
750    }
751}
752
753impl<T: Into<Value>> From<Option<T>> for Value {
754    fn from(x: Option<T>) -> Value {
755        match x {
756            None => Value::NULL,
757            Some(x) => x.into(),
758        }
759    }
760}
761
762macro_rules! into_value_impl (
763    (signed $t:ty) => (
764        impl From<$t> for Value {
765            fn from(x: $t) -> Value {
766                Value::Int(x as i64)
767            }
768        }
769    );
770    (unsigned $t:ty) => (
771        impl From<$t> for Value {
772            fn from(x: $t) -> Value {
773                Value::UInt(x as u64)
774            }
775        }
776    );
777);
778
779into_value_impl!(signed i8);
780into_value_impl!(signed i16);
781into_value_impl!(signed i32);
782into_value_impl!(signed i64);
783into_value_impl!(signed isize);
784into_value_impl!(unsigned u8);
785into_value_impl!(unsigned u16);
786into_value_impl!(unsigned u32);
787into_value_impl!(unsigned u64);
788into_value_impl!(unsigned usize);
789
790impl From<i128> for Value {
791    fn from(x: i128) -> Value {
792        if let Some(x) = x.to_i64() {
793            Value::Int(x)
794        } else if let Some(x) = x.to_u64() {
795            Value::UInt(x)
796        } else {
797            Value::Bytes(x.to_string().into())
798        }
799    }
800}
801
802impl From<u128> for Value {
803    fn from(x: u128) -> Value {
804        if let Some(x) = x.to_u64() {
805            Value::UInt(x)
806        } else {
807            Value::Bytes(x.to_string().into())
808        }
809    }
810}
811
812impl From<f32> for Value {
813    fn from(x: f32) -> Value {
814        Value::Float(x)
815    }
816}
817
818impl From<f64> for Value {
819    fn from(x: f64) -> Value {
820        Value::Double(x)
821    }
822}
823
824impl From<bool> for Value {
825    fn from(x: bool) -> Value {
826        Value::Int(if x { 1 } else { 0 })
827    }
828}
829
830impl<'a> From<&'a [u8]> for Value {
831    fn from(x: &'a [u8]) -> Value {
832        Value::Bytes(x.into())
833    }
834}
835
836impl From<Box<[u8]>> for Value {
837    fn from(x: Box<[u8]>) -> Value {
838        Value::Bytes(x.into())
839    }
840}
841
842impl From<Arc<[u8]>> for Value {
843    fn from(x: Arc<[u8]>) -> Value {
844        Value::Bytes(x.as_ref().into())
845    }
846}
847
848impl From<Rc<[u8]>> for Value {
849    fn from(x: Rc<[u8]>) -> Value {
850        Value::Bytes(x.as_ref().into())
851    }
852}
853
854impl From<Vec<u8>> for Value {
855    fn from(x: Vec<u8>) -> Value {
856        Value::Bytes(x)
857    }
858}
859
860impl<'a> From<&'a str> for Value {
861    fn from(x: &'a str) -> Value {
862        let string: String = x.into();
863        Value::Bytes(string.into_bytes())
864    }
865}
866
867impl From<Box<str>> for Value {
868    fn from(x: Box<str>) -> Value {
869        Value::Bytes(String::from(x).into_bytes())
870    }
871}
872
873impl From<Arc<str>> for Value {
874    fn from(x: Arc<str>) -> Value {
875        Value::Bytes(x.as_ref().as_bytes().into())
876    }
877}
878
879impl From<Rc<str>> for Value {
880    fn from(x: Rc<str>) -> Value {
881        Value::Bytes(x.as_ref().as_bytes().into())
882    }
883}
884
885impl<'a, T: ToOwned> From<Cow<'a, T>> for Value
886where
887    T::Owned: Into<Value>,
888    &'a T: Into<Value>,
889{
890    fn from(x: Cow<'a, T>) -> Value {
891        match x {
892            Cow::Borrowed(x) => x.into(),
893            Cow::Owned(x) => x.into(),
894        }
895    }
896}
897
898impl From<String> for Value {
899    fn from(x: String) -> Value {
900        Value::Bytes(x.into_bytes())
901    }
902}
903
904impl<const N: usize> From<[u8; N]> for Value {
905    fn from(x: [u8; N]) -> Value {
906        Value::Bytes(x.to_vec())
907    }
908}
909
910#[cfg(test)]
911mod tests {
912    use super::*;
913    use proptest::prelude::*;
914
915    macro_rules! signed_primitive_roundtrip {
916        ($t:ty, $name:ident) => {
917            proptest! {
918                #[test]
919                fn $name(n: $t) {
920                    let val = Value::Int(n as i64);
921                    let val_bytes = Value::Bytes(n.to_string().into());
922                    assert_eq!(Value::from(from_value::<$t>(val.clone())), val);
923                    assert_eq!(Value::from(from_value::<$t>(val_bytes.clone())), val);
924                    if n >= 0 {
925                        let val_uint = Value::UInt(n as u64);
926                        assert_eq!(Value::from(from_value::<$t>(val_uint.clone())), val);
927                    }
928                }
929            }
930        };
931    }
932
933    macro_rules! unsigned_primitive_roundtrip {
934        ($t:ty, $name:ident) => {
935            proptest! {
936                #[test]
937                fn $name(n: $t) {
938                    let val = Value::UInt(n as u64);
939                    let val_bytes = Value::Bytes(n.to_string().into());
940                    assert_eq!(Value::from(from_value::<$t>(val.clone())), val);
941                    assert_eq!(Value::from(from_value::<$t>(val_bytes.clone())), val);
942                    if n as u64 <= i64::max_value() as u64 {
943                        let val_int = Value::Int(n as i64);
944                        assert_eq!(Value::from(from_value::<$t>(val_int.clone())), val);
945                    }
946                }
947            }
948        };
949    }
950
951    proptest! {
952        #[test]
953        fn bytes_roundtrip(s: Vec<u8>) {
954            let val = Value::Bytes(s);
955            assert_eq!(Value::from(from_value::<Vec<u8>>(val.clone())), val);
956        }
957
958        #[test]
959        fn string_roundtrip(s: String) {
960            let val = Value::Bytes(s.as_bytes().to_vec());
961            assert_eq!(Value::from(from_value::<String>(val.clone())), val);
962        }
963
964        #[test]
965        fn parse_mysql_time_string_parses_valid_time(
966            s in r"-?[0-8][0-9][0-9]:[0-5][0-9]:[0-5][0-9](\.[0-9]{1,6})?"
967        ) {
968            parse_mysql_time_string(s.as_bytes()).unwrap();
969            // Don't test `parse_mysql_time_string_with_time` here,
970            // as this tests valid MySQL TIME values, not valid time ranges within a day.
971            // Due to that, `time::parse` will return an Err for invalid time strings.
972        }
973
974        #[test]
975        fn parse_mysql_time_string_parses_correctly(
976            sign in 0..2,
977            h in 0u32..900,
978            m in 0u8..59,
979            s in 0u8..59,
980            have_us in 0..2,
981            us in 0u32..1000000,
982        ) {
983            let time_string = format!(
984                "{}{:02}:{:02}:{:02}{}",
985                if sign == 1 { "-" } else { "" },
986                h, m, s,
987                if have_us == 1 {
988                    format!(".{:06}", us)
989                } else {
990                    "".into()
991                }
992            );
993            let time = parse_mysql_time_string(time_string.as_bytes()).unwrap();
994            assert_eq!(time, (sign == 1, h, m, s, if have_us == 1 { us } else { 0 }));
995
996            // Don't test `parse_mysql_time_string_with_time` here,
997            // as this tests valid MySQL TIME values, not valid time ranges within a day.
998            // Due to that, `time::parse` will return an Err for invalid time strings.
999        }
1000
1001        #[test]
1002        fn parse_int_as_bool(n: i64) {
1003            let val = Value::Int(n);
1004            if n == 0 {
1005                assert_eq!(from_value::<bool>(val), false);
1006            } else {
1007                assert_eq!(from_value::<bool>(val), true);
1008            }
1009        }
1010
1011        #[test]
1012        fn parse_uint_as_bool(n: u64) {
1013            let val = Value::UInt(n);
1014            if n == 0 {
1015                assert_eq!(from_value::<bool>(val), false);
1016            } else {
1017                assert_eq!(from_value::<bool>(val), true);
1018            }
1019        }
1020
1021        #[test]
1022        fn i128_roundtrip(
1023            bytes_pos in r"16[0-9]{37}",
1024            bytes_neg in r"-16[0-9]{37}",
1025            uint in (i64::max_value() as u64 + 1)..u64::max_value(),
1026            int: i64,
1027        ) {
1028            let val_bytes_pos = Value::Bytes(bytes_pos.as_bytes().into());
1029            let val_bytes_neg = Value::Bytes(bytes_neg.as_bytes().into());
1030            let val_uint = Value::UInt(uint);
1031            let val_int = Value::Int(int);
1032
1033            assert_eq!(Value::from(from_value::<i128>(val_bytes_pos.clone())), val_bytes_pos);
1034            assert_eq!(Value::from(from_value::<i128>(val_bytes_neg.clone())), val_bytes_neg);
1035            assert_eq!(Value::from(from_value::<i128>(val_uint.clone())), val_uint);
1036            assert_eq!(Value::from(from_value::<i128>(val_int.clone())), val_int);
1037        }
1038
1039        #[test]
1040        fn u128_roundtrip(
1041            bytes in r"16[0-9]{37}",
1042            uint: u64,
1043            int in 0i64..i64::max_value(),
1044        ) {
1045            let val_bytes = Value::Bytes(bytes.as_bytes().into());
1046            let val_uint = Value::UInt(uint);
1047            let val_int = Value::Int(int);
1048
1049            assert_eq!(Value::from(from_value::<u128>(val_bytes.clone())), val_bytes);
1050            assert_eq!(Value::from(from_value::<u128>(val_uint.clone())), val_uint);
1051            assert_eq!(Value::from(from_value::<u128>(val_int)), Value::UInt(int as u64));
1052        }
1053
1054        #[test]
1055        fn f32_roundtrip(n: f32) {
1056            let val = Value::Float(n);
1057            let val_bytes = Value::Bytes(n.to_string().into());
1058            assert_eq!(Value::from(from_value::<f32>(val.clone())), val);
1059            assert_eq!(Value::from(from_value::<f32>(val_bytes)), val);
1060        }
1061
1062        #[test]
1063        fn f64_roundtrip(n: f64) {
1064            let val = Value::Double(n);
1065            let val_bytes = Value::Bytes(n.to_string().into());
1066            assert_eq!(Value::from(from_value::<f64>(val.clone())), val);
1067            assert_eq!(Value::from(from_value::<f64>(val_bytes)), val);
1068        }
1069    }
1070
1071    signed_primitive_roundtrip!(i8, i8_roundtrip);
1072    signed_primitive_roundtrip!(i16, i16_roundtrip);
1073    signed_primitive_roundtrip!(i32, i32_roundtrip);
1074    signed_primitive_roundtrip!(i64, i64_roundtrip);
1075
1076    unsigned_primitive_roundtrip!(u8, u8_roundtrip);
1077    unsigned_primitive_roundtrip!(u16, u16_roundtrip);
1078    unsigned_primitive_roundtrip!(u32, u32_roundtrip);
1079    unsigned_primitive_roundtrip!(u64, u64_roundtrip);
1080
1081    #[test]
1082    fn from_value_should_fail_on_integer_overflow() {
1083        let value = Value::Bytes(b"340282366920938463463374607431768211456"[..].into());
1084        assert!(from_value_opt::<u8>(value.clone()).is_err());
1085        assert!(from_value_opt::<i8>(value.clone()).is_err());
1086        assert!(from_value_opt::<u16>(value.clone()).is_err());
1087        assert!(from_value_opt::<i16>(value.clone()).is_err());
1088        assert!(from_value_opt::<u32>(value.clone()).is_err());
1089        assert!(from_value_opt::<i32>(value.clone()).is_err());
1090        assert!(from_value_opt::<u64>(value.clone()).is_err());
1091        assert!(from_value_opt::<i64>(value.clone()).is_err());
1092        assert!(from_value_opt::<u128>(value.clone()).is_err());
1093        assert!(from_value_opt::<i128>(value).is_err());
1094    }
1095
1096    #[test]
1097    fn from_value_should_fail_on_integer_underflow() {
1098        let value = Value::Bytes(b"-170141183460469231731687303715884105729"[..].into());
1099        assert!(from_value_opt::<u8>(value.clone()).is_err());
1100        assert!(from_value_opt::<i8>(value.clone()).is_err());
1101        assert!(from_value_opt::<u16>(value.clone()).is_err());
1102        assert!(from_value_opt::<i16>(value.clone()).is_err());
1103        assert!(from_value_opt::<u32>(value.clone()).is_err());
1104        assert!(from_value_opt::<i32>(value.clone()).is_err());
1105        assert!(from_value_opt::<u64>(value.clone()).is_err());
1106        assert!(from_value_opt::<i64>(value.clone()).is_err());
1107        assert!(from_value_opt::<u128>(value.clone()).is_err());
1108        assert!(from_value_opt::<i128>(value).is_err());
1109    }
1110
1111    #[cfg(feature = "nightly")]
1112    #[cfg(feature = "chrono")]
1113    #[bench]
1114    fn bench_parse_mysql_datetime_string(bencher: &mut test::Bencher) {
1115        let text = "1234-12-12 12:12:12.123456";
1116        bencher.bytes = text.len() as u64;
1117        bencher.iter(|| {
1118            parse_mysql_datetime_string(text.as_bytes()).unwrap();
1119        });
1120    }
1121
1122    #[cfg(feature = "nightly")]
1123    #[bench]
1124    fn bench_parse_mysql_time_string(bencher: &mut test::Bencher) {
1125        let text = "-012:34:56.012345";
1126        bencher.bytes = text.len() as u64;
1127        bencher.iter(|| {
1128            parse_mysql_time_string(text.as_bytes()).unwrap();
1129        });
1130    }
1131
1132    #[test]
1133    fn value_float_read_conversions_work() {
1134        let original_f32 = std::f32::consts::PI;
1135        let float_value = Value::Float(original_f32);
1136
1137        // Reading an f32 from a MySQL float works.
1138        let converted_f32: f32 = f32::from_value_opt(float_value.clone()).unwrap();
1139        assert_eq!(converted_f32, original_f32);
1140
1141        // Reading an f64 from a MySQL float also works (lossless cast).
1142        let converted_f64: f64 = f64::from_value_opt(float_value).unwrap();
1143        assert_eq!(converted_f64, original_f32 as f64);
1144    }
1145
1146    #[test]
1147    fn value_double_read_conversions_work() {
1148        let original_f64 = std::f64::consts::PI;
1149        let double_value = Value::Double(original_f64);
1150
1151        // Reading an f64 from a MySQL double works.
1152        let converted_f64: f64 = f64::from_value_opt(double_value.clone()).unwrap();
1153        assert_eq!(converted_f64, original_f64);
1154
1155        // Reading an f32 from a MySQL double fails (precision loss).
1156        assert!(f32::from_value_opt(double_value).is_err());
1157    }
1158
1159    #[cfg(feature = "nightly")]
1160    #[bench]
1161    fn bench_parse_mysql_datetime_string_with_time(bencher: &mut test::Bencher) {
1162        let text = "1234-12-12 12:12:12.123456";
1163        bencher.bytes = text.len() as u64;
1164        bencher.iter(|| {
1165            parse_mysql_datetime_string_with_time(text.as_bytes()).unwrap();
1166        });
1167    }
1168
1169    #[cfg(feature = "nightly")]
1170    #[bench]
1171    fn bench_parse_mysql_time_string_with_time(bencher: &mut test::Bencher) {
1172        let text = "12:34:56.012345";
1173        bencher.bytes = text.len() as u64;
1174        bencher.iter(|| {
1175            parse_mysql_time_string_with_time(text.as_bytes()).unwrap();
1176        });
1177    }
1178}