use std::array::TryFromSliceError;
use jiff::Timestamp;
#[derive(Debug, Clone, thiserror::Error)]
#[error("data parsing error")]
pub enum ParseError {
#[error("invalid timestamp: {0}")]
Timestamp(#[from] jiff::Error),
#[error("too little data: {0}")]
NeedData(#[from] TryFromSliceError),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Request {
pub client: Timestamp,
}
impl Request {
pub fn to_bytes(&self) -> [u8; 8] {
self.client.as_microsecond().to_be_bytes()
}
pub fn from_bytes(bytes: [u8; 8]) -> Result<Self, ParseError> {
Ok(Self {
client: Timestamp::from_microsecond(i64::from_be_bytes(bytes))?,
})
}
}
impl From<Request> for Vec<u8> {
fn from(request: Request) -> Self {
request.to_bytes().to_vec()
}
}
impl TryFrom<&[u8]> for Request {
type Error = ParseError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
Self::from_bytes(bytes[..8].try_into()?)
}
}
#[derive(Debug, Clone)]
pub struct Response {
pub client: Timestamp,
pub server: Timestamp,
}
impl Response {
pub fn to_bytes(&self) -> [u8; 16] {
let mut bytes = [0; 16];
bytes[..8].copy_from_slice(&self.client.as_microsecond().to_be_bytes());
bytes[8..].copy_from_slice(&self.server.as_microsecond().to_be_bytes());
bytes
}
pub fn from_bytes(bytes: [u8; 16]) -> Result<Self, ParseError> {
Ok(Self {
client: Timestamp::from_microsecond(i64::from_be_bytes(
bytes[..8].try_into().unwrap(),
))?,
server: Timestamp::from_microsecond(i64::from_be_bytes(
bytes[8..].try_into().unwrap(),
))?,
})
}
}
impl From<Response> for Vec<u8> {
fn from(response: Response) -> Self {
response.to_bytes().to_vec()
}
}
impl TryFrom<&[u8]> for Response {
type Error = ParseError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
Self::from_bytes(bytes[..16].try_into()?)
}
}