use chrono_tz_0_10::{TZ_VARIANTS, Tz};
use crate::{
ConstDecodeError, ConstEncodeError, DecodeError, EncodeError, Varint, decode_i16_varint,
encode_i16_varint_to, encoded_i16_varint_len, utils::Buffer,
};
use core::num::NonZeroUsize;
const TZ_VALUES: [i16; TZ_VARIANTS.len()] = const {
let mut values = [0; TZ_VARIANTS.len()];
let mut i = 0;
while i < TZ_VARIANTS.len() {
values[i] = TZ_VARIANTS[i] as i16;
i += 1;
}
values
};
#[inline]
pub const fn encoded_tz_len(tz: Tz) -> NonZeroUsize {
encoded_i16_varint_len(tz as i16)
}
#[inline]
pub const fn encode_tz_to(tz: Tz, buf: &mut [u8]) -> Result<NonZeroUsize, ConstEncodeError> {
encode_i16_varint_to(tz as i16, buf)
}
#[inline]
pub const fn encode_tz(tz: Tz) -> Buffer<{ Tz::MAX_ENCODED_LEN.get() + 1 }> {
let mut buf = [0; Tz::MAX_ENCODED_LEN.get() + 1];
let len = match encode_tz_to(tz, &mut buf) {
Ok(len) => len,
Err(_) => panic!(
"Timezone value is larger than buffer capacity, please report bug to https://github.com/al8n/varing/issues"
),
};
buf[Tz::MAX_ENCODED_LEN.get()] = len.get() as u8;
Buffer::new(buf)
}
#[inline]
pub const fn decode_tz(buf: &[u8]) -> Result<(NonZeroUsize, Tz), ConstDecodeError> {
match decode_i16_varint(buf) {
Ok((len, tz)) => {
let mut i = 0;
let mut found = None;
while i < TZ_VALUES.len() {
if TZ_VALUES[i] == tz {
found = Some(TZ_VARIANTS[i]);
break;
}
i += 1;
}
if let Some(tz) = found {
Ok((len, tz))
} else {
Err(ConstDecodeError::other("Invalid timezone value"))
}
}
Err(err) => Err(err),
}
}
impl Varint for Tz {
const MIN_ENCODED_LEN: NonZeroUsize = i16::MIN_ENCODED_LEN;
const MAX_ENCODED_LEN: NonZeroUsize = encoded_i16_varint_len(TZ_VALUES.len() as i16);
#[inline]
fn encoded_len(&self) -> NonZeroUsize {
encoded_tz_len(*self)
}
#[inline]
fn encode(&self, buf: &mut [u8]) -> Result<NonZeroUsize, EncodeError> {
encode_tz_to(*self, buf).map_err(Into::into)
}
#[inline]
fn decode(buf: &[u8]) -> Result<(NonZeroUsize, Self), DecodeError>
where
Self: Sized,
{
decode_tz(buf).map_err(Into::into)
}
}
#[cfg(test)]
mod tests {
use quickcheck::Arbitrary;
use super::{TZ_VALUES, TZ_VARIANTS, Varint, decode_tz, encode_tz, encoded_tz_len};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Tz(super::Tz);
impl From<Tz> for super::Tz {
fn from(value: Tz) -> Self {
value.0
}
}
impl Arbitrary for Tz {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let val = (u16::arbitrary(g) % super::TZ_VARIANTS.len() as u16) as i16;
let idx = TZ_VALUES.iter().position(|&v| v == val).unwrap();
Self(TZ_VARIANTS[idx])
}
}
fuzzy!(@varint_into (Tz(super::Tz)));
fuzzy!(@const_varint_into (Tz(super::Tz)));
}