Skip to main content

fory_core/serializer/
weak.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
18//! Serialization support for [`crate::types::weak::RcWeak`] and [`crate::types::weak::ArcWeak`].
19
20use crate::context::{ReadContext, WriteContext};
21use crate::error::Error;
22use crate::resolver::{RefFlag, RefMode};
23use crate::resolver::{TypeInfo, TypeResolver};
24use crate::serializer::{ForyDefault, Serializer};
25use crate::type_id::TypeId;
26use crate::types::{ArcWeak, RcWeak};
27use std::rc::Rc;
28use std::sync::Arc;
29
30impl<T: Serializer + ForyDefault + 'static> Serializer for RcWeak<T> {
31    fn fory_is_shared_ref() -> bool {
32        true
33    }
34
35    fn fory_write(
36        &self,
37        context: &mut WriteContext,
38        ref_mode: RefMode,
39        write_type_info: bool,
40        has_generics: bool,
41    ) -> Result<(), Error> {
42        // Weak pointers require track_ref to be enabled on the Fory instance
43        if !context.is_track_ref() {
44            return Err(Error::invalid_ref(
45                "RcWeak requires track_ref to be enabled. Use Fory::builder().track_ref(true).build()",
46            ));
47        }
48        // Weak MUST use ref tracking - otherwise read value will be lost
49        if ref_mode != RefMode::Tracking {
50            return Err(Error::invalid_ref(
51                "RcWeak requires RefMode::Tracking for serialization",
52            ));
53        }
54        if let Some(rc) = self.upgrade() {
55            if !context
56                .ref_writer
57                .try_write_rc_ref(&mut context.writer, &rc)
58            {
59                if write_type_info {
60                    T::fory_write_type_info(context)?;
61                }
62                T::fory_write_data_generic(&*rc, context, has_generics)?;
63            }
64        } else {
65            context.writer.write_i8(RefFlag::Null as i8);
66        }
67        Ok(())
68    }
69
70    fn fory_write_data_generic(&self, _: &mut WriteContext, _: bool) -> Result<(), Error> {
71        Err(Error::not_allowed(
72            "RcWeak<T> should be written using `fory_write` to handle reference tracking properly",
73        ))
74    }
75
76    fn fory_write_data(&self, _: &mut WriteContext) -> Result<(), Error> {
77        Err(Error::not_allowed(
78            "RcWeak<T> should be written using `fory_write` to handle reference tracking properly",
79        ))
80    }
81
82    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
83        T::fory_write_type_info(context)
84    }
85
86    fn fory_read(
87        context: &mut ReadContext,
88        ref_mode: RefMode,
89        read_type_info: bool,
90    ) -> Result<Self, Error> {
91        // Weak MUST track refs
92        debug_assert!(
93            ref_mode == RefMode::Tracking,
94            "RcWeak requires RefMode::Tracking"
95        );
96        read_rc_weak::<T>(context, read_type_info, None)
97    }
98
99    fn fory_read_with_type_info(
100        context: &mut ReadContext,
101        ref_mode: RefMode,
102        typeinfo: Rc<TypeInfo>,
103    ) -> Result<Self, Error> {
104        debug_assert!(
105            ref_mode == RefMode::Tracking,
106            "RcWeak requires RefMode::Tracking"
107        );
108        read_rc_weak::<T>(context, false, Some(typeinfo))
109    }
110
111    fn fory_read_data(_: &mut ReadContext) -> Result<Self, Error> {
112        Err(Error::not_allowed("RcWeak<T> should be written using `fory_read/fory_read_with_type_info` to handle reference tracking properly"))
113    }
114
115    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
116        T::fory_read_type_info(context)
117    }
118
119    fn fory_reserved_space() -> usize {
120        // RcWeak is a shared ref, return a const to avoid infinite recursion
121        4
122    }
123
124    fn fory_get_type_id(type_resolver: &TypeResolver) -> Result<TypeId, Error> {
125        T::fory_get_type_id(type_resolver)
126    }
127
128    fn fory_get_type_info(type_resolver: &TypeResolver) -> Result<Rc<TypeInfo>, Error> {
129        T::fory_get_type_info(type_resolver)
130    }
131
132    fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<TypeId, Error> {
133        if let Some(rc) = self.upgrade() {
134            (*rc).fory_type_id_dyn(type_resolver)
135        } else {
136            T::fory_get_type_id(type_resolver)
137        }
138    }
139
140    fn fory_static_type_id() -> TypeId {
141        T::fory_static_type_id()
142    }
143
144    fn as_any(&self) -> &dyn std::any::Any {
145        self
146    }
147}
148
149fn read_rc_weak<T: Serializer + ForyDefault + 'static>(
150    context: &mut ReadContext,
151    read_type_info: bool,
152    type_info: Option<Rc<TypeInfo>>,
153) -> Result<RcWeak<T>, Error> {
154    // Always read ref flag - Weak requires tracking
155    let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?;
156    match ref_flag {
157        RefFlag::Null => Ok(RcWeak::new()),
158        RefFlag::RefValue => {
159            context.inc_depth()?;
160            let data = if let Some(type_info) = type_info {
161                T::fory_read_with_type_info(context, RefMode::None, type_info)?
162            } else {
163                if read_type_info {
164                    context.read_any_type_info()?;
165                }
166                T::fory_read_data(context)?
167            };
168            context.dec_depth();
169            let rc = Rc::new(data);
170            let ref_id = context.ref_reader.store_rc_ref(rc);
171            let rc = context.ref_reader.get_rc_ref::<T>(ref_id).unwrap();
172            Ok(RcWeak::from(&rc))
173        }
174        RefFlag::Ref => {
175            let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
176            if let Some(rc) = context.ref_reader.get_rc_ref::<T>(ref_id) {
177                Ok(RcWeak::from(&rc))
178            } else {
179                let result_weak = RcWeak::new();
180                let callback_weak = result_weak.clone();
181                context.ref_reader.add_callback(Box::new(move |ref_reader| {
182                    if let Some(rc) = ref_reader.get_rc_ref::<T>(ref_id) {
183                        callback_weak.update(Rc::downgrade(&rc));
184                    }
185                }));
186
187                Ok(result_weak)
188            }
189        }
190        RefFlag::NotNullValue => Err(Error::invalid_ref("RcWeak can't hold a strong ref value")),
191    }
192}
193
194impl<T: ForyDefault> ForyDefault for RcWeak<T> {
195    fn fory_default() -> Self {
196        RcWeak::new()
197    }
198}
199
200impl<T: Serializer + ForyDefault + Send + Sync + 'static> Serializer for ArcWeak<T> {
201    fn fory_is_shared_ref() -> bool {
202        true
203    }
204
205    fn fory_write(
206        &self,
207        context: &mut WriteContext,
208        ref_mode: RefMode,
209        write_type_info: bool,
210        has_generics: bool,
211    ) -> Result<(), Error> {
212        // Weak pointers require track_ref to be enabled on the Fory instance
213        if !context.is_track_ref() {
214            return Err(Error::invalid_ref(
215                "ArcWeak requires track_ref to be enabled. Use Fory::builder().track_ref(true).build()",
216            ));
217        }
218        // Weak MUST use ref tracking - otherwise read value will be lost
219        if ref_mode != RefMode::Tracking {
220            return Err(Error::invalid_ref(
221                "ArcWeak requires RefMode::Tracking for serialization",
222            ));
223        }
224        if let Some(arc) = self.upgrade() {
225            if !context
226                .ref_writer
227                .try_write_arc_ref(&mut context.writer, &arc)
228            {
229                if write_type_info {
230                    T::fory_write_type_info(context)?;
231                }
232                T::fory_write_data_generic(&*arc, context, has_generics)?;
233            }
234        } else {
235            context.writer.write_i8(RefFlag::Null as i8);
236        }
237        Ok(())
238    }
239
240    fn fory_write_data_generic(&self, _: &mut WriteContext, _: bool) -> Result<(), Error> {
241        Err(Error::not_allowed(
242            "ArcWeak<T> should be written using `fory_write` to handle reference tracking properly",
243        ))
244    }
245
246    fn fory_write_data(&self, _: &mut WriteContext) -> Result<(), Error> {
247        Err(Error::not_allowed(
248            "ArcWeak<T> should be written using `fory_write` to handle reference tracking properly",
249        ))
250    }
251
252    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
253        T::fory_write_type_info(context)
254    }
255
256    fn fory_read(
257        context: &mut ReadContext,
258        ref_mode: RefMode,
259        read_type_info: bool,
260    ) -> Result<Self, Error> {
261        // Weak MUST track refs
262        debug_assert!(
263            ref_mode == RefMode::Tracking,
264            "ArcWeak requires RefMode::Tracking"
265        );
266        read_arc_weak(context, read_type_info, None)
267    }
268
269    fn fory_read_with_type_info(
270        context: &mut ReadContext,
271        ref_mode: RefMode,
272        typeinfo: Rc<TypeInfo>,
273    ) -> Result<Self, Error> {
274        debug_assert!(
275            ref_mode == RefMode::Tracking,
276            "ArcWeak requires RefMode::Tracking"
277        );
278        read_arc_weak::<T>(context, false, Some(typeinfo))
279    }
280
281    fn fory_read_data(_: &mut ReadContext) -> Result<Self, Error> {
282        Err(Error::not_allowed("ArcWeak<T> should be written using `fory_read/fory_read_with_type_info` to handle reference tracking properly"))
283    }
284
285    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
286        T::fory_read_type_info(context)
287    }
288
289    fn fory_reserved_space() -> usize {
290        // ArcWeak is a shared ref, return a const to avoid infinite recursion
291        4
292    }
293
294    fn fory_get_type_id(type_resolver: &TypeResolver) -> Result<TypeId, Error> {
295        T::fory_get_type_id(type_resolver)
296    }
297
298    fn fory_get_type_info(type_resolver: &TypeResolver) -> Result<Rc<TypeInfo>, Error> {
299        T::fory_get_type_info(type_resolver)
300    }
301
302    fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<TypeId, Error> {
303        if let Some(arc) = self.upgrade() {
304            (*arc).fory_type_id_dyn(type_resolver)
305        } else {
306            T::fory_get_type_id(type_resolver)
307        }
308    }
309
310    fn fory_static_type_id() -> TypeId {
311        T::fory_static_type_id()
312    }
313
314    fn as_any(&self) -> &dyn std::any::Any {
315        self
316    }
317}
318
319fn read_arc_weak<T: Serializer + ForyDefault + 'static>(
320    context: &mut ReadContext,
321    read_type_info: bool,
322    type_info: Option<Rc<TypeInfo>>,
323) -> Result<ArcWeak<T>, Error> {
324    // Always read ref flag - Weak requires tracking
325    let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?;
326    match ref_flag {
327        RefFlag::Null => Ok(ArcWeak::new()),
328        RefFlag::RefValue => {
329            context.inc_depth()?;
330            let data = if let Some(type_info) = type_info {
331                T::fory_read_with_type_info(context, RefMode::None, type_info)?
332            } else {
333                if read_type_info {
334                    context.read_any_type_info()?;
335                }
336                T::fory_read_data(context)?
337            };
338            context.dec_depth();
339            let arc = Arc::new(data);
340            let ref_id = context.ref_reader.store_arc_ref(arc);
341            let arc = context.ref_reader.get_arc_ref::<T>(ref_id).unwrap();
342            let weak = ArcWeak::from(&arc);
343            Ok(weak)
344        }
345        RefFlag::Ref => {
346            let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
347            let weak = ArcWeak::new();
348
349            if let Some(arc) = context.ref_reader.get_arc_ref::<T>(ref_id) {
350                weak.update(Arc::downgrade(&arc));
351            } else {
352                let callback_weak = weak.clone();
353                context.ref_reader.add_callback(Box::new(move |ref_reader| {
354                    if let Some(arc) = ref_reader.get_arc_ref::<T>(ref_id) {
355                        callback_weak.update(Arc::downgrade(&arc));
356                    }
357                }));
358            }
359            Ok(weak)
360        }
361        RefFlag::NotNullValue => Err(Error::invalid_ref("ArcWeak can't hold a strong ref value")),
362    }
363}
364
365impl<T: ForyDefault> ForyDefault for ArcWeak<T> {
366    fn fory_default() -> Self {
367        ArcWeak::new()
368    }
369}