#![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)]
use crate::rules::runtime::ast::Rule;
use crate::{PluralCategory, PluralElements, PluralElementsInner, PluralOperands, PluralRules};
use alloc::borrow::{Cow, ToOwned};
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt;
use core::marker::PhantomData;
use icu_provider::prelude::*;
use yoke::Yokeable;
use zerofrom::ZeroFrom;
use zerovec::ule::vartuple::VarTuple;
use zerovec::ule::vartuple::VarTupleULE;
use zerovec::ule::AsULE;
use zerovec::ule::EncodeAsVarULE;
use zerovec::ule::UleError;
use zerovec::ule::VarULE;
use zerovec::ule::ULE;
use zerovec::VarZeroSlice;
#[cfg(feature = "compiled_data")]
#[derive(Debug)]
pub struct Baked;
#[cfg(feature = "compiled_data")]
#[allow(unused_imports)]
const _: () = {
use icu_plurals_data::*;
mod icu {
pub use crate as plurals;
pub use icu_plurals_data::icu_locale as locale;
}
make_provider!(Baked);
impl_cardinal_v1_marker!(Baked);
impl_ordinal_v1_marker!(Baked);
#[cfg(feature = "experimental")]
impl_plural_ranges_v1_marker!(Baked);
};
#[cfg(feature = "datagen")]
pub const MARKERS: &[DataMarkerInfo] = &[
CardinalV1Marker::INFO,
OrdinalV1Marker::INFO,
#[cfg(feature = "experimental")]
PluralRangesV1Marker::INFO,
];
#[icu_provider::data_struct(
CardinalV1Marker = "plurals/cardinal@1",
OrdinalV1Marker = "plurals/ordinal@1"
)]
#[derive(Default, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_plurals::provider))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
pub struct PluralRulesV1<'data> {
#[cfg_attr(feature = "serde", serde(borrow))]
pub zero: Option<Rule<'data>>,
#[cfg_attr(feature = "serde", serde(borrow))]
pub one: Option<Rule<'data>>,
#[cfg_attr(feature = "serde", serde(borrow))]
pub two: Option<Rule<'data>>,
#[cfg_attr(feature = "serde", serde(borrow))]
pub few: Option<Rule<'data>>,
#[cfg_attr(feature = "serde", serde(borrow))]
pub many: Option<Rule<'data>>,
}
#[cfg(any(feature = "datagen", feature = "experimental"))]
pub use ranges::*;
#[cfg(any(feature = "datagen", feature = "experimental"))]
mod ranges {
use crate::PluralCategory;
use icu_provider::prelude::*;
use zerovec::ZeroMap;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)]
#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_plurals::provider))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[zerovec::make_ule(RawPluralCategoryULE)]
#[repr(u8)]
#[cfg_attr(
any(feature = "datagen", feature = "serde"),
serde(rename_all = "lowercase")
)]
pub enum RawPluralCategory {
Other = 0,
Zero = 1,
One = 2,
Two = 3,
Few = 4,
Many = 5,
}
impl RawPluralCategory {
#[cfg(any(feature = "datagen", feature = "serde"))]
const fn as_str(self) -> &'static str {
match self {
Self::Other => "other",
Self::Zero => "zero",
Self::One => "one",
Self::Two => "two",
Self::Few => "few",
Self::Many => "many",
}
}
}
impl From<RawPluralCategory> for PluralCategory {
fn from(value: RawPluralCategory) -> Self {
match value {
RawPluralCategory::Other => PluralCategory::Other,
RawPluralCategory::Zero => PluralCategory::Zero,
RawPluralCategory::One => PluralCategory::One,
RawPluralCategory::Two => PluralCategory::Two,
RawPluralCategory::Few => PluralCategory::Few,
RawPluralCategory::Many => PluralCategory::Many,
}
}
}
impl From<PluralCategory> for RawPluralCategory {
fn from(value: PluralCategory) -> Self {
match value {
PluralCategory::Zero => RawPluralCategory::Zero,
PluralCategory::One => RawPluralCategory::One,
PluralCategory::Two => RawPluralCategory::Two,
PluralCategory::Few => RawPluralCategory::Few,
PluralCategory::Many => RawPluralCategory::Many,
PluralCategory::Other => RawPluralCategory::Other,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)]
#[cfg_attr(feature = "datagen", derive(databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_plurals::provider))]
#[zerovec::make_ule(UnvalidatedPluralRangeULE)]
pub struct UnvalidatedPluralRange(pub u8);
impl UnvalidatedPluralRange {
pub fn from_range(start: RawPluralCategory, end: RawPluralCategory) -> Self {
let start = start as u8;
let end = end as u8;
debug_assert!(start < 16);
debug_assert!(end < 16);
let range = (start << 4) | end;
Self(range)
}
}
#[cfg(feature = "datagen")]
impl serde::Serialize for UnvalidatedPluralRange {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::Error;
struct PrettyPrinter(RawPluralCategory, RawPluralCategory);
impl core::fmt::Display for PrettyPrinter {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(self.0.as_str())?;
f.write_str("--")?;
f.write_str(self.1.as_str())
}
}
if serializer.is_human_readable() {
let start = RawPluralCategory::new_from_u8(self.0 >> 4)
.ok_or_else(|| S::Error::custom("invalid tag in UnvalidatedPluralRange"))?;
let end = RawPluralCategory::new_from_u8(self.0 & 0x0F)
.ok_or_else(|| S::Error::custom("invalid tag in UnvalidatedPluralRange"))?;
serializer.collect_str(&PrettyPrinter(start, end))
} else {
self.0.serialize(serializer)
}
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for UnvalidatedPluralRange {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{Error, Visitor};
struct HumanReadableVisitor;
impl Visitor<'_> for HumanReadableVisitor {
type Value = UnvalidatedPluralRange;
fn expecting(&self, formatter: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
write!(
formatter,
"a plural range of the form <PluralCategory>-<PluralCategory>",
)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
const VARIANTS: [&str; 6] = [
RawPluralCategory::Other.as_str(),
RawPluralCategory::Zero.as_str(),
RawPluralCategory::One.as_str(),
RawPluralCategory::Two.as_str(),
RawPluralCategory::Few.as_str(),
RawPluralCategory::Many.as_str(),
];
let (start, end) = v
.split_once("--")
.ok_or_else(|| E::custom("expected token `--` in plural range"))?;
let start = PluralCategory::get_for_cldr_string(start)
.ok_or_else(|| E::unknown_variant(start, &VARIANTS))?;
let end = PluralCategory::get_for_cldr_string(end)
.ok_or_else(|| E::unknown_variant(end, &VARIANTS))?;
Ok(UnvalidatedPluralRange::from_range(start.into(), end.into()))
}
}
if deserializer.is_human_readable() {
deserializer.deserialize_str(HumanReadableVisitor)
} else {
Ok(Self(<u8>::deserialize(deserializer)?))
}
}
}
#[icu_provider::data_struct(PluralRangesV1Marker = "plurals/ranges@1")]
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_plurals::provider))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[yoke(prove_covariance_manually)]
pub struct PluralRangesV1<'data> {
#[cfg_attr(feature = "serde", serde(borrow))]
pub ranges: ZeroMap<'data, UnvalidatedPluralRange, RawPluralCategory>,
}
}
#[derive(Debug, PartialEq, Yokeable, ZeroFrom)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_plurals::provider))]
#[cfg_attr(
feature = "serde",
serde(
transparent,
bound(
serialize = "V: serde::Serialize + PartialEq",
deserialize = "Box<PluralElementsPackedULE<V>>: serde::Deserialize<'de>"
)
)
)]
pub struct PluralElementsPackedCow<'data, V: VarULE + ?Sized> {
#[cfg_attr(
feature = "serde",
serde(
borrow,
deserialize_with = "deserialize_plural_elements_packed_cow::<_, V>"
)
)]
pub elements: Cow<'data, PluralElementsPackedULE<V>>,
}
#[derive(Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct PluralElementsPackedULE<V: VarULE + ?Sized> {
_v: PhantomData<V>,
bytes: [u8],
}
impl<V: VarULE + ?Sized> ToOwned for PluralElementsPackedULE<V> {
type Owned = Box<PluralElementsPackedULE<V>>;
fn to_owned(&self) -> Self::Owned {
self.to_boxed()
}
}
unsafe impl<V> VarULE for PluralElementsPackedULE<V>
where
V: VarULE + ?Sized,
{
fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
let unpacked_bytes =
Self::unpack_bytes(bytes).ok_or_else(|| UleError::length::<Self>(bytes.len()))?;
if unpacked_bytes.lead_byte & 0x70 != 0 {
return Err(UleError::parse::<Self>());
}
V::validate_bytes(unpacked_bytes.v_bytes)?;
if let Some(specials_bytes) = unpacked_bytes.specials_bytes {
PluralElementsTupleSliceVarULE::<V>::validate_bytes(specials_bytes)?;
}
Ok(())
}
unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
core::mem::transmute(bytes)
}
}
impl<V> PluralElementsPackedULE<V>
where
V: VarULE + ?Sized,
{
pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
core::mem::transmute(bytes)
}
#[inline]
fn unpack_bytes(bytes: &[u8]) -> Option<PluralElementsUnpackedBytes> {
let (lead_byte, remainder) = bytes.split_first()?;
if lead_byte & 0x80 == 0 {
Some(PluralElementsUnpackedBytes {
lead_byte: *lead_byte,
v_bytes: remainder,
specials_bytes: None,
})
} else {
let (second_byte, remainder) = remainder.split_first()?;
let v_length = *second_byte as usize;
if remainder.len() < v_length {
return None;
}
let (v_bytes, remainder) = remainder.split_at(v_length);
Some(PluralElementsUnpackedBytes {
lead_byte: *lead_byte,
v_bytes,
specials_bytes: Some(remainder),
})
}
}
fn as_parts(&self) -> PluralElementsUnpacked<V> {
let unpacked_bytes = unsafe { Self::unpack_bytes(&self.bytes).unwrap_unchecked() };
let metadata = FourBitMetadata(unpacked_bytes.lead_byte & 0x0F);
let default = unsafe { V::from_bytes_unchecked(unpacked_bytes.v_bytes) };
#[allow(clippy::manual_map)] let specials = if let Some(specials_bytes) = unpacked_bytes.specials_bytes {
Some(unsafe {
PluralElementsTupleSliceVarULE::<V>::from_bytes_unchecked(specials_bytes)
})
} else {
None
};
PluralElementsUnpacked {
default: (metadata, default),
specials,
}
}
pub fn get<'a>(&'a self, op: PluralOperands, rules: &PluralRules) -> (FourBitMetadata, &'a V) {
let parts = self.as_parts();
let category = rules.category_for(op);
match parts.specials {
Some(specials) => {
if op.is_exactly_zero() {
if let Some(value) = get_special(specials, PluralElementsKeysV1::ExplicitZero) {
return value;
}
}
if op.is_exactly_one() {
if let Some(value) = get_special(specials, PluralElementsKeysV1::ExplicitOne) {
return value;
}
}
match category {
PluralCategory::Zero => Some(PluralElementsKeysV1::Zero),
PluralCategory::One => Some(PluralElementsKeysV1::One),
PluralCategory::Two => Some(PluralElementsKeysV1::Two),
PluralCategory::Few => Some(PluralElementsKeysV1::Few),
PluralCategory::Many => Some(PluralElementsKeysV1::Many),
PluralCategory::Other => None,
}
.and_then(|key| get_special(specials, key))
}
None => None,
}
.unwrap_or(parts.default)
}
#[cfg(feature = "datagen")]
pub fn decode(&self) -> PluralElements<(FourBitMetadata, &V)> {
PluralElements(PluralElementsInner::from_packed(self))
}
pub fn get_default(&self) -> (FourBitMetadata, &V) {
self.as_parts().default
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[zerovec::make_ule(PluralCategoryV1ULE)]
#[repr(u8)]
#[cfg_attr(feature = "datagen", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
enum PluralElementsKeysV1 {
Zero = 0,
One = 1,
Two = 2,
Few = 3,
Many = 4,
ExplicitZero = 5,
ExplicitOne = 6,
}
impl<T> PluralElementsInner<T>
where
T: PartialEq,
{
fn get_specials_tuples(&self) -> impl Iterator<Item = (PluralElementsKeysV1, &T)> {
[
self.zero
.as_ref()
.filter(|&p| *p != self.other)
.map(|s| (PluralElementsKeysV1::Zero, s)),
self.one
.as_ref()
.filter(|&p| *p != self.other)
.map(|s| (PluralElementsKeysV1::One, s)),
self.two
.as_ref()
.filter(|&p| *p != self.other)
.map(|s| (PluralElementsKeysV1::Two, s)),
self.few
.as_ref()
.filter(|&p| *p != self.other)
.map(|s| (PluralElementsKeysV1::Few, s)),
self.many
.as_ref()
.filter(|&p| *p != self.other)
.map(|s| (PluralElementsKeysV1::Many, s)),
self.explicit_zero
.as_ref()
.filter(|&p| *p != self.other)
.map(|s| (PluralElementsKeysV1::ExplicitZero, s)),
self.explicit_one
.as_ref()
.filter(|&p| *p != self.other)
.map(|s| (PluralElementsKeysV1::ExplicitOne, s)),
]
.into_iter()
.flatten()
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct FourBitMetadata(u8);
impl FourBitMetadata {
pub fn try_from_byte(byte: u8) -> Option<Self> {
if byte < 0x80 {
Some(Self(byte))
} else {
None
}
}
pub fn zero() -> Self {
Self(0)
}
pub fn get(self) -> u8 {
self.0
}
}
#[derive(Debug, Copy, Clone)]
struct PluralCategoryAndMetadata {
pub plural_category: PluralElementsKeysV1,
pub metadata: FourBitMetadata,
}
struct PluralCategoryAndMetadataUnpacked {
pub plural_category_byte: u8,
pub metadata_byte: u8,
}
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
struct PluralCategoryAndMetadataPackedULE(
u8,
);
impl From<PluralCategoryAndMetadata> for PluralCategoryAndMetadataPackedULE {
fn from(value: PluralCategoryAndMetadata) -> Self {
let byte = ((value.plural_category as u8) << 4) | value.metadata.get();
debug_assert!(
PluralCategoryAndMetadata::try_from_unpacked(Self::unpack_byte(byte)).is_some()
);
Self(byte)
}
}
unsafe impl ULE for PluralCategoryAndMetadataPackedULE {
fn validate_bytes(bytes: &[u8]) -> Result<(), zerovec::ule::UleError> {
bytes
.iter()
.all(|byte| {
let unpacked = Self::unpack_byte(*byte);
PluralCategoryAndMetadata::try_from_unpacked(unpacked).is_some()
})
.then_some(())
.ok_or_else(UleError::parse::<Self>)
}
}
impl PluralCategoryAndMetadataPackedULE {
fn unpack_byte(byte: u8) -> PluralCategoryAndMetadataUnpacked {
let plural_category_byte = (byte & 0xF0) >> 4;
let metadata_byte = byte & 0x0F;
PluralCategoryAndMetadataUnpacked {
plural_category_byte,
metadata_byte,
}
}
fn get(self) -> PluralCategoryAndMetadata {
let unpacked = Self::unpack_byte(self.0);
unsafe { PluralCategoryAndMetadata::try_from_unpacked(unpacked).unwrap_unchecked() }
}
}
impl PluralCategoryAndMetadata {
fn try_from_unpacked(unpacked: PluralCategoryAndMetadataUnpacked) -> Option<Self> {
let plural_category = PluralElementsKeysV1::new_from_u8(unpacked.plural_category_byte)?;
let metadata = FourBitMetadata::try_from_byte(unpacked.metadata_byte)?;
Some(Self {
plural_category,
metadata,
})
}
}
impl AsULE for PluralCategoryAndMetadata {
type ULE = PluralCategoryAndMetadataPackedULE;
#[inline]
fn to_unaligned(self) -> Self::ULE {
PluralCategoryAndMetadataPackedULE::from(self)
}
#[inline]
fn from_unaligned(unaligned: Self::ULE) -> Self {
unaligned.get()
}
}
type PluralElementsTupleSliceVarULE<V> = VarZeroSlice<VarTupleULE<PluralCategoryAndMetadata, V>>;
type PluralElementWithMetadata<'a, T> = (FourBitMetadata, &'a T);
struct PluralElementsPackedBuilder<'a, T> {
pub default: PluralElementWithMetadata<'a, T>,
pub specials: Option<Vec<VarTuple<PluralCategoryAndMetadata, &'a T>>>,
}
struct PluralElementsUnpacked<'a, V: VarULE + ?Sized> {
pub default: PluralElementWithMetadata<'a, V>,
pub specials: Option<&'a PluralElementsTupleSliceVarULE<V>>,
}
struct PluralElementsUnpackedBytes<'a> {
pub lead_byte: u8,
pub v_bytes: &'a [u8],
pub specials_bytes: Option<&'a [u8]>,
}
fn get_special<V: VarULE + ?Sized>(
data: &PluralElementsTupleSliceVarULE<V>,
key: PluralElementsKeysV1,
) -> Option<(FourBitMetadata, &V)> {
data.iter()
.filter_map(|ule| {
let PluralCategoryAndMetadata {
plural_category,
metadata,
} = ule.sized.get();
(plural_category == key).then_some((metadata, &ule.variable))
})
.next()
}
impl<T> PluralElementsInner<(FourBitMetadata, T)>
where
T: PartialEq,
{
fn to_packed_builder<'a, V>(&'a self) -> PluralElementsPackedBuilder<'a, T>
where
&'a T: EncodeAsVarULE<V>,
V: VarULE + ?Sized,
{
let specials = self
.get_specials_tuples()
.map(|(plural_category, (metadata, t))| VarTuple {
sized: PluralCategoryAndMetadata {
plural_category,
metadata: *metadata,
},
variable: t,
})
.collect::<Vec<_>>();
PluralElementsPackedBuilder {
default: (self.other.0, &self.other.1),
specials: if specials.is_empty() {
None
} else {
Some(specials)
},
}
}
}
unsafe impl<T, V> EncodeAsVarULE<PluralElementsPackedULE<V>>
for PluralElements<(FourBitMetadata, T)>
where
T: PartialEq + fmt::Debug,
for<'a> &'a T: EncodeAsVarULE<V>,
V: VarULE + ?Sized,
{
fn encode_var_ule_as_slices<R>(&self, _cb: impl FnOnce(&[&[u8]]) -> R) -> R {
unreachable!()
}
fn encode_var_ule_len(&self) -> usize {
let builder = self.0.to_packed_builder();
1 + builder.default.1.encode_var_ule_len()
+ match builder.specials {
Some(specials) => {
1 + EncodeAsVarULE::<PluralElementsTupleSliceVarULE<V>>::encode_var_ule_len(
&specials,
)
}
None => 0,
}
}
fn encode_var_ule_write(&self, dst: &mut [u8]) {
let builder = self.0.to_packed_builder();
#[allow(clippy::unwrap_used)] let (lead_byte, remainder) = dst.split_first_mut().unwrap();
*lead_byte = builder.default.0.get();
if let Some(specials) = builder.specials {
*lead_byte |= 0x80;
#[allow(clippy::unwrap_used)] let (second_byte, remainder) = remainder.split_first_mut().unwrap();
*second_byte = match u8::try_from(builder.default.1.encode_var_ule_len()) {
Ok(x) => x,
#[allow(clippy::panic)] Err(_) => {
panic!("other value too long to be packed: {self:?}")
}
};
let (v_bytes, specials_bytes) = remainder.split_at_mut(*second_byte as usize);
builder.default.1.encode_var_ule_write(v_bytes);
EncodeAsVarULE::<PluralElementsTupleSliceVarULE<V>>::encode_var_ule_write(
&specials,
specials_bytes,
);
} else {
builder.default.1.encode_var_ule_write(remainder)
};
}
}
#[cfg(feature = "datagen")]
impl<'a, V> PluralElementsInner<(FourBitMetadata, &'a V)>
where
V: VarULE + ?Sized,
{
fn from_packed(packed: &'a PluralElementsPackedULE<V>) -> Self {
let parts = packed.as_parts();
PluralElementsInner {
other: parts.default,
zero: parts
.specials
.and_then(|specials| get_special(specials, PluralElementsKeysV1::Zero)),
one: parts
.specials
.and_then(|specials| get_special(specials, PluralElementsKeysV1::One)),
two: parts
.specials
.and_then(|specials| get_special(specials, PluralElementsKeysV1::Two)),
few: parts
.specials
.and_then(|specials| get_special(specials, PluralElementsKeysV1::Few)),
many: parts
.specials
.and_then(|specials| get_special(specials, PluralElementsKeysV1::Many)),
explicit_zero: parts
.specials
.and_then(|specials| get_special(specials, PluralElementsKeysV1::ExplicitZero)),
explicit_one: parts
.specials
.and_then(|specials| get_special(specials, PluralElementsKeysV1::ExplicitOne)),
}
}
}
#[cfg(feature = "serde")]
impl<T> PluralElementsInner<(FourBitMetadata, T)> {
fn into_packed<V>(self) -> Box<PluralElementsPackedULE<V>>
where
T: PartialEq + fmt::Debug,
for<'a> &'a T: EncodeAsVarULE<V>,
V: VarULE + ?Sized,
{
zerovec::ule::encode_varule_to_box(&PluralElements(self))
}
}
#[cfg(feature = "serde")]
impl<'de, 'data, V> serde::Deserialize<'de> for &'data PluralElementsPackedULE<V>
where
'de: 'data,
V: VarULE + ?Sized,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
if deserializer.is_human_readable() {
Err(serde::de::Error::custom(
"&PluralElementsPackedULE cannot be deserialized from human-readable formats",
))
} else {
let bytes = <&[u8]>::deserialize(deserializer)?;
PluralElementsPackedULE::<V>::parse_bytes(bytes).map_err(serde::de::Error::custom)
}
}
}
#[cfg(feature = "serde")]
impl<'de, V> serde::Deserialize<'de> for Box<PluralElementsPackedULE<V>>
where
V: VarULE + ?Sized,
Box<V>: serde::Deserialize<'de> + PartialEq + fmt::Debug,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
if deserializer.is_human_readable() {
let plural_elements: PluralElementsInner<(FourBitMetadata, Box<V>)> =
PluralElementsInner::deserialize(deserializer)?;
Ok(plural_elements.into_packed())
} else {
let bytes = <&[u8]>::deserialize(deserializer)?;
PluralElementsPackedULE::<V>::parse_bytes(bytes)
.map(|ule| ule.to_owned())
.map_err(serde::de::Error::custom)
}
}
}
#[cfg(feature = "datagen")]
impl<V> serde::Serialize for PluralElementsPackedULE<V>
where
V: PartialEq + serde::Serialize + VarULE + ?Sized,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if serializer.is_human_readable() {
let plural_elements: PluralElementsInner<(FourBitMetadata, &V)> =
PluralElementsInner::from_packed(self);
plural_elements.serialize(serializer)
} else {
serializer.serialize_bytes(self.as_bytes())
}
}
}
#[cfg(feature = "datagen")]
impl<'a, V> databake::Bake for &'a PluralElementsPackedULE<V>
where
&'a V: databake::Bake,
V: VarULE + ?Sized,
{
fn bake(&self, ctx: &databake::CrateEnv) -> databake::TokenStream {
ctx.insert("icu_plurals");
let bytes = (&self.bytes).bake(ctx);
databake::quote! {
unsafe { icu_plurals::provider::PluralElementsPackedULE::from_bytes_unchecked(#bytes) }
}
}
}
#[cfg(feature = "datagen")]
impl<'a, V> databake::BakeSize for &'a PluralElementsPackedULE<V>
where
&'a V: databake::Bake,
V: VarULE + ?Sized,
{
fn borrows_size(&self) -> usize {
self.bytes.len()
}
}
#[cfg(feature = "serde")]
fn deserialize_plural_elements_packed_cow<'de, 'data, D, V>(
deserializer: D,
) -> Result<Cow<'data, PluralElementsPackedULE<V>>, D::Error>
where
'de: 'data,
D: serde::Deserializer<'de>,
V: VarULE + ?Sized,
Box<PluralElementsPackedULE<V>>: serde::Deserialize<'de>,
{
use serde::Deserialize;
if deserializer.is_human_readable() {
let value = Box::<PluralElementsPackedULE<V>>::deserialize(deserializer)?;
Ok(Cow::Owned(value))
} else {
let value = <&'de PluralElementsPackedULE<V>>::deserialize(deserializer)?;
Ok(Cow::Borrowed(value))
}
}
impl<V> Clone for PluralElementsPackedCow<'_, V>
where
V: VarULE + ?Sized,
{
fn clone(&self) -> Self {
Self {
elements: self.elements.clone(),
}
}
}
impl<T, V> From<PluralElements<T>> for PluralElementsPackedCow<'static, V>
where
V: VarULE + ?Sized,
T: PartialEq + fmt::Debug,
for<'a> &'a T: EncodeAsVarULE<V>,
{
fn from(value: PluralElements<T>) -> Self {
let elements =
zerovec::ule::encode_varule_to_box(&value.map(|s| (FourBitMetadata::zero(), s)));
Self {
elements: Cow::Owned(elements),
}
}
}
impl<V> PluralElementsPackedCow<'_, V>
where
V: VarULE + ?Sized,
{
pub fn get<'a>(&'a self, op: PluralOperands, rules: &PluralRules) -> &'a V {
self.elements.get(op, rules).1
}
}
#[test]
fn test_serde_singleton_roundtrip() {
let plural_elements = PluralElements::new((FourBitMetadata::zero(), "abc"));
let ule = zerovec::ule::encode_varule_to_box(&plural_elements);
let postcard_bytes = postcard::to_allocvec(&ule).unwrap();
assert_eq!(
postcard_bytes,
&[
4, 0x00, b'a', b'b', b'c', ]
);
let postcard_ule: Box<PluralElementsPackedULE<str>> =
postcard::from_bytes(&postcard_bytes).unwrap();
assert_eq!(ule, postcard_ule);
let postcard_borrowed: &PluralElementsPackedULE<str> =
postcard::from_bytes(&postcard_bytes).unwrap();
assert_eq!(&*ule, postcard_borrowed);
let postcard_cow: PluralElementsPackedCow<str> = postcard::from_bytes(&postcard_bytes).unwrap();
assert_eq!(&*ule, &*postcard_cow.elements);
assert!(matches!(postcard_cow.elements, Cow::Borrowed(_)));
let json_str = serde_json::to_string(&ule).unwrap();
let json_ule: Box<PluralElementsPackedULE<str>> = serde_json::from_str(&json_str).unwrap();
assert_eq!(ule, json_ule);
}
#[test]
fn test_serde_nonsingleton_roundtrip() {
let plural_elements = PluralElements::new((FourBitMetadata::zero(), "abc"))
.with_one_value(Some((FourBitMetadata::zero(), "defg")));
let ule = zerovec::ule::encode_varule_to_box(&plural_elements);
let postcard_bytes = postcard::to_allocvec(&ule).unwrap();
assert_eq!(
postcard_bytes,
&[
12, 0x80, 3, b'a', b'b', b'c', 1, 0, 0x10, b'd', b'e', b'f', b'g' ]
);
let postcard_ule: Box<PluralElementsPackedULE<str>> =
postcard::from_bytes(&postcard_bytes).unwrap();
assert_eq!(ule, postcard_ule);
let postcard_borrowed: &PluralElementsPackedULE<str> =
postcard::from_bytes(&postcard_bytes).unwrap();
assert_eq!(&*ule, postcard_borrowed);
let json_str = serde_json::to_string(&ule).unwrap();
let json_ule: Box<PluralElementsPackedULE<str>> = serde_json::from_str(&json_str).unwrap();
assert_eq!(ule, json_ule);
}