use crate::ToHana;
use serde::ser::Error as _;
use std::str::FromStr;
use time::{format_description::FormatItem, macros::format_description, Time};
#[derive(Debug)]
pub struct HanaTime(pub Time);
impl HanaTime {
pub fn into_inner(self) -> Time {
self.0
}
}
impl std::ops::Deref for HanaTime {
type Target = Time;
fn deref(&self) -> &Self::Target {
&self.0
}
}
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> {
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)
}
}
#[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)
}
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`"))?,
)
}
}