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 crate::error::Error;
19use crate::resolver::context::{ReadContext, WriteContext};
20use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
21use crate::serializer::{ForyDefault, Serializer};
22use crate::types::{RefFlag, RefMode, TypeId};
23use std::rc::Rc;
24
25impl<T: Serializer + ForyDefault + 'static> Serializer for Rc<T> {
26    fn fory_is_shared_ref() -> bool {
27        true
28    }
29
30    fn fory_write(
31        &self,
32        context: &mut WriteContext,
33        ref_mode: RefMode,
34        write_type_info: bool,
35        has_generics: bool,
36    ) -> Result<(), Error> {
37        match ref_mode {
38            RefMode::None => {
39                // No ref flag - write inner directly
40                if write_type_info {
41                    T::fory_write_type_info(context)?;
42                }
43                T::fory_write_data_generic(self, context, has_generics)
44            }
45            RefMode::NullOnly => {
46                // Only null check, no ref tracking
47                context.writer.write_i8(RefFlag::NotNullValue as i8);
48                if write_type_info {
49                    T::fory_write_type_info(context)?;
50                }
51                T::fory_write_data_generic(self, context, has_generics)
52            }
53            RefMode::Tracking => {
54                // Full ref tracking with RefWriter
55                if context
56                    .ref_writer
57                    .try_write_rc_ref(&mut context.writer, self)
58                {
59                    // Already written as ref - done
60                    return Ok(());
61                }
62                // First occurrence - write type info and data
63                if write_type_info {
64                    T::fory_write_type_info(context)?;
65                }
66                T::fory_write_data_generic(self, context, has_generics)
67            }
68        }
69    }
70
71    fn fory_write_data_generic(
72        &self,
73        context: &mut WriteContext,
74        has_generics: bool,
75    ) -> Result<(), Error> {
76        if T::fory_is_shared_ref() {
77            return Err(Error::not_allowed(
78                "Rc<T> where T is a shared ref type is not allowed for serialization.",
79            ));
80        }
81        T::fory_write_data_generic(&**self, context, has_generics)
82    }
83
84    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
85        self.fory_write_data_generic(context, false)
86    }
87
88    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
89        T::fory_write_type_info(context)
90    }
91
92    fn fory_read(
93        context: &mut ReadContext,
94        ref_mode: RefMode,
95        read_type_info: bool,
96    ) -> Result<Self, Error> {
97        read_rc(context, ref_mode, read_type_info, None)
98    }
99
100    fn fory_read_with_type_info(
101        context: &mut ReadContext,
102        ref_mode: RefMode,
103        typeinfo: Rc<TypeInfo>,
104    ) -> Result<Self, Error>
105    where
106        Self: Sized + ForyDefault,
107    {
108        read_rc(context, ref_mode, false, Some(typeinfo))
109    }
110
111    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
112        if T::fory_is_shared_ref() {
113            return Err(Error::not_allowed(
114                "Rc<T> where T is a shared ref type is not allowed for deserialization.",
115            ));
116        }
117        let inner = T::fory_read_data(context)?;
118        Ok(Rc::new(inner))
119    }
120
121    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
122        T::fory_read_type_info(context)
123    }
124
125    fn fory_reserved_space() -> usize {
126        // Rc is a shared ref, so we just need space for the ref tracking
127        // We don't recursively compute inner type's space to avoid infinite recursion
128        4
129    }
130
131    fn fory_get_type_id(type_resolver: &TypeResolver) -> Result<TypeId, Error> {
132        T::fory_get_type_id(type_resolver)
133    }
134
135    fn fory_get_type_info(type_resolver: &TypeResolver) -> Result<Rc<TypeInfo>, Error> {
136        match type_resolver.get_type_info(&std::any::TypeId::of::<T>()) {
137            Ok(info) => Ok(info),
138            Err(e) => Err(Error::enhance_type_error::<T>(e)),
139        }
140    }
141
142    fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<TypeId, Error> {
143        (**self).fory_type_id_dyn(type_resolver)
144    }
145
146    fn fory_static_type_id() -> TypeId {
147        T::fory_static_type_id()
148    }
149
150    fn as_any(&self) -> &dyn std::any::Any {
151        self
152    }
153}
154
155fn read_rc<T: Serializer + ForyDefault + 'static>(
156    context: &mut ReadContext,
157    ref_mode: RefMode,
158    read_type_info: bool,
159    typeinfo: Option<Rc<TypeInfo>>,
160) -> Result<Rc<T>, Error> {
161    match ref_mode {
162        RefMode::None => {
163            // No ref flag - read inner directly
164            let inner = read_rc_inner::<T>(context, read_type_info, typeinfo)?;
165            Ok(Rc::new(inner))
166        }
167        RefMode::NullOnly => {
168            // Read NotNullValue flag (Null not allowed for Rc)
169            let ref_flag = context.reader.read_i8()?;
170            if ref_flag == RefFlag::Null as i8 {
171                return Err(Error::invalid_ref("Rc cannot be null"));
172            }
173            let inner = read_rc_inner::<T>(context, read_type_info, typeinfo)?;
174            Ok(Rc::new(inner))
175        }
176        RefMode::Tracking => {
177            // Full ref tracking
178            let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?;
179            match ref_flag {
180                RefFlag::Null => Err(Error::invalid_ref("Rc cannot be null")),
181                RefFlag::Ref => {
182                    let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
183                    context.ref_reader.get_rc_ref::<T>(ref_id).ok_or_else(|| {
184                        Error::invalid_ref(format!("Rc reference {ref_id} not found"))
185                    })
186                }
187                RefFlag::NotNullValue => {
188                    let inner = read_rc_inner::<T>(context, read_type_info, typeinfo)?;
189                    Ok(Rc::new(inner))
190                }
191                RefFlag::RefValue => {
192                    let ref_id = context.ref_reader.reserve_ref_id();
193                    let inner = read_rc_inner::<T>(context, read_type_info, typeinfo)?;
194                    let rc = Rc::new(inner);
195                    context.ref_reader.store_rc_ref_at(ref_id, rc.clone());
196                    Ok(rc)
197                }
198            }
199        }
200    }
201}
202
203fn read_rc_inner<T: Serializer + ForyDefault + 'static>(
204    context: &mut ReadContext,
205    read_type_info: bool,
206    typeinfo: Option<Rc<TypeInfo>>,
207) -> Result<T, Error> {
208    // Read type info if needed, then read data directly
209    // No recursive ref handling needed since Rc<T> only wraps allowed types
210    if let Some(typeinfo) = typeinfo {
211        return T::fory_read_with_type_info(context, RefMode::None, typeinfo);
212    }
213    if read_type_info {
214        T::fory_read_type_info(context)?;
215    }
216    T::fory_read_data(context)
217}
218
219impl<T: ForyDefault> ForyDefault for Rc<T> {
220    fn fory_default() -> Self {
221        Rc::new(T::fory_default())
222    }
223}