1use crate::{Decode, Encode, Layout, Result};
2
3pub mod ops {
5 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7 #[allow(non_camel_case_types)]
8 pub enum Ordering {
9 Less,
10 Equal,
11 Greater,
12 }
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct Timestamp {
18 pub microseconds: i64,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
23pub struct Date {
24 pub days_epoch: i32,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub struct Time {
30 pub microseconds: i64,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
35pub struct Decimal(pub i64);
36
37impl Encode for Timestamp {
38 type HeadPtr = ();
39
40 fn encode_head(&self, buf: &mut crate::bytes::BytesMut) {
41 self.microseconds.encode_head(buf)
42 }
43
44 fn encode_body(&self, _: (), _: &mut crate::bytes::BytesMut) {}
45}
46
47impl Layout for Timestamp {
48 fn head_size() -> usize {
49 i64::head_size()
50 }
51}
52
53impl Decode for Timestamp {
54 fn decode(buf: &[u8]) -> Result<Self> {
55 Ok(Self {
56 microseconds: i64::decode(buf)?,
57 })
58 }
59}
60impl Encode for Date {
61 type HeadPtr = ();
62
63 fn encode_head(&self, buf: &mut crate::bytes::BytesMut) {
64 self.days_epoch.encode_head(buf)
65 }
66
67 fn encode_body(&self, _: (), _: &mut crate::bytes::BytesMut) {}
68}
69impl Layout for Date {
70 fn head_size() -> usize {
71 i32::head_size()
72 }
73}
74impl Decode for Date {
75 fn decode(buf: &[u8]) -> Result<Self> {
76 Ok(Self {
77 days_epoch: i32::decode(buf)?,
78 })
79 }
80}
81impl Encode for Time {
82 type HeadPtr = ();
83
84 fn encode_head(&self, buf: &mut crate::bytes::BytesMut) {
85 self.microseconds.encode_head(buf)
86 }
87
88 fn encode_body(&self, _: (), _: &mut crate::bytes::BytesMut) {}
89}
90impl Layout for Time {
91 fn head_size() -> usize {
92 i64::head_size()
93 }
94}
95impl Decode for Time {
96 fn decode(buf: &[u8]) -> Result<Self> {
97 Ok(Self {
98 microseconds: i64::decode(buf)?,
99 })
100 }
101}
102impl Encode for Decimal {
103 type HeadPtr = ();
104
105 fn encode_head(&self, buf: &mut crate::bytes::BytesMut) {
106 self.0.encode_head(buf)
107 }
108
109 fn encode_body(&self, _: (), _: &mut crate::bytes::BytesMut) {}
110}
111impl Layout for Decimal {
112 fn head_size() -> usize {
113 i64::head_size()
114 }
115}
116impl Decode for Decimal {
117 fn decode(buf: &[u8]) -> Result<Self> {
118 Ok(Self(i64::decode(buf)?))
119 }
120}
121impl Encode for ops::Ordering {
122 type HeadPtr = ();
123
124 fn encode_head(&self, buf: &mut crate::bytes::BytesMut) {
125 let tag = match self {
126 Self::Less => 0_u8,
127 Self::Equal => 1,
128 Self::Greater => 2,
129 };
130 tag.encode_head(buf)
131 }
132
133 fn encode_body(&self, _: (), _: &mut crate::bytes::BytesMut) {}
134}
135impl Layout for ops::Ordering {
136 fn head_size() -> usize {
137 8
138 }
139}
140impl Decode for ops::Ordering {
141 fn decode(buf: &[u8]) -> Result<Self> {
142 Ok(match u8::decode(buf)? {
143 0 => Self::Less,
144 1 => Self::Equal,
145 2 => Self::Greater,
146 _ => return Err(crate::Error::InvalidData),
147 })
148 }
149}
150
151#[cfg(feature = "chrono")]
152mod chrono_impls {
153 use chrono::{Datelike, Timelike};
154
155 use super::{Date, Time, Timestamp};
156
157 const EPOCH_DAYS_FROM_CE: i32 = 719_163;
158 const MICROS_PER_SECOND: u32 = 1_000_000;
159 const MICROS_PER_DAY: i64 = 86_400_000_000;
160
161 impl TryFrom<Timestamp> for chrono::DateTime<chrono::Utc> {
162 type Error = crate::Error;
163
164 fn try_from(value: Timestamp) -> core::result::Result<Self, Self::Error> {
165 chrono::DateTime::from_timestamp_micros(value.microseconds)
166 .ok_or(crate::Error::InvalidData)
167 }
168 }
169
170 impl From<chrono::DateTime<chrono::Utc>> for Timestamp {
171 fn from(value: chrono::DateTime<chrono::Utc>) -> Self {
172 Self {
173 microseconds: value.timestamp_micros(),
174 }
175 }
176 }
177
178 impl TryFrom<Date> for chrono::NaiveDate {
179 type Error = crate::Error;
180
181 fn try_from(value: Date) -> core::result::Result<Self, Self::Error> {
182 chrono::NaiveDate::from_num_days_from_ce_opt(value.days_epoch + EPOCH_DAYS_FROM_CE)
183 .ok_or(crate::Error::InvalidData)
184 }
185 }
186
187 impl TryFrom<chrono::NaiveDate> for Date {
188 type Error = crate::Error;
189
190 fn try_from(value: chrono::NaiveDate) -> core::result::Result<Self, Self::Error> {
191 let days = value.num_days_from_ce() - EPOCH_DAYS_FROM_CE;
192 Ok(Self { days_epoch: days })
193 }
194 }
195
196 impl TryFrom<Time> for chrono::NaiveTime {
197 type Error = crate::Error;
198
199 fn try_from(value: Time) -> core::result::Result<Self, Self::Error> {
200 if !(0..MICROS_PER_DAY).contains(&value.microseconds) {
201 return Err(crate::Error::InvalidData);
202 }
203
204 let secs = u32::try_from(value.microseconds / i64::from(MICROS_PER_SECOND))
205 .map_err(|_| crate::Error::InvalidData)?;
206 let micros = u32::try_from(value.microseconds % i64::from(MICROS_PER_SECOND))
207 .map_err(|_| crate::Error::InvalidData)?;
208
209 chrono::NaiveTime::from_num_seconds_from_midnight_opt(secs, micros * 1_000)
210 .ok_or(crate::Error::InvalidData)
211 }
212 }
213
214 impl From<chrono::NaiveTime> for Time {
215 fn from(value: chrono::NaiveTime) -> Self {
216 let secs = i64::from(value.num_seconds_from_midnight());
217 let micros = i64::from(value.nanosecond() / 1_000);
218 Self {
219 microseconds: secs * i64::from(MICROS_PER_SECOND) + micros,
220 }
221 }
222 }
223}