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