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    #[inline(always)]
252    fn metadata_target_type_id() -> std::any::TypeId {
253        C::metadata_target_type_id()
254    }
255
256    const IS_POLYMORPHIC: bool = C::IS_POLYMORPHIC;
257
258    const IS_SHARED_REF: bool = true;
259
260    const IS_WRAPPER: bool = true;
261
262    const REQUIRES_SCOPED_ACCESS: bool = C::REQUIRES_SCOPED_ACCESS;
263
264    #[inline(always)]
265    fn dynamic_type_id(value: &Rc<T>) -> Result<Option<std::any::TypeId>, Error> {
266        C::dynamic_type_id(value)
267    }
268}
269
270impl<T, C, const NULLABLE: bool, const TRACK_REF: bool> Codec<Rc<T>>
271    for RcCodec<T, C, NULLABLE, TRACK_REF>
272where
273    T: 'static,
274    C: Codec<T>,
275{
276    #[inline(always)]
277    fn field_type(type_resolver: &TypeResolver) -> Result<FieldType, Error> {
278        let mut field_type = C::field_type(type_resolver)?;
279        field_type.nullable = NULLABLE;
280        field_type.track_ref = TRACK_REF;
281        Ok(field_type)
282    }
283
284    #[inline(always)]
285    fn write_field(value: &Rc<T>, context: &mut WriteContext) -> Result<(), Error> {
286        Self::write_with_mode(
287            value,
288            context,
289            codec_ref_mode::<T, C, NULLABLE, TRACK_REF>(),
290            codec_write_type_info::<T, C>(context),
291            true,
292        )
293    }
294
295    #[inline(always)]
296    fn read_field(context: &mut ReadContext) -> Result<Rc<T>, Error> {
297        <Self as Serializer>::read(
298            context,
299            codec_ref_mode::<T, C, NULLABLE, TRACK_REF>(),
300            codec_read_type_info_static::<T, C>(context),
301        )
302    }
303
304    #[inline(always)]
305    fn read_data_with_type(
306        context: &mut ReadContext,
307        remote_data_type: &FieldType,
308    ) -> Result<Rc<T>, Error> {
309        check_child::<T, C>()?;
310        reserve_rc::<T>(context)?;
311        Ok(Rc::new(C::read_data_with_type(context, remote_data_type)?))
312    }
313
314    #[inline(always)]
315    fn read_field_with_type(
316        context: &mut ReadContext,
317        remote_field_type: &FieldType,
318    ) -> Result<Rc<T>, Error> {
319        read_rc_with_type::<T, C>(
320            context,
321            field_ref_mode(remote_field_type),
322            remote_field_type,
323        )
324    }
325
326    #[inline(always)]
327    fn write_with_mode(
328        value: &Rc<T>,
329        context: &mut WriteContext,
330        ref_mode: RefMode,
331        write_type_info: bool,
332        has_generics: bool,
333    ) -> Result<(), Error> {
334        if !write_ref(value, context, ref_mode) {
335            return Ok(());
336        }
337        write_inner_field::<T, C>(value, context, write_type_info, has_generics)
338    }
339
340    #[inline(always)]
341    fn write_with_type_info(
342        value: &Rc<T>,
343        context: &mut WriteContext,
344        ref_mode: RefMode,
345        type_info: &Rc<TypeInfo>,
346        has_generics: bool,
347    ) -> Result<(), Error> {
348        if !write_ref(value, context, ref_mode) {
349            return Ok(());
350        }
351        write_inner_field_with_type_info::<T, C>(value, context, type_info, has_generics)
352    }
353
354    #[inline(always)]
355    fn read_type_info_value(
356        context: &mut ReadContext,
357    ) -> Result<super::codec::CodecReadType, Error> {
358        C::read_type_info_value(context)
359    }
360}
361
362macro_rules! read_rc_owner {
363    ($context:ident, $ref_mode:expr, $read_inner:expr, $default:expr) => {
364        match $ref_mode {
365            RefMode::None => Ok(Rc::new($read_inner?)),
366            RefMode::NullOnly => {
367                if $context.reader.read_i8()? == RefFlag::Null as i8 {
368                    return $default;
369                }
370                Ok(Rc::new($read_inner?))
371            }
372            RefMode::Tracking => match $context.ref_reader.read_ref_flag(&mut $context.reader)? {
373                RefFlag::Null => $default,
374                RefFlag::Ref => {
375                    let ref_id = $context.ref_reader.read_ref_id(&mut $context.reader)?;
376                    $context
377                        .ref_reader
378                        .get_rc_ref::<T>(ref_id)
379                        .ok_or_else(|| missing_rc_ref(ref_id))
380                }
381                RefFlag::NotNullValue => Ok(Rc::new($read_inner?)),
382                RefFlag::RefValue => {
383                    let ref_id = $context.ref_reader.reserve_ref_id();
384                    let value = Rc::new($read_inner?);
385                    $context.ref_reader.store_rc_ref_at(ref_id, value.clone());
386                    Ok(value)
387                }
388            },
389        }
390    };
391}
392
393#[inline(always)]
394fn read_rc<T: 'static, C: Serializer<Target = T>>(
395    context: &mut ReadContext,
396    ref_mode: RefMode,
397    read_type_info: bool,
398    type_info: Option<&Rc<TypeInfo>>,
399) -> Result<Rc<T>, Error> {
400    read_rc_owner!(
401        context,
402        ref_mode,
403        read_inner::<T, C>(context, read_type_info, type_info),
404        <RcCodec<T, C, false, false> as Serializer>::default_value(context)
405    )
406}
407
408#[inline(always)]
409fn read_rc_with_type<T: 'static, C: Codec<T>>(
410    context: &mut ReadContext,
411    ref_mode: RefMode,
412    remote_field_type: &FieldType,
413) -> Result<Rc<T>, Error> {
414    read_rc_owner!(
415        context,
416        ref_mode,
417        read_inner_with_type::<T, C>(context, remote_field_type),
418        <RcCodec<T, C, false, false> as Serializer>::default_value(context)
419    )
420}
421
422impl_single_carrier_serializer!(RcSerializer, Rc, RcCodec, wrapper = true);