Skip to main content

fory_core/serializer/
rc.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    codec_read_type_info, codec_read_type_info_static, codec_ref_mode, codec_write_type_info,
20    field_ref_mode, Codec,
21};
22use crate::context::{ReadContext, WriteContext};
23use crate::error::Error;
24use crate::meta::FieldType;
25use crate::resolver::{RefFlag, RefMode, TypeInfo, TypeResolver};
26use crate::serializer::Serializer;
27use crate::type_id::TypeId;
28use std::marker::PhantomData;
29use std::rc::Rc;
30
31pub struct RcCodec<T, C, const NULLABLE: bool, const TRACK_REF: bool>(PhantomData<(T, C)>);
32
33#[cold]
34#[inline(never)]
35fn shared_rc_child() -> Error {
36    Error::not_allowed("Rc<T> where T is a shared ref type is not allowed")
37}
38
39#[cold]
40#[inline(never)]
41fn missing_rc_ref(ref_id: u32) -> Error {
42    Error::invalid_ref(format!("Rc reference {ref_id} not found"))
43}
44
45#[inline(always)]
46fn check_child<T: 'static, C: Serializer<Target = T>>() -> Result<(), Error> {
47    // Nested shared owners would compete for reference framing and identity
48    // while both wrappers remain transparent on the wire.
49    if C::IS_SHARED_REF {
50        Err(shared_rc_child())
51    } else {
52        Ok(())
53    }
54}
55
56#[inline(always)]
57fn reserve_rc<T>(context: &mut ReadContext) -> Result<(), Error> {
58    let bytes = std::mem::size_of::<T>();
59    if bytes != 0 {
60        context.reserve_graph_memory(bytes)?;
61    }
62    Ok(())
63}
64
65#[inline(always)]
66fn write_inner<T: 'static, C: Serializer<Target = T>>(
67    value: &T,
68    context: &mut WriteContext,
69    write_type_info: bool,
70) -> Result<(), Error> {
71    check_child::<T, C>()?;
72    C::write(value, context, RefMode::None, write_type_info)
73}
74
75#[inline(always)]
76fn write_inner_with_type_info<T: 'static, C: Serializer<Target = T>>(
77    value: &T,
78    context: &mut WriteContext,
79    type_info: &Rc<TypeInfo>,
80) -> Result<(), Error> {
81    check_child::<T, C>()?;
82    C::write_with_type_info(value, context, RefMode::None, type_info)
83}
84
85#[inline(always)]
86fn write_inner_field<T: 'static, C: Codec<T>>(
87    value: &T,
88    context: &mut WriteContext,
89    write_type_info: bool,
90    has_generics: bool,
91) -> Result<(), Error> {
92    check_child::<T, C>()?;
93    C::write_with_mode(value, context, RefMode::None, write_type_info, has_generics)
94}
95
96#[inline(always)]
97fn write_inner_field_with_type_info<T: 'static, C: Codec<T>>(
98    value: &T,
99    context: &mut WriteContext,
100    type_info: &Rc<TypeInfo>,
101    has_generics: bool,
102) -> Result<(), Error> {
103    check_child::<T, C>()?;
104    <C as Codec<T>>::write_with_type_info(value, context, RefMode::None, type_info, has_generics)
105}
106
107#[inline(always)]
108fn write_ref<T>(value: &Rc<T>, context: &mut WriteContext, ref_mode: RefMode) -> bool {
109    match ref_mode {
110        RefMode::None => true,
111        RefMode::NullOnly => {
112            context.writer.write_i8(RefFlag::NotNullValue as i8);
113            true
114        }
115        RefMode::Tracking => !context
116            .ref_writer
117            .try_write_rc_ref(&mut context.writer, value),
118    }
119}
120
121#[inline(always)]
122fn read_inner<T: 'static, C: Serializer<Target = T>>(
123    context: &mut ReadContext,
124    read_type_info: bool,
125    type_info: Option<&Rc<TypeInfo>>,
126) -> Result<T, Error> {
127    check_child::<T, C>()?;
128    reserve_rc::<T>(context)?;
129    if let Some(type_info) = type_info {
130        return C::read_with_type_info(context, RefMode::None, type_info);
131    }
132    if read_type_info {
133        C::read_type_info(context)?;
134    }
135    C::read_data(context)
136}
137
138#[inline(always)]
139fn read_inner_with_type<T: 'static, C: Codec<T>>(
140    context: &mut ReadContext,
141    remote_field_type: &FieldType,
142) -> Result<T, Error> {
143    check_child::<T, C>()?;
144    reserve_rc::<T>(context)?;
145    // The Rc envelope owns only reference framing. A compatible
146    // metadata-bearing child still owns its inline TypeInfo before its body,
147    // while declared carrier children consume the remote schema directly.
148    if codec_read_type_info::<T, C>(context, remote_field_type) {
149        return C::read(context, RefMode::None, true);
150    }
151    C::read_data_with_type(context, remote_field_type)
152}
153
154impl<T, C, const NULLABLE: bool, const TRACK_REF: bool> Serializer
155    for RcCodec<T, C, NULLABLE, TRACK_REF>
156where
157    T: 'static,
158    C: Serializer<Target = T>,
159{
160    type Target = Rc<T>;
161
162    #[inline(always)]
163    fn reserved_space() -> usize {
164        4
165    }
166
167    #[inline(always)]
168    fn write_data(value: &Rc<T>, context: &mut WriteContext) -> Result<(), Error> {
169        write_inner::<T, C>(value, context, false)
170    }
171
172    #[inline(always)]
173    fn read_data(context: &mut ReadContext) -> Result<Rc<T>, Error> {
174        Ok(Rc::new(read_inner::<T, C>(context, false, None)?))
175    }
176
177    #[inline(always)]
178    fn write(
179        value: &Rc<T>,
180        context: &mut WriteContext,
181        ref_mode: RefMode,
182        write_type_info: bool,
183    ) -> Result<(), Error> {
184        if !write_ref(value, context, ref_mode) {
185            return Ok(());
186        }
187        write_inner::<T, C>(value, context, write_type_info)
188    }
189
190    #[inline(always)]
191    fn write_type_info_value(
192        context: &mut WriteContext,
193        target_type_id: std::any::TypeId,
194    ) -> Result<Rc<TypeInfo>, Error> {
195        C::write_type_info_value(context, target_type_id)
196    }
197
198    #[inline(always)]
199    fn write_with_type_info(
200        value: &Rc<T>,
201        context: &mut WriteContext,
202        ref_mode: RefMode,
203        type_info: &Rc<TypeInfo>,
204    ) -> Result<(), Error> {
205        if !write_ref(value, context, ref_mode) {
206            return Ok(());
207        }
208        write_inner_with_type_info::<T, C>(value, context, type_info)
209    }
210
211    #[inline(always)]
212    fn read(
213        context: &mut ReadContext,
214        ref_mode: RefMode,
215        read_type_info: bool,
216    ) -> Result<Rc<T>, Error> {
217        read_rc::<T, C>(context, ref_mode, read_type_info, None)
218    }
219
220    #[inline(always)]
221    fn read_with_type_info(
222        context: &mut ReadContext,
223        ref_mode: RefMode,
224        type_info: &Rc<TypeInfo>,
225    ) -> Result<Rc<T>, Error> {
226        read_rc::<T, C>(context, ref_mode, false, Some(type_info))
227    }
228
229    #[inline(always)]
230    fn default_value(context: &mut ReadContext) -> Result<Rc<T>, Error> {
231        check_child::<T, C>()?;
232        reserve_rc::<T>(context)?;
233        Ok(Rc::new(C::default_value(context)?))
234    }
235
236    #[inline(always)]
237    fn write_type_info(context: &mut WriteContext) -> Result<(), Error> {
238        C::write_type_info(context)
239    }
240
241    #[inline(always)]
242    fn read_type_info(context: &mut ReadContext) -> Result<(), Error> {
243        C::read_type_info(context)
244    }
245
246    #[inline(always)]
247    fn static_type_id() -> TypeId {
248        C::static_type_id()
249    }
250
251    const IS_POLYMORPHIC: bool = C::IS_POLYMORPHIC;
252
253    const IS_SHARED_REF: bool = true;
254
255    const IS_WRAPPER: bool = true;
256
257    const REQUIRES_SCOPED_ACCESS: bool = C::REQUIRES_SCOPED_ACCESS;
258
259    #[inline(always)]
260    fn dynamic_type_id(value: &Rc<T>) -> Result<Option<std::any::TypeId>, Error> {
261        C::dynamic_type_id(value)
262    }
263}
264
265impl<T, C, const NULLABLE: bool, const TRACK_REF: bool> Codec<Rc<T>>
266    for RcCodec<T, C, NULLABLE, TRACK_REF>
267where
268    T: 'static,
269    C: Codec<T>,
270{
271    #[inline(always)]
272    fn field_type(type_resolver: &TypeResolver) -> Result<FieldType, Error> {
273        let mut field_type = C::field_type(type_resolver)?;
274        field_type.nullable = NULLABLE;
275        field_type.track_ref = TRACK_REF;
276        Ok(field_type)
277    }
278
279    #[inline(always)]
280    fn write_field(value: &Rc<T>, context: &mut WriteContext) -> Result<(), Error> {
281        Self::write_with_mode(
282            value,
283            context,
284            codec_ref_mode::<T, C, NULLABLE, TRACK_REF>(),
285            codec_write_type_info::<T, C>(context),
286            true,
287        )
288    }
289
290    #[inline(always)]
291    fn read_field(context: &mut ReadContext) -> Result<Rc<T>, Error> {
292        <Self as Serializer>::read(
293            context,
294            codec_ref_mode::<T, C, NULLABLE, TRACK_REF>(),
295            codec_read_type_info_static::<T, C>(context),
296        )
297    }
298
299    #[inline(always)]
300    fn read_data_with_type(
301        context: &mut ReadContext,
302        remote_data_type: &FieldType,
303    ) -> Result<Rc<T>, Error> {
304        check_child::<T, C>()?;
305        reserve_rc::<T>(context)?;
306        Ok(Rc::new(C::read_data_with_type(context, remote_data_type)?))
307    }
308
309    #[inline(always)]
310    fn read_field_with_type(
311        context: &mut ReadContext,
312        remote_field_type: &FieldType,
313    ) -> Result<Rc<T>, Error> {
314        read_rc_with_type::<T, C>(
315            context,
316            field_ref_mode(remote_field_type),
317            remote_field_type,
318        )
319    }
320
321    #[inline(always)]
322    fn write_with_mode(
323        value: &Rc<T>,
324        context: &mut WriteContext,
325        ref_mode: RefMode,
326        write_type_info: bool,
327        has_generics: bool,
328    ) -> Result<(), Error> {
329        if !write_ref(value, context, ref_mode) {
330            return Ok(());
331        }
332        write_inner_field::<T, C>(value, context, write_type_info, has_generics)
333    }
334
335    #[inline(always)]
336    fn write_with_type_info(
337        value: &Rc<T>,
338        context: &mut WriteContext,
339        ref_mode: RefMode,
340        type_info: &Rc<TypeInfo>,
341        has_generics: bool,
342    ) -> Result<(), Error> {
343        if !write_ref(value, context, ref_mode) {
344            return Ok(());
345        }
346        write_inner_field_with_type_info::<T, C>(value, context, type_info, has_generics)
347    }
348
349    #[inline(always)]
350    fn read_type_info_value(
351        context: &mut ReadContext,
352    ) -> Result<super::codec::CodecReadType, Error> {
353        C::read_type_info_value(context)
354    }
355}
356
357macro_rules! read_rc_owner {
358    ($context:ident, $ref_mode:expr, $read_inner:expr, $default:expr) => {
359        match $ref_mode {
360            RefMode::None => Ok(Rc::new($read_inner?)),
361            RefMode::NullOnly => {
362                if $context.reader.read_i8()? == RefFlag::Null as i8 {
363                    return $default;
364                }
365                Ok(Rc::new($read_inner?))
366            }
367            RefMode::Tracking => match $context.ref_reader.read_ref_flag(&mut $context.reader)? {
368                RefFlag::Null => $default,
369                RefFlag::Ref => {
370                    let ref_id = $context.ref_reader.read_ref_id(&mut $context.reader)?;
371                    $context
372                        .ref_reader
373                        .get_rc_ref::<T>(ref_id)
374                        .ok_or_else(|| missing_rc_ref(ref_id))
375                }
376                RefFlag::NotNullValue => Ok(Rc::new($read_inner?)),
377                RefFlag::RefValue => {
378                    let ref_id = $context.ref_reader.reserve_ref_id();
379                    let value = Rc::new($read_inner?);
380                    $context.ref_reader.store_rc_ref_at(ref_id, value.clone());
381                    Ok(value)
382                }
383            },
384        }
385    };
386}
387
388#[inline(always)]
389fn read_rc<T: 'static, C: Serializer<Target = T>>(
390    context: &mut ReadContext,
391    ref_mode: RefMode,
392    read_type_info: bool,
393    type_info: Option<&Rc<TypeInfo>>,
394) -> Result<Rc<T>, Error> {
395    read_rc_owner!(
396        context,
397        ref_mode,
398        read_inner::<T, C>(context, read_type_info, type_info),
399        <RcCodec<T, C, false, false> as Serializer>::default_value(context)
400    )
401}
402
403#[inline(always)]
404fn read_rc_with_type<T: 'static, C: Codec<T>>(
405    context: &mut ReadContext,
406    ref_mode: RefMode,
407    remote_field_type: &FieldType,
408) -> Result<Rc<T>, Error> {
409    read_rc_owner!(
410        context,
411        ref_mode,
412        read_inner_with_type::<T, C>(context, remote_field_type),
413        <RcCodec<T, C, false, false> as Serializer>::default_value(context)
414    )
415}
416
417impl_single_carrier_serializer!(RcSerializer, Rc, RcCodec, wrapper = true);