1use core::num::NonZero;
2
3use crate::{Internal, Packed, Schema};
4
5#[non_exhaustive]
9#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
10pub struct Shape {
11 pub max_length: usize,
17
18 pub max_depth: usize,
23
24 pub count: NonZero<usize>,
26
27 pub max_bits: u32,
29}
30
31macro_rules! assign_max {
33 ($a:expr, $b:expr) => {{
34 let b = $b;
35 if $a < b {
36 $a = b;
37 }
38 }};
39}
40
41impl Shape {
42 pub const fn max_length(&self, separator: &str) -> usize {
47 self.max_length + self.max_depth * separator.len()
48 }
49
50 pub const fn new(schema: &Schema) -> Self {
52 let mut m = Self {
53 max_depth: 0,
54 max_length: 0,
55 count: NonZero::<usize>::MIN,
56 max_bits: 0,
57 };
58 if let Some(internal) = schema.internal.as_ref() {
59 match internal {
60 Internal::Named(nameds) => {
61 let bits = Packed::bits_for(nameds.len() - 1);
62 let mut index = 0;
63 let mut count = 0;
64 while index < nameds.len() {
65 let named = &nameds[index];
66 let child = Self::new(named.schema);
67 assign_max!(m.max_depth, 1 + child.max_depth);
68 assign_max!(m.max_length, named.name.len() + child.max_length);
69 assign_max!(m.max_bits, bits + child.max_bits);
70 count += child.count.get();
71 index += 1;
72 }
73 m.count = NonZero::new(count).unwrap();
74 }
75 Internal::Numbered(numbereds) => {
76 let bits = Packed::bits_for(numbereds.len() - 1);
77 let mut index = 0;
78 let mut count = 0;
79 while index < numbereds.len() {
80 let numbered = &numbereds[index];
81 let len = 1 + match index.checked_ilog10() {
82 None => 0,
83 Some(len) => len as usize,
84 };
85 let child = Self::new(numbered.schema);
86 assign_max!(m.max_depth, 1 + child.max_depth);
87 assign_max!(m.max_length, len + child.max_length);
88 assign_max!(m.max_bits, bits + child.max_bits);
89 count += child.count.get();
90 index += 1;
91 }
92 m.count = NonZero::new(count).unwrap();
93 }
94 Internal::Homogeneous(homogeneous) => {
95 m = Self::new(homogeneous.schema);
96 m.max_depth += 1;
97 m.max_length += 1 + homogeneous.len.ilog10() as usize;
98 m.max_bits += Packed::bits_for(homogeneous.len.get() - 1);
99 m.count = m.count.checked_mul(homogeneous.len).unwrap();
100 }
101 }
102 }
103 m
104 }
105}