vortex_array/stats/
flatbuffers.rs1use flatbuffers::FlatBufferBuilder;
5use flatbuffers::WIPOffset;
6use vortex_dtype::DType;
7use vortex_dtype::Nullability;
8use vortex_dtype::PType;
9use vortex_error::VortexResult;
10use vortex_error::vortex_bail;
11use vortex_flatbuffers::WriteFlatBuffer;
12use vortex_flatbuffers::array as fba;
13
14use crate::expr::stats::Precision;
15use crate::expr::stats::Stat;
16use crate::scalar::ScalarValue;
17use crate::stats::StatsSet;
18use crate::stats::StatsSetRef;
19
20impl WriteFlatBuffer for StatsSetRef<'_> {
21 type Target<'t> = fba::ArrayStats<'t>;
22
23 fn write_flatbuffer<'fb>(
25 &self,
26 fbb: &mut FlatBufferBuilder<'fb>,
27 ) -> VortexResult<WIPOffset<Self::Target<'fb>>> {
28 self.with_typed_stats_set(|stats_set| stats_set.values.write_flatbuffer(fbb))
29 }
30}
31
32impl WriteFlatBuffer for StatsSet {
33 type Target<'t> = fba::ArrayStats<'t>;
34
35 fn write_flatbuffer<'fb>(
37 &self,
38 fbb: &mut FlatBufferBuilder<'fb>,
39 ) -> VortexResult<WIPOffset<Self::Target<'fb>>> {
40 let (min_precision, min) = self
41 .get(Stat::Min)
42 .map(|min| {
43 (
44 if min.is_exact() {
45 fba::Precision::Exact
46 } else {
47 fba::Precision::Inexact
48 },
49 Some(
50 fbb.create_vector(&ScalarValue::to_proto_bytes::<Vec<u8>>(Some(
51 &min.into_inner(),
52 ))),
53 ),
54 )
55 })
56 .unwrap_or_else(|| (fba::Precision::Inexact, None));
57
58 let (max_precision, max) = self
59 .get(Stat::Max)
60 .map(|max| {
61 (
62 if max.is_exact() {
63 fba::Precision::Exact
64 } else {
65 fba::Precision::Inexact
66 },
67 Some(
68 fbb.create_vector(&ScalarValue::to_proto_bytes::<Vec<u8>>(Some(
69 &max.into_inner(),
70 ))),
71 ),
72 )
73 })
74 .unwrap_or_else(|| (fba::Precision::Inexact, None));
75
76 let sum = self
77 .get(Stat::Sum)
78 .and_then(Precision::as_exact)
79 .map(|sum| fbb.create_vector(&ScalarValue::to_proto_bytes::<Vec<u8>>(Some(&sum))));
80
81 let stat_args = &fba::ArrayStatsArgs {
82 min,
83 min_precision,
84 max,
85 max_precision,
86 sum,
87 is_sorted: self
88 .get_as::<bool>(Stat::IsSorted, &DType::Bool(Nullability::NonNullable))
89 .and_then(Precision::as_exact),
90 is_strict_sorted: self
91 .get_as::<bool>(Stat::IsStrictSorted, &DType::Bool(Nullability::NonNullable))
92 .and_then(Precision::as_exact),
93 is_constant: self
94 .get_as::<bool>(Stat::IsConstant, &DType::Bool(Nullability::NonNullable))
95 .and_then(Precision::as_exact),
96 null_count: self
97 .get_as::<u64>(Stat::NullCount, &PType::U64.into())
98 .and_then(Precision::as_exact),
99 uncompressed_size_in_bytes: self
100 .get_as::<u64>(Stat::UncompressedSizeInBytes, &PType::U64.into())
101 .and_then(Precision::as_exact),
102 nan_count: self
103 .get_as::<u64>(Stat::NaNCount, &PType::U64.into())
104 .and_then(Precision::as_exact),
105 };
106
107 Ok(fba::ArrayStats::create(fbb, stat_args))
108 }
109}
110
111impl StatsSet {
112 pub fn from_flatbuffer<'a>(
114 fb: &fba::ArrayStats<'a>,
115 array_dtype: &DType,
116 ) -> VortexResult<Self> {
117 let mut stats_set = StatsSet::default();
118
119 for stat in Stat::all() {
120 let stat_dtype = stat.dtype(array_dtype);
121
122 match stat {
123 Stat::IsConstant => {
124 if let Some(is_constant) = fb.is_constant() {
125 stats_set.set(Stat::IsConstant, Precision::Exact(is_constant.into()));
126 }
127 }
128 Stat::IsSorted => {
129 if let Some(is_sorted) = fb.is_sorted() {
130 stats_set.set(Stat::IsSorted, Precision::Exact(is_sorted.into()));
131 }
132 }
133 Stat::IsStrictSorted => {
134 if let Some(is_strict_sorted) = fb.is_strict_sorted() {
135 stats_set.set(
136 Stat::IsStrictSorted,
137 Precision::Exact(is_strict_sorted.into()),
138 );
139 }
140 }
141 Stat::Max => {
142 if let Some(max) = fb.max()
143 && let Some(stat_dtype) = stat_dtype
144 {
145 let value = ScalarValue::from_proto_bytes(max.bytes(), &stat_dtype)?;
146 let Some(value) = value else {
147 continue;
148 };
149
150 stats_set.set(
151 Stat::Max,
152 match fb.max_precision() {
153 fba::Precision::Exact => Precision::Exact(value),
154 fba::Precision::Inexact => Precision::Inexact(value),
155 other => vortex_bail!("Corrupted max_precision field: {other:?}"),
156 },
157 );
158 }
159 }
160 Stat::Min => {
161 if let Some(min) = fb.min()
162 && let Some(stat_dtype) = stat_dtype
163 {
164 let value = ScalarValue::from_proto_bytes(min.bytes(), &stat_dtype)?;
165 let Some(value) = value else {
166 continue;
167 };
168
169 stats_set.set(
170 Stat::Min,
171 match fb.min_precision() {
172 fba::Precision::Exact => Precision::Exact(value),
173 fba::Precision::Inexact => Precision::Inexact(value),
174 other => vortex_bail!("Corrupted min_precision field: {other:?}"),
175 },
176 );
177 }
178 }
179 Stat::NullCount => {
180 if let Some(null_count) = fb.null_count() {
181 stats_set.set(Stat::NullCount, Precision::Exact(null_count.into()));
182 }
183 }
184 Stat::UncompressedSizeInBytes => {
185 if let Some(uncompressed_size_in_bytes) = fb.uncompressed_size_in_bytes() {
186 stats_set.set(
187 Stat::UncompressedSizeInBytes,
188 Precision::Exact(uncompressed_size_in_bytes.into()),
189 );
190 }
191 }
192 Stat::Sum => {
193 if let Some(sum) = fb.sum()
194 && let Some(stat_dtype) = stat_dtype
195 {
196 let value = ScalarValue::from_proto_bytes(sum.bytes(), &stat_dtype)?;
197 let Some(value) = value else {
198 continue;
199 };
200
201 stats_set.set(Stat::Sum, Precision::Exact(value));
202 }
203 }
204 Stat::NaNCount => {
205 if let Some(nan_count) = fb.nan_count() {
206 stats_set.set(
207 Stat::NaNCount,
208 Precision::Exact(ScalarValue::from(nan_count)),
209 );
210 }
211 }
212 }
213 }
214
215 Ok(stats_set)
216 }
217}