Skip to main content

fory_core/serializer/
map.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    field_ref_mode, field_type_with_ref_flags, generic_field_type, Codec, CodecReadType,
20};
21use super::collection::{field_read_data_always_advances, settle_unbacked_items};
22use crate::context::{ReadContext, WriteContext};
23use crate::error::Error;
24use crate::meta::FieldType;
25use crate::resolver::{RefFlag, RefMode, TypeInfo, TypeResolver};
26use crate::serializer::{core::read_value_type_info, Serializer};
27use crate::type_id::{need_to_write_type_for_field, TypeId, SIZE_OF_REF_AND_TYPE};
28use std::borrow::Cow;
29use std::collections::{BTreeMap, HashMap};
30use std::marker::PhantomData;
31use std::rc::Rc;
32
33const MAX_CHUNK_SIZE: u8 = 255;
34pub(crate) const TRACKING_KEY_REF: u8 = 0b1;
35pub(crate) const KEY_NULL: u8 = 0b10;
36pub(crate) const DECL_KEY_TYPE: u8 = 0b100;
37pub(crate) const TRACKING_VALUE_REF: u8 = 0b1000;
38pub(crate) const VALUE_NULL: u8 = 0b10000;
39pub(crate) const DECL_VALUE_TYPE: u8 = 0b100000;
40
41pub struct BTreeMapCodec<K, V, KC, VC, const NULLABLE: bool, const TRACK_REF: bool>(
42    PhantomData<(K, V, KC, VC)>,
43);
44
45pub struct HashMapCodec<K, V, KC, VC, const NULLABLE: bool, const TRACK_REF: bool>(
46    PhantomData<(K, V, KC, VC)>,
47);
48
49trait MapTarget<K, V>: Sized {
50    fn with_capacity(capacity: usize) -> Self;
51    fn insert(&mut self, key: K, value: V);
52}
53
54impl<K: Eq + std::hash::Hash, V> MapTarget<K, V> for HashMap<K, V> {
55    #[inline(always)]
56    fn with_capacity(capacity: usize) -> Self {
57        HashMap::with_capacity(capacity)
58    }
59
60    #[inline(always)]
61    fn insert(&mut self, key: K, value: V) {
62        HashMap::insert(self, key, value);
63    }
64}
65
66impl<K: Ord, V> MapTarget<K, V> for BTreeMap<K, V> {
67    #[inline(always)]
68    fn with_capacity(_: usize) -> Self {
69        BTreeMap::new()
70    }
71
72    #[inline(always)]
73    fn insert(&mut self, key: K, value: V) {
74        BTreeMap::insert(self, key, value);
75    }
76}
77
78#[inline(always)]
79fn write_entry_type<T: 'static, S: Serializer<Target = T>>(
80    context: &mut WriteContext,
81    target_type_id: Option<std::any::TypeId>,
82) -> Result<Option<Rc<TypeInfo>>, Error> {
83    if let Some(target_type_id) = target_type_id {
84        S::write_type_info_value(context, target_type_id).map(Some)
85    } else {
86        S::write_type_info(context)?;
87        Ok(None)
88    }
89}
90
91macro_rules! map_write_mode {
92    (value, $T:ty, $S:ty, $value:expr, $context:expr, $ref_mode:expr, $write_type:expr, $has_generics:expr) => {
93        <$S as Serializer>::write($value, $context, $ref_mode, $write_type)
94    };
95    (field, $T:ty, $C:ty, $value:expr, $context:expr, $ref_mode:expr, $write_type:expr, $has_generics:expr) => {
96        <$C as Codec<$T>>::write_with_mode($value, $context, $ref_mode, $write_type, $has_generics)
97    };
98}
99
100macro_rules! map_write_with_info {
101    (value, $T:ty, $S:ty, $value:expr, $context:expr, $ref_mode:expr, $type_info:expr, $has_generics:expr) => {
102        <$S as Serializer>::write_with_type_info($value, $context, $ref_mode, $type_info)
103    };
104    (field, $T:ty, $C:ty, $value:expr, $context:expr, $ref_mode:expr, $type_info:expr, $has_generics:expr) => {
105        <$C as Codec<$T>>::write_with_type_info(
106            $value,
107            $context,
108            $ref_mode,
109            $type_info,
110            $has_generics,
111        )
112    };
113}
114
115macro_rules! map_write_entry {
116    ($layer:ident, $T:ty, $C:ty, $value:expr, $context:expr, $track_ref:expr, $has_generics:expr, $type_info:expr) => {{
117        let ref_mode = if $track_ref {
118            RefMode::Tracking
119        } else {
120            RefMode::None
121        };
122        if let Some(type_info) = $type_info {
123            map_write_with_info!(
124                $layer,
125                $T,
126                $C,
127                $value,
128                $context,
129                ref_mode,
130                type_info,
131                $has_generics
132            )
133        } else {
134            map_write_mode!(
135                $layer,
136                $T,
137                $C,
138                $value,
139                $context,
140                ref_mode,
141                false,
142                $has_generics
143            )
144        }
145    }};
146}
147
148macro_rules! map_reserved_space {
149    (value, $T:ty, $S:ty) => {
150        <$S as Serializer>::reserved_space()
151    };
152    (field, $T:ty, $C:ty) => {
153        <$C as Codec<$T>>::field_reserved_space()
154    };
155}
156
157macro_rules! write_map_data_body {
158    (
159        $layer:ident,
160        $K:ident,
161        $V:ident,
162        $KC:ident,
163        $VC:ident,
164        $iter:expr,
165        $len:expr,
166        $context:expr,
167        $has_generics:expr
168    ) => {{
169        let context = $context;
170        let len = $len;
171        context.writer.write_var_u32(len as u32);
172        if len == 0 {
173            return Ok(());
174        }
175        context.writer.reserve(
176            len.saturating_mul(
177                map_reserved_space!($layer, $K, $KC)
178                    .saturating_add(map_reserved_space!($layer, $V, $VC)),
179            ),
180        );
181
182        let has_generics = $has_generics;
183        let key_declared = has_generics && !need_to_write_type_for_field($KC::static_type_id());
184        let value_declared = has_generics && !need_to_write_type_for_field($VC::static_type_id());
185        let key_polymorphic = $KC::IS_POLYMORPHIC;
186        let value_polymorphic = $VC::IS_POLYMORPHIC;
187        let key_shared = $KC::IS_SHARED_REF;
188        let value_shared = $VC::IS_SHARED_REF;
189        let mut key_type = None;
190        let mut value_type = None;
191        let mut key_info = None;
192        let mut value_info = None;
193        let mut header_offset = 0;
194        let mut pair_count = 0u8;
195        let mut need_header = true;
196
197        for (key, value) in $iter {
198            // MAP emits both type headers before either body. Holder serializers
199            // release this inspection immediately; resolved body writes
200            // revalidate the value, so matching entries can still share one
201            // chunk TypeInfo.
202            let next_key_type = if key_polymorphic {
203                $KC::dynamic_type_id(key)?
204            } else {
205                None
206            };
207            let next_value_type = if value_polymorphic {
208                $VC::dynamic_type_id(value)?
209            } else {
210                None
211            };
212            let key_none = if key_polymorphic {
213                next_key_type.is_none()
214            } else {
215                $KC::is_none(key)
216            };
217            let value_none = if value_polymorphic {
218                next_value_type.is_none()
219            } else {
220                $VC::is_none(value)
221            };
222            if key_none || value_none {
223                if pair_count != 0 {
224                    context.writer.set_bytes(header_offset + 1, &[pair_count]);
225                    pair_count = 0;
226                    need_header = true;
227                }
228                if key_none && value_none {
229                    context.writer.write_u8(KEY_NULL | VALUE_NULL);
230                    continue;
231                }
232                if value_none {
233                    let mut header = VALUE_NULL;
234                    if key_shared {
235                        header |= TRACKING_KEY_REF;
236                    }
237                    if key_declared && !key_polymorphic {
238                        header |= DECL_KEY_TYPE;
239                        context.writer.write_u8(header);
240                        map_write_entry!(
241                            $layer,
242                            $K,
243                            $KC,
244                            key,
245                            context,
246                            key_shared,
247                            has_generics,
248                            None
249                        )?;
250                    } else {
251                        context.writer.write_u8(header);
252                        if key_shared {
253                            map_write_mode!(
254                                $layer,
255                                $K,
256                                $KC,
257                                key,
258                                context,
259                                RefMode::Tracking,
260                                true,
261                                has_generics
262                            )?;
263                        } else {
264                            let key_info = write_entry_type::<$K, $KC>(context, next_key_type)?;
265                            map_write_entry!(
266                                $layer,
267                                $K,
268                                $KC,
269                                key,
270                                context,
271                                false,
272                                has_generics,
273                                key_info.as_ref()
274                            )?;
275                        }
276                    }
277                    continue;
278                }
279                let mut header = KEY_NULL;
280                if value_shared {
281                    header |= TRACKING_VALUE_REF;
282                }
283                if value_declared && !value_polymorphic {
284                    header |= DECL_VALUE_TYPE;
285                    context.writer.write_u8(header);
286                    map_write_entry!(
287                        $layer,
288                        $V,
289                        $VC,
290                        value,
291                        context,
292                        value_shared,
293                        has_generics,
294                        None
295                    )?;
296                } else {
297                    context.writer.write_u8(header);
298                    if value_shared {
299                        map_write_mode!(
300                            $layer,
301                            $V,
302                            $VC,
303                            value,
304                            context,
305                            RefMode::Tracking,
306                            true,
307                            has_generics
308                        )?;
309                    } else {
310                        let value_info = write_entry_type::<$V, $VC>(context, next_value_type)?;
311                        map_write_entry!(
312                            $layer,
313                            $V,
314                            $VC,
315                            value,
316                            context,
317                            false,
318                            has_generics,
319                            value_info.as_ref()
320                        )?;
321                    }
322                }
323                continue;
324            }
325
326            let types_changed = (key_polymorphic || value_polymorphic)
327                && (next_key_type != key_type || next_value_type != value_type);
328            if need_header || types_changed {
329                if pair_count != 0 {
330                    context.writer.set_bytes(header_offset + 1, &[pair_count]);
331                    pair_count = 0;
332                }
333                header_offset = context.writer.len();
334                context.writer.write_i16(-1);
335                let mut header = 0;
336                if key_shared {
337                    header |= TRACKING_KEY_REF;
338                }
339                if value_shared {
340                    header |= TRACKING_VALUE_REF;
341                }
342                if key_declared && !key_polymorphic {
343                    header |= DECL_KEY_TYPE;
344                    key_info = None;
345                } else {
346                    key_info = write_entry_type::<$K, $KC>(context, next_key_type)?;
347                }
348                if value_declared && !value_polymorphic {
349                    header |= DECL_VALUE_TYPE;
350                    value_info = None;
351                } else {
352                    value_info = write_entry_type::<$V, $VC>(context, next_value_type)?;
353                }
354                context.writer.set_bytes(header_offset, &[header]);
355                need_header = false;
356                key_type = next_key_type;
357                value_type = next_value_type;
358            }
359
360            map_write_entry!(
361                $layer,
362                $K,
363                $KC,
364                key,
365                context,
366                key_shared,
367                has_generics,
368                key_info.as_ref()
369            )?;
370            map_write_entry!(
371                $layer,
372                $V,
373                $VC,
374                value,
375                context,
376                value_shared,
377                has_generics,
378                value_info.as_ref()
379            )?;
380            pair_count += 1;
381            if pair_count == MAX_CHUNK_SIZE {
382                context.writer.set_bytes(header_offset + 1, &[pair_count]);
383                pair_count = 0;
384                need_header = true;
385                key_type = None;
386                value_type = None;
387                key_info = None;
388                value_info = None;
389            }
390        }
391        if pair_count != 0 {
392            context.writer.set_bytes(header_offset + 1, &[pair_count]);
393        }
394        Ok(())
395    }};
396}
397
398fn write_value_map_data<'a, K, V, KS, VS, I>(
399    iter: I,
400    len: usize,
401    context: &mut WriteContext,
402) -> Result<(), Error>
403where
404    K: 'static + 'a,
405    V: 'static + 'a,
406    KS: Serializer<Target = K>,
407    VS: Serializer<Target = V>,
408    I: Iterator<Item = (&'a K, &'a V)>,
409{
410    write_map_data_body!(value, K, V, KS, VS, iter, len, context, false)
411}
412
413fn write_field_map_data<'a, K, V, KC, VC, I>(
414    iter: I,
415    len: usize,
416    context: &mut WriteContext,
417    has_generics: bool,
418) -> Result<(), Error>
419where
420    K: 'static + 'a,
421    V: 'static + 'a,
422    KC: Codec<K>,
423    VC: Codec<V>,
424    I: Iterator<Item = (&'a K, &'a V)>,
425{
426    write_map_data_body!(field, K, V, KC, VC, iter, len, context, has_generics)
427}
428
429enum EntryReadType<'a> {
430    Direct,
431    Field(Cow<'a, FieldType>),
432    TypeInfo(Rc<TypeInfo>),
433}
434
435#[inline(always)]
436fn read_value_entry_type<T, S>(
437    context: &mut ReadContext,
438    declared: bool,
439) -> Result<Option<Rc<TypeInfo>>, Error>
440where
441    T: 'static,
442    S: Serializer<Target = T>,
443{
444    if declared {
445        return Ok(None);
446    }
447    read_value_type_info::<S>(context)
448}
449
450#[inline(always)]
451fn read_value_entry<T, S>(
452    context: &mut ReadContext,
453    read_type: &Option<Rc<TypeInfo>>,
454    track_ref: bool,
455) -> Result<T, Error>
456where
457    T: 'static,
458    S: Serializer<Target = T>,
459{
460    let ref_mode = if track_ref {
461        RefMode::Tracking
462    } else {
463        RefMode::None
464    };
465    match read_type {
466        None => S::read(context, ref_mode, false),
467        Some(type_info) => S::read_with_type_info(context, ref_mode, type_info),
468    }
469}
470
471#[inline(always)]
472fn read_entry_type<'a, T: 'static, C: Codec<T>>(
473    context: &mut ReadContext,
474    declared: bool,
475    remote_field_type: Option<&'a FieldType>,
476    index: usize,
477    track_ref: bool,
478) -> Result<EntryReadType<'a>, Error> {
479    if declared {
480        return match remote_field_type {
481            Some(field_type) => {
482                let field_type = generic_field_type(field_type, index, "map")?;
483                Ok(EntryReadType::Field(field_type_with_ref_flags(
484                    field_type,
485                    field_type.nullable,
486                    track_ref,
487                )))
488            }
489            None => Ok(EntryReadType::Direct),
490        };
491    }
492    match C::read_type_info_value(context)? {
493        CodecReadType::Field(mut field_type) => {
494            field_type.track_ref = track_ref;
495            Ok(EntryReadType::Field(Cow::Owned(field_type)))
496        }
497        CodecReadType::TypeInfo(type_info) => Ok(EntryReadType::TypeInfo(type_info)),
498    }
499}
500
501#[inline(always)]
502fn read_entry<T: 'static, C: Codec<T>>(
503    context: &mut ReadContext,
504    read_type: &EntryReadType<'_>,
505    track_ref: bool,
506) -> Result<T, Error> {
507    let ref_mode = if track_ref {
508        RefMode::Tracking
509    } else {
510        RefMode::None
511    };
512    match read_type {
513        EntryReadType::Direct => C::read(context, ref_mode, false),
514        EntryReadType::TypeInfo(type_info) => C::read_with_type_info(context, ref_mode, type_info),
515        EntryReadType::Field(field_type) if track_ref => {
516            C::read_field_with_type(context, field_type)
517        }
518        EntryReadType::Field(field_type) => C::read_data_with_type(context, field_type),
519    }
520}
521
522macro_rules! map_read_mode {
523    (value, $T:ty, $S:ty, $context:expr, $ref_mode:expr, $read_type:expr) => {
524        <$S as Serializer>::read($context, $ref_mode, $read_type)
525    };
526    (field, $T:ty, $C:ty, $context:expr, $ref_mode:expr, $read_type:expr) => {
527        <$C as Serializer>::read($context, $ref_mode, $read_type)
528    };
529}
530
531macro_rules! map_read_entry_type {
532    (value, $T:ty, $S:ty, $context:expr, $declared:expr, $remote:expr, $index:expr, $tracked:expr) => {
533        read_value_entry_type::<$T, $S>($context, $declared)
534    };
535    (field, $T:ty, $C:ty, $context:expr, $declared:expr, $remote:expr, $index:expr, $tracked:expr) => {
536        read_entry_type::<$T, $C>($context, $declared, $remote, $index, $tracked)
537    };
538}
539
540macro_rules! map_read_entry {
541    (value, $T:ty, $S:ty, $context:expr, $read_type:expr, $tracked:expr) => {
542        read_value_entry::<$T, $S>($context, $read_type, $tracked)
543    };
544    (field, $T:ty, $C:ty, $context:expr, $read_type:expr, $tracked:expr) => {
545        read_entry::<$T, $C>($context, $read_type, $tracked)
546    };
547}
548
549macro_rules! entry_read_data_always_advances {
550    (value, $T:ty, $S:ty, $read_type:expr) => {
551        <$S as Serializer>::READ_DATA_ALWAYS_ADVANCES
552            && $read_type
553                .as_ref()
554                .map_or(true, |type_info| type_info.has_exact_local_schema())
555    };
556    (field, $T:ty, $C:ty, $read_type:expr) => {
557        <$C as Serializer>::READ_DATA_ALWAYS_ADVANCES
558            && match $read_type {
559                EntryReadType::Direct => true,
560                EntryReadType::TypeInfo(type_info) => type_info.has_exact_local_schema(),
561                EntryReadType::Field(field_type) => field_read_data_always_advances(field_type),
562            }
563    };
564}
565
566#[cold]
567#[inline(never)]
568fn invalid_map_chunk() -> Error {
569    Error::invalid_data("map chunk size must be within the remaining entry count")
570}
571
572#[cold]
573#[inline(never)]
574fn map_memory_overflow() -> Error {
575    Error::invalid_data("graph memory estimate overflows")
576}
577
578#[cold]
579#[inline(never)]
580fn map_type_mismatch(remote: u32) -> Error {
581    Error::type_mismatch(TypeId::MAP as u32, remote)
582}
583
584macro_rules! read_map_data_body {
585    (
586        $layer:ident,
587        $M:ident,
588        $K:ident,
589        $V:ident,
590        $KC:ident,
591        $VC:ident,
592        $context:expr,
593        $remote_field_type:expr
594    ) => {{
595        let context = $context;
596        let len = context.reader.read_var_u32()?;
597        let capacity = len as usize;
598        let required = if <$KC as Serializer>::READ_DATA_ALWAYS_ADVANCES
599            || <$VC as Serializer>::READ_DATA_ALWAYS_ADVANCES
600        {
601            capacity
602        } else {
603            capacity.saturating_sub(context.remaining_unbacked_container_items())
604        };
605        context.reader.check_bound(required)?;
606        let elem_bytes = std::mem::size_of::<$K>()
607            .checked_add(std::mem::size_of::<$V>())
608            .and_then(|bytes| bytes.checked_mul(capacity))
609            .ok_or_else(map_memory_overflow)?;
610        context.reserve_graph_memory(elem_bytes)?;
611        let mut map = $M::with_capacity(capacity);
612        let mut read = 0u32;
613        while read < len {
614            let header = context.reader.read_u8()?;
615            if header & KEY_NULL != 0 && header & VALUE_NULL != 0 {
616                map.insert($KC::default_value(context)?, $VC::default_value(context)?);
617                read += 1;
618                continue;
619            }
620            let key_declared = header & DECL_KEY_TYPE != 0;
621            let value_declared = header & DECL_VALUE_TYPE != 0;
622            let key_tracked = header & TRACKING_KEY_REF != 0;
623            let value_tracked = header & TRACKING_VALUE_REF != 0;
624            if header & KEY_NULL != 0 {
625                let value = if value_tracked && !value_declared {
626                    map_read_mode!($layer, $V, $VC, context, RefMode::Tracking, true)?
627                } else {
628                    let value_type = map_read_entry_type!(
629                        $layer,
630                        $V,
631                        $VC,
632                        context,
633                        value_declared,
634                        $remote_field_type,
635                        1,
636                        value_tracked
637                    )?;
638                    map_read_entry!($layer, $V, $VC, context, &value_type, value_tracked)?
639                };
640                map.insert($KC::default_value(context)?, value);
641                read += 1;
642                continue;
643            }
644            if header & VALUE_NULL != 0 {
645                let key = if key_tracked && !key_declared {
646                    map_read_mode!($layer, $K, $KC, context, RefMode::Tracking, true)?
647                } else {
648                    let key_type = map_read_entry_type!(
649                        $layer,
650                        $K,
651                        $KC,
652                        context,
653                        key_declared,
654                        $remote_field_type,
655                        0,
656                        key_tracked
657                    )?;
658                    map_read_entry!($layer, $K, $KC, context, &key_type, key_tracked)?
659                };
660                map.insert(key, $VC::default_value(context)?);
661                read += 1;
662                continue;
663            }
664            let chunk_size = context.reader.read_u8()? as u32;
665            if chunk_size == 0 {
666                return Err(invalid_map_chunk());
667            }
668            let end = read
669                .checked_add(chunk_size)
670                .filter(|end| *end <= len)
671                .ok_or_else(invalid_map_chunk)?;
672            let key_type = map_read_entry_type!(
673                $layer,
674                $K,
675                $KC,
676                context,
677                key_declared,
678                $remote_field_type,
679                0,
680                key_tracked
681            )?;
682            let value_type = map_read_entry_type!(
683                $layer,
684                $V,
685                $VC,
686                context,
687                value_declared,
688                $remote_field_type,
689                1,
690                value_tracked
691            )?;
692            let entry_read_always_advances = key_tracked
693                || value_tracked
694                || entry_read_data_always_advances!($layer, $K, $KC, &key_type)
695                || entry_read_data_always_advances!($layer, $V, $VC, &value_type);
696            if entry_read_always_advances {
697                while read < end {
698                    let key = map_read_entry!($layer, $K, $KC, context, &key_type, key_tracked)?;
699                    let value =
700                        map_read_entry!($layer, $V, $VC, context, &value_type, value_tracked)?;
701                    map.insert(key, value);
702                    read += 1;
703                }
704            } else {
705                let chunk_start = context.reader.get_cursor();
706                while read < end {
707                    let key = map_read_entry!($layer, $K, $KC, context, &key_type, key_tracked)?;
708                    let value =
709                        map_read_entry!($layer, $V, $VC, context, &value_type, value_tracked)?;
710                    map.insert(key, value);
711                    read += 1;
712                }
713                settle_unbacked_items(context, chunk_size as usize, chunk_start)?;
714            }
715        }
716        Ok(map)
717    }};
718}
719
720fn read_value_map_data<M, K, V, KS, VS>(context: &mut ReadContext) -> Result<M, Error>
721where
722    K: 'static,
723    V: 'static,
724    KS: Serializer<Target = K>,
725    VS: Serializer<Target = V>,
726    M: MapTarget<K, V>,
727{
728    read_map_data_body!(value, M, K, V, KS, VS, context, ())
729}
730
731fn read_field_map_data<M, K, V, KC, VC>(
732    context: &mut ReadContext,
733    remote_field_type: Option<&FieldType>,
734) -> Result<M, Error>
735where
736    K: 'static,
737    V: 'static,
738    KC: Codec<K>,
739    VC: Codec<V>,
740    M: MapTarget<K, V>,
741{
742    read_map_data_body!(field, M, K, V, KC, VC, context, remote_field_type)
743}
744
745macro_rules! impl_map_codec {
746    ($codec:ident, $target:ident, [$($key_bound:tt)+]) => {
747        impl<K, V, KS, VS, const NULLABLE: bool, const TRACK_REF: bool> Serializer
748            for $codec<K, V, KS, VS, NULLABLE, TRACK_REF>
749        where
750            K: $($key_bound)+ + 'static,
751            V: 'static,
752            KS: Serializer<Target = K>,
753            VS: Serializer<Target = V>,
754        {
755            type Target = $target<K, V>;
756
757            #[inline(always)]
758            fn write_data(
759                value: &Self::Target,
760                context: &mut WriteContext,
761            ) -> Result<(), Error> {
762                write_value_map_data::<K, V, KS, VS, _>(
763                    value.iter(),
764                    value.len(),
765                    context,
766                )
767            }
768
769            #[inline(always)]
770            fn read_data(context: &mut ReadContext) -> Result<Self::Target, Error> {
771                read_value_map_data::<Self::Target, K, V, KS, VS>(context)
772            }
773
774            #[inline(always)]
775            fn default_value(_: &mut ReadContext) -> Result<Self::Target, Error> {
776                Ok(<Self::Target as MapTarget<K, V>>::with_capacity(0))
777            }
778
779            #[inline(always)]
780            fn write_type_info(context: &mut WriteContext) -> Result<(), Error> {
781                context.writer.write_u8(TypeId::MAP as u8);
782                Ok(())
783            }
784
785            #[inline(always)]
786            fn read_type_info(context: &mut ReadContext) -> Result<(), Error> {
787                let remote = context.reader.read_u8()? as u32;
788                if remote == TypeId::MAP as u32 {
789                    Ok(())
790                } else {
791                    Err(map_type_mismatch(remote))
792                }
793            }
794
795            #[inline(always)]
796            fn static_type_id() -> TypeId {
797                TypeId::MAP
798            }
799
800            #[inline(always)]
801            fn reserved_space() -> usize {
802                std::mem::size_of::<u32>() + SIZE_OF_REF_AND_TYPE
803            }
804
805            const READ_DATA_ALWAYS_ADVANCES: bool = true;
806        }
807
808        impl<K, V, KC, VC, const NULLABLE: bool, const TRACK_REF: bool>
809            Codec<$target<K, V>> for $codec<K, V, KC, VC, NULLABLE, TRACK_REF>
810        where
811            K: $($key_bound)+ + 'static,
812            V: 'static,
813            KC: Codec<K>,
814            VC: Codec<V>,
815        {
816            #[inline(always)]
817            fn field_type(type_resolver: &TypeResolver) -> Result<FieldType, Error> {
818                Ok(FieldType::new_with_ref(
819                    TypeId::MAP as u32,
820                    NULLABLE,
821                    TRACK_REF,
822                    vec![
823                        KC::field_type(type_resolver)?,
824                        VC::field_type(type_resolver)?,
825                    ],
826                ))
827            }
828
829            #[inline(always)]
830            fn write_field(
831                value: &$target<K, V>,
832                context: &mut WriteContext,
833            ) -> Result<(), Error> {
834                if NULLABLE || TRACK_REF {
835                    context.writer.write_i8(RefFlag::NotNullValue as i8);
836                }
837                write_field_map_data::<K, V, KC, VC, _>(
838                    value.iter(),
839                    value.len(),
840                    context,
841                    true,
842                )
843            }
844
845            #[inline(always)]
846            fn read_field(context: &mut ReadContext) -> Result<$target<K, V>, Error> {
847                if (NULLABLE || TRACK_REF)
848                    && context.reader.read_i8()? == RefFlag::Null as i8
849                {
850                    return Ok(
851                        <$target<K, V> as MapTarget<K, V>>::with_capacity(0)
852                    );
853                }
854                <Self as Serializer>::read_data(context)
855            }
856
857            #[inline(always)]
858            fn read_data_with_type(
859                context: &mut ReadContext,
860                remote_data_type: &FieldType,
861            ) -> Result<$target<K, V>, Error> {
862                read_field_map_data::<$target<K, V>, K, V, KC, VC>(
863                    context,
864                    Some(remote_data_type),
865                )
866            }
867
868            #[inline(always)]
869            fn read_field_with_type(
870                context: &mut ReadContext,
871                remote_field_type: &FieldType,
872            ) -> Result<$target<K, V>, Error> {
873                if field_ref_mode(remote_field_type) != RefMode::None
874                    && context.reader.read_i8()? == RefFlag::Null as i8
875                {
876                    return Ok(
877                        <$target<K, V> as MapTarget<K, V>>::with_capacity(0)
878                    );
879                }
880                Self::read_data_with_type(context, remote_field_type)
881            }
882
883            #[inline(always)]
884            fn write_with_mode(
885                value: &$target<K, V>,
886                context: &mut WriteContext,
887                ref_mode: RefMode,
888                write_type_info: bool,
889                has_generics: bool,
890            ) -> Result<(), Error> {
891                if !has_generics {
892                    return <Self as Serializer>::write(
893                        value,
894                        context,
895                        ref_mode,
896                        write_type_info,
897                    );
898                }
899                if ref_mode != RefMode::None {
900                    context.writer.write_i8(RefFlag::NotNullValue as i8);
901                }
902                if write_type_info {
903                    <Self as Serializer>::write_type_info(context)?;
904                }
905                write_field_map_data::<K, V, KC, VC, _>(
906                    value.iter(),
907                    value.len(),
908                    context,
909                    true,
910                )
911            }
912        }
913    };
914}
915
916impl_map_codec!(HashMapCodec, HashMap, [Eq + std::hash::Hash]);
917impl_map_codec!(BTreeMapCodec, BTreeMap, [Ord]);
918
919macro_rules! impl_map_serializer {
920    ($provider:ident, $target:ident, $codec:ident, [$($key_bound:tt)+]) => {
921        #[doc = concat!(
922            "Statically serializes `",
923            stringify!($target),
924            "<KS::Target, VS::Target>` at roots or recursive carrier nodes. ",
925            "This zero-sized carrier composes its key and value serializers and is not ",
926            "registered independently."
927        )]
928        pub struct $provider<KS, VS>(PhantomData<fn() -> (KS, VS)>);
929
930        impl<KS, VS> Serializer for $provider<KS, VS>
931        where
932            KS: Serializer,
933            VS: Serializer,
934            KS::Target: $($key_bound)+,
935        {
936            type Target = $target<KS::Target, VS::Target>;
937
938            const READ_DATA_ALWAYS_ADVANCES: bool = true;
939
940            #[inline(always)]
941            fn write_data(value: &Self::Target, context: &mut WriteContext) -> Result<(), Error> {
942                <$codec<
943                    KS::Target,
944                    VS::Target,
945                    KS,
946                    VS,
947                    false,
948                    false,
949                > as Serializer>::write_data(value, context)
950            }
951
952            #[inline(always)]
953            fn read_data(context: &mut ReadContext) -> Result<Self::Target, Error> {
954                <$codec<
955                    KS::Target,
956                    VS::Target,
957                    KS,
958                    VS,
959                    false,
960                    false,
961                > as Serializer>::read_data(context)
962            }
963
964            #[inline(always)]
965            fn default_value(context: &mut ReadContext) -> Result<Self::Target, Error> {
966                <$codec<
967                    KS::Target,
968                    VS::Target,
969                    KS,
970                    VS,
971                    false,
972                    false,
973                > as Serializer>::default_value(context)
974            }
975
976            #[inline(always)]
977            fn write(
978                value: &Self::Target,
979                context: &mut WriteContext,
980                ref_mode: RefMode,
981                write_type_info: bool,
982            ) -> Result<(), Error> {
983                <$codec<
984                    KS::Target,
985                    VS::Target,
986                    KS,
987                    VS,
988                    false,
989                    false,
990                > as Serializer>::write(
991                    value,
992                    context,
993                    ref_mode,
994                    write_type_info,
995                )
996            }
997
998            #[inline(always)]
999            fn read(
1000                context: &mut ReadContext,
1001                ref_mode: RefMode,
1002                read_type_info: bool,
1003            ) -> Result<Self::Target, Error> {
1004                <$codec<
1005                    KS::Target,
1006                    VS::Target,
1007                    KS,
1008                    VS,
1009                    false,
1010                    false,
1011                > as Serializer>::read(
1012                    context,
1013                    ref_mode,
1014                    read_type_info,
1015                )
1016            }
1017
1018            #[inline(always)]
1019            fn read_with_type_info(
1020                context: &mut ReadContext,
1021                ref_mode: RefMode,
1022                type_info: &Rc<TypeInfo>,
1023            ) -> Result<Self::Target, Error> {
1024                <$codec<
1025                    KS::Target,
1026                    VS::Target,
1027                    KS,
1028                    VS,
1029                    false,
1030                    false,
1031                > as Serializer>::read_with_type_info(
1032                    context,
1033                    ref_mode,
1034                    type_info,
1035                )
1036            }
1037
1038            #[inline(always)]
1039            fn write_type_info(context: &mut WriteContext) -> Result<(), Error> {
1040                <$codec<
1041                    KS::Target,
1042                    VS::Target,
1043                    KS,
1044                    VS,
1045                    false,
1046                    false,
1047                > as Serializer>::write_type_info(context)
1048            }
1049
1050            #[inline(always)]
1051            fn read_type_info(context: &mut ReadContext) -> Result<(), Error> {
1052                <$codec<
1053                    KS::Target,
1054                    VS::Target,
1055                    KS,
1056                    VS,
1057                    false,
1058                    false,
1059                > as Serializer>::read_type_info(context)
1060            }
1061
1062            #[inline(always)]
1063            fn static_type_id() -> TypeId {
1064                TypeId::MAP
1065            }
1066
1067            #[inline(always)]
1068            fn reserved_space() -> usize {
1069                std::mem::size_of::<u32>() + SIZE_OF_REF_AND_TYPE
1070            }
1071        }
1072
1073        impl<K, V> Serializer for $target<K, V>
1074        where
1075            K: Serializer<Target = K> + $($key_bound)+,
1076            V: Serializer<Target = V>,
1077        {
1078            type Target = Self;
1079
1080            const READ_DATA_ALWAYS_ADVANCES: bool = true;
1081
1082            #[inline(always)]
1083            fn write_data(value: &Self, context: &mut WriteContext) -> Result<(), Error> {
1084                <$provider<K, V> as Serializer>::write_data(value, context)
1085            }
1086
1087            #[inline(always)]
1088            fn read_data(context: &mut ReadContext) -> Result<Self, Error> {
1089                <$provider<K, V> as Serializer>::read_data(context)
1090            }
1091
1092            #[inline(always)]
1093            fn default_value(context: &mut ReadContext) -> Result<Self, Error> {
1094                <$provider<K, V> as Serializer>::default_value(context)
1095            }
1096
1097            #[inline(always)]
1098            fn write(
1099                value: &Self,
1100                context: &mut WriteContext,
1101                ref_mode: RefMode,
1102                write_type_info: bool,
1103            ) -> Result<(), Error> {
1104                <$provider<K, V> as Serializer>::write(
1105                    value,
1106                    context,
1107                    ref_mode,
1108                    write_type_info,
1109                )
1110            }
1111
1112            #[inline(always)]
1113            fn read(
1114                context: &mut ReadContext,
1115                ref_mode: RefMode,
1116                read_type_info: bool,
1117            ) -> Result<Self, Error> {
1118                <$provider<K, V> as Serializer>::read(
1119                    context,
1120                    ref_mode,
1121                    read_type_info,
1122                )
1123            }
1124
1125            #[inline(always)]
1126            fn read_with_type_info(
1127                context: &mut ReadContext,
1128                ref_mode: RefMode,
1129                type_info: &Rc<TypeInfo>,
1130            ) -> Result<Self, Error> {
1131                <$provider<K, V> as Serializer>::read_with_type_info(
1132                    context,
1133                    ref_mode,
1134                    type_info,
1135                )
1136            }
1137
1138            #[inline(always)]
1139            fn write_type_info(context: &mut WriteContext) -> Result<(), Error> {
1140                <$provider<K, V> as Serializer>::write_type_info(context)
1141            }
1142
1143            #[inline(always)]
1144            fn read_type_info(context: &mut ReadContext) -> Result<(), Error> {
1145                <$provider<K, V> as Serializer>::read_type_info(context)
1146            }
1147
1148            #[inline(always)]
1149            fn static_type_id() -> TypeId {
1150                TypeId::MAP
1151            }
1152
1153            #[inline(always)]
1154            fn reserved_space() -> usize {
1155                std::mem::size_of::<u32>() + SIZE_OF_REF_AND_TYPE
1156            }
1157        }
1158    };
1159}
1160
1161impl_map_serializer!(
1162    HashMapSerializer,
1163    HashMap,
1164    HashMapCodec,
1165    [Eq + std::hash::Hash]
1166);
1167impl_map_serializer!(BTreeMapSerializer, BTreeMap, BTreeMapCodec, [Ord]);
1168
1169#[cfg(test)]
1170mod tests {
1171    use super::*;
1172    use crate::{Config, Reader};
1173
1174    #[test]
1175    fn empty_entries_use_root_budget() {
1176        let bytes = [3, DECL_KEY_TYPE | DECL_VALUE_TYPE, 3];
1177        let mut context = ReadContext::new(TypeResolver::default(), Config::default());
1178        context.remaining_graph_memory_bytes = usize::MAX;
1179        context.remaining_unbacked_container_items = 2;
1180        context.attach_reader(Reader::new(&bytes));
1181
1182        let error =
1183            read_value_map_data::<BTreeMap<(), ()>, (), (), (), ()>(&mut context).unwrap_err();
1184        assert!(error.to_string().contains("max_unbacked_container_items"));
1185    }
1186}