Skip to content

Commit edfcac6

Browse files
committed
Checkpoint
1 parent d50a18d commit edfcac6

File tree

2 files changed

+192
-8
lines changed

2 files changed

+192
-8
lines changed

components/datetime/src/provider/neo/packed_pattern.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ pub struct PackedSkeletonDataBuilder<'a> {
2121
pub variant1: Option<LengthPluralElements<'a>>,
2222
}
2323

24-
25-
2624
// #[zerovec::make_varule(TaggedPatternULE)]
2725
pub struct TaggedPattern<'data> {
2826
pub tag: u8,

components/plurals/src/provider.rs

Lines changed: 192 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,17 @@
1515
//!
1616
//! Read more about data providers: [`icu_provider`]
1717
18-
use crate::rules::runtime::ast::Rule;
18+
use core::marker::PhantomData;
1919
use icu_provider::prelude::*;
2020
use icu_provider::DynamicDataMarker;
21+
use zerovec::ule::vartuple::TinyVarVar;
22+
use zerovec::ule::vartuple::TinyVarVarULE;
23+
use zerovec::ule::vartuple::VarTupleULE;
24+
use zerovec::ule::UleError;
25+
use zerovec::ule::VarULE;
26+
use zerovec::ule::ULE;
27+
use zerovec::VarZeroSlice;
28+
use crate::rules::runtime::ast::Rule;
2129

2230
#[cfg(feature = "compiled_data")]
2331
#[derive(Debug)]
@@ -327,7 +335,7 @@ use alloc::borrow::Cow;
327335
use zerovec::ule::AsULE;
328336
use zerovec::VarZeroVec;
329337

330-
#[derive(Debug, Clone, Copy)]
338+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
331339
#[zerovec::make_ule(PluralCategoryV1ULE)]
332340
#[repr(u8)]
333341
#[cfg_attr(feature = "datagen", derive(serde::Serialize))]
@@ -475,12 +483,190 @@ impl<'a, 'b> From<PluralElements<'b, str>> for PluralElementsV1<'a> {
475483
}
476484
}
477485

