Skip to main content

fory_core/serializer/
array.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use super::codec::{
19    allows_missing_generics, field_ref_mode, field_types_compatible, generic_field_type, Codec,
20    CodecReadType,
21};
22use super::collection::{
23    write_collection_data, write_collection_value_data, DECL_ELEMENT_TYPE, HAS_NULL, IS_SAME_TYPE,
24    TRACKING_REF,
25};
26use super::primitive_list;
27use crate::context::{ReadContext, WriteContext};
28use crate::error::Error;
29use crate::meta::FieldType;
30use crate::resolver::{RefFlag, RefMode, TypeInfo, TypeResolver};
31use crate::serializer::{core::read_group_type_info, core::read_value_type_info, Serializer};
32use crate::type_id::{TypeId, SIZE_OF_REF_AND_TYPE};
33use std::marker::PhantomData;
34use std::mem::MaybeUninit;
35use std::rc::Rc;
36
37pub struct ArrayCodec<T, C, const N: usize, const NULLABLE: bool, const TRACK_REF: bool>(
38    PhantomData<(T, C)>,
39);
40
41struct ArrayInitGuard<T, const N: usize> {
42    values: [MaybeUninit<T>; N],
43    initialized: usize,
44}
45
46impl<T, const N: usize> ArrayInitGuard<T, N> {
47    #[inline(always)]
48    fn new() -> Self {
49        Self {
50            values: unsafe { MaybeUninit::uninit().assume_init() },
51            initialized: 0,
52        }
53    }
54
55    #[inline(always)]
56    fn push(&mut self, value: T) {
57        self.values[self.initialized].write(value);
58        self.initialized += 1;
59    }
60
61    #[inline(always)]
62    unsafe fn finish(self) -> [T; N] {
63        debug_assert_eq!(self.initialized, N);
64        let result = std::ptr::read(self.values.as_ptr().cast::<[T; N]>());
65        std::mem::forget(self);
66        result
67    }
68}
69
70impl<T, const N: usize> Drop for ArrayInitGuard<T, N> {
71    fn drop(&mut self) {
72        for value in &mut self.values[..self.initialized] {
73            unsafe {
74                value.assume_init_drop();
75            }
76        }
77    }
78}
79
80pub(super) fn try_init_array<T, E, const N: usize>(
81    mut read: impl FnMut() -> Result<T, E>,
82) -> Result<[T; N], E> {
83    let mut values = ArrayInitGuard::<T, N>::new();
84    for _ in 0..N {
85        values.push(read()?);
86    }
87    Ok(unsafe { values.finish() })
88}
89
90#[inline(always)]
91fn selected_array_type_id<T: 'static, S: Serializer<Target = T>>() -> Option<TypeId> {
92    primitive_list::array_type_id::<T, S>(false)
93}
94
95#[cold]
96#[inline(never)]
97fn array_len_mismatch(len: usize, expected: usize) -> Error {
98    Error::invalid_data(format!(
99        "Array length mismatch: expected {expected}, got {len}"
100    ))
101}
102
103#[cold]
104#[inline(never)]
105fn non_polymorphic_array() -> Error {
106    Error::type_error("Type inconsistent, target array element is not polymorphic")
107}
108
109#[cold]
110#[inline(never)]
111fn array_type_mismatch(expected: u32, actual: u32) -> Error {
112    Error::type_mismatch(expected, actual)
113}
114
115#[inline(always)]
116fn check_array_len(len: u32, expected: usize) -> Result<(), Error> {
117    let len = len as usize;
118    if len != expected {
119        return Err(array_len_mismatch(len, expected));
120    }
121    // N is compile-time and fixed-array reads do not allocate from this wire
122    // count; each concrete child body retains its own readability checks.
123    Ok(())
124}
125
126#[inline(always)]
127fn read_declared_items<T, C, const N: usize>(
128    context: &mut ReadContext,
129    element_type: &FieldType,
130    has_null: bool,
131) -> Result<[T; N], Error>
132where
133    T: 'static,
134    C: Codec<T>,
135{
136    try_init_array(|| {
137        if has_null && context.reader.read_i8()? == RefFlag::Null as i8 {
138            C::default_value(context)
139        } else {
140            C::read_data_with_type(context, element_type)
141        }
142    })
143}
144
145#[inline(always)]
146fn read_typed_items<T, C, const N: usize>(
147    context: &mut ReadContext,
148    read_type: &CodecReadType,
149    has_null: bool,
150) -> Result<[T; N], Error>
151where
152    T: 'static,
153    C: Codec<T>,
154{
155    try_init_array(|| {
156        if has_null && context.reader.read_i8()? == RefFlag::Null as i8 {
157            return C::default_value(context);
158        }
159        match read_type {
160            CodecReadType::Field(field_type) => C::read_data_with_type(context, field_type),
161            CodecReadType::TypeInfo(type_info) => C::read_data_with_type_info(context, type_info),
162        }
163    })
164}
165
166macro_rules! array_read_declared_dyn {
167    (value, $T:ty, $S:ty, $N:ident, $context:expr, $remote:expr, $ref_mode:expr, $has_null:expr, $track_ref:expr) => {
168        try_init_array(|| <$S as Serializer>::read($context, $ref_mode, false))
169    };
170    (field, $T:ty, $C:ty, $N:ident, $context:expr, $remote:expr, $ref_mode:expr, $has_null:expr, $track_ref:expr) => {{
171        let element_type = generic_field_type($remote, 0, "array")?;
172        if field_ref_mode(element_type) != $ref_mode {
173            return Err(array_ref_mismatch());
174        }
175        try_init_array(|| <$C as Codec<$T>>::read_field_with_type($context, element_type))
176    }};
177}
178
179macro_rules! array_read_declared {
180    (value, $T:ty, $S:ty, $N:ident, $context:expr, $remote:expr, $has_null:expr) => {
181        try_init_array(|| {
182            if $has_null && $context.reader.read_i8()? == RefFlag::Null as i8 {
183                <$S as Serializer>::default_value($context)
184            } else {
185                <$S as Serializer>::read_data($context)
186            }
187        })
188    };
189    (field, $T:ty, $C:ty, $N:ident, $context:expr, $remote:expr, $has_null:expr) => {{
190        let element_type = generic_field_type($remote, 0, "array")?;
191        read_declared_items::<$T, $C, $N>($context, element_type, $has_null)
192    }};
193}
194
195macro_rules! array_read_typed {
196    (value, $T:ty, $S:ty, $N:ident, $context:expr, $has_null:expr) => {{
197        let type_info = read_value_type_info::<$S, false>($context)?;
198        try_init_array(|| {
199            if $has_null && $context.reader.read_i8()? == RefFlag::Null as i8 {
200                return <$S as Serializer>::default_value($context);
201            }
202            match type_info.as_ref() {
203                Some(type_info) => {
204                    <$S as Serializer>::read_with_type_info($context, RefMode::None, type_info)
205                }
206                None => <$S as Serializer>::read_data($context),
207            }
208        })
209    }};
210    (field, $T:ty, $C:ty, $N:ident, $context:expr, $has_null:expr) => {{
211        let read_type = <$C as Codec<$T>>::read_type_info_value($context)?;
212        read_typed_items::<$T, $C, $N>($context, &read_type, $has_null)
213    }};
214}
215
216macro_rules! array_group_type_info {
217    (value, $C:ty, $context:expr) => {
218        read_group_type_info::<$C, false>($context)
219    };
220    (field, $C:ty, $context:expr) => {
221        read_group_type_info::<$C, true>($context)
222    };
223}
224
225macro_rules! read_object_array_body {
226    ($layer:ident, $T:ident, $C:ident, $N:ident, $context:expr, $remote:expr) => {{
227        let context = $context;
228        let len = context.reader.read_var_u32()?;
229        check_array_len(len, $N)?;
230        if $N == 0 {
231            return try_init_array(|| unreachable!());
232        }
233        let header = context.reader.read_u8()?;
234        let track_ref = (header & TRACKING_REF) != 0;
235        let same_type = (header & IS_SAME_TYPE) != 0;
236        let has_null = (header & HAS_NULL) != 0;
237        let declared = (header & DECL_ELEMENT_TYPE) != 0;
238        let ref_mode = if track_ref {
239            RefMode::Tracking
240        } else if has_null {
241            RefMode::NullOnly
242        } else {
243            RefMode::None
244        };
245
246        if $C::IS_POLYMORPHIC || $C::IS_SHARED_REF {
247            if same_type {
248                if declared {
249                    return array_read_declared_dyn!(
250                        $layer, $T, $C, $N, context, $remote, ref_mode, has_null, track_ref
251                    );
252                }
253                let type_info = array_group_type_info!($layer, $C, context)?;
254                return try_init_array(|| {
255                    <$C as Serializer>::read_with_type_info(context, ref_mode, &type_info)
256                });
257            }
258            return try_init_array(|| <$C as Serializer>::read(context, ref_mode, true));
259        }
260
261        if !same_type {
262            return Err(non_polymorphic_array());
263        }
264        if declared {
265            return array_read_declared!($layer, $T, $C, $N, context, $remote, has_null);
266        }
267        array_read_typed!($layer, $T, $C, $N, context, has_null)
268    }};
269}
270
271#[inline(always)]
272fn read_value_object_array<T, S, const N: usize>(context: &mut ReadContext) -> Result<[T; N], Error>
273where
274    T: 'static,
275    S: Serializer<Target = T>,
276{
277    read_object_array_body!(value, T, S, N, context, ())
278}
279
280#[inline(always)]
281fn read_field_object_array<T, C, const N: usize>(
282    context: &mut ReadContext,
283    remote_field_type: &FieldType,
284) -> Result<[T; N], Error>
285where
286    T: 'static,
287    C: Codec<T>,
288{
289    read_object_array_body!(field, T, C, N, context, remote_field_type)
290}
291
292#[cold]
293#[inline(never)]
294fn array_ref_mismatch() -> Error {
295    Error::invalid_data("array header conflicts with declared element metadata")
296}
297
298impl<T, S, const N: usize, const NULLABLE: bool, const TRACK_REF: bool> Serializer
299    for ArrayCodec<T, S, N, NULLABLE, TRACK_REF>
300where
301    T: 'static,
302    S: Serializer<Target = T>,
303{
304    type Target = [T; N];
305
306    const READ_DATA_ALWAYS_ADVANCES: bool = true;
307
308    #[inline(always)]
309    fn write_data(value: &Self::Target, context: &mut WriteContext) -> Result<(), Error> {
310        if let Some(type_id) = selected_array_type_id::<T, S>() {
311            return primitive_list::write_data::<T, S>(value, context, type_id);
312        }
313        write_collection_value_data::<T, S, _, false, true>(value.iter(), context)
314    }
315
316    #[inline(always)]
317    fn read_data(context: &mut ReadContext) -> Result<Self::Target, Error> {
318        if let Some(type_id) = selected_array_type_id::<T, S>() {
319            return primitive_list::read_array::<T, S, N>(context, type_id);
320        }
321        read_value_object_array::<T, S, N>(context)
322    }
323
324    #[inline(always)]
325    fn default_value(context: &mut ReadContext) -> Result<Self::Target, Error> {
326        try_init_array(|| S::default_value(context))
327    }
328
329    #[inline(always)]
330    fn write_type_info(context: &mut WriteContext) -> Result<(), Error> {
331        match selected_array_type_id::<T, S>() {
332            Some(type_id) => primitive_list::write_type_info(context, type_id),
333            None => {
334                context.writer.write_u8(TypeId::LIST as u8);
335                Ok(())
336            }
337        }
338    }
339
340    #[inline(always)]
341    fn read_type_info(context: &mut ReadContext) -> Result<(), Error> {
342        match selected_array_type_id::<T, S>() {
343            Some(type_id) => primitive_list::read_type_info(context, type_id),
344            None => {
345                let remote = context.reader.read_u8()? as u32;
346                if remote != TypeId::LIST as u32 {
347                    return Err(array_type_mismatch(TypeId::LIST as u32, remote));
348                }
349                Ok(())
350            }
351        }
352    }
353
354    #[inline(always)]
355    fn static_type_id() -> TypeId {
356        selected_array_type_id::<T, S>().unwrap_or(TypeId::LIST)
357    }
358
359    #[inline(always)]
360    fn reserved_space() -> usize {
361        match selected_array_type_id::<T, S>() {
362            Some(_) => std::mem::size_of::<T>() * N + SIZE_OF_REF_AND_TYPE,
363            None => std::mem::size_of::<u32>() + SIZE_OF_REF_AND_TYPE,
364        }
365    }
366}
367
368impl<T, C, const N: usize, const NULLABLE: bool, const TRACK_REF: bool> Codec<[T; N]>
369    for ArrayCodec<T, C, N, NULLABLE, TRACK_REF>
370where
371    T: 'static,
372    C: Codec<T>,
373{
374    #[inline(always)]
375    fn field_type(type_resolver: &TypeResolver) -> Result<FieldType, Error> {
376        if let Some(type_id) = selected_array_type_id::<T, C>() {
377            return Ok(FieldType::new_with_ref(
378                type_id as u32,
379                NULLABLE,
380                TRACK_REF,
381                Vec::new(),
382            ));
383        }
384        Ok(FieldType::new_with_ref(
385            TypeId::LIST as u32,
386            NULLABLE,
387            TRACK_REF,
388            vec![C::field_type(type_resolver)?],
389        ))
390    }
391
392    #[inline(always)]
393    fn write_field(value: &[T; N], context: &mut WriteContext) -> Result<(), Error> {
394        if NULLABLE || TRACK_REF {
395            context.writer.write_i8(RefFlag::NotNullValue as i8);
396        }
397        if selected_array_type_id::<T, C>().is_some() {
398            <Self as Serializer>::write_data(value, context)
399        } else {
400            write_collection_data::<T, C, _, false, true>(value.iter(), context, true)
401        }
402    }
403
404    #[inline(always)]
405    fn read_field(context: &mut ReadContext) -> Result<[T; N], Error> {
406        if (NULLABLE || TRACK_REF) && context.reader.read_i8()? == RefFlag::Null as i8 {
407            return <Self as Serializer>::default_value(context);
408        }
409        <Self as Serializer>::read_data(context)
410    }
411
412    #[inline(always)]
413    fn read_compatible(
414        context: &mut ReadContext,
415        local_field_type: &FieldType,
416        remote_field_type: &FieldType,
417    ) -> Result<Option<[T; N]>, Error> {
418        if field_types_compatible(local_field_type, remote_field_type)
419            || local_field_type.compatible_shape_match(remote_field_type)
420            || (local_field_type.type_id == remote_field_type.type_id
421                && allows_missing_generics(local_field_type.type_id)
422                && (local_field_type.generics.is_empty() || remote_field_type.generics.is_empty()))
423        {
424            return Self::read_field_with_type(context, remote_field_type).map(Some);
425        }
426        Ok(None)
427    }
428
429    #[inline(always)]
430    fn read_data_with_type(
431        context: &mut ReadContext,
432        remote_data_type: &FieldType,
433    ) -> Result<[T; N], Error> {
434        if let Some(type_id) = selected_array_type_id::<T, C>() {
435            if remote_data_type.type_id != TypeId::LIST as u32 {
436                return primitive_list::read_array::<T, C, N>(context, type_id);
437            }
438        }
439        read_field_object_array::<T, C, N>(context, remote_data_type)
440    }
441
442    #[inline(always)]
443    fn read_field_with_type(
444        context: &mut ReadContext,
445        remote_field_type: &FieldType,
446    ) -> Result<[T; N], Error> {
447        if field_ref_mode(remote_field_type) != RefMode::None
448            && context.reader.read_i8()? == RefFlag::Null as i8
449        {
450            return <Self as Serializer>::default_value(context);
451        }
452        Self::read_data_with_type(context, remote_field_type)
453    }
454
455    #[inline(always)]
456    fn write_with_mode(
457        value: &[T; N],
458        context: &mut WriteContext,
459        ref_mode: RefMode,
460        write_type_info: bool,
461        has_generics: bool,
462    ) -> Result<(), Error> {
463        if selected_array_type_id::<T, C>().is_some() || !has_generics {
464            return <Self as Serializer>::write(value, context, ref_mode, write_type_info);
465        }
466        if ref_mode != RefMode::None {
467            context.writer.write_i8(RefFlag::NotNullValue as i8);
468        }
469        if write_type_info {
470            <Self as Serializer>::write_type_info(context)?;
471        }
472        write_collection_data::<T, C, _, false, true>(value.iter(), context, true)
473    }
474}
475
476type RootArrayCodec<S, const N: usize> = ArrayCodec<<S as Serializer>::Target, S, N, false, false>;
477
478/// Statically serializes `[S::Target; N]` at roots or recursive carrier nodes.
479///
480/// This zero-sized carrier composes the child serializer `S` and is not
481/// registered independently.
482pub struct ArraySerializer<S, const N: usize>(PhantomData<fn() -> S>);
483
484impl<S: Serializer, const N: usize> Serializer for ArraySerializer<S, N> {
485    type Target = [S::Target; N];
486
487    const READ_DATA_ALWAYS_ADVANCES: bool = true;
488
489    #[inline(always)]
490    fn write_data(value: &Self::Target, context: &mut WriteContext) -> Result<(), Error> {
491        <RootArrayCodec<S, N> as Serializer>::write_data(value, context)
492    }
493
494    #[inline(always)]
495    fn read_data(context: &mut ReadContext) -> Result<Self::Target, Error> {
496        <RootArrayCodec<S, N> as Serializer>::read_data(context)
497    }
498
499    #[inline(always)]
500    fn default_value(context: &mut ReadContext) -> Result<Self::Target, Error> {
501        <RootArrayCodec<S, N> as Serializer>::default_value(context)
502    }
503
504    #[inline(always)]
505    fn write(
506        value: &Self::Target,
507        context: &mut WriteContext,
508        ref_mode: RefMode,
509        write_type_info: bool,
510    ) -> Result<(), Error> {
511        <RootArrayCodec<S, N> as Serializer>::write(value, context, ref_mode, write_type_info)
512    }
513
514    #[inline(always)]
515    fn read(
516        context: &mut ReadContext,
517        ref_mode: RefMode,
518        read_type_info: bool,
519    ) -> Result<Self::Target, Error> {
520        <RootArrayCodec<S, N> as Serializer>::read(context, ref_mode, read_type_info)
521    }
522
523    #[inline(always)]
524    fn read_with_type_info(
525        context: &mut ReadContext,
526        ref_mode: RefMode,
527        type_info: &Rc<TypeInfo>,
528    ) -> Result<Self::Target, Error> {
529        <RootArrayCodec<S, N> as Serializer>::read_with_type_info(context, ref_mode, type_info)
530    }
531
532    #[inline(always)]
533    fn write_type_info(context: &mut WriteContext) -> Result<(), Error> {
534        <RootArrayCodec<S, N> as Serializer>::write_type_info(context)
535    }
536
537    #[inline(always)]
538    fn read_type_info(context: &mut ReadContext) -> Result<(), Error> {
539        <RootArrayCodec<S, N> as Serializer>::read_type_info(context)
540    }
541
542    #[inline(always)]
543    fn static_type_id() -> TypeId {
544        <RootArrayCodec<S, N> as Serializer>::static_type_id()
545    }
546
547    #[inline(always)]
548    fn reserved_space() -> usize {
549        <RootArrayCodec<S, N> as Serializer>::reserved_space()
550    }
551}
552
553impl<T, const N: usize> Serializer for [T; N]
554where
555    T: Serializer<Target = T>,
556{
557    type Target = Self;
558
559    const READ_DATA_ALWAYS_ADVANCES: bool = true;
560
561    #[inline(always)]
562    fn write_data(value: &Self, context: &mut WriteContext) -> Result<(), Error> {
563        <ArraySerializer<T, N> as Serializer>::write_data(value, context)
564    }
565
566    #[inline(always)]
567    fn read_data(context: &mut ReadContext) -> Result<Self, Error> {
568        <ArraySerializer<T, N> as Serializer>::read_data(context)
569    }
570
571    #[inline(always)]
572    fn default_value(context: &mut ReadContext) -> Result<Self, Error> {
573        <ArraySerializer<T, N> as Serializer>::default_value(context)
574    }
575
576    #[inline(always)]
577    fn write(
578        value: &Self,
579        context: &mut WriteContext,
580        ref_mode: RefMode,
581        write_type_info: bool,
582    ) -> Result<(), Error> {
583        <ArraySerializer<T, N> as Serializer>::write(value, context, ref_mode, write_type_info)
584    }
585
586    #[inline(always)]
587    fn read(
588        context: &mut ReadContext,
589        ref_mode: RefMode,
590        read_type_info: bool,
591    ) -> Result<Self, Error> {
592        <ArraySerializer<T, N> as Serializer>::read(context, ref_mode, read_type_info)
593    }
594
595    #[inline(always)]
596    fn read_with_type_info(
597        context: &mut ReadContext,
598        ref_mode: RefMode,
599        type_info: &Rc<TypeInfo>,
600    ) -> Result<Self, Error> {
601        <ArraySerializer<T, N> as Serializer>::read_with_type_info(context, ref_mode, type_info)
602    }
603
604    #[inline(always)]
605    fn write_type_info(context: &mut WriteContext) -> Result<(), Error> {
606        <ArraySerializer<T, N> as Serializer>::write_type_info(context)
607    }
608
609    #[inline(always)]
610    fn read_type_info(context: &mut ReadContext) -> Result<(), Error> {
611        <ArraySerializer<T, N> as Serializer>::read_type_info(context)
612    }
613
614    #[inline(always)]
615    fn static_type_id() -> TypeId {
616        <ArraySerializer<T, N> as Serializer>::static_type_id()
617    }
618
619    #[inline(always)]
620    fn reserved_space() -> usize {
621        <ArraySerializer<T, N> as Serializer>::reserved_space()
622    }
623}