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(&self, length: Length, variant: PackedSkeletonVariant) -> PatternBorrowed {
478 use Length::*;
479 use PackedSkeletonVariant::*;
480 let lms = self.header & constants::LMS_MASK;
481 let pattern_index = if matches!(variant, Standard) {
482 match (length, lms) {
484 (Long, _) => 0,
485 (Medium, constants::LMS | constants::LM_S) => 0,
486 (Medium, _) => 1,
487 (Short, constants::LMS) => 0,
488 (Short, constants::L_MS | constants::LM_S) => 1,
489 (Short, _) => 2,
490 }
491 } else {
492 let s_offset = match lms {
493 constants::LMS => 0,
494 constants::L_MS | constants::LM_S => 1,
495 _ => 2,
496 };
497 let q = self.header & constants::Q_BIT;
498 if q == 0 {
499 let chunk_in_low_bits = match (length, variant) {
501 (Long, Variant0) => self.header >> 3,
502 (Medium, Variant0) => self.header >> 6,
503 (Short, Variant0) => self.header >> 9,
504 (Long, Variant1) => self.header >> 12,
505 (Medium, Variant1) => self.header >> 15,
506 (Short, Variant1) => self.header >> 18,
507 (_, Standard) => {
508 debug_assert!(false, "unreachable");
509 return PatternBorrowed::DEFAULT;
510 }
511 };
512 let chunk = chunk_in_low_bits & constants::CHUNK_MASK;
513 if chunk == 0 {
514 return self.get(length, Standard);
516 }
517 chunk - 1
518 } else {
519 let additional_offset = match (length, variant) {
521 (Long, Variant0) => 1,
522 (Medium, Variant0) => 2,
523 (Short, Variant0) => 3,
524 (Long, Variant1) => 4,
525 (Medium, Variant1) => 5,
526 (Short, Variant1) => 6,
527 (_, Standard) => {
528 debug_assert!(false, "unreachable");
529 return PatternBorrowed::DEFAULT;
530 }
531 };
532 s_offset + additional_offset
533 }
534 };
535 let Some(plural_elements) = self.elements.get(pattern_index as usize) else {
536 debug_assert!(false, "unreachable");
537 return PatternBorrowed::DEFAULT;
538 };
539 let (metadata, items) = plural_elements.get_default();
540 PatternBorrowed {
541 metadata: PatternMetadata::from_u8(metadata.get()),
542 items,
543 }
544 }
545
546 fn get_as_plural_elements(
547 &self,
548 length: Length,
549 variant: PackedSkeletonVariant,
550 ) -> PluralElements<Pattern> {
551 PluralElements::new(self.get(length, variant).as_pattern())
552 }
553
554 pub fn to_builder(&self) -> PackedPatternsBuilder {
556 use Length::*;
557 use PackedSkeletonVariant::*;
558 let mut builder = PackedPatternsBuilder {
559 standard: LengthPluralElements {
560 long: self.get_as_plural_elements(Long, Standard),
561 medium: self.get_as_plural_elements(Medium, Standard),
562 short: self.get_as_plural_elements(Short, Standard),
563 },
564 variant0: Some(LengthPluralElements {
565 long: self.get_as_plural_elements(Long, Variant0),
566 medium: self.get_as_plural_elements(Medium, Variant0),
567 short: self.get_as_plural_elements(Short, Variant0),
568 }),
569 variant1: Some(LengthPluralElements {
570 long: self.get_as_plural_elements(Long, Variant1),
571 medium: self.get_as_plural_elements(Medium, Variant1),
572 short: self.get_as_plural_elements(Short, Variant1),
573 }),
574 };
575 builder.simplify();
576 builder
577 }
578}
579
580#[cfg(feature = "serde")]
581mod _serde {
582 use super::*;
583 use crate::provider::pattern::reference;
584 use zerovec::VarZeroSlice;
585
586 #[cfg_attr(feature = "serde", derive(serde::Deserialize))]
587 #[cfg_attr(feature = "datagen", derive(serde::Serialize))]
588 struct PackedPatternsMachine<'data> {
589 pub header: u32,
590 #[serde(borrow)]
591 pub elements: &'data VarZeroSlice<PluralElementsPackedULE<ZeroSlice<PatternItem>>>,
592 }
593
594 #[cfg_attr(feature = "serde", derive(serde::Deserialize))]
595 #[cfg_attr(feature = "datagen", derive(serde::Serialize))]
596 #[derive(Default)]
597 struct PackedPatternsHuman {
598 #[cfg_attr(
599 feature = "serde",
600 serde(default, skip_serializing_if = "core::ops::Not::not")
601 )]
602 pub(super) has_explicit_medium: bool,
603 #[cfg_attr(
604 feature = "serde",
605 serde(default, skip_serializing_if = "core::ops::Not::not")
606 )]
607 pub(super) has_explicit_short: bool,
608 #[cfg_attr(
609 feature = "serde",
610 serde(default, skip_serializing_if = "core::ops::Not::not")
611 )]
612 pub(super) has_one_pattern_per_variant: bool,
613 #[cfg_attr(
614 feature = "serde",
615 serde(default, skip_serializing_if = "Option::is_none")
616 )]
617 pub(super) variant_pattern_indices: Option<[u32; 6]>,
618 pub(super) elements: Vec<reference::Pattern>,
619 }
620
621 impl<'de, 'data> serde::Deserialize<'de> for PackedPatterns<'data>
622 where
623 'de: 'data,
624 {
625 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
626 where
627 D: serde::Deserializer<'de>,
628 {
629 use serde::de::Error as _;
630 if deserializer.is_human_readable() {
631 let human = <PackedPatternsHuman>::deserialize(deserializer)?;
632 let variant_indices = match (
633 human.has_one_pattern_per_variant,
634 human.variant_pattern_indices,
635 ) {
636 (true, None) => VariantIndices::OnePatternPerVariant,
637 (false, Some(chunks)) => VariantIndices::IndicesPerVariant(
638 VariantPatternIndex::try_from_chunks_u32(chunks).ok_or_else(|| {
639 D::Error::custom("variant pattern index out of range")
640 })?,
641 ),
642 _ => {
643 return Err(D::Error::custom(
644 "must have either one pattern per variant or indices",
645 ))
646 }
647 };
648 let elements = human
649 .elements
650 .iter()
651 .map(|pattern| PluralElements::new(pattern.to_runtime_pattern()))
652 .collect();
653 let unpacked = UnpackedPatterns {
654 has_explicit_medium: human.has_explicit_medium,
655 has_explicit_short: human.has_explicit_short,
656 variant_indices,
657 elements,
658 };
659 Ok(unpacked.build())
660 } else {
661 let machine = <PackedPatternsMachine>::deserialize(deserializer)?;
662 Ok(Self {
663 header: machine.header,
664 elements: machine.elements.as_varzerovec(),
665 })
666 }
667 }
668 }
669
670 #[cfg(feature = "datagen")]
671 impl serde::Serialize for PackedPatterns<'_> {
672 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
673 where
674 S: serde::Serializer,
675 {
676 use serde::ser::Error as _;
677 if serializer.is_human_readable() {
678 let unpacked = UnpackedPatterns::from_packed(self);
679 let mut human = PackedPatternsHuman {
680 has_explicit_medium: unpacked.has_explicit_medium,
681 has_explicit_short: unpacked.has_explicit_short,
682 ..Default::default()
683 };
684 match unpacked.variant_indices {
685 VariantIndices::OnePatternPerVariant => {
686 human.has_one_pattern_per_variant = true;
687 }
688 VariantIndices::IndicesPerVariant(chunks) => {
689 let chunks = VariantPatternIndex::to_chunks_u32(chunks);
690 human.variant_pattern_indices = Some(chunks);
691 }
692 }
693 human.elements = Vec::with_capacity(unpacked.elements.len());
694 for pattern_elements in unpacked.elements.into_iter() {
695 let pattern = pattern_elements
696 .try_into_other()
697 .ok_or_else(|| S::Error::custom("cannot yet serialize plural patterns"))?;
698 human.elements.push(reference::Pattern::from(&pattern));
699 }
700 human.serialize(serializer)
701 } else {
702 let machine = PackedPatternsMachine {
703 header: self.header,
704 elements: &self.elements,
705 };
706 machine.serialize(serializer)
707 }
708 }
709 }
710}
711
712#[cfg(test)]
713mod tests {
714 use super::*;
715 use crate::provider::pattern::reference;
716
717 const PATTERN_STRS: &[&str] = &[
718 "M/d/y",
719 "HH:mm",
720 "MMM d y G",
721 "E",
722 "E MMM d",
723 "dd.MM.yy",
724 "h a",
725 "hh:mm:ss B",
726 "y MMMM",
727 ];
728
729 fn get_patterns() -> Vec<Pattern<'static>> {
730 PATTERN_STRS
731 .iter()
732 .map(|s| {
733 s.parse::<reference::Pattern>()
734 .unwrap()
735 .to_runtime_pattern()
736 })
737 .collect::<Vec<_>>()
738 }
739
740 #[test]
741 fn test_basic() {
742 let patterns = get_patterns();
743 let mut it = patterns.iter().cloned();
744 let lms0 = LengthPluralElements {
745 long: PluralElements::new(it.next().unwrap()),
746 medium: PluralElements::new(it.next().unwrap()),
747 short: PluralElements::new(it.next().unwrap()),
748 };
749 let lms1 = LengthPluralElements {
750 long: PluralElements::new(it.next().unwrap()),
751 medium: PluralElements::new(it.next().unwrap()),
752 short: PluralElements::new(it.next().unwrap()),
753 };
754 let lms2 = LengthPluralElements {
755 long: PluralElements::new(it.next().unwrap()),
756 medium: PluralElements::new(it.next().unwrap()),
757 short: PluralElements::new(it.next().unwrap()),
758 };
759 let lms0a = LengthPluralElements {
760 long: PluralElements::new(patterns[0].clone()),
761 medium: PluralElements::new(patterns[0].clone()),
762 short: PluralElements::new(patterns[1].clone()),
763 };
764 let lms1a = LengthPluralElements {
765 long: PluralElements::new(patterns[3].clone()),
766 medium: PluralElements::new(patterns[4].clone()),
767 short: PluralElements::new(patterns[4].clone()),
768 };
769
770 {
771 let builder = PackedPatternsBuilder {
773 standard: lms0.clone(),
774 variant0: Some(lms1.clone()),
775 variant1: Some(lms2.clone()),
776 };
777 let packed = builder.clone().build();
778 assert_eq!(packed.header, 7);
779 assert_eq!(packed.elements.len(), 9);
780 for (pattern_elements, expected) in packed.elements.iter().zip(patterns.iter()) {
781 assert_eq!(pattern_elements.get_default().1, &expected.items);
782 }
783 let recovered_builder = packed.to_builder();
784 assert_eq!(builder, recovered_builder);
785 }
786 {
787 let builder = PackedPatternsBuilder {
789 standard: lms0.clone(),
790 variant0: Some(lms0.clone()),
791 variant1: Some(lms2.clone()),
792 };
793 let packed = builder.clone().build();
794 assert_eq!(packed.header, 0x1AC003);
795 assert_eq!(packed.elements.len(), 6);
796 let recovered_builder = packed.to_builder();
797 assert_ne!(builder, recovered_builder);
798 let mut builder = builder;
799 builder.simplify();
800 assert_eq!(builder, recovered_builder);
801 }
802 {
803 let builder = PackedPatternsBuilder {
805 standard: lms0.clone(),
806 variant0: None,
807 variant1: None,
808 };
809 let packed = builder.clone().build();
810 assert_eq!(packed.header, 3);
811 assert_eq!(packed.elements.len(), 3);
812 let recovered_builder = packed.to_builder();
813 assert_eq!(builder, recovered_builder);
814 }
815 {
816 let builder = PackedPatternsBuilder {
818 standard: lms0a.clone(),
819 variant0: Some(lms0.clone()),
820 variant1: Some(lms1.clone()),
821 };
822 let packed = builder.clone().build();
823 assert_eq!(packed.header, 0x1AC682);
824 assert_eq!(packed.elements.len(), 6);
825 let recovered_builder = packed.to_builder();
826 assert_eq!(builder, recovered_builder);
827 }
828 {
829 let builder = PackedPatternsBuilder {
831 standard: lms0a.clone(),
832 variant0: Some(lms1.clone()),
833 variant1: Some(lms2.clone()),
834 };
835 let packed = builder.clone().build();
836 assert_eq!(packed.header, 6);
837 assert_eq!(packed.elements.len(), 8);
838 let recovered_builder = packed.to_builder();
839 assert_eq!(builder, recovered_builder);
840 }
841 {
842 let builder = PackedPatternsBuilder {
844 standard: lms1a.clone(),
845 variant0: Some(lms0a.clone()),
846 variant1: Some(lms2.clone()),
847 };
848 let packed = builder.clone().build();
849 assert_eq!(packed.header, 0x1F58D9);
850 assert_eq!(packed.elements.len(), 7);
851 let recovered_builder = packed.to_builder();
852 assert_eq!(builder, recovered_builder);
853 }
854 }
855
856 #[cfg(feature = "datagen")]
857 #[test]
858 fn test_serde() {
859 let patterns = get_patterns();
860 let lms0a = LengthPluralElements {
861 long: PluralElements::new(patterns[0].clone()),
862 medium: PluralElements::new(patterns[0].clone()),
863 short: PluralElements::new(patterns[1].clone()),
864 };
865 let lms1 = LengthPluralElements {
866 long: PluralElements::new(patterns[3].clone()),
867 medium: PluralElements::new(patterns[4].clone()),
868 short: PluralElements::new(patterns[5].clone()),
869 };
870
871 let builder = PackedPatternsBuilder {
872 standard: lms0a,
873 variant0: Some(lms1),
874 variant1: None,
875 };
876 let packed = builder.clone().build();
877
878 let bincode_bytes = bincode::serialize(&packed).unwrap();
879 assert_eq!(
880 bincode_bytes.as_slice(),
881 &[
882 26, 11, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 5, 0, 16, 0, 26, 0, 30, 0, 46, 0, 0, 128,
883 32, 1, 0, 0, 47, 128, 64, 1, 0, 0, 47, 128, 16, 1, 2, 128, 114, 2, 0, 0, 58, 128,
884 128, 2, 0, 128, 80, 1, 0, 128, 80, 1, 0, 0, 32, 128, 32, 3, 0, 0, 32, 128, 64, 1,
885 0, 128, 64, 2, 0, 0, 46, 128, 32, 2, 0, 0, 46, 128, 16, 2
886 ][..]
887 );
888 let bincode_recovered = bincode::deserialize::<PackedPatterns>(&bincode_bytes).unwrap();
889 assert_eq!(builder, bincode_recovered.to_builder());
890
891 let json_str = serde_json::to_string(&packed).unwrap();
892 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\"]}");
893 let json_recovered = serde_json::from_str::<PackedPatterns>(&json_str).unwrap();
894 assert_eq!(builder, json_recovered.to_builder());
895 }
896}