478-
struct PluralElementsSingletonVarULE<V> {}
479-
480-
struct PluralElementsMapVarULE {}
481-
482486
#[test]
483487
fn plural_elements_niche() {
484488
assert_eq!(core::mem::size_of::<PluralElementsV1>(), 48);
485489
assert_eq!(core::mem::size_of::<Option<PluralElementsV1>>(), 48);
486490
}
491+
492+
/// Four bits of metadata that are stored and retrieved with the plural elements.
493+
#[derive(Debug, Copy, Clone)]
494+
#[repr(transparent)]
495+
pub struct FourBitMetadata(u8);
496+
497+
/// Representation: `ppppmmmm`
498+
/// - `pppp` = plural category (including explicit value)
499+
/// - `mmmm` = [`FourBitMetadata`]
500+
#[derive(Debug, Copy, Clone)]
501+
#[repr(transparent)]
502+
struct PluralCategoryAndMetadata(
503+
// Invariant: representation is as stated in the struct docs
504+
u8,
505+
);
506+
507+
impl PluralCategoryAndMetadata {
508+
fn get(self) -> (PluralElementsKeysV1, FourBitMetadata) {
509+
let plural_category_byte = (self.0 & 0xF0) >> 4;
510+
// Safety: by invariant
511+
let plural_category =
512+
unsafe { PluralElementsKeysV1::new_from_u8(plural_category_byte).unwrap_unchecked() };
513+
let metadata = FourBitMetadata(self.0 & 0x0F);
514+
(plural_category, metadata)
515+
}
516+
}
517+
518+
unsafe impl ULE for PluralCategoryAndMetadata {
519+
fn validate_byte_slice(bytes: &[u8]) -> Result<(), zerovec::ule::UleError> {
520+
bytes
521+
.iter()
522+
.all(|byte| {
523+
let plural_category_byte = (byte & 0xF0) >> 4;
524+
PluralElementsKeysV1::new_from_u8(plural_category_byte).is_some()
525+
})
526+
.then_some(())
527+
.ok_or_else(|| UleError::parse::<Self>())
528+
}
529+
}
530+
531+
impl AsULE for PluralCategoryAndMetadata {
532+
type ULE = Self;
533+
#[inline]
534+
fn to_unaligned(self) -> Self::ULE {
535+
self
536+
}
537+
#[inline]
538+
fn from_unaligned(unaligned: Self::ULE) -> Self {
539+
unaligned
540+
}
541+
}
542+
543+
type PluralElementsSingletonVarULE<V> = V;
544+
545+
type PluralElementsTupleSliceVarULE<V> = VarZeroSlice<VarTupleULE<PluralCategoryAndMetadata, V>>;
546+
547+
type PluralElementsDefaultMapVarULE<V> = TinyVarVarULE<V, PluralElementsTupleSliceVarULE<V>>;
548+
549+
fn get_special<V: VarULE + ?Sized>(
550+
data: &PluralElementsTupleSliceVarULE<V>,
551+
key: PluralElementsKeysV1,
552+
) -> Option<(&V, FourBitMetadata)> {
553+
data.iter()
554+
.filter_map(|ule| {
555+
let (current_key, metadata) = ule.sized.get();
556+
(current_key == key).then_some((&ule.variable, metadata))
557+
})
558+
.next()
559+
}
560+
561+
/// A bitpacked DST for [`PluralElements`].
562+
///
563+
/// Can be put in a [`Cow`] or a [`VarZeroVec`].
564+
#[derive(Debug)]
565+
#[repr(transparent)]
566+
pub struct PluralElementsPackedULE<V: VarULE + ?Sized> {
567+
_v: PhantomData<V>,
568+
/// Invariant Representation:
569+
///
570+
/// First byte: `d...mmmm`
571+
/// - `d` = 0 if singleton, 1 if a map
572+
/// - `...` = padding, should be 0
573+
/// - `mmmm` = [`FourBitMetadata`] for the default value
574+
///
575+
/// Remainder: either [`PluralElementsSingletonVarULE`] or [`PluralElementsDefaultMapVarULE`]
576+
/// based on the discriminant `d`
577+
bytes: [u8],
578+
}
579+
580+
impl<V: VarULE + ?Sized> ToOwned for PluralElementsPackedULE<V> {
581+
type Owned = Box<PluralElementsPackedULE<V>>;
582+
fn to_owned(&self) -> Self::Owned {
583+
self.to_boxed()
584+
}
585+
}
586+
587+
unsafe impl<V> VarULE for PluralElementsPackedULE<V>
588+
where
589+
V: VarULE + ?Sized,
590+
{
591+
fn validate_byte_slice(bytes: &[u8]) -> Result<(), zerovec::ule::UleError> {
592+
let (lead_byte, remainder) = bytes
593+
.split_first()
594+
.ok_or_else(|| UleError::length::<Self>(bytes.len()))?;
595+
if lead_byte & 0x8F != 0 {
596+
return Err(UleError::parse::<Self>());
597+
}
598+
if lead_byte & 0x80 == 0 {
599+
PluralElementsSingletonVarULE::<V>::validate_byte_slice(remainder)
600+
} else {
601+
PluralElementsDefaultMapVarULE::<V>::validate_byte_slice(remainder)
602+
}
603+
}
604+
605+
unsafe fn from_byte_slice_unchecked(bytes: &[u8]) -> &Self {
606+
// Safety: the bytes are valid by trait invariant, and we are transparent over bytes
607+
core::mem::transmute(bytes)
608+
}
609+
}
610+
611+
impl<V> PluralElementsPackedULE<V>
612+
where
613+
V: VarULE + ?Sized,
614+
{
615+
/// Unpacks this structure into the default value and the optional list of specials.
616+
fn as_parts(
617+
&self,
618+
) -> (
619+
(&V, FourBitMetadata),
620+
Option<&PluralElementsTupleSliceVarULE<V>>,
621+
) {
622+
// Safety: the bytes are valid by invariant
623+
let (lead_byte, remainder) = unsafe { self.bytes.split_first().unwrap_unchecked() };
624+
let metadata = FourBitMetadata(lead_byte & 0x0F);
625+
if lead_byte & 0x80 == 0 {
626+
// Safety: the bytes are valid by invariant
627+
let inner =
628+
unsafe { PluralElementsSingletonVarULE::<V>::from_byte_slice_unchecked(remainder) };
629+
((inner, metadata), None)
630+
} else {
631+
// Safety: the bytes are valid by invariant
632+
let inner = unsafe {
633+
PluralElementsDefaultMapVarULE::<V>::from_byte_slice_unchecked(remainder)
634+
};
635+
let (default, tuple_slice) = inner.get();
636+
((default, metadata), Some(tuple_slice))
637+
}
638+
}
639+
640+
/// Returns the value for the given [`PluralOperands`] and [`PluralRules`].
641+
pub fn get<'a>(&'a self, op: PluralOperands, rules: &PluralRules) -> (&'a V, FourBitMetadata) {
642+
let (default, specials) = self.as_parts();
643+
644+
let category = rules.category_for(op);
645+
646+
match specials {
647+
Some(specials) => {
648+
if op.is_exactly_zero() {
649+
if let Some(value) = get_special(specials, PluralElementsKeysV1::ExplicitZero) {
650+
return value;
651+
}
652+
}
653+
if op.is_exactly_one() {
654+
if let Some(value) = get_special(specials, PluralElementsKeysV1::ExplicitOne) {
655+
return value;
656+
}
657+
}
658+
match category {
659+
PluralCategory::Zero => Some(PluralElementsKeysV1::Zero),
660+
PluralCategory::One => Some(PluralElementsKeysV1::One),
661+
PluralCategory::Two => Some(PluralElementsKeysV1::Two),
662+
PluralCategory::Few => Some(PluralElementsKeysV1::Few),
663+
PluralCategory::Many => Some(PluralElementsKeysV1::Many),
664+
PluralCategory::Other => None,
665+
}
666+
.and_then(|key| get_special(specials, key))
667+
}
668+
None => None,
669+
}
670+
.unwrap_or(default)
671+
}
672+
}

0 commit comments

Comments
 (0)