use core::cmp::{Ord, PartialOrd};
use displaydoc::Display;
use zerovec::ule::{AsULE, ZeroVecError, ULE};
#[cfg(doc)]
use crate::fields::{Hour, Weekday};
#[derive(Display, Debug, PartialEq, Copy, Clone)]
#[non_exhaustive]
pub enum LengthError {
#[displaydoc("Invalid length")]
InvalidLength,
}
#[cfg(feature = "std")]
impl std::error::Error for LengthError {}
#[derive(Debug, Eq, PartialEq, Clone, Copy, Ord, PartialOrd)]
#[cfg_attr(
feature = "datagen",
derive(serde::Serialize, databake::Bake),
databake(path = icu_datetime::fields),
)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[allow(clippy::exhaustive_enums)] pub enum FieldLength {
One,
TwoDigit,
Abbreviated,
Wide,
Narrow,
Six,
Fixed(u8),
}
impl FieldLength {
#[inline]
pub(crate) fn idx(&self) -> u8 {
match self {
FieldLength::One => 1,
FieldLength::TwoDigit => 2,
FieldLength::Abbreviated => 3,
FieldLength::Wide => 4,
FieldLength::Narrow => 5,
FieldLength::Six => 6,
FieldLength::Fixed(p) => 128 + p.min(&127),
}
}
#[inline]
pub(crate) fn from_idx(idx: u8) -> Result<Self, LengthError> {
Ok(match idx {
1 => Self::One,
2 => Self::TwoDigit,
3 => Self::Abbreviated,
4 => Self::Wide,
5 => Self::Narrow,
6 => Self::Six,
idx => {
if idx < 128 {
return Err(LengthError::InvalidLength);
}
Self::Fixed(idx - 128)
}
})
}
#[inline]
#[cfg(feature = "datagen")]
pub(crate) fn to_len(self) -> usize {
match self {
FieldLength::One => 1,
FieldLength::TwoDigit => 2,
FieldLength::Abbreviated => 3,
FieldLength::Wide => 4,
FieldLength::Narrow => 5,
FieldLength::Six => 6,
FieldLength::Fixed(p) => p as usize,
}
}
}
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct FieldLengthULE(u8);
impl AsULE for FieldLength {
type ULE = FieldLengthULE;
fn to_unaligned(self) -> Self::ULE {
FieldLengthULE(self.idx())
}
fn from_unaligned(unaligned: Self::ULE) -> Self {
#[allow(clippy::unwrap_used)] Self::from_idx(unaligned.0).unwrap()
}
}
impl FieldLengthULE {
#[inline]
pub(crate) fn validate_byte(byte: u8) -> Result<(), ZeroVecError> {
FieldLength::from_idx(byte)
.map(|_| ())
.map_err(|_| ZeroVecError::parse::<FieldLength>())
}
}
unsafe impl ULE for FieldLengthULE {
fn validate_byte_slice(bytes: &[u8]) -> Result<(), ZeroVecError> {
for byte in bytes {
Self::validate_byte(*byte)?;
}
Ok(())
}
}