Skip to main content

ptars_core/
arrow_to_proto.rs

1use arrow::array::ArrayData;
2use arrow_array::builder::BinaryBuilder;
3use arrow_array::types::{
4    Date32Type, DurationMicrosecondType, DurationMillisecondType, DurationNanosecondType,
5    DurationSecondType, Float32Type, Float64Type, Int32Type, Int64Type, Time32MillisecondType,
6    Time32SecondType, Time64MicrosecondType, Time64NanosecondType, TimestampMicrosecondType,
7    TimestampMillisecondType, TimestampNanosecondType, TimestampSecondType, UInt32Type, UInt64Type,
8};
9use arrow_array::{
10    Array, ArrowPrimitiveType, BinaryArray, BooleanArray, LargeBinaryArray, LargeListArray,
11    LargeStringArray, ListArray, MapArray, PrimitiveArray, RecordBatch, StringArray, StructArray,
12};
13use arrow_schema::{DataType, TimeUnit};
14use chrono::{Datelike, NaiveDate};
15use prost::encoding::{encode_key, encode_varint, WireType};
16
17use prost_reflect::{EnumDescriptor, FieldDescriptor, Kind, MessageDescriptor};
18
19/// Look up enum number by name, returning 0 (proto3 default) for unknown names.
20fn enum_number_from_name(name: &str, enum_descriptor: &EnumDescriptor) -> i32 {
21    enum_descriptor
22        .get_value_by_name(name)
23        .map(|v| v.number())
24        .unwrap_or(0)
25}
26
27// Days from CE epoch to Unix epoch (1970-01-01)
28const CE_OFFSET: i32 = 719163;
29
30// ---------------------------------------------------------------------------
31// Helper column refs (abstract over Regular / Large array variants)
32// ---------------------------------------------------------------------------
33
34enum StringColumnRef<'a> {
35    Regular(&'a StringArray),
36    Large(&'a LargeStringArray),
37}
38
39impl StringColumnRef<'_> {
40    fn is_null(&self, idx: usize) -> bool {
41        match self {
42            Self::Regular(a) => a.is_null(idx),
43            Self::Large(a) => a.is_null(idx),
44        }
45    }
46    fn value(&self, idx: usize) -> &str {
47        match self {
48            Self::Regular(a) => a.value(idx),
49            Self::Large(a) => a.value(idx),
50        }
51    }
52}
53
54enum BinaryColumnRef<'a> {
55    Regular(&'a BinaryArray),
56    Large(&'a LargeBinaryArray),
57}
58
59impl BinaryColumnRef<'_> {
60    fn is_null(&self, idx: usize) -> bool {
61        match self {
62            Self::Regular(a) => a.is_null(idx),
63            Self::Large(a) => a.is_null(idx),
64        }
65    }
66    fn value(&self, idx: usize) -> &[u8] {
67        match self {
68            Self::Regular(a) => a.value(idx),
69            Self::Large(a) => a.value(idx),
70        }
71    }
72}
73
74/// Abstracts over ListArray / LargeListArray.
75#[derive(Clone, Copy)]
76enum GenericListArray<'a> {
77    Regular(&'a ListArray),
78    Large(&'a LargeListArray),
79}
80
81impl<'a> GenericListArray<'a> {
82    fn from_array(array: &'a dyn Array) -> Option<Self> {
83        array
84            .as_any()
85            .downcast_ref::<ListArray>()
86            .map(GenericListArray::Regular)
87            .or_else(|| {
88                array
89                    .as_any()
90                    .downcast_ref::<LargeListArray>()
91                    .map(GenericListArray::Large)
92            })
93    }
94    fn is_null(&self, i: usize) -> bool {
95        match self {
96            Self::Regular(a) => a.is_null(i),
97            Self::Large(a) => a.is_null(i),
98        }
99    }
100    fn value_offsets(&self, i: usize) -> (usize, usize) {
101        match self {
102            Self::Regular(a) => {
103                let o = a.value_offsets();
104                (o[i] as usize, o[i + 1] as usize)
105            }
106            Self::Large(a) => {
107                let o = a.value_offsets();
108                (o[i] as usize, o[i + 1] as usize)
109            }
110        }
111    }
112}
113
114// ---------------------------------------------------------------------------
115// Time conversion helpers (mirroring arrow_to_proto.rs logic)
116// ---------------------------------------------------------------------------
117
118fn time_unit_to_seconds_and_nanos(value: i64, unit: TimeUnit) -> (i64, i32) {
119    match unit {
120        TimeUnit::Second => (value, 0),
121        TimeUnit::Millisecond => {
122            let mut seconds = value / 1_000;
123            let mut nanos = ((value % 1_000) * 1_000_000) as i32;
124            if nanos < 0 {
125                seconds -= 1;
126                nanos += 1_000_000_000;
127            }
128            (seconds, nanos)
129        }
130        TimeUnit::Microsecond => {
131            let mut seconds = value / 1_000_000;
132            let mut nanos = ((value % 1_000_000) * 1_000) as i32;
133            if nanos < 0 {
134                seconds -= 1;
135                nanos += 1_000_000_000;
136            }
137            (seconds, nanos)
138        }
139        TimeUnit::Nanosecond => {
140            let mut seconds = value / 1_000_000_000;
141            let mut nanos = (value % 1_000_000_000) as i32;
142            if nanos < 0 {
143                seconds -= 1;
144                nanos += 1_000_000_000;
145            }
146            (seconds, nanos)
147        }
148    }
149}
150
151fn time_unit_to_duration_seconds_and_nanos(value: i64, unit: TimeUnit) -> (i64, i32) {
152    match unit {
153        TimeUnit::Second => (value, 0),
154        TimeUnit::Millisecond => {
155            let seconds = value / 1_000;
156            let nanos = ((value % 1_000) * 1_000_000) as i32;
157            (seconds, nanos)
158        }
159        TimeUnit::Microsecond => {
160            let seconds = value / 1_000_000;
161            let nanos = ((value % 1_000_000) * 1_000) as i32;
162            (seconds, nanos)
163        }
164        TimeUnit::Nanosecond => {
165            let seconds = value / 1_000_000_000;
166            let nanos = (value % 1_000_000_000) as i32;
167            (seconds, nanos)
168        }
169    }
170}
171
172fn time32_unit_to_nanos(value: i32, unit: TimeUnit) -> i64 {
173    match unit {
174        TimeUnit::Second => i64::from(value) * 1_000_000_000,
175        TimeUnit::Millisecond => i64::from(value) * 1_000_000,
176        _ => panic!("Time32 only supports Second and Millisecond units"),
177    }
178}
179
180fn time64_unit_to_nanos(value: i64, unit: TimeUnit) -> i64 {
181    match unit {
182        TimeUnit::Microsecond => value * 1_000,
183        TimeUnit::Nanosecond => value,
184        _ => panic!("Time64 only supports Microsecond and Nanosecond units"),
185    }
186}
187
188// ---------------------------------------------------------------------------
189// Direct wire-format encoding helpers for well-known types
190// ---------------------------------------------------------------------------
191
192/// Encode a Timestamp (seconds=1, nanos=2) directly into buf.
193/// Both fields use int64/int32 varint encoding. Skips default values.
194fn encode_timestamp_fields(seconds: i64, nanos: i32, buf: &mut Vec<u8>) {
195    if seconds != 0 {
196        prost::encoding::int64::encode(1, &seconds, buf);
197    }
198    if nanos != 0 {
199        prost::encoding::int32::encode(2, &nanos, buf);
200    }
201}
202
203/// Encode a Duration (seconds=1, nanos=2) directly into buf.
204fn encode_duration_fields(seconds: i64, nanos: i32, buf: &mut Vec<u8>) {
205    if seconds != 0 {
206        prost::encoding::int64::encode(1, &seconds, buf);
207    }
208    if nanos != 0 {
209        prost::encoding::int32::encode(2, &nanos, buf);
210    }
211}
212
213/// Encode a Date (year=1, month=2, day=3) directly into buf.
214fn encode_date_fields(days: i32, buf: &mut Vec<u8>) {
215    if days == 0 {
216        // Special case: year=0, month=0, day=0 — all default, empty message
217        return;
218    }
219    let date = NaiveDate::from_num_days_from_ce_opt(days + CE_OFFSET).unwrap();
220    let year = date.year();
221    let month = date.month() as i32;
222    let day = date.day() as i32;
223    if year != 0 {
224        prost::encoding::int32::encode(1, &year, buf);
225    }
226    if month != 0 {
227        prost::encoding::int32::encode(2, &month, buf);
228    }
229    if day != 0 {
230        prost::encoding::int32::encode(3, &day, buf);
231    }
232}
233
234/// Encode a TimeOfDay (hours=1, minutes=2, seconds=3, nanos=4) directly into buf.
235fn encode_time_of_day_fields(total_nanos: i64, buf: &mut Vec<u8>) {
236    let hours = (total_nanos / 3_600_000_000_000) as i32;
237    let remaining = total_nanos % 3_600_000_000_000;
238    let minutes = (remaining / 60_000_000_000) as i32;
239    let remaining = remaining % 60_000_000_000;
240    let seconds = (remaining / 1_000_000_000) as i32;
241    let nanos = (remaining % 1_000_000_000) as i32;
242
243    if hours != 0 {
244        prost::encoding::int32::encode(1, &hours, buf);
245    }
246    if minutes != 0 {
247        prost::encoding::int32::encode(2, &minutes, buf);
248    }
249    if seconds != 0 {
250        prost::encoding::int32::encode(3, &seconds, buf);
251    }
252    if nanos != 0 {
253        prost::encoding::int32::encode(4, &nanos, buf);
254    }
255}
256
257/// Write a length-delimited submessage: tag + varint(len) + bytes
258fn write_submessage(tag: u32, content: &[u8], buf: &mut Vec<u8>) {
259    encode_key(tag, WireType::LengthDelimited, buf);
260    encode_varint(content.len() as u64, buf);
261    buf.extend_from_slice(content);
262}
263
264// ---------------------------------------------------------------------------
265// FieldEncoder: one variant per proto kind
266// ---------------------------------------------------------------------------
267
268enum FieldEncoder<'a> {
269    // Scalar variants
270    Double {
271        tag: u32,
272        arr: &'a PrimitiveArray<Float64Type>,
273        has_presence: bool,
274    },
275    Float {
276        tag: u32,
277        arr: &'a PrimitiveArray<Float32Type>,
278        has_presence: bool,
279    },
280    Int32 {
281        tag: u32,
282        arr: &'a PrimitiveArray<Int32Type>,
283        has_presence: bool,
284    },
285    Int64 {
286        tag: u32,
287        arr: &'a PrimitiveArray<Int64Type>,
288        has_presence: bool,
289    },
290    UInt32 {
291        tag: u32,
292        arr: &'a PrimitiveArray<UInt32Type>,
293        has_presence: bool,
294    },
295    UInt64 {
296        tag: u32,
297        arr: &'a PrimitiveArray<UInt64Type>,
298        has_presence: bool,
299    },
300    Sint32 {
301        tag: u32,
302        arr: &'a PrimitiveArray<Int32Type>,
303        has_presence: bool,
304    },
305    Sint64 {
306        tag: u32,
307        arr: &'a PrimitiveArray<Int64Type>,
308        has_presence: bool,
309    },
310    Sfixed32 {
311        tag: u32,
312        arr: &'a PrimitiveArray<Int32Type>,
313        has_presence: bool,
314    },
315    Sfixed64 {
316        tag: u32,
317        arr: &'a PrimitiveArray<Int64Type>,
318        has_presence: bool,
319    },
320    Fixed32 {
321        tag: u32,
322        arr: &'a PrimitiveArray<UInt32Type>,
323        has_presence: bool,
324    },
325    Fixed64 {
326        tag: u32,
327        arr: &'a PrimitiveArray<UInt64Type>,
328        has_presence: bool,
329    },
330    Bool {
331        tag: u32,
332        arr: &'a BooleanArray,
333        has_presence: bool,
334    },
335    String {
336        tag: u32,
337        col: StringColumnRef<'a>,
338        has_presence: bool,
339    },
340    Bytes {
341        tag: u32,
342        col: BinaryColumnRef<'a>,
343        has_presence: bool,
344    },
345
346    // Enum variants
347    EnumInt32 {
348        tag: u32,
349        arr: &'a PrimitiveArray<Int32Type>,
350        has_presence: bool,
351    },
352    EnumString {
353        tag: u32,
354        col: StringColumnRef<'a>,
355        enum_descriptor: EnumDescriptor,
356        has_presence: bool,
357    },
358    EnumBinary {
359        tag: u32,
360        col: BinaryColumnRef<'a>,
361        enum_descriptor: EnumDescriptor,
362        has_presence: bool,
363    },
364
365    // Nested message (regular)
366    Message {
367        tag: u32,
368        struct_arr: &'a StructArray,
369        sub_encoder: MessageEncoder<'a>,
370    },
371
372    // Well-known types (singular)
373    Timestamp {
374        tag: u32,
375        unit: TimeUnit,
376        array: WellKnownPrimitiveArray<'a>,
377    },
378    Duration {
379        tag: u32,
380        unit: TimeUnit,
381        array: WellKnownPrimitiveArray<'a>,
382    },
383    Date {
384        tag: u32,
385        arr: &'a PrimitiveArray<Date32Type>,
386    },
387    TimeOfDay {
388        tag: u32,
389        array: TimeOfDayArray<'a>,
390    },
391
392    // Wrapper types (singular)
393    WrapperDouble {
394        tag: u32,
395        arr: &'a PrimitiveArray<Float64Type>,
396    },
397    WrapperFloat {
398        tag: u32,
399        arr: &'a PrimitiveArray<Float32Type>,
400    },
401    WrapperInt64 {
402        tag: u32,
403        arr: &'a PrimitiveArray<Int64Type>,
404    },
405    WrapperUInt64 {
406        tag: u32,
407        arr: &'a PrimitiveArray<UInt64Type>,
408    },
409    WrapperInt32 {
410        tag: u32,
411        arr: &'a PrimitiveArray<Int32Type>,
412    },
413    WrapperUInt32 {
414        tag: u32,
415        arr: &'a PrimitiveArray<UInt32Type>,
416    },
417    WrapperBool {
418        tag: u32,
419        arr: &'a BooleanArray,
420    },
421    WrapperString {
422        tag: u32,
423        col: StringColumnRef<'a>,
424    },
425    WrapperBytes {
426        tag: u32,
427        col: BinaryColumnRef<'a>,
428    },
429
430    // Repeated fields
431    RepeatedPacked {
432        tag: u32,
433        list: GenericListArray<'a>,
434        encoder: PackedEncoder<'a>,
435    },
436    RepeatedBool {
437        tag: u32,
438        list: GenericListArray<'a>,
439        values: &'a BooleanArray,
440    },
441    RepeatedString {
442        tag: u32,
443        list: GenericListArray<'a>,
444        col: StringColumnRef<'a>,
445    },
446    RepeatedBytes {
447        tag: u32,
448        list: GenericListArray<'a>,
449        col: BinaryColumnRef<'a>,
450    },
451    RepeatedEnumInt32 {
452        tag: u32,
453        list: GenericListArray<'a>,
454        values: &'a PrimitiveArray<Int32Type>,
455    },
456    RepeatedEnumString {
457        tag: u32,
458        list: GenericListArray<'a>,
459        col: StringColumnRef<'a>,
460        enum_descriptor: EnumDescriptor,
461    },
462    RepeatedEnumBinary {
463        tag: u32,
464        list: GenericListArray<'a>,
465        col: BinaryColumnRef<'a>,
466        enum_descriptor: EnumDescriptor,
467    },
468    RepeatedMessage {
469        tag: u32,
470        list: GenericListArray<'a>,
471        sub_encoder: MessageEncoder<'a>,
472    },
473    RepeatedTimestamp {
474        tag: u32,
475        list: GenericListArray<'a>,
476        unit: TimeUnit,
477        values: WellKnownPrimitiveArray<'a>,
478    },
479    RepeatedDuration {
480        tag: u32,
481        list: GenericListArray<'a>,
482        unit: TimeUnit,
483        values: WellKnownPrimitiveArray<'a>,
484    },
485    RepeatedDate {
486        tag: u32,
487        list: GenericListArray<'a>,
488        values: &'a PrimitiveArray<Date32Type>,
489    },
490    RepeatedTimeOfDay {
491        tag: u32,
492        list: GenericListArray<'a>,
493        values: TimeOfDayArray<'a>,
494    },
495    RepeatedWrapperDouble {
496        tag: u32,
497        list: GenericListArray<'a>,
498        values: &'a PrimitiveArray<Float64Type>,
499    },
500    RepeatedWrapperFloat {
501        tag: u32,
502        list: GenericListArray<'a>,
503        values: &'a PrimitiveArray<Float32Type>,
504    },
505    RepeatedWrapperInt64 {
506        tag: u32,
507        list: GenericListArray<'a>,
508        values: &'a PrimitiveArray<Int64Type>,
509    },
510    RepeatedWrapperUInt64 {
511        tag: u32,
512        list: GenericListArray<'a>,
513        values: &'a PrimitiveArray<UInt64Type>,
514    },
515    RepeatedWrapperInt32 {
516        tag: u32,
517        list: GenericListArray<'a>,
518        values: &'a PrimitiveArray<Int32Type>,
519    },
520    RepeatedWrapperUInt32 {
521        tag: u32,
522        list: GenericListArray<'a>,
523        values: &'a PrimitiveArray<UInt32Type>,
524    },
525    RepeatedWrapperBool {
526        tag: u32,
527        list: GenericListArray<'a>,
528        values: &'a BooleanArray,
529    },
530    RepeatedWrapperString {
531        tag: u32,
532        list: GenericListArray<'a>,
533        col: StringColumnRef<'a>,
534    },
535    RepeatedWrapperBytes {
536        tag: u32,
537        list: GenericListArray<'a>,
538        col: BinaryColumnRef<'a>,
539    },
540
541    // Map fields
542    Map {
543        tag: u32,
544        map_array: &'a MapArray,
545        key_encoder: MapKeyEncoder<'a>,
546        value_encoder: MapValueEncoder<'a>,
547    },
548}
549
550/// Holds a timestamp/duration array of any time unit.
551enum WellKnownPrimitiveArray<'a> {
552    Second(&'a PrimitiveArray<TimestampSecondType>),
553    Millisecond(&'a PrimitiveArray<TimestampMillisecondType>),
554    Microsecond(&'a PrimitiveArray<TimestampMicrosecondType>),
555    Nanosecond(&'a PrimitiveArray<TimestampNanosecondType>),
556    DurSecond(&'a PrimitiveArray<DurationSecondType>),
557    DurMillisecond(&'a PrimitiveArray<DurationMillisecondType>),
558    DurMicrosecond(&'a PrimitiveArray<DurationMicrosecondType>),
559    DurNanosecond(&'a PrimitiveArray<DurationNanosecondType>),
560}
561
562impl WellKnownPrimitiveArray<'_> {
563    fn is_null(&self, idx: usize) -> bool {
564        match self {
565            Self::Second(a) => a.is_null(idx),
566            Self::Millisecond(a) => a.is_null(idx),
567            Self::Microsecond(a) => a.is_null(idx),
568            Self::Nanosecond(a) => a.is_null(idx),
569            Self::DurSecond(a) => a.is_null(idx),
570            Self::DurMillisecond(a) => a.is_null(idx),
571            Self::DurMicrosecond(a) => a.is_null(idx),
572            Self::DurNanosecond(a) => a.is_null(idx),
573        }
574    }
575    fn value_i64(&self, idx: usize) -> i64 {
576        match self {
577            Self::Second(a) => a.value(idx),
578            Self::Millisecond(a) => a.value(idx),
579            Self::Microsecond(a) => a.value(idx),
580            Self::Nanosecond(a) => a.value(idx),
581            Self::DurSecond(a) => a.value(idx),
582            Self::DurMillisecond(a) => a.value(idx),
583            Self::DurMicrosecond(a) => a.value(idx),
584            Self::DurNanosecond(a) => a.value(idx),
585        }
586    }
587}
588
589/// Holds a time-of-day array of any time unit.
590enum TimeOfDayArray<'a> {
591    Time32Second(&'a PrimitiveArray<Time32SecondType>),
592    Time32Millisecond(&'a PrimitiveArray<Time32MillisecondType>),
593    Time64Microsecond(&'a PrimitiveArray<Time64MicrosecondType>),
594    Time64Nanosecond(&'a PrimitiveArray<Time64NanosecondType>),
595}
596
597impl TimeOfDayArray<'_> {
598    fn is_null(&self, idx: usize) -> bool {
599        match self {
600            Self::Time32Second(a) => a.is_null(idx),
601            Self::Time32Millisecond(a) => a.is_null(idx),
602            Self::Time64Microsecond(a) => a.is_null(idx),
603            Self::Time64Nanosecond(a) => a.is_null(idx),
604        }
605    }
606    fn to_nanos(&self, idx: usize) -> i64 {
607        match self {
608            Self::Time32Second(a) => time32_unit_to_nanos(a.value(idx), TimeUnit::Second),
609            Self::Time32Millisecond(a) => time32_unit_to_nanos(a.value(idx), TimeUnit::Millisecond),
610            Self::Time64Microsecond(a) => time64_unit_to_nanos(a.value(idx), TimeUnit::Microsecond),
611            Self::Time64Nanosecond(a) => time64_unit_to_nanos(a.value(idx), TimeUnit::Nanosecond),
612        }
613    }
614}
615
616/// Encoder for packed repeated numeric fields.
617enum PackedEncoder<'a> {
618    Int32(&'a PrimitiveArray<Int32Type>),
619    Int64(&'a PrimitiveArray<Int64Type>),
620    UInt32(&'a PrimitiveArray<UInt32Type>),
621    UInt64(&'a PrimitiveArray<UInt64Type>),
622    Sint32(&'a PrimitiveArray<Int32Type>),
623    Sint64(&'a PrimitiveArray<Int64Type>),
624    Sfixed32(&'a PrimitiveArray<Int32Type>),
625    Sfixed64(&'a PrimitiveArray<Int64Type>),
626    Fixed32(&'a PrimitiveArray<UInt32Type>),
627    Fixed64(&'a PrimitiveArray<UInt64Type>),
628    Float32(&'a PrimitiveArray<Float32Type>),
629    Float64(&'a PrimitiveArray<Float64Type>),
630}
631
632impl PackedEncoder<'_> {
633    /// Encode elements in [start..end) as packed wire format (no tag, just values).
634    fn encode_packed_values(&self, start: usize, end: usize, buf: &mut Vec<u8>) {
635        match self {
636            Self::Int32(arr) => {
637                for i in start..end {
638                    let v = if arr.is_null(i) { 0 } else { arr.value(i) };
639                    encode_varint(v as u64, buf);
640                }
641            }
642            Self::Int64(arr) => {
643                for i in start..end {
644                    let v = if arr.is_null(i) { 0 } else { arr.value(i) };
645                    encode_varint(v as u64, buf);
646                }
647            }
648            Self::UInt32(arr) => {
649                for i in start..end {
650                    let v = if arr.is_null(i) { 0 } else { arr.value(i) };
651                    encode_varint(u64::from(v), buf);
652                }
653            }
654            Self::UInt64(arr) => {
655                for i in start..end {
656                    let v = if arr.is_null(i) { 0 } else { arr.value(i) };
657                    encode_varint(v, buf);
658                }
659            }
660            Self::Sint32(arr) => {
661                for i in start..end {
662                    let v = if arr.is_null(i) { 0 } else { arr.value(i) };
663                    // zigzag encoding
664                    encode_varint(((v << 1) ^ (v >> 31)) as u32 as u64, buf);
665                }
666            }
667            Self::Sint64(arr) => {
668                for i in start..end {
669                    let v = if arr.is_null(i) { 0 } else { arr.value(i) };
670                    // zigzag encoding
671                    encode_varint(((v << 1) ^ (v >> 63)) as u64, buf);
672                }
673            }
674            Self::Sfixed32(arr) => {
675                for i in start..end {
676                    let v = if arr.is_null(i) { 0 } else { arr.value(i) };
677                    buf.extend_from_slice(&v.to_le_bytes());
678                }
679            }
680            Self::Sfixed64(arr) => {
681                for i in start..end {
682                    let v = if arr.is_null(i) { 0 } else { arr.value(i) };
683                    buf.extend_from_slice(&v.to_le_bytes());
684                }
685            }
686            Self::Fixed32(arr) => {
687                for i in start..end {
688                    let v = if arr.is_null(i) { 0 } else { arr.value(i) };
689                    buf.extend_from_slice(&v.to_le_bytes());
690                }
691            }
692            Self::Fixed64(arr) => {
693                for i in start..end {
694                    let v = if arr.is_null(i) { 0 } else { arr.value(i) };
695                    buf.extend_from_slice(&v.to_le_bytes());
696                }
697            }
698            Self::Float32(arr) => {
699                for i in start..end {
700                    let v = if arr.is_null(i) { 0.0 } else { arr.value(i) };
701                    buf.extend_from_slice(&v.to_le_bytes());
702                }
703            }
704            Self::Float64(arr) => {
705                for i in start..end {
706                    let v = if arr.is_null(i) { 0.0 } else { arr.value(i) };
707                    buf.extend_from_slice(&v.to_le_bytes());
708                }
709            }
710        }
711    }
712}
713
714/// Encoder for map key fields.
715/// Each variant uses the correct wire encoding for its proto type.
716enum MapKeyEncoder<'a> {
717    String(StringColumnRef<'a>),
718    Int32(&'a PrimitiveArray<Int32Type>),
719    Sint32(&'a PrimitiveArray<Int32Type>),
720    Sfixed32(&'a PrimitiveArray<Int32Type>),
721    Int64(&'a PrimitiveArray<Int64Type>),
722    Sint64(&'a PrimitiveArray<Int64Type>),
723    Sfixed64(&'a PrimitiveArray<Int64Type>),
724    UInt32(&'a PrimitiveArray<UInt32Type>),
725    Fixed32(&'a PrimitiveArray<UInt32Type>),
726    UInt64(&'a PrimitiveArray<UInt64Type>),
727    Fixed64(&'a PrimitiveArray<UInt64Type>),
728    Bool(&'a BooleanArray),
729}
730
731impl MapKeyEncoder<'_> {
732    fn encode_at(&self, idx: usize, buf: &mut Vec<u8>) {
733        match self {
734            Self::String(col) => {
735                if !col.is_null(idx) {
736                    let v = col.value(idx);
737                    encode_key(1, WireType::LengthDelimited, buf);
738                    encode_varint(v.len() as u64, buf);
739                    buf.extend_from_slice(v.as_bytes());
740                }
741            }
742            Self::Int32(arr) => {
743                if !arr.is_null(idx) {
744                    let v = arr.value(idx);
745                    if v != 0 {
746                        prost::encoding::int32::encode(1, &v, buf);
747                    }
748                }
749            }
750            Self::Sint32(arr) => {
751                if !arr.is_null(idx) {
752                    let v = arr.value(idx);
753                    if v != 0 {
754                        prost::encoding::sint32::encode(1, &v, buf);
755                    }
756                }
757            }
758            Self::Sfixed32(arr) => {
759                if !arr.is_null(idx) {
760                    let v = arr.value(idx);
761                    if v != 0 {
762                        prost::encoding::sfixed32::encode(1, &v, buf);
763                    }
764                }
765            }
766            Self::Int64(arr) => {
767                if !arr.is_null(idx) {
768                    let v = arr.value(idx);
769                    if v != 0 {
770                        prost::encoding::int64::encode(1, &v, buf);
771                    }
772                }
773            }
774            Self::Sint64(arr) => {
775                if !arr.is_null(idx) {
776                    let v = arr.value(idx);
777                    if v != 0 {
778                        prost::encoding::sint64::encode(1, &v, buf);
779                    }
780                }
781            }
782            Self::Sfixed64(arr) => {
783                if !arr.is_null(idx) {
784                    let v = arr.value(idx);
785                    if v != 0 {
786                        prost::encoding::sfixed64::encode(1, &v, buf);
787                    }
788                }
789            }
790            Self::UInt32(arr) => {
791                if !arr.is_null(idx) {
792                    let v = arr.value(idx);
793                    if v != 0 {
794                        prost::encoding::uint32::encode(1, &v, buf);
795                    }
796                }
797            }
798            Self::Fixed32(arr) => {
799                if !arr.is_null(idx) {
800                    let v = arr.value(idx);
801                    if v != 0 {
802                        prost::encoding::fixed32::encode(1, &v, buf);
803                    }
804                }
805            }
806            Self::UInt64(arr) => {
807                if !arr.is_null(idx) {
808                    let v = arr.value(idx);
809                    if v != 0 {
810                        prost::encoding::uint64::encode(1, &v, buf);
811                    }
812                }
813            }
814            Self::Fixed64(arr) => {
815                if !arr.is_null(idx) {
816                    let v = arr.value(idx);
817                    if v != 0 {
818                        prost::encoding::fixed64::encode(1, &v, buf);
819                    }
820                }
821            }
822            Self::Bool(arr) => {
823                if !arr.is_null(idx) {
824                    let v = arr.value(idx);
825                    if v {
826                        prost::encoding::bool::encode(1, &v, buf);
827                    }
828                }
829            }
830        }
831    }
832}
833
834/// Encoder for map value fields.
835enum MapValueEncoder<'a> {
836    Double(&'a PrimitiveArray<Float64Type>),
837    Float(&'a PrimitiveArray<Float32Type>),
838    Int32(&'a PrimitiveArray<Int32Type>),
839    Sint32(&'a PrimitiveArray<Int32Type>),
840    Sfixed32(&'a PrimitiveArray<Int32Type>),
841    Int64(&'a PrimitiveArray<Int64Type>),
842    Sint64(&'a PrimitiveArray<Int64Type>),
843    Sfixed64(&'a PrimitiveArray<Int64Type>),
844    UInt32(&'a PrimitiveArray<UInt32Type>),
845    Fixed32(&'a PrimitiveArray<UInt32Type>),
846    UInt64(&'a PrimitiveArray<UInt64Type>),
847    Fixed64(&'a PrimitiveArray<UInt64Type>),
848    Bool(&'a BooleanArray),
849    String(StringColumnRef<'a>),
850    Bytes(BinaryColumnRef<'a>),
851    EnumInt32(&'a PrimitiveArray<Int32Type>),
852    EnumString(StringColumnRef<'a>, EnumDescriptor),
853    EnumBinary(BinaryColumnRef<'a>, EnumDescriptor),
854    Message(&'a StructArray, MessageEncoder<'a>),
855    Timestamp(TimeUnit, WellKnownPrimitiveArray<'a>),
856    Duration(TimeUnit, WellKnownPrimitiveArray<'a>),
857    Date(&'a PrimitiveArray<Date32Type>),
858    TimeOfDay(TimeOfDayArray<'a>),
859    WrapperDouble(&'a PrimitiveArray<Float64Type>),
860    WrapperFloat(&'a PrimitiveArray<Float32Type>),
861    WrapperInt64(&'a PrimitiveArray<Int64Type>),
862    WrapperUInt64(&'a PrimitiveArray<UInt64Type>),
863    WrapperInt32(&'a PrimitiveArray<Int32Type>),
864    WrapperUInt32(&'a PrimitiveArray<UInt32Type>),
865    WrapperBool(&'a BooleanArray),
866    WrapperString(StringColumnRef<'a>),
867    WrapperBytes(BinaryColumnRef<'a>),
868}
869
870impl MapValueEncoder<'_> {
871    fn encode_at(&self, idx: usize, buf: &mut Vec<u8>) {
872        match self {
873            Self::Double(arr) => {
874                if !arr.is_null(idx) {
875                    let v = arr.value(idx);
876                    if v != 0.0 {
877                        prost::encoding::double::encode(2, &v, buf);
878                    }
879                }
880            }
881            Self::Float(arr) => {
882                if !arr.is_null(idx) {
883                    let v = arr.value(idx);
884                    if v != 0.0 {
885                        prost::encoding::float::encode(2, &v, buf);
886                    }
887                }
888            }
889            Self::Int32(arr) => {
890                if !arr.is_null(idx) {
891                    let v = arr.value(idx);
892                    if v != 0 {
893                        prost::encoding::int32::encode(2, &v, buf);
894                    }
895                }
896            }
897            Self::Sint32(arr) => {
898                if !arr.is_null(idx) {
899                    let v = arr.value(idx);
900                    if v != 0 {
901                        prost::encoding::sint32::encode(2, &v, buf);
902                    }
903                }
904            }
905            Self::Sfixed32(arr) => {
906                if !arr.is_null(idx) {
907                    let v = arr.value(idx);
908                    if v != 0 {
909                        prost::encoding::sfixed32::encode(2, &v, buf);
910                    }
911                }
912            }
913            Self::Int64(arr) => {
914                if !arr.is_null(idx) {
915                    let v = arr.value(idx);
916                    if v != 0 {
917                        prost::encoding::int64::encode(2, &v, buf);
918                    }
919                }
920            }
921            Self::Sint64(arr) => {
922                if !arr.is_null(idx) {
923                    let v = arr.value(idx);
924                    if v != 0 {
925                        prost::encoding::sint64::encode(2, &v, buf);
926                    }
927                }
928            }
929            Self::Sfixed64(arr) => {
930                if !arr.is_null(idx) {
931                    let v = arr.value(idx);
932                    if v != 0 {
933                        prost::encoding::sfixed64::encode(2, &v, buf);
934                    }
935                }
936            }
937            Self::UInt32(arr) => {
938                if !arr.is_null(idx) {
939                    let v = arr.value(idx);
940                    if v != 0 {
941                        prost::encoding::uint32::encode(2, &v, buf);
942                    }
943                }
944            }
945            Self::Fixed32(arr) => {
946                if !arr.is_null(idx) {
947                    let v = arr.value(idx);
948                    if v != 0 {
949                        prost::encoding::fixed32::encode(2, &v, buf);
950                    }
951                }
952            }
953            Self::UInt64(arr) => {
954                if !arr.is_null(idx) {
955                    let v = arr.value(idx);
956                    if v != 0 {
957                        prost::encoding::uint64::encode(2, &v, buf);
958                    }
959                }
960            }
961            Self::Fixed64(arr) => {
962                if !arr.is_null(idx) {
963                    let v = arr.value(idx);
964                    if v != 0 {
965                        prost::encoding::fixed64::encode(2, &v, buf);
966                    }
967                }
968            }
969            Self::Bool(arr) => {
970                if !arr.is_null(idx) {
971                    let v = arr.value(idx);
972                    if v {
973                        prost::encoding::bool::encode(2, &v, buf);
974                    }
975                }
976            }
977            Self::String(col) => {
978                if !col.is_null(idx) {
979                    let v = col.value(idx);
980                    if !v.is_empty() {
981                        encode_key(2, WireType::LengthDelimited, buf);
982                        encode_varint(v.len() as u64, buf);
983                        buf.extend_from_slice(v.as_bytes());
984                    }
985                }
986            }
987            Self::Bytes(col) => {
988                if !col.is_null(idx) {
989                    let v = col.value(idx);
990                    if !v.is_empty() {
991                        encode_key(2, WireType::LengthDelimited, buf);
992                        encode_varint(v.len() as u64, buf);
993                        buf.extend_from_slice(v);
994                    }
995                }
996            }
997            Self::EnumInt32(arr) => {
998                if !arr.is_null(idx) {
999                    let v = arr.value(idx);
1000                    if v != 0 {
1001                        prost::encoding::int32::encode(2, &v, buf);
1002                    }
1003                }
1004            }
1005            Self::EnumString(col, ed) => {
1006                if !col.is_null(idx) {
1007                    let v = enum_number_from_name(col.value(idx), ed);
1008                    if v != 0 {
1009                        prost::encoding::int32::encode(2, &v, buf);
1010                    }
1011                }
1012            }
1013            Self::EnumBinary(col, ed) => {
1014                if !col.is_null(idx) {
1015                    let name = std::str::from_utf8(col.value(idx)).unwrap();
1016                    let v = enum_number_from_name(name, ed);
1017                    if v != 0 {
1018                        prost::encoding::int32::encode(2, &v, buf);
1019                    }
1020                }
1021            }
1022            Self::Message(struct_arr, sub_enc) => {
1023                if struct_arr.is_valid(idx) {
1024                    let mut tmp = Vec::new();
1025                    sub_enc.encode_row(idx, &mut tmp);
1026                    write_submessage(2, &tmp, buf);
1027                }
1028            }
1029            Self::Timestamp(unit, arr) => {
1030                if !arr.is_null(idx) {
1031                    let (s, n) = time_unit_to_seconds_and_nanos(arr.value_i64(idx), *unit);
1032                    let mut tmp = Vec::new();
1033                    encode_timestamp_fields(s, n, &mut tmp);
1034                    write_submessage(2, &tmp, buf);
1035                }
1036            }
1037            Self::Duration(unit, arr) => {
1038                if !arr.is_null(idx) {
1039                    let (s, n) = time_unit_to_duration_seconds_and_nanos(arr.value_i64(idx), *unit);
1040                    let mut tmp = Vec::new();
1041                    encode_duration_fields(s, n, &mut tmp);
1042                    write_submessage(2, &tmp, buf);
1043                }
1044            }
1045            Self::Date(arr) => {
1046                if !arr.is_null(idx) {
1047                    let mut tmp = Vec::new();
1048                    encode_date_fields(arr.value(idx), &mut tmp);
1049                    write_submessage(2, &tmp, buf);
1050                }
1051            }
1052            Self::TimeOfDay(arr) => {
1053                if !arr.is_null(idx) {
1054                    let mut tmp = Vec::new();
1055                    encode_time_of_day_fields(arr.to_nanos(idx), &mut tmp);
1056                    write_submessage(2, &tmp, buf);
1057                }
1058            }
1059            Self::WrapperDouble(arr) => {
1060                if !arr.is_null(idx) {
1061                    let mut tmp = Vec::new();
1062                    prost::encoding::double::encode(1, &arr.value(idx), &mut tmp);
1063                    write_submessage(2, &tmp, buf);
1064                }
1065            }
1066            Self::WrapperFloat(arr) => {
1067                if !arr.is_null(idx) {
1068                    let mut tmp = Vec::new();
1069                    prost::encoding::float::encode(1, &arr.value(idx), &mut tmp);
1070                    write_submessage(2, &tmp, buf);
1071                }
1072            }
1073            Self::WrapperInt64(arr) => {
1074                if !arr.is_null(idx) {
1075                    let mut tmp = Vec::new();
1076                    prost::encoding::int64::encode(1, &arr.value(idx), &mut tmp);
1077                    write_submessage(2, &tmp, buf);
1078                }
1079            }
1080            Self::WrapperUInt64(arr) => {
1081                if !arr.is_null(idx) {
1082                    let mut tmp = Vec::new();
1083                    prost::encoding::uint64::encode(1, &arr.value(idx), &mut tmp);
1084                    write_submessage(2, &tmp, buf);
1085                }
1086            }
1087            Self::WrapperInt32(arr) => {
1088                if !arr.is_null(idx) {
1089                    let mut tmp = Vec::new();
1090                    prost::encoding::int32::encode(1, &arr.value(idx), &mut tmp);
1091                    write_submessage(2, &tmp, buf);
1092                }
1093            }
1094            Self::WrapperUInt32(arr) => {
1095                if !arr.is_null(idx) {
1096                    let mut tmp = Vec::new();
1097                    prost::encoding::uint32::encode(1, &arr.value(idx), &mut tmp);
1098                    write_submessage(2, &tmp, buf);
1099                }
1100            }
1101            Self::WrapperBool(arr) => {
1102                if !arr.is_null(idx) {
1103                    let mut tmp = Vec::new();
1104                    prost::encoding::bool::encode(1, &arr.value(idx), &mut tmp);
1105                    write_submessage(2, &tmp, buf);
1106                }
1107            }
1108            Self::WrapperString(col) => {
1109                if !col.is_null(idx) {
1110                    let v = col.value(idx);
1111                    let mut tmp = Vec::new();
1112                    encode_key(1, WireType::LengthDelimited, &mut tmp);
1113                    encode_varint(v.len() as u64, &mut tmp);
1114                    tmp.extend_from_slice(v.as_bytes());
1115                    write_submessage(2, &tmp, buf);
1116                }
1117            }
1118            Self::WrapperBytes(col) => {
1119                if !col.is_null(idx) {
1120                    let v = col.value(idx);
1121                    let mut tmp = Vec::new();
1122                    encode_key(1, WireType::LengthDelimited, &mut tmp);
1123                    encode_varint(v.len() as u64, &mut tmp);
1124                    tmp.extend_from_slice(v);
1125                    write_submessage(2, &tmp, buf);
1126                }
1127            }
1128        }
1129    }
1130}
1131
1132// ---------------------------------------------------------------------------
1133// FieldEncoder::encode_at — the main per-row encoding dispatch
1134// ---------------------------------------------------------------------------
1135
1136impl FieldEncoder<'_> {
1137    fn encode_at(&self, idx: usize, buf: &mut Vec<u8>) {
1138        match self {
1139            // ----- scalars -----
1140            Self::Double {
1141                tag,
1142                arr,
1143                has_presence,
1144            } => {
1145                if arr.is_null(idx) {
1146                    return;
1147                }
1148                let val = arr.value(idx);
1149                if !has_presence && val == 0.0 {
1150                    return;
1151                }
1152                prost::encoding::double::encode(*tag, &val, buf);
1153            }
1154            Self::Float {
1155                tag,
1156                arr,
1157                has_presence,
1158            } => {
1159                if arr.is_null(idx) {
1160                    return;
1161                }
1162                let val = arr.value(idx);
1163                if !has_presence && val == 0.0 {
1164                    return;
1165                }
1166                prost::encoding::float::encode(*tag, &val, buf);
1167            }
1168            Self::Int32 {
1169                tag,
1170                arr,
1171                has_presence,
1172            } => {
1173                if arr.is_null(idx) {
1174                    return;
1175                }
1176                let val = arr.value(idx);
1177                if !has_presence && val == 0 {
1178                    return;
1179                }
1180                prost::encoding::int32::encode(*tag, &val, buf);
1181            }
1182            Self::Int64 {
1183                tag,
1184                arr,
1185                has_presence,
1186            } => {
1187                if arr.is_null(idx) {
1188                    return;
1189                }
1190                let val = arr.value(idx);
1191                if !has_presence && val == 0 {
1192                    return;
1193                }
1194                prost::encoding::int64::encode(*tag, &val, buf);
1195            }
1196            Self::UInt32 {
1197                tag,
1198                arr,
1199                has_presence,
1200            } => {
1201                if arr.is_null(idx) {
1202                    return;
1203                }
1204                let val = arr.value(idx);
1205                if !has_presence && val == 0 {
1206                    return;
1207                }
1208                prost::encoding::uint32::encode(*tag, &val, buf);
1209            }
1210            Self::UInt64 {
1211                tag,
1212                arr,
1213                has_presence,
1214            } => {
1215                if arr.is_null(idx) {
1216                    return;
1217                }
1218                let val = arr.value(idx);
1219                if !has_presence && val == 0 {
1220                    return;
1221                }
1222                prost::encoding::uint64::encode(*tag, &val, buf);
1223            }
1224            Self::Sint32 {
1225                tag,
1226                arr,
1227                has_presence,
1228            } => {
1229                if arr.is_null(idx) {
1230                    return;
1231                }
1232                let val = arr.value(idx);
1233                if !has_presence && val == 0 {
1234                    return;
1235                }
1236                prost::encoding::sint32::encode(*tag, &val, buf);
1237            }
1238            Self::Sint64 {
1239                tag,
1240                arr,
1241                has_presence,
1242            } => {
1243                if arr.is_null(idx) {
1244                    return;
1245                }
1246                let val = arr.value(idx);
1247                if !has_presence && val == 0 {
1248                    return;
1249                }
1250                prost::encoding::sint64::encode(*tag, &val, buf);
1251            }
1252            Self::Sfixed32 {
1253                tag,
1254                arr,
1255                has_presence,
1256            } => {
1257                if arr.is_null(idx) {
1258                    return;
1259                }
1260                let val = arr.value(idx);
1261                if !has_presence && val == 0 {
1262                    return;
1263                }
1264                prost::encoding::sfixed32::encode(*tag, &val, buf);
1265            }
1266            Self::Sfixed64 {
1267                tag,
1268                arr,
1269                has_presence,
1270            } => {
1271                if arr.is_null(idx) {
1272                    return;
1273                }
1274                let val = arr.value(idx);
1275                if !has_presence && val == 0 {
1276                    return;
1277                }
1278                prost::encoding::sfixed64::encode(*tag, &val, buf);
1279            }
1280            Self::Fixed32 {
1281                tag,
1282                arr,
1283                has_presence,
1284            } => {
1285                if arr.is_null(idx) {
1286                    return;
1287                }
1288                let val = arr.value(idx);
1289                if !has_presence && val == 0 {
1290                    return;
1291                }
1292                prost::encoding::fixed32::encode(*tag, &val, buf);
1293            }
1294            Self::Fixed64 {
1295                tag,
1296                arr,
1297                has_presence,
1298            } => {
1299                if arr.is_null(idx) {
1300                    return;
1301                }
1302                let val = arr.value(idx);
1303                if !has_presence && val == 0 {
1304                    return;
1305                }
1306                prost::encoding::fixed64::encode(*tag, &val, buf);
1307            }
1308            Self::Bool {
1309                tag,
1310                arr,
1311                has_presence,
1312            } => {
1313                if arr.is_null(idx) {
1314                    return;
1315                }
1316                let val = arr.value(idx);
1317                if !has_presence && !val {
1318                    return;
1319                }
1320                prost::encoding::bool::encode(*tag, &val, buf);
1321            }
1322            Self::String {
1323                tag,
1324                col,
1325                has_presence,
1326            } => {
1327                if col.is_null(idx) {
1328                    return;
1329                }
1330                let val = col.value(idx);
1331                if !has_presence && val.is_empty() {
1332                    return;
1333                }
1334                encode_key(*tag, WireType::LengthDelimited, buf);
1335                encode_varint(val.len() as u64, buf);
1336                buf.extend_from_slice(val.as_bytes());
1337            }
1338            Self::Bytes {
1339                tag,
1340                col,
1341                has_presence,
1342            } => {
1343                if col.is_null(idx) {
1344                    return;
1345                }
1346                let val = col.value(idx);
1347                if !has_presence && val.is_empty() {
1348                    return;
1349                }
1350                encode_key(*tag, WireType::LengthDelimited, buf);
1351                encode_varint(val.len() as u64, buf);
1352                buf.extend_from_slice(val);
1353            }
1354
1355            // ----- enums -----
1356            Self::EnumInt32 {
1357                tag,
1358                arr,
1359                has_presence,
1360            } => {
1361                if arr.is_null(idx) {
1362                    return;
1363                }
1364                let val = arr.value(idx);
1365                if !has_presence && val == 0 {
1366                    return;
1367                }
1368                prost::encoding::int32::encode(*tag, &val, buf);
1369            }
1370            Self::EnumString {
1371                tag,
1372                col,
1373                enum_descriptor,
1374                has_presence,
1375            } => {
1376                if col.is_null(idx) {
1377                    return;
1378                }
1379                let val = enum_number_from_name(col.value(idx), enum_descriptor);
1380                if !has_presence && val == 0 {
1381                    return;
1382                }
1383                prost::encoding::int32::encode(*tag, &val, buf);
1384            }
1385            Self::EnumBinary {
1386                tag,
1387                col,
1388                enum_descriptor,
1389                has_presence,
1390            } => {
1391                if col.is_null(idx) {
1392                    return;
1393                }
1394                let name = std::str::from_utf8(col.value(idx)).unwrap();
1395                let val = enum_number_from_name(name, enum_descriptor);
1396                if !has_presence && val == 0 {
1397                    return;
1398                }
1399                prost::encoding::int32::encode(*tag, &val, buf);
1400            }
1401
1402            // ----- nested message -----
1403            Self::Message {
1404                tag,
1405                struct_arr,
1406                sub_encoder,
1407            } => {
1408                if !struct_arr.is_valid(idx) {
1409                    return;
1410                }
1411                let mut tmp = Vec::new();
1412                sub_encoder.encode_row(idx, &mut tmp);
1413                write_submessage(*tag, &tmp, buf);
1414            }
1415
1416            // ----- well-known: Timestamp -----
1417            Self::Timestamp { tag, unit, array } => {
1418                if array.is_null(idx) {
1419                    return;
1420                }
1421                let (s, n) = time_unit_to_seconds_and_nanos(array.value_i64(idx), *unit);
1422                let mut tmp = Vec::new();
1423                encode_timestamp_fields(s, n, &mut tmp);
1424                write_submessage(*tag, &tmp, buf);
1425            }
1426            // ----- well-known: Duration -----
1427            Self::Duration { tag, unit, array } => {
1428                if array.is_null(idx) {
1429                    return;
1430                }
1431                let (s, n) = time_unit_to_duration_seconds_and_nanos(array.value_i64(idx), *unit);
1432                let mut tmp = Vec::new();
1433                encode_duration_fields(s, n, &mut tmp);
1434                write_submessage(*tag, &tmp, buf);
1435            }
1436            // ----- well-known: Date -----
1437            Self::Date { tag, arr } => {
1438                if arr.is_null(idx) {
1439                    return;
1440                }
1441                let mut tmp = Vec::new();
1442                encode_date_fields(arr.value(idx), &mut tmp);
1443                write_submessage(*tag, &tmp, buf);
1444            }
1445            // ----- well-known: TimeOfDay -----
1446            Self::TimeOfDay { tag, array } => {
1447                if array.is_null(idx) {
1448                    return;
1449                }
1450                let mut tmp = Vec::new();
1451                encode_time_of_day_fields(array.to_nanos(idx), &mut tmp);
1452                write_submessage(*tag, &tmp, buf);
1453            }
1454
1455            // ----- wrapper types -----
1456            Self::WrapperDouble { tag, arr } => {
1457                if arr.is_null(idx) {
1458                    return;
1459                }
1460                let mut tmp = Vec::new();
1461                prost::encoding::double::encode(1, &arr.value(idx), &mut tmp);
1462                write_submessage(*tag, &tmp, buf);
1463            }
1464            Self::WrapperFloat { tag, arr } => {
1465                if arr.is_null(idx) {
1466                    return;
1467                }
1468                let mut tmp = Vec::new();
1469                prost::encoding::float::encode(1, &arr.value(idx), &mut tmp);
1470                write_submessage(*tag, &tmp, buf);
1471            }
1472            Self::WrapperInt64 { tag, arr } => {
1473                if arr.is_null(idx) {
1474                    return;
1475                }
1476                let mut tmp = Vec::new();
1477                prost::encoding::int64::encode(1, &arr.value(idx), &mut tmp);
1478                write_submessage(*tag, &tmp, buf);
1479            }
1480            Self::WrapperUInt64 { tag, arr } => {
1481                if arr.is_null(idx) {
1482                    return;
1483                }
1484                let mut tmp = Vec::new();
1485                prost::encoding::uint64::encode(1, &arr.value(idx), &mut tmp);
1486                write_submessage(*tag, &tmp, buf);
1487            }
1488            Self::WrapperInt32 { tag, arr } => {
1489                if arr.is_null(idx) {
1490                    return;
1491                }
1492                let mut tmp = Vec::new();
1493                prost::encoding::int32::encode(1, &arr.value(idx), &mut tmp);
1494                write_submessage(*tag, &tmp, buf);
1495            }
1496            Self::WrapperUInt32 { tag, arr } => {
1497                if arr.is_null(idx) {
1498                    return;
1499                }
1500                let mut tmp = Vec::new();
1501                prost::encoding::uint32::encode(1, &arr.value(idx), &mut tmp);
1502                write_submessage(*tag, &tmp, buf);
1503            }
1504            Self::WrapperBool { tag, arr } => {
1505                if arr.is_null(idx) {
1506                    return;
1507                }
1508                let mut tmp = Vec::new();
1509                prost::encoding::bool::encode(1, &arr.value(idx), &mut tmp);
1510                write_submessage(*tag, &tmp, buf);
1511            }
1512            Self::WrapperString { tag, col } => {
1513                if col.is_null(idx) {
1514                    return;
1515                }
1516                let v = col.value(idx);
1517                let mut tmp = Vec::new();
1518                encode_key(1, WireType::LengthDelimited, &mut tmp);
1519                encode_varint(v.len() as u64, &mut tmp);
1520                tmp.extend_from_slice(v.as_bytes());
1521                write_submessage(*tag, &tmp, buf);
1522            }
1523            Self::WrapperBytes { tag, col } => {
1524                if col.is_null(idx) {
1525                    return;
1526                }
1527                let v = col.value(idx);
1528                let mut tmp = Vec::new();
1529                encode_key(1, WireType::LengthDelimited, &mut tmp);
1530                encode_varint(v.len() as u64, &mut tmp);
1531                tmp.extend_from_slice(v);
1532                write_submessage(*tag, &tmp, buf);
1533            }
1534
1535            // ----- repeated packed (int32/int64/uint32/uint64/float/double) -----
1536            Self::RepeatedPacked { tag, list, encoder } => {
1537                if list.is_null(idx) {
1538                    return;
1539                }
1540                let (start, end) = list.value_offsets(idx);
1541                if start >= end {
1542                    return;
1543                }
1544                let mut packed = Vec::new();
1545                encoder.encode_packed_values(start, end, &mut packed);
1546                encode_key(*tag, WireType::LengthDelimited, buf);
1547                encode_varint(packed.len() as u64, buf);
1548                buf.extend_from_slice(&packed);
1549            }
1550            Self::RepeatedBool { tag, list, values } => {
1551                if list.is_null(idx) {
1552                    return;
1553                }
1554                let (start, end) = list.value_offsets(idx);
1555                if start >= end {
1556                    return;
1557                }
1558                let mut packed = Vec::new();
1559                for i in start..end {
1560                    encode_varint(u64::from(values.value(i)), &mut packed);
1561                }
1562                encode_key(*tag, WireType::LengthDelimited, buf);
1563                encode_varint(packed.len() as u64, buf);
1564                buf.extend_from_slice(&packed);
1565            }
1566            Self::RepeatedString { tag, list, col } => {
1567                if list.is_null(idx) {
1568                    return;
1569                }
1570                let (start, end) = list.value_offsets(idx);
1571                for i in start..end {
1572                    if col.is_null(i) {
1573                        continue;
1574                    }
1575                    let v = col.value(i);
1576                    encode_key(*tag, WireType::LengthDelimited, buf);
1577                    encode_varint(v.len() as u64, buf);
1578                    buf.extend_from_slice(v.as_bytes());
1579                }
1580            }
1581            Self::RepeatedBytes { tag, list, col } => {
1582                if list.is_null(idx) {
1583                    return;
1584                }
1585                let (start, end) = list.value_offsets(idx);
1586                for i in start..end {
1587                    if col.is_null(i) {
1588                        continue;
1589                    }
1590                    let v = col.value(i);
1591                    encode_key(*tag, WireType::LengthDelimited, buf);
1592                    encode_varint(v.len() as u64, buf);
1593                    buf.extend_from_slice(v);
1594                }
1595            }
1596            Self::RepeatedEnumInt32 { tag, list, values } => {
1597                if list.is_null(idx) {
1598                    return;
1599                }
1600                let (start, end) = list.value_offsets(idx);
1601                if start >= end {
1602                    return;
1603                }
1604                let mut packed = Vec::new();
1605                for i in start..end {
1606                    let v = if values.is_null(i) {
1607                        0
1608                    } else {
1609                        values.value(i)
1610                    };
1611                    encode_varint(v as u64, &mut packed);
1612                }
1613                encode_key(*tag, WireType::LengthDelimited, buf);
1614                encode_varint(packed.len() as u64, buf);
1615                buf.extend_from_slice(&packed);
1616            }
1617            Self::RepeatedEnumString {
1618                tag,
1619                list,
1620                col,
1621                enum_descriptor,
1622            } => {
1623                if list.is_null(idx) {
1624                    return;
1625                }
1626                let (start, end) = list.value_offsets(idx);
1627                if start >= end {
1628                    return;
1629                }
1630                let mut packed = Vec::new();
1631                for i in start..end {
1632                    if col.is_null(i) {
1633                        continue;
1634                    }
1635                    let v = enum_number_from_name(col.value(i), enum_descriptor);
1636                    encode_varint(v as u64, &mut packed);
1637                }
1638                if !packed.is_empty() {
1639                    encode_key(*tag, WireType::LengthDelimited, buf);
1640                    encode_varint(packed.len() as u64, buf);
1641                    buf.extend_from_slice(&packed);
1642                }
1643            }
1644            Self::RepeatedEnumBinary {
1645                tag,
1646                list,
1647                col,
1648                enum_descriptor,
1649            } => {
1650                if list.is_null(idx) {
1651                    return;
1652                }
1653                let (start, end) = list.value_offsets(idx);
1654                if start >= end {
1655                    return;
1656                }
1657                let mut packed = Vec::new();
1658                for i in start..end {
1659                    if col.is_null(i) {
1660                        continue;
1661                    }
1662                    let name = std::str::from_utf8(col.value(i)).unwrap();
1663                    let v = enum_number_from_name(name, enum_descriptor);
1664                    encode_varint(v as u64, &mut packed);
1665                }
1666                if !packed.is_empty() {
1667                    encode_key(*tag, WireType::LengthDelimited, buf);
1668                    encode_varint(packed.len() as u64, buf);
1669                    buf.extend_from_slice(&packed);
1670                }
1671            }
1672            Self::RepeatedMessage {
1673                tag,
1674                list,
1675                sub_encoder,
1676            } => {
1677                if list.is_null(idx) {
1678                    return;
1679                }
1680                let (start, end) = list.value_offsets(idx);
1681                for i in start..end {
1682                    let mut tmp = Vec::new();
1683                    sub_encoder.encode_row(i, &mut tmp);
1684                    write_submessage(*tag, &tmp, buf);
1685                }
1686            }
1687            Self::RepeatedTimestamp {
1688                tag,
1689                list,
1690                unit,
1691                values,
1692            } => {
1693                if list.is_null(idx) {
1694                    return;
1695                }
1696                let (start, end) = list.value_offsets(idx);
1697                for i in start..end {
1698                    if values.is_null(i) {
1699                        continue;
1700                    }
1701                    let (s, n) = time_unit_to_seconds_and_nanos(values.value_i64(i), *unit);
1702                    let mut tmp = Vec::new();
1703                    encode_timestamp_fields(s, n, &mut tmp);
1704                    write_submessage(*tag, &tmp, buf);
1705                }
1706            }
1707            Self::RepeatedDuration {
1708                tag,
1709                list,
1710                unit,
1711                values,
1712            } => {
1713                if list.is_null(idx) {
1714                    return;
1715                }
1716                let (start, end) = list.value_offsets(idx);
1717                for i in start..end {
1718                    if values.is_null(i) {
1719                        continue;
1720                    }
1721                    let (s, n) =
1722                        time_unit_to_duration_seconds_and_nanos(values.value_i64(i), *unit);
1723                    let mut tmp = Vec::new();
1724                    encode_duration_fields(s, n, &mut tmp);
1725                    write_submessage(*tag, &tmp, buf);
1726                }
1727            }
1728            Self::RepeatedDate { tag, list, values } => {
1729                if list.is_null(idx) {
1730                    return;
1731                }
1732                let (start, end) = list.value_offsets(idx);
1733                for i in start..end {
1734                    let mut tmp = Vec::new();
1735                    encode_date_fields(values.value(i), &mut tmp);
1736                    write_submessage(*tag, &tmp, buf);
1737                }
1738            }
1739            Self::RepeatedTimeOfDay { tag, list, values } => {
1740                if list.is_null(idx) {
1741                    return;
1742                }
1743                let (start, end) = list.value_offsets(idx);
1744                for i in start..end {
1745                    if values.is_null(i) {
1746                        continue;
1747                    }
1748                    let mut tmp = Vec::new();
1749                    encode_time_of_day_fields(values.to_nanos(i), &mut tmp);
1750                    write_submessage(*tag, &tmp, buf);
1751                }
1752            }
1753            Self::RepeatedWrapperDouble { tag, list, values } => encode_repeated_wrapper_primitive(
1754                idx,
1755                *tag,
1756                list,
1757                values,
1758                |v, t| prost::encoding::double::encode(1, &v, t),
1759                buf,
1760            ),
1761            Self::RepeatedWrapperFloat { tag, list, values } => encode_repeated_wrapper_primitive(
1762                idx,
1763                *tag,
1764                list,
1765                values,
1766                |v, t| prost::encoding::float::encode(1, &v, t),
1767                buf,
1768            ),
1769            Self::RepeatedWrapperInt64 { tag, list, values } => encode_repeated_wrapper_primitive(
1770                idx,
1771                *tag,
1772                list,
1773                values,
1774                |v, t| prost::encoding::int64::encode(1, &v, t),
1775                buf,
1776            ),
1777            Self::RepeatedWrapperUInt64 { tag, list, values } => encode_repeated_wrapper_primitive(
1778                idx,
1779                *tag,
1780                list,
1781                values,
1782                |v, t| prost::encoding::uint64::encode(1, &v, t),
1783                buf,
1784            ),
1785            Self::RepeatedWrapperInt32 { tag, list, values } => encode_repeated_wrapper_primitive(
1786                idx,
1787                *tag,
1788                list,
1789                values,
1790                |v, t| prost::encoding::int32::encode(1, &v, t),
1791                buf,
1792            ),
1793            Self::RepeatedWrapperUInt32 { tag, list, values } => encode_repeated_wrapper_primitive(
1794                idx,
1795                *tag,
1796                list,
1797                values,
1798                |v, t| prost::encoding::uint32::encode(1, &v, t),
1799                buf,
1800            ),
1801            Self::RepeatedWrapperBool { tag, list, values } => {
1802                if list.is_null(idx) {
1803                    return;
1804                }
1805                let (start, end) = list.value_offsets(idx);
1806                for i in start..end {
1807                    if values.is_null(i) {
1808                        continue;
1809                    }
1810                    let mut tmp = Vec::new();
1811                    prost::encoding::bool::encode(1, &values.value(i), &mut tmp);
1812                    write_submessage(*tag, &tmp, buf);
1813                }
1814            }
1815            Self::RepeatedWrapperString { tag, list, col } => {
1816                if list.is_null(idx) {
1817                    return;
1818                }
1819                let (start, end) = list.value_offsets(idx);
1820                for i in start..end {
1821                    if col.is_null(i) {
1822                        continue;
1823                    }
1824                    let v = col.value(i);
1825                    let mut tmp = Vec::new();
1826                    encode_key(1, WireType::LengthDelimited, &mut tmp);
1827                    encode_varint(v.len() as u64, &mut tmp);
1828                    tmp.extend_from_slice(v.as_bytes());
1829                    write_submessage(*tag, &tmp, buf);
1830                }
1831            }
1832            Self::RepeatedWrapperBytes { tag, list, col } => {
1833                if list.is_null(idx) {
1834                    return;
1835                }
1836                let (start, end) = list.value_offsets(idx);
1837                for i in start..end {
1838                    if col.is_null(i) {
1839                        continue;
1840                    }
1841                    let v = col.value(i);
1842                    let mut tmp = Vec::new();
1843                    encode_key(1, WireType::LengthDelimited, &mut tmp);
1844                    encode_varint(v.len() as u64, &mut tmp);
1845                    tmp.extend_from_slice(v);
1846                    write_submessage(*tag, &tmp, buf);
1847                }
1848            }
1849
1850            // ----- map fields -----
1851            Self::Map {
1852                tag,
1853                map_array,
1854                key_encoder,
1855                value_encoder,
1856            } => {
1857                if map_array.is_null(idx) {
1858                    return;
1859                }
1860                let start = map_array.value_offsets()[idx] as usize;
1861                let end = map_array.value_offsets()[idx + 1] as usize;
1862                for i in start..end {
1863                    let mut entry = Vec::new();
1864                    key_encoder.encode_at(i, &mut entry);
1865                    value_encoder.encode_at(i, &mut entry);
1866                    write_submessage(*tag, &entry, buf);
1867                }
1868            }
1869        }
1870    }
1871}
1872
1873/// Helper for repeated wrapper primitives.
1874fn encode_repeated_wrapper_primitive<P: ArrowPrimitiveType>(
1875    idx: usize,
1876    tag: u32,
1877    list: &GenericListArray,
1878    values: &PrimitiveArray<P>,
1879    encode_value: impl Fn(P::Native, &mut Vec<u8>),
1880    buf: &mut Vec<u8>,
1881) {
1882    if list.is_null(idx) {
1883        return;
1884    }
1885    let (start, end) = list.value_offsets(idx);
1886    for i in start..end {
1887        if values.is_null(i) {
1888            continue;
1889        }
1890        let mut tmp = Vec::new();
1891        encode_value(values.value(i), &mut tmp);
1892        write_submessage(tag, &tmp, buf);
1893    }
1894}
1895
1896// ---------------------------------------------------------------------------
1897// MessageEncoder: holds Vec<FieldEncoder>, built from descriptor + arrays
1898// ---------------------------------------------------------------------------
1899
1900/// Encodes rows directly from Arrow arrays to protobuf wire format.
1901pub struct MessageEncoder<'a> {
1902    encoders: Vec<FieldEncoder<'a>>,
1903}
1904
1905impl<'a> MessageEncoder<'a> {
1906    /// Build a MessageEncoder from a RecordBatch (top-level).
1907    pub fn from_record_batch(descriptor: &MessageDescriptor, batch: &'a RecordBatch) -> Self {
1908        let mut encoders = Vec::new();
1909        for field in descriptor.fields() {
1910            if let Some(column) = batch.column_by_name(field.name()) {
1911                if let Some(enc) = build_field_encoder(&field, column.as_ref()) {
1912                    encoders.push(enc);
1913                }
1914            }
1915        }
1916        Self { encoders }
1917    }
1918
1919    /// Build a MessageEncoder from a StructArray (nested messages).
1920    fn from_struct_array(descriptor: &MessageDescriptor, struct_arr: &'a StructArray) -> Self {
1921        let mut encoders = Vec::new();
1922        for field in descriptor.fields() {
1923            if let Some(column) = struct_arr.column_by_name(field.name()) {
1924                if let Some(enc) = build_field_encoder(&field, column.as_ref()) {
1925                    encoders.push(enc);
1926                }
1927            }
1928        }
1929        Self { encoders }
1930    }
1931
1932    /// Encode a single row into the buffer.
1933    fn encode_row(&self, idx: usize, buf: &mut Vec<u8>) {
1934        for encoder in &self.encoders {
1935            encoder.encode_at(idx, buf);
1936        }
1937    }
1938}
1939
1940// ---------------------------------------------------------------------------
1941// build_field_encoder: construct a FieldEncoder from a FieldDescriptor + array
1942// ---------------------------------------------------------------------------
1943
1944fn build_field_encoder<'a>(
1945    field: &FieldDescriptor,
1946    array: &'a dyn Array,
1947) -> Option<FieldEncoder<'a>> {
1948    if field.is_map() {
1949        return build_map_encoder(field, array);
1950    }
1951    if field.is_list() {
1952        return build_repeated_encoder(field, array);
1953    }
1954
1955    let tag: u32 = field.number();
1956    let has_presence = field.supports_presence();
1957
1958    match field.kind() {
1959        Kind::Double => {
1960            let arr = array
1961                .as_any()
1962                .downcast_ref::<PrimitiveArray<Float64Type>>()?;
1963            Some(FieldEncoder::Double {
1964                tag,
1965                arr,
1966                has_presence,
1967            })
1968        }
1969        Kind::Float => {
1970            let arr = array
1971                .as_any()
1972                .downcast_ref::<PrimitiveArray<Float32Type>>()?;
1973            Some(FieldEncoder::Float {
1974                tag,
1975                arr,
1976                has_presence,
1977            })
1978        }
1979        Kind::Int32 => {
1980            let arr = array.as_any().downcast_ref::<PrimitiveArray<Int32Type>>()?;
1981            Some(FieldEncoder::Int32 {
1982                tag,
1983                arr,
1984                has_presence,
1985            })
1986        }
1987        Kind::Int64 => {
1988            let arr = array.as_any().downcast_ref::<PrimitiveArray<Int64Type>>()?;
1989            Some(FieldEncoder::Int64 {
1990                tag,
1991                arr,
1992                has_presence,
1993            })
1994        }
1995        Kind::Uint32 => {
1996            let arr = array
1997                .as_any()
1998                .downcast_ref::<PrimitiveArray<UInt32Type>>()?;
1999            Some(FieldEncoder::UInt32 {
2000                tag,
2001                arr,
2002                has_presence,
2003            })
2004        }
2005        Kind::Uint64 => {
2006            let arr = array
2007                .as_any()
2008                .downcast_ref::<PrimitiveArray<UInt64Type>>()?;
2009            Some(FieldEncoder::UInt64 {
2010                tag,
2011                arr,
2012                has_presence,
2013            })
2014        }
2015        Kind::Sint32 => {
2016            let arr = array.as_any().downcast_ref::<PrimitiveArray<Int32Type>>()?;
2017            Some(FieldEncoder::Sint32 {
2018                tag,
2019                arr,
2020                has_presence,
2021            })
2022        }
2023        Kind::Sint64 => {
2024            let arr = array.as_any().downcast_ref::<PrimitiveArray<Int64Type>>()?;
2025            Some(FieldEncoder::Sint64 {
2026                tag,
2027                arr,
2028                has_presence,
2029            })
2030        }
2031        Kind::Sfixed32 => {
2032            let arr = array.as_any().downcast_ref::<PrimitiveArray<Int32Type>>()?;
2033            Some(FieldEncoder::Sfixed32 {
2034                tag,
2035                arr,
2036                has_presence,
2037            })
2038        }
2039        Kind::Sfixed64 => {
2040            let arr = array.as_any().downcast_ref::<PrimitiveArray<Int64Type>>()?;
2041            Some(FieldEncoder::Sfixed64 {
2042                tag,
2043                arr,
2044                has_presence,
2045            })
2046        }
2047        Kind::Fixed32 => {
2048            let arr = array
2049                .as_any()
2050                .downcast_ref::<PrimitiveArray<UInt32Type>>()?;
2051            Some(FieldEncoder::Fixed32 {
2052                tag,
2053                arr,
2054                has_presence,
2055            })
2056        }
2057        Kind::Fixed64 => {
2058            let arr = array
2059                .as_any()
2060                .downcast_ref::<PrimitiveArray<UInt64Type>>()?;
2061            Some(FieldEncoder::Fixed64 {
2062                tag,
2063                arr,
2064                has_presence,
2065            })
2066        }
2067        Kind::Bool => {
2068            let arr = array.as_any().downcast_ref::<BooleanArray>()?;
2069            Some(FieldEncoder::Bool {
2070                tag,
2071                arr,
2072                has_presence,
2073            })
2074        }
2075        Kind::String => {
2076            let col = make_string_col_ref(array)?;
2077            Some(FieldEncoder::String {
2078                tag,
2079                col,
2080                has_presence,
2081            })
2082        }
2083        Kind::Bytes => {
2084            let col = make_binary_col_ref(array)?;
2085            Some(FieldEncoder::Bytes {
2086                tag,
2087                col,
2088                has_presence,
2089            })
2090        }
2091        Kind::Enum(enum_desc) => build_enum_encoder(tag, has_presence, array, &enum_desc),
2092        Kind::Message(msg_desc) => build_message_encoder(tag, array, &msg_desc),
2093    }
2094}
2095
2096fn make_string_col_ref(array: &dyn Array) -> Option<StringColumnRef<'_>> {
2097    array
2098        .as_any()
2099        .downcast_ref::<StringArray>()
2100        .map(StringColumnRef::Regular)
2101        .or_else(|| {
2102            array
2103                .as_any()
2104                .downcast_ref::<LargeStringArray>()
2105                .map(StringColumnRef::Large)
2106        })
2107}
2108
2109fn make_binary_col_ref(array: &dyn Array) -> Option<BinaryColumnRef<'_>> {
2110    array
2111        .as_any()
2112        .downcast_ref::<BinaryArray>()
2113        .map(BinaryColumnRef::Regular)
2114        .or_else(|| {
2115            array
2116                .as_any()
2117                .downcast_ref::<LargeBinaryArray>()
2118                .map(BinaryColumnRef::Large)
2119        })
2120}
2121
2122fn build_enum_encoder<'a>(
2123    tag: u32,
2124    has_presence: bool,
2125    array: &'a dyn Array,
2126    enum_descriptor: &EnumDescriptor,
2127) -> Option<FieldEncoder<'a>> {
2128    match array.data_type() {
2129        DataType::Int32 => {
2130            let arr = array.as_any().downcast_ref::<PrimitiveArray<Int32Type>>()?;
2131            Some(FieldEncoder::EnumInt32 {
2132                tag,
2133                arr,
2134                has_presence,
2135            })
2136        }
2137        DataType::Utf8 => {
2138            let a = array.as_any().downcast_ref::<StringArray>()?;
2139            Some(FieldEncoder::EnumString {
2140                tag,
2141                col: StringColumnRef::Regular(a),
2142                enum_descriptor: enum_descriptor.clone(),
2143                has_presence,
2144            })
2145        }
2146        DataType::LargeUtf8 => {
2147            let a = array.as_any().downcast_ref::<LargeStringArray>()?;
2148            Some(FieldEncoder::EnumString {
2149                tag,
2150                col: StringColumnRef::Large(a),
2151                enum_descriptor: enum_descriptor.clone(),
2152                has_presence,
2153            })
2154        }
2155        DataType::Binary => {
2156            let a = array.as_any().downcast_ref::<BinaryArray>()?;
2157            Some(FieldEncoder::EnumBinary {
2158                tag,
2159                col: BinaryColumnRef::Regular(a),
2160                enum_descriptor: enum_descriptor.clone(),
2161                has_presence,
2162            })
2163        }
2164        DataType::LargeBinary => {
2165            let a = array.as_any().downcast_ref::<LargeBinaryArray>()?;
2166            Some(FieldEncoder::EnumBinary {
2167                tag,
2168                col: BinaryColumnRef::Large(a),
2169                enum_descriptor: enum_descriptor.clone(),
2170                has_presence,
2171            })
2172        }
2173        _ => None,
2174    }
2175}
2176
2177/// Build encoder for a singular message field (regular or well-known).
2178fn build_message_encoder<'a>(
2179    tag: u32,
2180    array: &'a dyn Array,
2181    msg_desc: &MessageDescriptor,
2182) -> Option<FieldEncoder<'a>> {
2183    match msg_desc.full_name() {
2184        "google.protobuf.Timestamp" => build_timestamp_encoder(tag, array),
2185        "google.protobuf.Duration" => build_duration_encoder(tag, array),
2186        "google.type.Date" => {
2187            let arr = array
2188                .as_any()
2189                .downcast_ref::<PrimitiveArray<Date32Type>>()?;
2190            Some(FieldEncoder::Date { tag, arr })
2191        }
2192        "google.type.TimeOfDay" => {
2193            let ta = build_time_of_day_array(array)?;
2194            Some(FieldEncoder::TimeOfDay { tag, array: ta })
2195        }
2196        "google.protobuf.DoubleValue" => Some(FieldEncoder::WrapperDouble {
2197            tag,
2198            arr: array.as_any().downcast_ref()?,
2199        }),
2200        "google.protobuf.FloatValue" => Some(FieldEncoder::WrapperFloat {
2201            tag,
2202            arr: array.as_any().downcast_ref()?,
2203        }),
2204        "google.protobuf.Int64Value" => Some(FieldEncoder::WrapperInt64 {
2205            tag,
2206            arr: array.as_any().downcast_ref()?,
2207        }),
2208        "google.protobuf.UInt64Value" => Some(FieldEncoder::WrapperUInt64 {
2209            tag,
2210            arr: array.as_any().downcast_ref()?,
2211        }),
2212        "google.protobuf.Int32Value" => Some(FieldEncoder::WrapperInt32 {
2213            tag,
2214            arr: array.as_any().downcast_ref()?,
2215        }),
2216        "google.protobuf.UInt32Value" => Some(FieldEncoder::WrapperUInt32 {
2217            tag,
2218            arr: array.as_any().downcast_ref()?,
2219        }),
2220        "google.protobuf.BoolValue" => Some(FieldEncoder::WrapperBool {
2221            tag,
2222            arr: array.as_any().downcast_ref()?,
2223        }),
2224        "google.protobuf.StringValue" => {
2225            let col = make_string_col_ref(array)?;
2226            Some(FieldEncoder::WrapperString { tag, col })
2227        }
2228        "google.protobuf.BytesValue" => {
2229            let col = make_binary_col_ref(array)?;
2230            Some(FieldEncoder::WrapperBytes { tag, col })
2231        }
2232        _ => {
2233            let struct_arr = array.as_any().downcast_ref::<StructArray>()?;
2234            let sub_encoder = MessageEncoder::from_struct_array(msg_desc, struct_arr);
2235            Some(FieldEncoder::Message {
2236                tag,
2237                struct_arr,
2238                sub_encoder,
2239            })
2240        }
2241    }
2242}
2243
2244fn build_timestamp_encoder(tag: u32, array: &dyn Array) -> Option<FieldEncoder<'_>> {
2245    let unit = match array.data_type() {
2246        DataType::Timestamp(u, _) => *u,
2247        _ => return None,
2248    };
2249    let wk = match unit {
2250        TimeUnit::Second => WellKnownPrimitiveArray::Second(array.as_any().downcast_ref()?),
2251        TimeUnit::Millisecond => {
2252            WellKnownPrimitiveArray::Millisecond(array.as_any().downcast_ref()?)
2253        }
2254        TimeUnit::Microsecond => {
2255            WellKnownPrimitiveArray::Microsecond(array.as_any().downcast_ref()?)
2256        }
2257        TimeUnit::Nanosecond => WellKnownPrimitiveArray::Nanosecond(array.as_any().downcast_ref()?),
2258    };
2259    Some(FieldEncoder::Timestamp {
2260        tag,
2261        unit,
2262        array: wk,
2263    })
2264}
2265
2266fn build_duration_encoder(tag: u32, array: &dyn Array) -> Option<FieldEncoder<'_>> {
2267    let unit = match array.data_type() {
2268        DataType::Duration(u) => *u,
2269        _ => return None,
2270    };
2271    let wk = match unit {
2272        TimeUnit::Second => WellKnownPrimitiveArray::DurSecond(array.as_any().downcast_ref()?),
2273        TimeUnit::Millisecond => {
2274            WellKnownPrimitiveArray::DurMillisecond(array.as_any().downcast_ref()?)
2275        }
2276        TimeUnit::Microsecond => {
2277            WellKnownPrimitiveArray::DurMicrosecond(array.as_any().downcast_ref()?)
2278        }
2279        TimeUnit::Nanosecond => {
2280            WellKnownPrimitiveArray::DurNanosecond(array.as_any().downcast_ref()?)
2281        }
2282    };
2283    Some(FieldEncoder::Duration {
2284        tag,
2285        unit,
2286        array: wk,
2287    })
2288}
2289
2290fn build_time_of_day_array(array: &dyn Array) -> Option<TimeOfDayArray<'_>> {
2291    match array.data_type() {
2292        DataType::Time32(TimeUnit::Second) => {
2293            Some(TimeOfDayArray::Time32Second(array.as_any().downcast_ref()?))
2294        }
2295        DataType::Time32(TimeUnit::Millisecond) => Some(TimeOfDayArray::Time32Millisecond(
2296            array.as_any().downcast_ref()?,
2297        )),
2298        DataType::Time64(TimeUnit::Microsecond) => Some(TimeOfDayArray::Time64Microsecond(
2299            array.as_any().downcast_ref()?,
2300        )),
2301        DataType::Time64(TimeUnit::Nanosecond) => Some(TimeOfDayArray::Time64Nanosecond(
2302            array.as_any().downcast_ref()?,
2303        )),
2304        _ => None,
2305    }
2306}
2307
2308// ---------------------------------------------------------------------------
2309// Repeated field encoder construction
2310// ---------------------------------------------------------------------------
2311
2312fn build_repeated_encoder<'a>(
2313    field: &FieldDescriptor,
2314    array: &'a dyn Array,
2315) -> Option<FieldEncoder<'a>> {
2316    let tag = field.number();
2317    let list = GenericListArray::from_array(array)?;
2318    let values: &'a dyn Array = match &list {
2319        GenericListArray::Regular(a) => a.values().as_ref(),
2320        GenericListArray::Large(a) => a.values().as_ref(),
2321    };
2322
2323    match field.kind() {
2324        Kind::Int32 => {
2325            let arr = values
2326                .as_any()
2327                .downcast_ref::<PrimitiveArray<Int32Type>>()?;
2328            Some(FieldEncoder::RepeatedPacked {
2329                tag,
2330                list,
2331                encoder: PackedEncoder::Int32(arr),
2332            })
2333        }
2334        Kind::Sint32 => {
2335            let arr = values
2336                .as_any()
2337                .downcast_ref::<PrimitiveArray<Int32Type>>()?;
2338            Some(FieldEncoder::RepeatedPacked {
2339                tag,
2340                list,
2341                encoder: PackedEncoder::Sint32(arr),
2342            })
2343        }
2344        Kind::Sfixed32 => {
2345            let arr = values
2346                .as_any()
2347                .downcast_ref::<PrimitiveArray<Int32Type>>()?;
2348            Some(FieldEncoder::RepeatedPacked {
2349                tag,
2350                list,
2351                encoder: PackedEncoder::Sfixed32(arr),
2352            })
2353        }
2354        Kind::Int64 => {
2355            let arr = values
2356                .as_any()
2357                .downcast_ref::<PrimitiveArray<Int64Type>>()?;
2358            Some(FieldEncoder::RepeatedPacked {
2359                tag,
2360                list,
2361                encoder: PackedEncoder::Int64(arr),
2362            })
2363        }
2364        Kind::Sint64 => {
2365            let arr = values
2366                .as_any()
2367                .downcast_ref::<PrimitiveArray<Int64Type>>()?;
2368            Some(FieldEncoder::RepeatedPacked {
2369                tag,
2370                list,
2371                encoder: PackedEncoder::Sint64(arr),
2372            })
2373        }
2374        Kind::Sfixed64 => {
2375            let arr = values
2376                .as_any()
2377                .downcast_ref::<PrimitiveArray<Int64Type>>()?;
2378            Some(FieldEncoder::RepeatedPacked {
2379                tag,
2380                list,
2381                encoder: PackedEncoder::Sfixed64(arr),
2382            })
2383        }
2384        Kind::Uint32 => {
2385            let arr = values
2386                .as_any()
2387                .downcast_ref::<PrimitiveArray<UInt32Type>>()?;
2388            Some(FieldEncoder::RepeatedPacked {
2389                tag,
2390                list,
2391                encoder: PackedEncoder::UInt32(arr),
2392            })
2393        }
2394        Kind::Fixed32 => {
2395            let arr = values
2396                .as_any()
2397                .downcast_ref::<PrimitiveArray<UInt32Type>>()?;
2398            Some(FieldEncoder::RepeatedPacked {
2399                tag,
2400                list,
2401                encoder: PackedEncoder::Fixed32(arr),
2402            })
2403        }
2404        Kind::Uint64 => {
2405            let arr = values
2406                .as_any()
2407                .downcast_ref::<PrimitiveArray<UInt64Type>>()?;
2408            Some(FieldEncoder::RepeatedPacked {
2409                tag,
2410                list,
2411                encoder: PackedEncoder::UInt64(arr),
2412            })
2413        }
2414        Kind::Fixed64 => {
2415            let arr = values
2416                .as_any()
2417                .downcast_ref::<PrimitiveArray<UInt64Type>>()?;
2418            Some(FieldEncoder::RepeatedPacked {
2419                tag,
2420                list,
2421                encoder: PackedEncoder::Fixed64(arr),
2422            })
2423        }
2424        Kind::Float => {
2425            let arr = values
2426                .as_any()
2427                .downcast_ref::<PrimitiveArray<Float32Type>>()?;
2428            Some(FieldEncoder::RepeatedPacked {
2429                tag,
2430                list,
2431                encoder: PackedEncoder::Float32(arr),
2432            })
2433        }
2434        Kind::Double => {
2435            let arr = values
2436                .as_any()
2437                .downcast_ref::<PrimitiveArray<Float64Type>>()?;
2438            Some(FieldEncoder::RepeatedPacked {
2439                tag,
2440                list,
2441                encoder: PackedEncoder::Float64(arr),
2442            })
2443        }
2444        Kind::Bool => {
2445            let arr = values.as_any().downcast_ref::<BooleanArray>()?;
2446            Some(FieldEncoder::RepeatedBool {
2447                tag,
2448                list,
2449                values: arr,
2450            })
2451        }
2452        Kind::String => {
2453            let col = make_string_col_ref(values)?;
2454            Some(FieldEncoder::RepeatedString { tag, list, col })
2455        }
2456        Kind::Bytes => {
2457            let col = make_binary_col_ref(values)?;
2458            Some(FieldEncoder::RepeatedBytes { tag, list, col })
2459        }
2460        Kind::Enum(enum_desc) => build_repeated_enum_encoder(tag, list, values, &enum_desc),
2461        Kind::Message(msg_desc) => build_repeated_message_encoder(tag, list, values, &msg_desc),
2462    }
2463}
2464
2465fn build_repeated_enum_encoder<'a>(
2466    tag: u32,
2467    list: GenericListArray<'a>,
2468    values: &'a dyn Array,
2469    enum_desc: &EnumDescriptor,
2470) -> Option<FieldEncoder<'a>> {
2471    match values.data_type() {
2472        DataType::Int32 => {
2473            let arr = values
2474                .as_any()
2475                .downcast_ref::<PrimitiveArray<Int32Type>>()?;
2476            Some(FieldEncoder::RepeatedEnumInt32 {
2477                tag,
2478                list,
2479                values: arr,
2480            })
2481        }
2482        DataType::Utf8 | DataType::LargeUtf8 => {
2483            let col = make_string_col_ref(values)?;
2484            Some(FieldEncoder::RepeatedEnumString {
2485                tag,
2486                list,
2487                col,
2488                enum_descriptor: enum_desc.clone(),
2489            })
2490        }
2491        DataType::Binary | DataType::LargeBinary => {
2492            let col = make_binary_col_ref(values)?;
2493            Some(FieldEncoder::RepeatedEnumBinary {
2494                tag,
2495                list,
2496                col,
2497                enum_descriptor: enum_desc.clone(),
2498            })
2499        }
2500        _ => None,
2501    }
2502}
2503
2504fn build_repeated_message_encoder<'a>(
2505    tag: u32,
2506    list: GenericListArray<'a>,
2507    values: &'a dyn Array,
2508    msg_desc: &MessageDescriptor,
2509) -> Option<FieldEncoder<'a>> {
2510    match msg_desc.full_name() {
2511        "google.protobuf.Timestamp" => {
2512            let unit = match values.data_type() {
2513                DataType::Timestamp(u, _) => *u,
2514                _ => return None,
2515            };
2516            let wk = match unit {
2517                TimeUnit::Second => {
2518                    WellKnownPrimitiveArray::Second(values.as_any().downcast_ref()?)
2519                }
2520                TimeUnit::Millisecond => {
2521                    WellKnownPrimitiveArray::Millisecond(values.as_any().downcast_ref()?)
2522                }
2523                TimeUnit::Microsecond => {
2524                    WellKnownPrimitiveArray::Microsecond(values.as_any().downcast_ref()?)
2525                }
2526                TimeUnit::Nanosecond => {
2527                    WellKnownPrimitiveArray::Nanosecond(values.as_any().downcast_ref()?)
2528                }
2529            };
2530            Some(FieldEncoder::RepeatedTimestamp {
2531                tag,
2532                list,
2533                unit,
2534                values: wk,
2535            })
2536        }
2537        "google.protobuf.Duration" => {
2538            let unit = match values.data_type() {
2539                DataType::Duration(u) => *u,
2540                _ => return None,
2541            };
2542            let wk = match unit {
2543                TimeUnit::Second => {
2544                    WellKnownPrimitiveArray::DurSecond(values.as_any().downcast_ref()?)
2545                }
2546                TimeUnit::Millisecond => {
2547                    WellKnownPrimitiveArray::DurMillisecond(values.as_any().downcast_ref()?)
2548                }
2549                TimeUnit::Microsecond => {
2550                    WellKnownPrimitiveArray::DurMicrosecond(values.as_any().downcast_ref()?)
2551                }
2552                TimeUnit::Nanosecond => {
2553                    WellKnownPrimitiveArray::DurNanosecond(values.as_any().downcast_ref()?)
2554                }
2555            };
2556            Some(FieldEncoder::RepeatedDuration {
2557                tag,
2558                list,
2559                unit,
2560                values: wk,
2561            })
2562        }
2563        "google.type.Date" => {
2564            let arr = values
2565                .as_any()
2566                .downcast_ref::<PrimitiveArray<Date32Type>>()?;
2567            Some(FieldEncoder::RepeatedDate {
2568                tag,
2569                list,
2570                values: arr,
2571            })
2572        }
2573        "google.type.TimeOfDay" => {
2574            let ta = build_time_of_day_array(values)?;
2575            Some(FieldEncoder::RepeatedTimeOfDay {
2576                tag,
2577                list,
2578                values: ta,
2579            })
2580        }
2581        "google.protobuf.DoubleValue" => Some(FieldEncoder::RepeatedWrapperDouble {
2582            tag,
2583            list,
2584            values: values.as_any().downcast_ref()?,
2585        }),
2586        "google.protobuf.FloatValue" => Some(FieldEncoder::RepeatedWrapperFloat {
2587            tag,
2588            list,
2589            values: values.as_any().downcast_ref()?,
2590        }),
2591        "google.protobuf.Int64Value" => Some(FieldEncoder::RepeatedWrapperInt64 {
2592            tag,
2593            list,
2594            values: values.as_any().downcast_ref()?,
2595        }),
2596        "google.protobuf.UInt64Value" => Some(FieldEncoder::RepeatedWrapperUInt64 {
2597            tag,
2598            list,
2599            values: values.as_any().downcast_ref()?,
2600        }),
2601        "google.protobuf.Int32Value" => Some(FieldEncoder::RepeatedWrapperInt32 {
2602            tag,
2603            list,
2604            values: values.as_any().downcast_ref()?,
2605        }),
2606        "google.protobuf.UInt32Value" => Some(FieldEncoder::RepeatedWrapperUInt32 {
2607            tag,
2608            list,
2609            values: values.as_any().downcast_ref()?,
2610        }),
2611        "google.protobuf.BoolValue" => Some(FieldEncoder::RepeatedWrapperBool {
2612            tag,
2613            list,
2614            values: values.as_any().downcast_ref()?,
2615        }),
2616        "google.protobuf.StringValue" => {
2617            let col = make_string_col_ref(values)?;
2618            Some(FieldEncoder::RepeatedWrapperString { tag, list, col })
2619        }
2620        "google.protobuf.BytesValue" => {
2621            let col = make_binary_col_ref(values)?;
2622            Some(FieldEncoder::RepeatedWrapperBytes { tag, list, col })
2623        }
2624        _ => {
2625            let struct_arr = values.as_any().downcast_ref::<StructArray>()?;
2626            let sub_encoder = MessageEncoder::from_struct_array(msg_desc, struct_arr);
2627            Some(FieldEncoder::RepeatedMessage {
2628                tag,
2629                list,
2630                sub_encoder,
2631            })
2632        }
2633    }
2634}
2635
2636// ---------------------------------------------------------------------------
2637// Map field encoder construction
2638// ---------------------------------------------------------------------------
2639
2640fn build_map_encoder<'a>(
2641    field: &FieldDescriptor,
2642    array: &'a dyn Array,
2643) -> Option<FieldEncoder<'a>> {
2644    let tag = field.number();
2645    let map_array = array.as_any().downcast_ref::<MapArray>()?;
2646
2647    let map_entry_descriptor = match field.kind() {
2648        Kind::Message(desc) => desc,
2649        _ => return None,
2650    };
2651    let key_field = map_entry_descriptor.get_field_by_name("key")?;
2652    let value_field = map_entry_descriptor.get_field_by_name("value")?;
2653
2654    let entries = map_array.entries();
2655    let key_array = entries.column_by_name("key")?;
2656    // Try "value" first, fall back to second struct field for custom map_value_name
2657    let value_array = entries
2658        .column_by_name("value")
2659        .or_else(|| entries.columns().get(1))?;
2660
2661    let key_encoder = build_map_key_encoder(key_array.as_ref(), &key_field)?;
2662    let value_encoder = build_map_value_encoder(value_array.as_ref(), &value_field)?;
2663
2664    Some(FieldEncoder::Map {
2665        tag,
2666        map_array,
2667        key_encoder,
2668        value_encoder,
2669    })
2670}
2671
2672fn build_map_key_encoder<'a>(
2673    array: &'a dyn Array,
2674    field: &FieldDescriptor,
2675) -> Option<MapKeyEncoder<'a>> {
2676    match field.kind() {
2677        Kind::String => Some(MapKeyEncoder::String(make_string_col_ref(array)?)),
2678        Kind::Int32 => Some(MapKeyEncoder::Int32(array.as_any().downcast_ref()?)),
2679        Kind::Sint32 => Some(MapKeyEncoder::Sint32(array.as_any().downcast_ref()?)),
2680        Kind::Sfixed32 => Some(MapKeyEncoder::Sfixed32(array.as_any().downcast_ref()?)),
2681        Kind::Int64 => Some(MapKeyEncoder::Int64(array.as_any().downcast_ref()?)),
2682        Kind::Sint64 => Some(MapKeyEncoder::Sint64(array.as_any().downcast_ref()?)),
2683        Kind::Sfixed64 => Some(MapKeyEncoder::Sfixed64(array.as_any().downcast_ref()?)),
2684        Kind::Uint32 => Some(MapKeyEncoder::UInt32(array.as_any().downcast_ref()?)),
2685        Kind::Fixed32 => Some(MapKeyEncoder::Fixed32(array.as_any().downcast_ref()?)),
2686        Kind::Uint64 => Some(MapKeyEncoder::UInt64(array.as_any().downcast_ref()?)),
2687        Kind::Fixed64 => Some(MapKeyEncoder::Fixed64(array.as_any().downcast_ref()?)),
2688        Kind::Bool => Some(MapKeyEncoder::Bool(array.as_any().downcast_ref()?)),
2689        _ => None,
2690    }
2691}
2692
2693fn build_map_value_encoder<'a>(
2694    array: &'a dyn Array,
2695    field: &FieldDescriptor,
2696) -> Option<MapValueEncoder<'a>> {
2697    match field.kind() {
2698        Kind::Double => Some(MapValueEncoder::Double(array.as_any().downcast_ref()?)),
2699        Kind::Float => Some(MapValueEncoder::Float(array.as_any().downcast_ref()?)),
2700        Kind::Int32 => Some(MapValueEncoder::Int32(array.as_any().downcast_ref()?)),
2701        Kind::Sint32 => Some(MapValueEncoder::Sint32(array.as_any().downcast_ref()?)),
2702        Kind::Sfixed32 => Some(MapValueEncoder::Sfixed32(array.as_any().downcast_ref()?)),
2703        Kind::Int64 => Some(MapValueEncoder::Int64(array.as_any().downcast_ref()?)),
2704        Kind::Sint64 => Some(MapValueEncoder::Sint64(array.as_any().downcast_ref()?)),
2705        Kind::Sfixed64 => Some(MapValueEncoder::Sfixed64(array.as_any().downcast_ref()?)),
2706        Kind::Uint32 => Some(MapValueEncoder::UInt32(array.as_any().downcast_ref()?)),
2707        Kind::Fixed32 => Some(MapValueEncoder::Fixed32(array.as_any().downcast_ref()?)),
2708        Kind::Uint64 => Some(MapValueEncoder::UInt64(array.as_any().downcast_ref()?)),
2709        Kind::Fixed64 => Some(MapValueEncoder::Fixed64(array.as_any().downcast_ref()?)),
2710        Kind::Bool => Some(MapValueEncoder::Bool(array.as_any().downcast_ref()?)),
2711        Kind::String => Some(MapValueEncoder::String(make_string_col_ref(array)?)),
2712        Kind::Bytes => Some(MapValueEncoder::Bytes(make_binary_col_ref(array)?)),
2713        Kind::Enum(enum_desc) => match array.data_type() {
2714            DataType::Int32 => Some(MapValueEncoder::EnumInt32(array.as_any().downcast_ref()?)),
2715            DataType::Utf8 | DataType::LargeUtf8 => Some(MapValueEncoder::EnumString(
2716                make_string_col_ref(array)?,
2717                enum_desc.clone(),
2718            )),
2719            DataType::Binary | DataType::LargeBinary => Some(MapValueEncoder::EnumBinary(
2720                make_binary_col_ref(array)?,
2721                enum_desc.clone(),
2722            )),
2723            _ => None,
2724        },
2725        Kind::Message(msg_desc) => build_map_value_message_encoder(array, &msg_desc),
2726    }
2727}
2728
2729fn build_map_value_message_encoder<'a>(
2730    array: &'a dyn Array,
2731    msg_desc: &MessageDescriptor,
2732) -> Option<MapValueEncoder<'a>> {
2733    match msg_desc.full_name() {
2734        "google.protobuf.Timestamp" => {
2735            let unit = match array.data_type() {
2736                DataType::Timestamp(u, _) => *u,
2737                _ => return None,
2738            };
2739            let wk = match unit {
2740                TimeUnit::Second => WellKnownPrimitiveArray::Second(array.as_any().downcast_ref()?),
2741                TimeUnit::Millisecond => {
2742                    WellKnownPrimitiveArray::Millisecond(array.as_any().downcast_ref()?)
2743                }
2744                TimeUnit::Microsecond => {
2745                    WellKnownPrimitiveArray::Microsecond(array.as_any().downcast_ref()?)
2746                }
2747                TimeUnit::Nanosecond => {
2748                    WellKnownPrimitiveArray::Nanosecond(array.as_any().downcast_ref()?)
2749                }
2750            };
2751            Some(MapValueEncoder::Timestamp(unit, wk))
2752        }
2753        "google.protobuf.Duration" => {
2754            let unit = match array.data_type() {
2755                DataType::Duration(u) => *u,
2756                _ => return None,
2757            };
2758            let wk = match unit {
2759                TimeUnit::Second => {
2760                    WellKnownPrimitiveArray::DurSecond(array.as_any().downcast_ref()?)
2761                }
2762                TimeUnit::Millisecond => {
2763                    WellKnownPrimitiveArray::DurMillisecond(array.as_any().downcast_ref()?)
2764                }
2765                TimeUnit::Microsecond => {
2766                    WellKnownPrimitiveArray::DurMicrosecond(array.as_any().downcast_ref()?)
2767                }
2768                TimeUnit::Nanosecond => {
2769                    WellKnownPrimitiveArray::DurNanosecond(array.as_any().downcast_ref()?)
2770                }
2771            };
2772            Some(MapValueEncoder::Duration(unit, wk))
2773        }
2774        "google.type.Date" => Some(MapValueEncoder::Date(array.as_any().downcast_ref()?)),
2775        "google.type.TimeOfDay" => {
2776            let ta = build_time_of_day_array(array)?;
2777            Some(MapValueEncoder::TimeOfDay(ta))
2778        }
2779        "google.protobuf.DoubleValue" => Some(MapValueEncoder::WrapperDouble(
2780            array.as_any().downcast_ref()?,
2781        )),
2782        "google.protobuf.FloatValue" => Some(MapValueEncoder::WrapperFloat(
2783            array.as_any().downcast_ref()?,
2784        )),
2785        "google.protobuf.Int64Value" => Some(MapValueEncoder::WrapperInt64(
2786            array.as_any().downcast_ref()?,
2787        )),
2788        "google.protobuf.UInt64Value" => Some(MapValueEncoder::WrapperUInt64(
2789            array.as_any().downcast_ref()?,
2790        )),
2791        "google.protobuf.Int32Value" => Some(MapValueEncoder::WrapperInt32(
2792            array.as_any().downcast_ref()?,
2793        )),
2794        "google.protobuf.UInt32Value" => Some(MapValueEncoder::WrapperUInt32(
2795            array.as_any().downcast_ref()?,
2796        )),
2797        "google.protobuf.BoolValue" => {
2798            Some(MapValueEncoder::WrapperBool(array.as_any().downcast_ref()?))
2799        }
2800        "google.protobuf.StringValue" => {
2801            Some(MapValueEncoder::WrapperString(make_string_col_ref(array)?))
2802        }
2803        "google.protobuf.BytesValue" => {
2804            Some(MapValueEncoder::WrapperBytes(make_binary_col_ref(array)?))
2805        }
2806        _ => {
2807            let struct_arr = array.as_any().downcast_ref::<StructArray>()?;
2808            let sub_encoder = MessageEncoder::from_struct_array(msg_desc, struct_arr);
2809            Some(MapValueEncoder::Message(struct_arr, sub_encoder))
2810        }
2811    }
2812}
2813
2814// ---------------------------------------------------------------------------
2815// Public API
2816// ---------------------------------------------------------------------------
2817
2818/// Encode a RecordBatch directly to protobuf wire format bytes.
2819///
2820/// Returns a BinaryArray (as ArrayData) where each element is the protobuf
2821/// encoding of the corresponding row. This skips DynamicMessage allocation
2822/// and writes wire format directly from Arrow arrays.
2823pub fn record_batch_to_array(batch: &RecordBatch, descriptor: &MessageDescriptor) -> ArrayData {
2824    let encoder = MessageEncoder::from_record_batch(descriptor, batch);
2825    let mut results = BinaryBuilder::new();
2826    let mut row_buf = Vec::new();
2827
2828    for idx in 0..batch.num_rows() {
2829        row_buf.clear();
2830        encoder.encode_row(idx, &mut row_buf);
2831        results.append_value(&row_buf);
2832    }
2833
2834    results.finish().to_data()
2835}