1use 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 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);