Skip to main content

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