#![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)]
use zerovec::{
maps::ZeroMapKV,
ule::{AsULE, UleError, ULE},
};
use crate::dimension::provider::units_essentials::CompoundCount;
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_experimental::dimension::provider::pattern_key))]
#[repr(u8)]
pub enum PowerValue {
Two,
Three,
}
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_experimental::dimension::provider::pattern_key))]
pub enum PatternKey {
Binary(u8),
Decimal(i8),
Power {
power: PowerValue,
count: CompoundCount,
},
}
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
pub struct PatternKeyULE(u8);
unsafe impl ULE for PatternKeyULE {
fn validate_byte_slice(bytes: &[u8]) -> Result<(), zerovec::ule::UleError> {
for &byte in bytes.iter() {
if (byte & 0b1100_0000) == 0b1100_0000 {
return Err(UleError::parse::<Self>());
}
if (byte & 0b1100_0000) == 0b1000_0000 {
if (byte & 0b0010_0000) == 0 {
return Err(UleError::parse::<Self>());
}
if (byte & 0b0000_1000) != 0 {
return Err(UleError::parse::<Self>());
}
if (byte & 0b0000_0100) != 0 && (byte & 0b0000_0010) != 0 {
return Err(UleError::parse::<Self>());
}
}
}
Ok(())
}
}
impl AsULE for PatternKey {
type ULE = PatternKeyULE;
fn to_unaligned(self) -> Self::ULE {
let byte = match self {
PatternKey::Binary(value) => value,
PatternKey::Decimal(value) => {
let sign = if value < 0 { 0b0010_0000 } else { 0 };
debug_assert!(value > -32 && value < 32);
(0b01 << 6) | sign | (value.unsigned_abs() & 0b0001_1111)
}
PatternKey::Power { power, count } => {
let power_bits = {
match power {
PowerValue::Two => 0b10 << 4,
PowerValue::Three => 0b11 << 4,
}
};
(0b10 << 6) | power_bits | count as u8
}
};
PatternKeyULE(byte)
}
fn from_unaligned(unaligned: Self::ULE) -> Self {
let byte = unaligned.0;
let variant = (byte & 0b1100_0000) >> 6;
let value = byte & 0b0011_1111;
match variant {
0b00 => PatternKey::Binary(value),
0b01 => match value & 0b0010_0000 {
0b0000_0000 => PatternKey::Decimal(value as i8),
0b0010_0000 => PatternKey::Decimal(-((value & 0b0001_1111) as i8)),
_ => unreachable!(),
},
0b10 => {
let power = match value & 0b0011_0000 {
0b0010_0000 => PowerValue::Two,
0b0011_0000 => PowerValue::Three,
_ => unreachable!(),
};
let count = value & 0b0000_1111;
PatternKey::Power {
power,
count: count.into(),
}
}
_ => unreachable!(),
}
}
}
impl<'a> ZeroMapKV<'a> for PatternKey {
type Container = zerovec::ZeroVec<'a, PatternKey>;
type Slice = zerovec::ZeroSlice<PatternKey>;
type GetType = <PatternKey as AsULE>::ULE;
type OwnedType = PatternKey;
}
#[test]
fn test_pattern_key_ule() {
use PowerValue::{Three, Two};
let binary = PatternKey::Binary(0b0000_1111);
let binary_ule = binary.to_unaligned();
PatternKeyULE::validate_byte_slice(&[binary_ule.0]).unwrap();
assert_eq!(binary_ule.0, 0b0000_1111);
let decimal = PatternKey::Decimal(0b0000_1111);
let decimal_ule = decimal.to_unaligned();
PatternKeyULE::validate_byte_slice(&[decimal_ule.0]).unwrap();
assert_eq!(decimal_ule.0, 0b0100_1111);
let power2 = PatternKey::Power {
power: Two,
count: CompoundCount::Two,
};
let power2_ule = power2.to_unaligned();
PatternKeyULE::validate_byte_slice(&[power2_ule.0]).unwrap();
assert_eq!(power2_ule.0, 0b1010_0010);
let power3 = PatternKey::Power {
power: Three,
count: CompoundCount::Two,
};
let power3_ule = power3.to_unaligned();
PatternKeyULE::validate_byte_slice(&[power3_ule.0]).unwrap();
assert_eq!(power3_ule.0, 0b1011_0010);
let binary = PatternKey::from_unaligned(binary_ule);
assert_eq!(binary, PatternKey::Binary(0b0000_1111));
let decimal = PatternKey::from_unaligned(decimal_ule);
assert_eq!(decimal, PatternKey::Decimal(0b0000_1111));
let power2 = PatternKey::from_unaligned(power2_ule);
assert_eq!(
power2,
PatternKey::Power {
power: Two,
count: CompoundCount::Two,
}
);
let power3 = PatternKey::from_unaligned(power3_ule);
assert_eq!(
power3,
PatternKey::Power {
power: Three,
count: CompoundCount::Two,
}
);
let decimal_neg_1 = PatternKey::Decimal(-1);
let decimal_neg_1_ule = decimal_neg_1.to_unaligned();
assert_eq!(decimal_neg_1_ule.0, 0b0110_0001);
let decimal_neg_1 = PatternKey::from_unaligned(decimal_neg_1_ule);
assert_eq!(decimal_neg_1, PatternKey::Decimal(-1));
let unvalidated_bytes = [0b1100_0000];
assert_eq!(
PatternKeyULE::validate_byte_slice(&unvalidated_bytes),
Err(UleError::parse::<PatternKeyULE>())
);
let unvalidated_bytes = [0b1000_0000];
assert_eq!(
PatternKeyULE::validate_byte_slice(&unvalidated_bytes),
Err(UleError::parse::<PatternKeyULE>())
);
}