parquet_variant/builder/
metadata.rs1use std::collections::HashMap;
19
20use arrow_schema::ArrowError;
21use indexmap::IndexSet;
22
23use crate::{VariantMetadata, int_size};
24
25fn write_offset(buf: &mut Vec<u8>, value: usize, nbytes: u8) {
27 let bytes = value.to_le_bytes();
28 buf.extend_from_slice(&bytes[..nbytes as usize]);
29}
30
31pub trait MetadataBuilder: std::fmt::Debug {
37 fn try_upsert_field_name(&mut self, field_name: &str) -> Result<u32, ArrowError>;
41
42 fn field_name(&self, field_id: usize) -> &str;
45
46 fn num_field_names(&self) -> usize;
50
51 fn truncate_field_names(&mut self, new_size: usize);
53
54 fn finish(&mut self) -> usize;
56}
57
58impl MetadataBuilder for WritableMetadataBuilder {
59 fn try_upsert_field_name(&mut self, field_name: &str) -> Result<u32, ArrowError> {
60 Ok(self.upsert_field_name(field_name))
61 }
62 fn field_name(&self, field_id: usize) -> &str {
63 self.field_name(field_id)
64 }
65 fn num_field_names(&self) -> usize {
66 self.num_field_names()
67 }
68 fn truncate_field_names(&mut self, new_size: usize) {
69 self.field_names.truncate(new_size)
70 }
71 fn finish(&mut self) -> usize {
72 self.finish()
73 }
74}
75
76#[derive(Debug)]
85pub struct ReadOnlyMetadataBuilder<'m> {
86 metadata: &'m VariantMetadata<'m>,
87 known_field_names: HashMap<&'m str, u32>,
92}
93
94impl<'m> ReadOnlyMetadataBuilder<'m> {
95 pub fn new(metadata: &'m VariantMetadata<'m>) -> Self {
97 Self {
98 metadata,
99 known_field_names: HashMap::new(),
100 }
101 }
102}
103
104impl MetadataBuilder for ReadOnlyMetadataBuilder<'_> {
105 fn try_upsert_field_name(&mut self, field_name: &str) -> Result<u32, ArrowError> {
106 if let Some(field_id) = self.metadata.borrowed_field_id(field_name) {
114 return Ok(field_id);
115 }
116
117 if let Some(field_id) = self.known_field_names.get(field_name) {
118 return Ok(*field_id);
119 }
120
121 let Some((field_id, field_name)) = self.metadata.get_entry(field_name) else {
122 return Err(ArrowError::InvalidArgumentError(format!(
123 "Field name '{field_name}' not found in metadata dictionary"
124 )));
125 };
126
127 self.known_field_names.insert(field_name, field_id);
128 Ok(field_id)
129 }
130 fn field_name(&self, field_id: usize) -> &str {
131 &self.metadata[field_id]
132 }
133 fn num_field_names(&self) -> usize {
134 self.metadata.len()
135 }
136 fn truncate_field_names(&mut self, new_size: usize) {
137 debug_assert_eq!(self.metadata.len(), new_size);
138 }
139 fn finish(&mut self) -> usize {
140 self.metadata.bytes.len()
141 }
142}
143
144#[derive(Default, Debug)]
153pub struct WritableMetadataBuilder {
154 pub(crate) field_names: IndexSet<String>,
155
156 pub(crate) is_sorted: bool,
157
158 metadata_buffer: Vec<u8>,
160}
161
162impl WritableMetadataBuilder {
163 pub fn upsert_field_name(&mut self, field_name: &str) -> u32 {
165 let (id, new_entry) = self.field_names.insert_full(field_name.to_string());
166
167 if new_entry {
168 let n = self.num_field_names();
169
170 self.is_sorted =
175 n == 1 || self.is_sorted && (self.field_names[n - 2] < self.field_names[n - 1]);
176 }
177
178 id as u32
179 }
180
181 pub fn offset(&self) -> usize {
183 self.metadata_buffer.len()
184 }
185
186 fn num_field_names(&self) -> usize {
193 let n = self.field_names.len();
194 assert!(u32::try_from(n).is_ok());
195
196 n
197 }
198
199 fn field_name(&self, i: usize) -> &str {
200 &self.field_names[i]
201 }
202
203 fn metadata_size(&self) -> usize {
204 self.field_names.iter().map(|k| k.len()).sum()
205 }
206
207 pub fn finish(&mut self) -> usize {
211 let nkeys = self.num_field_names();
212
213 let total_dict_size = self.metadata_size();
215
216 let metadata_buffer = &mut self.metadata_buffer;
217 let is_sorted = std::mem::take(&mut self.is_sorted);
218 let field_names = std::mem::take(&mut self.field_names);
219
220 let max_offset = std::cmp::max(total_dict_size, nkeys);
222 let offset_size = int_size(max_offset) as u8;
223
224 let offset_start = 1 + offset_size as usize;
225 let string_start = offset_start + (nkeys + 1) * offset_size as usize;
226 let metadata_size = string_start + total_dict_size;
227
228 metadata_buffer.reserve(metadata_size);
229
230 metadata_buffer.push(0x01 | ((is_sorted as u8) << 4) | ((offset_size - 1) << 6));
232
233 write_offset(metadata_buffer, nkeys, offset_size);
235
236 let mut cur_offset = 0;
238 for key in &field_names {
239 write_offset(metadata_buffer, cur_offset, offset_size);
240 cur_offset += key.len();
241 }
242 write_offset(metadata_buffer, cur_offset, offset_size);
244
245 for key in field_names {
247 metadata_buffer.extend_from_slice(key.as_bytes());
248 }
249
250 metadata_buffer.len()
251 }
252
253 pub fn into_inner(self) -> Vec<u8> {
255 self.metadata_buffer
256 }
257}
258
259impl<S: AsRef<str>> FromIterator<S> for WritableMetadataBuilder {
260 fn from_iter<T: IntoIterator<Item = S>>(iter: T) -> Self {
261 let mut this = Self::default();
262 this.extend(iter);
263
264 this
265 }
266}
267
268impl<S: AsRef<str>> Extend<S> for WritableMetadataBuilder {
269 fn extend<T: IntoIterator<Item = S>>(&mut self, iter: T) {
270 let iter = iter.into_iter();
271 let (min, _) = iter.size_hint();
272
273 self.field_names.reserve(min);
274
275 for field_name in iter {
276 self.upsert_field_name(field_name.as_ref());
277 }
278 }
279}
280
281#[cfg(test)]
282mod test {
283 use crate::{
284 ParentState, ValueBuilder, VariantMetadata,
285 builder::{
286 metadata::{ReadOnlyMetadataBuilder, WritableMetadataBuilder},
287 object::ObjectBuilder,
288 },
289 };
290
291 #[test]
292 fn test_metadata_builder_from_iter() {
293 let metadata = WritableMetadataBuilder::from_iter(vec!["apple", "banana", "cherry"]);
294 assert_eq!(metadata.num_field_names(), 3);
295 assert_eq!(metadata.field_name(0), "apple");
296 assert_eq!(metadata.field_name(1), "banana");
297 assert_eq!(metadata.field_name(2), "cherry");
298 assert!(metadata.is_sorted);
299
300 let metadata = WritableMetadataBuilder::from_iter(["zebra", "apple", "banana"]);
301 assert_eq!(metadata.num_field_names(), 3);
302 assert_eq!(metadata.field_name(0), "zebra");
303 assert_eq!(metadata.field_name(1), "apple");
304 assert_eq!(metadata.field_name(2), "banana");
305 assert!(!metadata.is_sorted);
306
307 let metadata = WritableMetadataBuilder::from_iter(Vec::<&str>::new());
308 assert_eq!(metadata.num_field_names(), 0);
309 assert!(!metadata.is_sorted);
310 }
311
312 #[test]
313 fn test_metadata_builder_extend() {
314 let mut metadata = WritableMetadataBuilder::default();
315 assert_eq!(metadata.num_field_names(), 0);
316 assert!(!metadata.is_sorted);
317
318 metadata.extend(["apple", "cherry"]);
319 assert_eq!(metadata.num_field_names(), 2);
320 assert_eq!(metadata.field_name(0), "apple");
321 assert_eq!(metadata.field_name(1), "cherry");
322 assert!(metadata.is_sorted);
323
324 metadata.extend(vec!["dinosaur", "monkey"]);
326 assert_eq!(metadata.num_field_names(), 4);
327 assert_eq!(metadata.field_name(2), "dinosaur");
328 assert_eq!(metadata.field_name(3), "monkey");
329 assert!(metadata.is_sorted);
330
331 let initial_count = metadata.num_field_names();
333 metadata.extend(["apple", "monkey"]);
334 assert_eq!(metadata.num_field_names(), initial_count); }
336
337 #[test]
338 fn test_metadata_builder_extend_sort_order() {
339 let mut metadata = WritableMetadataBuilder::default();
340
341 metadata.extend(["middle"]);
342 assert!(metadata.is_sorted);
343
344 metadata.extend(["zebra"]);
345 assert!(metadata.is_sorted);
346
347 metadata.extend(["apple"]);
349 assert!(!metadata.is_sorted);
350 }
351
352 #[test]
353 fn test_metadata_builder_from_iter_with_string_types() {
354 let metadata = WritableMetadataBuilder::from_iter(["a", "b", "c"]);
356 assert_eq!(metadata.num_field_names(), 3);
357
358 let metadata = WritableMetadataBuilder::from_iter(vec![
360 "a".to_string(),
361 "b".to_string(),
362 "c".to_string(),
363 ]);
364 assert_eq!(metadata.num_field_names(), 3);
365
366 let field_names: Vec<Box<str>> = vec!["a".into(), "b".into(), "c".into()];
368 let metadata = WritableMetadataBuilder::from_iter(field_names);
369 assert_eq!(metadata.num_field_names(), 3);
370 }
371
372 #[test]
373 fn test_read_only_metadata_builder_fails_on_unknown_field() {
374 let mut default_builder = WritableMetadataBuilder::default();
376 default_builder.upsert_field_name("known_field");
377 default_builder.finish();
378 let metadata_bytes = default_builder.into_inner();
379
380 let metadata = VariantMetadata::try_new(&metadata_bytes).unwrap();
382 let mut metadata_builder = ReadOnlyMetadataBuilder::new(&metadata);
383 let mut value_builder = ValueBuilder::new();
384
385 {
386 let state = ParentState::variant(&mut value_builder, &mut metadata_builder);
387 let mut obj = ObjectBuilder::new(state, false);
388
389 obj.insert("known_field", "value");
391
392 let result = obj.try_insert("unknown_field", "value");
394 assert!(result.is_err());
395 assert!(
396 result
397 .unwrap_err()
398 .to_string()
399 .contains("Field name 'unknown_field' not found")
400 );
401 }
402 }
403}