1use super::pattern::{
8 runtime::{Pattern, PatternBorrowed, PatternMetadata},
9 PatternItem,
10};
11use crate::{options::Length, size_test_macro::size_test};
12use alloc::vec::Vec;
13use icu_plurals::{
14 provider::{FourBitMetadata, PluralElementsPackedULE},
15 PluralElements,
16};
17use icu_provider::prelude::*;
18use zerovec::{VarZeroVec, ZeroSlice};
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct LengthPluralElements<T> {
23 pub long: PluralElements<T>,
25 pub medium: PluralElements<T>,
27 pub short: PluralElements<T>,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct PackedPatternsBuilder<'a> {
34 pub standard: LengthPluralElements<Pattern<'a>>,
36 pub variant0: Option<LengthPluralElements<Pattern<'a>>>,
38 pub variant1: Option<LengthPluralElements<Pattern<'a>>>,
40}
41
42size_test!(PackedPatterns, packed_skeleton_data_size, 32);
43
44icu_provider::data_marker!(
45 DatetimePatternsDateBuddhistV1,
47 PackedPatterns<'static>
48);
49icu_provider::data_marker!(
50 DatetimePatternsDateChineseV1,
52 PackedPatterns<'static>
53);
54icu_provider::data_marker!(
55 DatetimePatternsDateCopticV1,
57 PackedPatterns<'static>
58);
59icu_provider::data_marker!(
60 DatetimePatternsDateDangiV1,
62 PackedPatterns<'static>
63);
64icu_provider::data_marker!(
65 DatetimePatternsDateEthiopianV1,
67 PackedPatterns<'static>
68);
69icu_provider::data_marker!(
70 DatetimePatternsDateGregorianV1,
72 PackedPatterns<'static>
73);
74icu_provider::data_marker!(
75 DatetimePatternsDateHebrewV1,
77 PackedPatterns<'static>
78);
79icu_provider::data_marker!(
80 DatetimePatternsDateIndianV1,
82 PackedPatterns<'static>
83);
84icu_provider::data_marker!(
85 DatetimePatternsDateHijriV1,
87 PackedPatterns<'static>
88);
89icu_provider::data_marker!(
90 DatetimePatternsDateJapaneseV1,
92 PackedPatterns<'static>
93);
94icu_provider::data_marker!(
95 DatetimePatternsDateJapanextV1,
97 PackedPatterns<'static>
98);
99icu_provider::data_marker!(
100 DatetimePatternsDatePersianV1,
102 PackedPatterns<'static>
103);
104icu_provider::data_marker!(
105 DatetimePatternsDateRocV1,
107 PackedPatterns<'static>
108);
109icu_provider::data_marker!(
110 DatetimePatternsTimeV1,
112 PackedPatterns<'static>
113);
114
115#[doc = packed_skeleton_data_size!()]
117#[derive(Debug, PartialEq, Eq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)]
191#[cfg_attr(feature = "datagen", derive(databake::Bake))]
192#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider))]
193pub struct PackedPatterns<'data> {
194 pub header: u32,
197 pub elements: VarZeroVec<'data, PluralElementsPackedULE<ZeroSlice<PatternItem>>>,
200}
201
202icu_provider::data_struct!(
203 PackedPatterns<'_>,
204 #[cfg(feature = "datagen")]
205);
206
207mod constants {
208 pub(super) const LMS: u32 = 0;
210 pub(super) const L_MS: u32 = 1;
212 pub(super) const LM_S: u32 = 2;
214 pub(super) const M_DIFFERS: u32 = 0x1;
216 pub(super) const S_DIFFERS: u32 = 0x2;
218 pub(super) const LMS_MASK: u32 = 0x3;
220 pub(super) const Q_BIT: u32 = 0x4;
222 pub(super) const CHUNK_MASK: u32 = 0x7;
224}
225
226struct UnpackedPatterns<'a> {
227 pub(super) has_explicit_medium: bool,
228 pub(super) has_explicit_short: bool,
229 pub(super) variant_indices: VariantIndices,
230 pub(super) elements: Vec<PluralElements<Pattern<'a>>>,
231}
232
233#[repr(u8)]
234#[derive(Copy, Clone)]
235enum VariantPatternIndex {
236 Inherit = 0,
237 I0 = 1,
238 I1 = 2,
239 I2 = 3,
240 I3 = 4,
241 I4 = 5,
242 I5 = 6,
243 I6 = 7,
244}
245
246impl VariantPatternIndex {
247 #[cfg(feature = "datagen")]
248 pub(super) fn from_header_with_shift(header: u32, shift: u32) -> Self {
249 match Self::try_from_u32((header >> shift) & constants::CHUNK_MASK) {
250 Some(x) => x,
251 None => {
252 debug_assert!(false, "unreachable");
253 Self::Inherit
254 }
255 }
256 }
257
258 fn try_from_u32(u: u32) -> Option<Self> {
259 match u {
260 0 => Some(Self::Inherit),
261 1 => Some(Self::I0),
262 2 => Some(Self::I1),
263 3 => Some(Self::I2),
264 4 => Some(Self::I3),
265 5 => Some(Self::I4),
266 6 => Some(Self::I5),
267 7 => Some(Self::I6),
268 _ => None,
269 }
270 }
271
272 pub(super) fn try_from_chunks_u32(chunks: [u32; 6]) -> Option<[Self; 6]> {
273 let [c0, c1, c2, c3, c4, c5] = chunks;
274 Some([
275 Self::try_from_u32(c0)?,
276 Self::try_from_u32(c1)?,
277 Self::try_from_u32(c2)?,
278 Self::try_from_u32(c3)?,
279 Self::try_from_u32(c4)?,
280 Self::try_from_u32(c5)?,
281 ])
282 }
283
284 pub(super) fn to_chunks_u32(chunks: [Self; 6]) -> [u32; 6] {
285 let [c0, c1, c2, c3, c4, c5] = chunks;
286 [
287 c0 as u32, c1 as u32, c2 as u32, c3 as u32, c4 as u32, c5 as u32,
288 ]
289 }
290}
291
292enum VariantIndices {
293 OnePatternPerVariant,
294 IndicesPerVariant([VariantPatternIndex; 6]),
295}
296
297impl<'a> UnpackedPatterns<'a> {
298 pub(super) fn build(&self) -> PackedPatterns<'static> {
299 let mut header = 0u32;
300 if self.has_explicit_medium {
301 header |= constants::M_DIFFERS;
302 }
303 if self.has_explicit_short {
304 header |= constants::S_DIFFERS;
305 }
306 match self.variant_indices {
307 VariantIndices::OnePatternPerVariant => {
308 header |= constants::Q_BIT;
309 }
310 VariantIndices::IndicesPerVariant(chunks) => {
311 let mut shift = 3;
312 for chunk_u32 in VariantPatternIndex::to_chunks_u32(chunks).iter() {
313 debug_assert!(*chunk_u32 <= constants::CHUNK_MASK);
314 header |= *chunk_u32 << shift;
315 shift += 3;
316 }
317 }
318 }
319 let elements: Vec<PluralElements<(FourBitMetadata, &ZeroSlice<PatternItem>)>> = self
320 .elements
321 .iter()
322 .map(|plural_elements| {
323 plural_elements.as_ref().map(|pattern| {
324 (
325 pattern.metadata.to_four_bit_metadata(),
326 pattern.items.as_slice(),
327 )
328 })
329 })
330 .collect();
331 PackedPatterns {
332 header,
333 elements: elements.as_slice().into(),
334 }
335 }
336
337 #[cfg(feature = "datagen")]
338 pub(super) fn from_packed(packed: &'a PackedPatterns<'_>) -> Self {
339 let variant_indices = if (packed.header & constants::Q_BIT) != 0 {
340 VariantIndices::OnePatternPerVariant
341 } else {
342 VariantIndices::IndicesPerVariant([
343 VariantPatternIndex::from_header_with_shift(packed.header, 3),
344 VariantPatternIndex::from_header_with_shift(packed.header, 6),
345 VariantPatternIndex::from_header_with_shift(packed.header, 9),
346 VariantPatternIndex::from_header_with_shift(packed.header, 12),
347 VariantPatternIndex::from_header_with_shift(packed.header, 15),
348 VariantPatternIndex::from_header_with_shift(packed.header, 18),
349 ])
350 };
351 let elements = packed
352 .elements
353 .iter()
354 .map(|plural_elements| {
355 plural_elements.decode().map(|(metadata, items)| {
356 PatternBorrowed {
357 metadata: PatternMetadata::from_u8(metadata.get()),
358 items,
359 }
360 .as_pattern()
361 })
362 })
363 .collect();
364 Self {
365 has_explicit_medium: (packed.header & constants::M_DIFFERS) != 0,
366 has_explicit_short: (packed.header & constants::S_DIFFERS) != 0,
367 variant_indices,
368 elements,
369 }
370 }
371}
372
373impl PackedPatternsBuilder<'_> {
374 pub fn build(mut self) -> PackedPatterns<'static> {
376 self.simplify();
377
378 let mut elements = Vec::new();
380 let mut has_explicit_medium = false;
381 let mut has_explicit_short = false;
382 elements.push(self.standard.long.as_ref().map(Pattern::as_ref));
383 let mut s_offset = 0;
384 if self.standard.medium != self.standard.long {
385 elements.push(self.standard.medium.as_ref().map(Pattern::as_ref));
386 has_explicit_medium = true;
387 s_offset += 1;
388 }
389 if self.standard.short != self.standard.medium {
390 elements.push(self.standard.short.as_ref().map(Pattern::as_ref));
391 has_explicit_short = true;
392 s_offset += 1;
393 }
394
395 let variant_patterns = [
397 self.variant0.as_ref().map(|v| &v.long),
398 self.variant0.as_ref().map(|v| &v.medium),
399 self.variant0.as_ref().map(|v| &v.short),
400 self.variant1.as_ref().map(|v| &v.long),
401 self.variant1.as_ref().map(|v| &v.medium),
402 self.variant1.as_ref().map(|v| &v.short),
403 ];
404 let fallbacks = [
405 &self.standard.long,
406 &self.standard.medium,
407 &self.standard.short,
408 &self.standard.long,
409 &self.standard.medium,
410 &self.standard.short,
411 ];
412 let mut chunks = [0u32; 6]; for ((pattern, fallback), chunk) in variant_patterns
414 .iter()
415 .zip(fallbacks.iter())
416 .zip(chunks.iter_mut())
417 {
418 if let Some(pattern) = pattern {
419 if pattern != fallback {
420 *chunk = match elements.iter().position(|p| p == *pattern) {
421 Some(i) => i as u32 + 1,
422 None => {
423 elements.push(pattern.as_ref().map(Pattern::as_ref));
424 elements.len() as u32
425 }
426 }
427 }
428 }
429 }
430
431 let variant_indices = if let Some(chunks) = VariantPatternIndex::try_from_chunks_u32(chunks)
434 {
435 VariantIndices::IndicesPerVariant(chunks)
437 } else {
438 elements.truncate(s_offset + 1);
440 elements.extend(variant_patterns.into_iter().zip(fallbacks.iter()).map(
441 |(pattern, fallback)| pattern.unwrap_or(fallback).as_ref().map(Pattern::as_ref),
442 ));
443 VariantIndices::OnePatternPerVariant
444 };
445
446 let unpacked = UnpackedPatterns {
448 has_explicit_medium,
449 has_explicit_short,
450 variant_indices,
451 elements,
452 };
453 unpacked.build()
454 }
455
456 fn simplify(&mut self) {
457 if self.variant0.as_ref() == Some(&self.standard) {
458 self.variant0 = None;
459 }
460 if self.variant1.as_ref() == Some(&self.standard) {
461 self.variant1 = None;
462 }
463 }
464}
465
466pub(crate) enum PackedSkeletonVariant {
468 Standard,
470 Variant0,
472 Variant1,
474}
475
476impl PackedPatterns<'_> {
477 pub(crate) fn get(
478 &self,
479 length: Length,
480 variant: PackedSkeletonVariant,
481 ) -> PatternBorrowed<'_> {
482 use Length::*;
483 use PackedSkeletonVariant::*;
484 let lms = self.header & constants::LMS_MASK;
485 let pattern_index = if matches!(variant, Standard) {
486 match (length, lms) {
488 (Long, _) => 0,
489 (Medium, constants::LMS | constants::LM_S) => 0,
490 (Medium, _) => 1,
491 (Short, constants::LMS) => 0,
492 (Short, constants::L_MS | constants::LM_S) => 1,
493 (Short, _) => 2,
494 }
495 } else {
496 let s_offset = match lms {
497 constants::LMS => 0,
498 constants::L_MS | constants::LM_S => 1,
499 _ => 2,
500 };
501 let q = self.header & constants::Q_BIT;
502 if q == 0 {
503 let chunk_in_low_bits = match (length, variant) {
505 (Long, Variant0) => self.header >> 3,
506 (Medium, Variant0) => self.header >> 6,
507 (Short, Variant0) => self.header >> 9,
508 (Long, Variant1) => self.header >> 12,
509 (Medium, Variant1) => self.header >> 15,
510 (Short, Variant1) => self.header >> 18,
511 (_, Standard) => {
512 debug_assert!(false, "unreachable");
513 return PatternBorrowed::DEFAULT;
514 }
515 };
516 let chunk = chunk_in_low_bits & constants::CHUNK_MASK;
517 if chunk == 0 {
518 return self.get(length, Standard);
520 }
521 chunk - 1
522 } else {
523 let additional_offset = match (length, variant) {
525 (Long, Variant0) => 1,
526 (Medium, Variant0) => 2,
527 (Short, Variant0) => 3,
528 (Long, Variant1) => 4,
529 (Medium, Variant1) => 5,
530 (Short, Variant1) => 6,
531 (_, Standard) => {
532 debug_assert!(false, "unreachable");
533 return PatternBorrowed::DEFAULT;
534 }
535 };
536 s_offset + additional_offset
537 }
538 };
539 let Some(plural_elements) = self.elements.get(pattern_index as usize) else {
540 debug_assert!(false, "unreachable");
541 return PatternBorrowed::DEFAULT;
542 };
543 let (metadata, items) = plural_elements.get_default();
544 PatternBorrowed {
545 metadata: PatternMetadata::from_u8(metadata.get()),
546 items,
547 }
548 }
549
550 fn get_as_plural_elements(
551 &self,
552 length: Length,
553 variant: PackedSkeletonVariant,
554 ) -> PluralElements<Pattern<'_>> {
555 PluralElements::new(self.get(length, variant).as_pattern())
556 }
557
558 pub fn to_builder(&self) -> PackedPatternsBuilder<'_> {
560 use Length::*;
561 use PackedSkeletonVariant::*;
562 let mut builder = PackedPatternsBuilder {
563 standard: LengthPluralElements {
564 long: self.get_as_plural_elements(Long, Standard),
565 medium: self.get_as_plural_elements(Medium, Standard),
566 short: self.get_as_plural_elements(Short, Standard),
567 },
568 variant0: Some(LengthPluralElements {
569 long: self.get_as_plural_elements(Long, Variant0),
570 medium: self.get_as_plural_elements(Medium, Variant0),
571 short: self.get_as_plural_elements(Short, Variant0),
572 }),
573 variant1: Some(LengthPluralElements {
574 long: self.get_as_plural_elements(Long, Variant1),
575 medium: self.get_as_plural_elements(Medium, Variant1),
576 short: self.get_as_plural_elements(Short, Variant1),
577 }),
578 };
579 builder.simplify();
580 builder
581 }
582}
583
584#[cfg(feature = "serde")]
585mod _serde {
586 use super::*;
587 use crate::provider::pattern::reference;
588 use zerovec::VarZeroSlice;
589
590 #[cfg_attr(feature = "serde", derive(serde::Deserialize))]
591 #[cfg_attr(feature = "datagen", derive(serde::Serialize))]
592 struct PackedPatternsMachine<'data> {
593 pub header: u32,
594 #[serde(borrow)]
595 pub elements: &'data VarZeroSlice<PluralElementsPackedULE<ZeroSlice<PatternItem>>>,
596 }
597
598 #[cfg_attr(feature = "serde", derive(serde::Deserialize))]
599 #[cfg_attr(feature = "datagen", derive(serde::Serialize))]
600 #[derive(Default)]
601 struct PackedPatternsHuman {
602 #[cfg_attr(
603 feature = "serde",
604 serde(default, skip_serializing_if = "core::ops::Not::not")
605 )]
606 pub(super) has_explicit_medium: bool,
607 #[cfg_attr(
608 feature = "serde",
609 serde(default, skip_serializing_if = "core::ops::Not::not")
610 )]
611 pub(super) has_explicit_short: bool,
612 #[cfg_attr(
613 feature = "serde",
614 serde(default, skip_serializing_if = "core::ops::Not::not")
615 )]
616 pub(super) has_one_pattern_per_variant: bool,
617 #[cfg_attr(
618 feature = "serde",
619 serde(default, skip_serializing_if = "Option::is_none")
620 )]
621 pub(super) variant_pattern_indices: Option<[u32; 6]>,
622 pub(super) elements: Vec<reference::Pattern>,
623 }
624
625 impl<'de, 'data> serde::Deserialize<'de> for PackedPatterns<'data>
626 where
627 'de: 'data,
628 {
629 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
630 where
631 D: serde::Deserializer<'de>,
632 {
633 use serde::de::Error as _;
634 if deserializer.is_human_readable() {
635 let human = <PackedPatternsHuman>::deserialize(deserializer)?;
636 let variant_indices = match (
637 human.has_one_pattern_per_variant,
638 human.variant_pattern_indices,
639 ) {
640 (true, None) => VariantIndices::OnePatternPerVariant,
641 (false, Some(chunks)) => VariantIndices::IndicesPerVariant(
642 VariantPatternIndex::try_from_chunks_u32(chunks).ok_or_else(|| {
643 D::Error::custom("variant pattern index out of range")
644 })?,
645 ),
646 _ => {
647 return Err(D::Error::custom(
648 "must have either one pattern per variant or indices",
649 ))
650 }
651 };
652 let elements = human
653 .elements
654 .iter()
655 .map(|pattern| PluralElements::new(pattern.to_runtime_pattern()))
656 .collect();
657 let unpacked = UnpackedPatterns {
658 has_explicit_medium: human.has_explicit_medium,
659 has_explicit_short: human.has_explicit_short,
660 variant_indices,
661 elements,
662 };
663 Ok(unpacked.build())
664 } else {
665 let machine = <PackedPatternsMachine>::deserialize(deserializer)?;
666 Ok(Self {
667 header: machine.header,
668 elements: machine.elements.as_varzerovec(),
669 })
670 }
671 }
672 }
673
674 #[cfg(feature = "datagen")]
675 impl serde::Serialize for PackedPatterns<'_> {
676 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
677 where
678 S: serde::Serializer,
679 {
680 use serde::ser::Error as _;
681 if serializer.is_human_readable() {
682 let unpacked = UnpackedPatterns::from_packed(self);
683 let mut human = PackedPatternsHuman {
684 has_explicit_medium: unpacked.has_explicit_medium,
685 has_explicit_short: unpacked.has_explicit_short,
686 ..Default::default()
687 };
688 match unpacked.variant_indices {
689 VariantIndices::OnePatternPerVariant => {
690 human.has_one_pattern_per_variant = true;
691 }
692 VariantIndices::IndicesPerVariant(chunks) => {
693 let chunks = VariantPatternIndex::to_chunks_u32(chunks);
694 human.variant_pattern_indices = Some(chunks);
695 }
696 }
697 human.elements = Vec::with_capacity(unpacked.elements.len());
698 for pattern_elements in unpacked.elements.into_iter() {
699 let pattern = pattern_elements
700 .try_into_other()
701 .ok_or_else(|| S::Error::custom("cannot yet serialize plural patterns"))?;
702 human.elements.push(reference::Pattern::from(&pattern));
703 }
704 human.serialize(serializer)
705 } else {
706 let machine = PackedPatternsMachine {
707 header: self.header,
708 elements: &self.elements,
709 };
710 machine.serialize(serializer)
711 }
712 }
713 }
714}
715
716#[cfg(test)]
717mod tests {
718 use super::*;
719 use crate::provider::pattern::reference;
720
721 const PATTERN_STRS: &[&str] = &[
722 "M/d/y",
723 "HH:mm",
724 "MMM d y G",
725 "E",
726 "E MMM d",
727 "dd.MM.yy",
728 "h a",
729 "hh:mm:ss B",
730 "y MMMM",
731 ];
732
733 fn get_patterns() -> Vec<Pattern<'static>> {
734 PATTERN_STRS
735 .iter()
736 .map(|s| {
737 s.parse::<reference::Pattern>()
738 .unwrap()
739 .to_runtime_pattern()
740 })
741 .collect::<Vec<_>>()
742 }
743
744 #[test]
745 fn test_basic() {
746 let patterns = get_patterns();
747 let mut it = patterns.iter().cloned();
748 let lms0 = LengthPluralElements {
749 long: PluralElements::new(it.next().unwrap()),
750 medium: PluralElements::new(it.next().unwrap()),
751 short: PluralElements::new(it.next().unwrap()),
752 };
753 let lms1 = LengthPluralElements {
754 long: PluralElements::new(it.next().unwrap()),
755 medium: PluralElements::new(it.next().unwrap()),
756 short: PluralElements::new(it.next().unwrap()),
757 };
758 let lms2 = LengthPluralElements {
759 long: PluralElements::new(it.next().unwrap()),
760 medium: PluralElements::new(it.next().unwrap()),
761 short: PluralElements::new(it.next().unwrap()),
762 };
763 let lms0a = LengthPluralElements {
764 long: PluralElements::new(patterns[0].clone()),
765 medium: PluralElements::new(patterns[0].clone()),
766 short: PluralElements::new(patterns[1].clone()),
767 };
768 let lms1a = LengthPluralElements {
769 long: PluralElements::new(patterns[3].clone()),
770 medium: PluralElements::new(patterns[4].clone()),
771 short: PluralElements::new(patterns[4].clone()),
772 };
773
774 {
775 let builder = PackedPatternsBuilder {
777 standard: lms0.clone(),
778 variant0: Some(lms1.clone()),
779 variant1: Some(lms2.clone()),
780 };
781 let packed = builder.clone().build();
782 assert_eq!(packed.header, 7);
783 assert_eq!(packed.elements.len(), 9);
784 for (pattern_elements, expected) in packed.elements.iter().zip(patterns.iter()) {
785 assert_eq!(pattern_elements.get_default().1, &expected.items);
786 }
787 let recovered_builder = packed.to_builder();
788 assert_eq!(builder, recovered_builder);
789 }
790 {
791 let builder = PackedPatternsBuilder {
793 standard: lms0.clone(),
794 variant0: Some(lms0.clone()),
795 variant1: Some(lms2.clone()),
796 };
797 let packed = builder.clone().build();
798 assert_eq!(packed.header, 0x1AC003);
799 assert_eq!(packed.elements.len(), 6);
800 let recovered_builder = packed.to_builder();
801 assert_ne!(builder, recovered_builder);
802 let mut builder = builder;
803 builder.simplify();
804 assert_eq!(builder, recovered_builder);
805 }
806 {
807 let builder = PackedPatternsBuilder {
809 standard: lms0.clone(),
810 variant0: None,
811 variant1: None,
812 };
813 let packed = builder.clone().build();
814 assert_eq!(packed.header, 3);
815 assert_eq!(packed.elements.len(), 3);
816 let recovered_builder = packed.to_builder();
817 assert_eq!(builder, recovered_builder);
818 }
819 {
820 let builder = PackedPatternsBuilder {
822 standard: lms0a.clone(),
823 variant0: Some(lms0.clone()),
824 variant1: Some(lms1.clone()),
825 };
826 let packed = builder.clone().build();
827 assert_eq!(packed.header, 0x1AC682);
828 assert_eq!(packed.elements.len(), 6);
829 let recovered_builder = packed.to_builder();
830 assert_eq!(builder, recovered_builder);
831 }
832 {
833 let builder = PackedPatternsBuilder {
835 standard: lms0a.clone(),
836 variant0: Some(lms1.clone()),
837 variant1: Some(lms2.clone()),
838 };
839 let packed = builder.clone().build();
840 assert_eq!(packed.header, 6);
841 assert_eq!(packed.elements.len(), 8);
842 let recovered_builder = packed.to_builder();
843 assert_eq!(builder, recovered_builder);
844 }
845 {
846 let builder = PackedPatternsBuilder {
848 standard: lms1a.clone(),
849 variant0: Some(lms0a.clone()),
850 variant1: Some(lms2.clone()),
851 };
852 let packed = builder.clone().build();
853 assert_eq!(packed.header, 0x1F58D9);
854 assert_eq!(packed.elements.len(), 7);
855 let recovered_builder = packed.to_builder();
856 assert_eq!(builder, recovered_builder);
857 }
858 }
859
860 #[cfg(feature = "datagen")]
861 #[test]
862 fn test_serde() {
863 let patterns = get_patterns();
864 let lms0a = LengthPluralElements {
865 long: PluralElements::new(patterns[0].clone()),
866 medium: PluralElements::new(patterns[0].clone()),
867 short: PluralElements::new(patterns[1].clone()),
868 };
869 let lms1 = LengthPluralElements {
870 long: PluralElements::new(patterns[3].clone()),
871 medium: PluralElements::new(patterns[4].clone()),
872 short: PluralElements::new(patterns[5].clone()),
873 };
874
875 let builder = PackedPatternsBuilder {
876 standard: lms0a,
877 variant0: Some(lms1),
878 variant1: None,
879 };
880 let packed = builder.clone().build();
881
882 let bincode_bytes = bincode::serialize(&packed).unwrap();
883 assert_eq!(
884 bincode_bytes.as_slice(),
885 &[
886 26, 11, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 5, 0, 16, 0, 26, 0, 30, 0, 46, 0, 0, 128,
887 32, 1, 0, 0, 47, 128, 64, 1, 0, 0, 47, 128, 16, 1, 2, 128, 114, 2, 0, 0, 58, 128,
888 128, 2, 0, 128, 80, 1, 0, 128, 80, 1, 0, 0, 32, 128, 32, 3, 0, 0, 32, 128, 64, 1,
889 0, 128, 64, 2, 0, 0, 46, 128, 32, 2, 0, 0, 46, 128, 16, 2
890 ][..]
891 );
892 let bincode_recovered = bincode::deserialize::<PackedPatterns>(&bincode_bytes).unwrap();
893 assert_eq!(builder, bincode_recovered.to_builder());
894
895 let json_str = serde_json::to_string(&packed).unwrap();
896 assert_eq!(json_str, "{\"has_explicit_short\":true,\"variant_pattern_indices\":[3,4,5,0,0,0],\"elements\":[\"M/d/y\",\"HH:mm\",\"E\",\"E MMM d\",\"dd.MM.yy\"]}");
897 let json_recovered = serde_json::from_str::<PackedPatterns>(&json_str).unwrap();
898 assert_eq!(builder, json_recovered.to_builder());
899 }
900}