Skip to main content

fory_core/serializer/
refcell.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::{codec_read_type_info_static, codec_ref_mode, codec_write_type_info, Codec};
19use crate::context::{ReadContext, WriteContext};
20use crate::error::Error;
21use crate::meta::FieldType;
22use crate::resolver::{RefMode, TypeInfo, TypeResolver};
23use crate::serializer::Serializer;
24use crate::type_id::TypeId;
25use std::cell::{Ref, RefCell};
26use std::marker::PhantomData;
27use std::rc::Rc;
28
29pub struct RefCellCodec<T, C, const NULLABLE: bool, const TRACK_REF: bool>(PhantomData<(T, C)>);
30
31#[inline(always)]
32fn borrow_for_write<T>(value: &RefCell<T>) -> Result<Ref<'_, T>, Error> {
33    match value.try_borrow() {
34        Ok(value) => Ok(value),
35        Err(_) => Err(refcell_borrow_error()),
36    }
37}
38
39#[cold]
40#[inline(never)]
41fn refcell_borrow_error() -> Error {
42    Error::invalid_data("cannot serialize RefCell while it is mutably borrowed")
43}
44
45impl<T, C, const NULLABLE: bool, const TRACK_REF: bool> Serializer
46    for RefCellCodec<T, C, NULLABLE, TRACK_REF>
47where
48    T: 'static,
49    C: Serializer<Target = T>,
50{
51    type Target = RefCell<T>;
52
53    #[inline(always)]
54    fn reserved_space() -> usize {
55        C::reserved_space()
56    }
57
58    #[inline(always)]
59    fn write_data(value: &RefCell<T>, context: &mut WriteContext) -> Result<(), Error> {
60        let value = borrow_for_write(value)?;
61        C::write_data(&value, context)
62    }
63
64    #[inline(always)]
65    fn read_data(context: &mut ReadContext) -> Result<RefCell<T>, Error> {
66        Ok(RefCell::new(C::read_data(context)?))
67    }
68
69    #[inline(always)]
70    fn write(
71        value: &RefCell<T>,
72        context: &mut WriteContext,
73        ref_mode: RefMode,
74        write_type_info: bool,
75    ) -> Result<(), Error> {
76        let value = borrow_for_write(value)?;
77        C::write(&value, context, ref_mode, write_type_info)
78    }
79
80    #[inline(always)]
81    fn write_type_info_value(
82        context: &mut WriteContext,
83        target_type_id: std::any::TypeId,
84    ) -> Result<Rc<TypeInfo>, Error> {
85        C::write_type_info_value(context, target_type_id)
86    }
87
88    #[inline(always)]
89    fn write_with_type_info(
90        value: &RefCell<T>,
91        context: &mut WriteContext,
92        ref_mode: RefMode,
93        type_info: &Rc<TypeInfo>,
94    ) -> Result<(), Error> {
95        let value = borrow_for_write(value)?;
96        C::write_with_type_info(&value, context, ref_mode, type_info)
97    }
98
99    #[inline(always)]
100    fn read(
101        context: &mut ReadContext,
102        ref_mode: RefMode,
103        read_type_info: bool,
104    ) -> Result<RefCell<T>, Error> {
105        Ok(RefCell::new(C::read(context, ref_mode, read_type_info)?))
106    }
107
108    #[inline(always)]
109    fn read_with_type_info(
110        context: &mut ReadContext,
111        ref_mode: RefMode,
112        type_info: &Rc<TypeInfo>,
113    ) -> Result<RefCell<T>, Error> {
114        Ok(RefCell::new(C::read_with_type_info(
115            context, ref_mode, type_info,
116        )?))
117    }
118
119    #[inline(always)]
120    fn default_value(context: &mut ReadContext) -> Result<RefCell<T>, Error> {
121        Ok(RefCell::new(C::default_value(context)?))
122    }
123
124    #[inline(always)]
125    fn write_type_info(context: &mut WriteContext) -> Result<(), Error> {
126        C::write_type_info(context)
127    }
128
129    #[inline(always)]
130    fn read_type_info(context: &mut ReadContext) -> Result<(), Error> {
131        C::read_type_info(context)
132    }
133
134    #[inline(always)]
135    fn static_type_id() -> TypeId {
136        C::static_type_id()
137    }
138
139    const IS_OPTIONAL: bool = C::IS_OPTIONAL;
140
141    const IS_POLYMORPHIC: bool = C::IS_POLYMORPHIC;
142
143    const IS_SHARED_REF: bool = C::IS_SHARED_REF;
144
145    const IS_WRAPPER: bool = true;
146
147    const REQUIRES_SCOPED_ACCESS: bool = true;
148
149    #[inline(always)]
150    fn is_none(value: &RefCell<T>) -> bool {
151        if !C::IS_OPTIONAL {
152            return false;
153        }
154        // Static inspection cannot return borrow errors. Use conservative
155        // metadata here; the fallible write path reports the borrow conflict.
156        match value.try_borrow() {
157            Ok(value) => C::is_none(&value),
158            Err(_) => false,
159        }
160    }
161
162    #[inline(always)]
163    fn dynamic_type_id(value: &RefCell<T>) -> Result<Option<std::any::TypeId>, Error> {
164        let value = borrow_for_write(value)?;
165        C::dynamic_type_id(&value)
166    }
167}
168
169impl<T, C, const NULLABLE: bool, const TRACK_REF: bool> Codec<RefCell<T>>
170    for RefCellCodec<T, C, NULLABLE, TRACK_REF>
171where
172    T: 'static,
173    C: Codec<T>,
174{
175    #[inline(always)]
176    fn field_type(type_resolver: &TypeResolver) -> Result<FieldType, Error> {
177        let mut field_type = C::field_type(type_resolver)?;
178        field_type.nullable = NULLABLE;
179        field_type.track_ref = TRACK_REF;
180        Ok(field_type)
181    }
182
183    #[inline(always)]
184    fn field_reserved_space() -> usize {
185        C::field_reserved_space()
186    }
187
188    #[inline(always)]
189    fn write_field(value: &RefCell<T>, context: &mut WriteContext) -> Result<(), Error> {
190        Self::write_with_mode(
191            value,
192            context,
193            codec_ref_mode::<T, C, NULLABLE, TRACK_REF>(),
194            codec_write_type_info::<T, C>(context),
195            true,
196        )
197    }
198
199    #[inline(always)]
200    fn read_field(context: &mut ReadContext) -> Result<RefCell<T>, Error> {
201        <Self as Serializer>::read(
202            context,
203            codec_ref_mode::<T, C, NULLABLE, TRACK_REF>(),
204            codec_read_type_info_static::<T, C>(context),
205        )
206    }
207
208    #[inline(always)]
209    fn read_data_with_type(
210        context: &mut ReadContext,
211        remote_data_type: &FieldType,
212    ) -> Result<RefCell<T>, Error> {
213        Ok(RefCell::new(C::read_data_with_type(
214            context,
215            remote_data_type,
216        )?))
217    }
218
219    #[inline(always)]
220    fn read_field_with_type(
221        context: &mut ReadContext,
222        remote_field_type: &FieldType,
223    ) -> Result<RefCell<T>, Error> {
224        Ok(RefCell::new(C::read_field_with_type(
225            context,
226            remote_field_type,
227        )?))
228    }
229
230    #[inline(always)]
231    fn write_with_mode(
232        value: &RefCell<T>,
233        context: &mut WriteContext,
234        ref_mode: RefMode,
235        write_type_info: bool,
236        has_generics: bool,
237    ) -> Result<(), Error> {
238        let value = borrow_for_write(value)?;
239        C::write_with_mode(&value, context, ref_mode, write_type_info, has_generics)
240    }
241
242    #[inline(always)]
243    fn write_with_type_info(
244        value: &RefCell<T>,
245        context: &mut WriteContext,
246        ref_mode: RefMode,
247        type_info: &Rc<TypeInfo>,
248        has_generics: bool,
249    ) -> Result<(), Error> {
250        let value = borrow_for_write(value)?;
251        <C as Codec<T>>::write_with_type_info(&value, context, ref_mode, type_info, has_generics)
252    }
253
254    #[inline(always)]
255    fn read_type_info_value(
256        context: &mut ReadContext,
257    ) -> Result<super::codec::CodecReadType, Error> {
258        C::read_type_info_value(context)
259    }
260}
261
262impl_single_carrier_serializer!(RefCellSerializer, RefCell, RefCellCodec, wrapper = true);