1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use crate::ToHana;
use serde::ser::Error as _;
use std::str::FromStr;
use time::{format_description::FormatItem, macros::format_description, Time};

/// Wraps a `time::Time`, helps with serializing from and deserializing into `time::Time`.
///
/// # Example for serialization
/// ```rust, no_run
/// use hdbconnect::ToHana;
/// use time::{macros::time,Time};
/// # let stmt = "...";
/// # let mut connection = hdbconnect::Connection::new("...").unwrap();
/// let ts: Time = time!(02:02:02.200000000);
/// let response = connection.prepare_and_execute(stmt, &(ts.to_hana())).unwrap();
/// ```
///
/// # Example for deserialization
///
/// Deserialize into `HanaTime`,
/// then use `deref()` or `to_inner()` to access the contained `Time`.
///
/// ```rust, no_run
///  use hdbconnect::time::HanaTime;
/// # let the_query = "...";
/// # let mut connection = hdbconnect::Connection::new("...").unwrap();
///  let times: Vec<HanaTime> = connection.query(the_query).unwrap().try_into().unwrap();
///  let hour = (*times[0]).hour();
/// ```
#[derive(Debug)]
pub struct HanaTime(pub Time);
impl HanaTime {
    /// Consumes the `HanaTime`, returning the wrapped `Time`.
    pub fn into_inner(self) -> Time {
        self.0
    }
}
impl std::ops::Deref for HanaTime {
    type Target = Time;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

// ***********
// deserialize
// ***********
impl<'de> serde::de::Deserialize<'de> for HanaTime {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        deserializer.deserialize_str(HanaTimeVisitor)
    }
}
impl FromStr for HanaTime {
    type Err = time::error::Parse;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        // subsecond is optional
        const DATE_T_TIME: &[FormatItem<'static>] = format_description!("[hour]:[minute]:[second]");
        const DATE_T_TIME_SUB: &[FormatItem<'static>] =
            format_description!("[hour]:[minute]:[second].[subsecond]");

        Time::parse(s, &DATE_T_TIME_SUB)
            .or_else(|_| Time::parse(s, &DATE_T_TIME))
            .map(HanaTime)
    }
}

pub(in crate::serde_db_impl) struct HanaTimeVisitor;
impl<'de> serde::de::Visitor<'de> for HanaTimeVisitor {
    type Value = HanaTime;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(
            formatter,
            "a String in the form [hour]:[minute]:[second].[subsecond]"
        )
    }

    fn visit_str<E>(self, value: &str) -> Result<HanaTime, E>
    where
        E: serde::de::Error,
    {
        HanaTime::from_str(value).map_err(E::custom)
    }
}

/// Helper method for deserializing database values into values of type `time::Time`.
///
/// # Example
///
/// Use serde's annotation `serde(deserialize_with = "..")` to refer to this method:
///
/// ```rust
///     use time::Time;
///     #[derive(serde::Deserialize)]
///     struct WithTs {
///         #[serde(deserialize_with = "hdbconnect::time::to_time")]
///         ts_o: Time,
///     }
/// ```
///
/// Unfortunately, the serde-annotation `deserialize_with` does not cover all cases,
/// since it can only be applied to struct fields;
/// it cannot be applied if you want to deserialize into a `Vec<Time>`
/// or a plain `Time`.
/// The best you can do then is to deserialize instead into [`HanaTime`] and use
/// `deref()` or `into_inner()` to access the contained `time::Time`.
#[allow(clippy::missing_errors_doc)]
pub fn to_time<'de, D>(input: D) -> Result<Time, D::Error>
where
    D: serde::de::Deserializer<'de>,
{
    input
        .deserialize_str(HanaTimeVisitor)
        .map(HanaTime::into_inner)
}

//
// serialize
//

impl ToHana<HanaTime> for Time {
    fn to_hana(self) -> HanaTime {
        HanaTime(self)
    }
}

impl serde::ser::Serialize for HanaTime {
    fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        const TIME_9: &[FormatItem<'static>] =
            format_description!("[hour]:[minute]:[second].[subsecond digits:9]");

        serializer.serialize_str(
            &self
                .0
                .format(TIME_9)
                .map_err(|_| S::Error::custom("failed formatting `Time`"))?,
        )
    }
}