use zerovec::{
maps::ZeroMapKV,
ule::{AsULE, UleError, ULE},
};
use crate::dimension::provider::currency::{
CurrencyPatternConfig, PatternSelection, PlaceholderValue,
};
const NO_PLACEHOLDER: u16 = 0b0111_1111_1111; const USE_ISO_CODE: u16 = 0b0111_1111_1110; pub const MAX_PLACEHOLDER_INDEX: u16 = 0b0111_1111_1101; #[derive(Copy, Clone, Debug, PartialEq)]
#[repr(transparent)]
pub struct CurrencyPatternConfigULE([u8; 3]);
unsafe impl ULE for CurrencyPatternConfigULE {
fn validate_byte_slice(bytes: &[u8]) -> Result<(), UleError> {
if bytes.len() % 3 != 0 {
return Err(UleError::length::<Self>(bytes.len()));
}
Ok(())
}
}
const PATTERN_SHORT_SHIFT: u8 = 7;
const PATTERN_NARROW_SHIFT: u8 = 6;
const INDEX_SHORT_SHIFT: u8 = 3;
const INDEX_NARROW_SHIFT: u8 = 0;
impl AsULE for CurrencyPatternConfig {
type ULE = CurrencyPatternConfigULE;
#[inline]
fn to_unaligned(self) -> Self::ULE {
let mut first_byte_ule: u8 = 0;
if self.short_pattern_selection == PatternSelection::StandardAlphaNextToNumber {
first_byte_ule |= 0b1 << PATTERN_SHORT_SHIFT;
}
if self.narrow_pattern_selection == PatternSelection::StandardAlphaNextToNumber {
first_byte_ule |= 0b1 << PATTERN_NARROW_SHIFT;
}
let [short_most_significant_byte, short_least_significant_byte_ule] =
match self.short_placeholder_value {
Some(PlaceholderValue::Index(index)) => index.to_be_bytes(),
Some(PlaceholderValue::ISO) => USE_ISO_CODE.to_be_bytes(),
None => NO_PLACEHOLDER.to_be_bytes(),
};
if short_most_significant_byte & 0b1111_1000 != 0 {
panic!(
"short_placeholder_value is too large {}, {}",
short_most_significant_byte, short_least_significant_byte_ule
)
}
first_byte_ule |= short_most_significant_byte << INDEX_SHORT_SHIFT;
let [narrow_most_significant_byte, narrow_least_significant_byte_ule] =
match self.narrow_placeholder_value {
Some(PlaceholderValue::Index(index)) => index.to_be_bytes(),
Some(PlaceholderValue::ISO) => USE_ISO_CODE.to_be_bytes(),
None => NO_PLACEHOLDER.to_be_bytes(),
};
if narrow_most_significant_byte & 0b1111_1000 != 0 {
panic!(
"narrow_placeholder_value is too large {}, {}",
narrow_most_significant_byte, narrow_least_significant_byte_ule
)
}
first_byte_ule |= narrow_most_significant_byte << INDEX_NARROW_SHIFT;
CurrencyPatternConfigULE([
first_byte_ule,
short_least_significant_byte_ule,
narrow_least_significant_byte_ule,
])
}
#[inline]
fn from_unaligned(unaligned: Self::ULE) -> Self {
let [first_byte, second_byte, third_byte] = unaligned.0;
let short_pattern_selection =
if first_byte & (0b1 << PATTERN_SHORT_SHIFT) == 0b1 << PATTERN_SHORT_SHIFT {
PatternSelection::StandardAlphaNextToNumber
} else {
PatternSelection::Standard
};
let narrow_pattern_selection =
if first_byte & (0b1 << PATTERN_NARROW_SHIFT) == 0b1 << PATTERN_NARROW_SHIFT {
PatternSelection::StandardAlphaNextToNumber
} else {
PatternSelection::Standard
};
let short_prefix = (first_byte & 0b111 << INDEX_SHORT_SHIFT) >> INDEX_SHORT_SHIFT;
let narrow_prefix = (first_byte & 0b111 << INDEX_NARROW_SHIFT) >> INDEX_NARROW_SHIFT;
let short_placeholder_value = ((short_prefix as u16) << 8) | second_byte as u16;
let narrow_placeholder_value = ((narrow_prefix as u16) << 8) | third_byte as u16;
let short_placeholder_value = match short_placeholder_value {
NO_PLACEHOLDER => None,
USE_ISO_CODE => Some(PlaceholderValue::ISO),
index => {
debug_assert!(index <= MAX_PLACEHOLDER_INDEX);
Some(PlaceholderValue::Index(index))
}
};
let narrow_placeholder_value = match narrow_placeholder_value {
NO_PLACEHOLDER => None,
USE_ISO_CODE => Some(PlaceholderValue::ISO),
index => {
debug_assert!(index <= MAX_PLACEHOLDER_INDEX);
Some(PlaceholderValue::Index(index))
}
};
CurrencyPatternConfig {
short_pattern_selection,
narrow_pattern_selection,
short_placeholder_value,
narrow_placeholder_value,
}
}
}
impl<'a> ZeroMapKV<'a> for CurrencyPatternConfig {
type Container = zerovec::ZeroVec<'a, CurrencyPatternConfig>;
type Slice = zerovec::ZeroSlice<CurrencyPatternConfig>;
type GetType = <CurrencyPatternConfig as AsULE>::ULE;
type OwnedType = CurrencyPatternConfig;
}