Skip to content

Commit 3461cf2

Browse files
author
kaori-seasons
committed
refactor; support mutex Serializer trait
1 parent d0b301c commit 3461cf2

File tree

7 files changed

+842
-13
lines changed

7 files changed

+842
-13
lines changed

rust/fory-core/src/meta/type_traits.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@
8686
//! - Trait objects (`dyn Trait`) are always polymorphic
8787
//! - Generic structs depend on their type parameters
8888
89-
use std::any::TypeId;
9089
use std::collections::HashMap;
9190
use std::rc::Rc;
9291
use std::sync::Arc;

rust/fory-core/src/resolver/ref_tracker.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,6 @@
2929
//! 3. **Performance**: Minimal overhead for acyclic graphs
3030
//! 4. **Extensibility**: Support future optimizations like reference counting analysis
3131
//!
32-
//! ## Current Status
33-
//!
34-
//! **Phase 4 (Week 11-12)**: Basic infrastructure reserved
35-
//! - Type definitions and interfaces
36-
//! - Placeholder implementations
37-
//! - Documentation and examples
38-
//!
39-
//! **Future Phases**: Full implementation
40-
//! - Cycle detection algorithm
41-
//! - Reference graph traversal
42-
//! - Memory optimization strategies
4332
//!
4433
//! ## Usage Example (Future)
4534
//!
@@ -73,7 +62,6 @@
7362
//! before writing reference data.
7463
7564
use std::collections::{HashMap, HashSet};
76-
use std::hash::{Hash, Hasher};
7765
use std::ptr;
7866

7967
/// Reference tracker for circular reference detection and graph management.

rust/fory-core/src/serializer/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ mod option;
3232
mod primitive_list;
3333
mod rc;
3434
mod refcell;
35+
mod rwlock;
3536
mod set;
3637
pub mod skip;
3738
mod string;

rust/fory-core/src/serializer/mutex.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
//! - A poisoned mutex (from a panicked holder) will cause `.lock().unwrap()` to panic
4343
//! during serialization — it is assumed this is a programmer error.
4444
use crate::error::Error;
45+
use crate::meta::type_traits::TypeCharacteristics;
4546
use crate::resolver::context::{ReadContext, WriteContext};
4647
use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
4748
use crate::serializer::{ForyDefault, Serializer};
@@ -157,3 +158,33 @@ impl<T: ForyDefault> ForyDefault for Mutex<T> {
157158
Mutex::new(T::fory_default())
158159
}
159160
}
161+
162+
// ============================================================================
163+
// TypeCharacteristics Implementation for Mutex<T>
164+
// ============================================================================
165+
166+
/// Mutex<T> inherits type characteristics from T.
167+
///
168+
/// Since Mutex is a transparent wrapper for thread-safe interior mutability,
169+
/// it preserves the morphic/polymorphic nature of the contained type.
170+
///
171+
/// # Examples
172+
///
173+
/// ```rust,ignore
174+
/// use std::sync::Mutex;
175+
/// use fory_core::meta::type_traits::TypeCharacteristics;
176+
///
177+
/// // Mutex<i32> is morphic because i32 is morphic
178+
/// assert!(Mutex::<i32>::is_morphic());
179+
///
180+
/// // Mutex<dyn Trait> would be polymorphic if the inner type is
181+
/// ```
182+
impl<T: TypeCharacteristics> TypeCharacteristics for Mutex<T> {
183+
fn is_morphic() -> bool {
184+
T::is_morphic()
185+
}
186+
187+
fn is_polymorphic() -> bool {
188+
T::is_polymorphic()
189+
}
190+
}

rust/fory-core/src/serializer/refcell.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
//! // Can be serialized by the Fory framework
3434
//! ```
3535
use crate::error::Error;
36+
use crate::meta::type_traits::TypeCharacteristics;
3637
use crate::resolver::context::{ReadContext, WriteContext};
3738
use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
3839
use crate::serializer::{ForyDefault, Serializer};
@@ -147,3 +148,31 @@ impl<T: ForyDefault> ForyDefault for RefCell<T> {
147148
RefCell::new(T::fory_default())
148149
}
149150
}
151+
152+
// ============================================================================
153+
// TypeCharacteristics Implementation for RefCell<T>
154+
// ============================================================================
155+
156+
/// RefCell<T> inherits type characteristics from T.
157+
///
158+
/// Since RefCell is a transparent wrapper for interior mutability,
159+
/// it preserves the morphic/polymorphic nature of the contained type.
160+
///
161+
/// # Examples
162+
///
163+
/// ```rust,ignore
164+
/// use std::cell::RefCell;
165+
/// use fory_core::meta::type_traits::TypeCharacteristics;
166+
///
167+
/// // RefCell<String> is morphic because String is morphic
168+
/// assert!(RefCell::<String>::is_morphic());
169+
/// ```
170+
impl<T: TypeCharacteristics> TypeCharacteristics for RefCell<T> {
171+
fn is_morphic() -> bool {
172+
T::is_morphic()
173+
}
174+
175+
fn is_polymorphic() -> bool {
176+
T::is_polymorphic()
177+
}
178+
}
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
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 `RwLock<T>`.
19+
//!
20+
//! This module implements [`Serializer`] and [`ForyDefault`] for [`std::sync::RwLock<T>`].
21+
//! It allows thread-safe read-write lock containers to be part of serialized graphs.
22+
//!
23+
//! Unlike [`std::rc::Rc`] and [`std::sync::Arc`], `RwLock` does not do reference counting, so this wrapper relies
24+
//! on the serialization of the contained `T` only.
25+
//!
26+
//! This is commonly used together with `Arc<RwLock<T>>` in multi-threaded applications
27+
//! where reads are more frequent than writes.
28+
//!
29+
//! # Example
30+
//! ```rust
31+
//! use std::sync::RwLock;
32+
//! use fory_core::{Serializer, ForyDefault};
33+
//!
34+
//! let rwlock = RwLock::new(42);
35+
//! // Can be serialized by the Fory framework
36+
//! ```
37+
//!
38+
//! # Caveats
39+
//!
40+
//! - Serialization locks the RwLock for reading while accessing the inner value.
41+
//! - If a write lock is held during serialization, this will block until the write completes.
42+
//! - You should serialize in a quiescent state with no concurrent writes for best performance.
43+
//! - A poisoned RwLock (from a panicked holder) will cause `.read().unwrap()` to panic
44+
//! during serialization — it is assumed this is a programmer error.
45+
46+
use crate::error::Error;
47+
use crate::meta::type_traits::TypeCharacteristics;
48+
use crate::resolver::context::{ReadContext, WriteContext};
49+
use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
50+
use crate::serializer::{ForyDefault, Serializer};
51+
use crate::types::TypeId;
52+
use std::rc::Rc;
53+
use std::sync::RwLock;
54+
55+
/// `Serializer` impl for `RwLock<T>`
56+
///
57+
/// Simply delegates to the serializer for `T`, allowing thread-safe read-write lock
58+
/// containers to be included in serialized graphs.
59+
impl<T: Serializer + ForyDefault> Serializer for RwLock<T> {
60+
fn fory_write(
61+
&self,
62+
context: &mut WriteContext,
63+
write_ref_data: bool,
64+
write_type_info: bool,
65+
has_generics: bool,
66+
) -> Result<(), Error> {
67+
// Don't add ref tracking for RwLock itself, just delegate to inner type
68+
// The inner type will handle its own ref tracking
69+
let guard = self.read().unwrap();
70+
T::fory_write(
71+
&*guard,
72+
context,
73+
write_ref_data,
74+
write_type_info,
75+
has_generics,
76+
)
77+
}
78+
79+
fn fory_write_data_generic(
80+
&self,
81+
context: &mut WriteContext,
82+
has_generics: bool,
83+
) -> Result<(), Error> {
84+
T::fory_write_data_generic(&*self.read().unwrap(), context, has_generics)
85+
}
86+
87+
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
88+
// When called from Rc/Arc, just delegate to inner type's data serialization
89+
let guard = self.read().unwrap();
90+
T::fory_write_data(&*guard, context)
91+
}
92+
93+
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
94+
T::fory_write_type_info(context)
95+
}
96+
97+
fn fory_reserved_space() -> usize {
98+
// RwLock is transparent, delegate to inner type
99+
T::fory_reserved_space()
100+
}
101+
102+
fn fory_read(
103+
context: &mut ReadContext,
104+
read_ref_info: bool,
105+
read_type_info: bool,
106+
) -> Result<Self, Error>
107+
where
108+
Self: Sized + ForyDefault,
109+
{
110+
Ok(RwLock::new(T::fory_read(
111+
context,
112+
read_ref_info,
113+
read_type_info,
114+
)?))
115+
}
116+
117+
fn fory_read_with_type_info(
118+
context: &mut ReadContext,
119+
read_ref_info: bool,
120+
type_info: Rc<TypeInfo>,
121+
) -> Result<Self, Error>
122+
where
123+
Self: Sized + ForyDefault,
124+
{
125+
Ok(RwLock::new(T::fory_read_with_type_info(
126+
context,
127+
read_ref_info,
128+
type_info,
129+
)?))
130+
}
131+
132+
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
133+
Ok(RwLock::new(T::fory_read_data(context)?))
134+
}
135+
136+
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
137+
T::fory_read_type_info(context)
138+
}
139+
140+
fn fory_get_type_id(type_resolver: &TypeResolver) -> Result<u32, Error> {
141+
T::fory_get_type_id(type_resolver)
142+
}
143+
144+
fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<u32, Error> {
145+
let guard = self.read().unwrap();
146+
(*guard).fory_type_id_dyn(type_resolver)
147+
}
148+
149+
fn fory_static_type_id() -> TypeId {
150+
T::fory_static_type_id()
151+
}
152+
153+
fn as_any(&self) -> &dyn std::any::Any {
154+
self
155+
}
156+
}
157+
158+
impl<T: ForyDefault> ForyDefault for RwLock<T> {
159+
fn fory_default() -> Self {
160+
RwLock::new(T::fory_default())
161+
}
162+
}
163+
164+
// ============================================================================
165+
// TypeCharacteristics Implementation for RwLock<T>
166+
// ============================================================================
167+
168+
/// RwLock<T> inherits type characteristics from T.
169+
///
170+
/// Since RwLock is a transparent wrapper for thread-safe read-write locking,
171+
/// it preserves the morphic/polymorphic nature of the contained type.
172+
///
173+
/// # Examples
174+
///
175+
/// ```rust,ignore
176+
/// use std::sync::RwLock;
177+
/// use fory_core::meta::type_traits::TypeCharacteristics;
178+
///
179+
/// // RwLock<Vec<i32>> is morphic because Vec<i32> is morphic
180+
/// assert!(RwLock::<Vec<i32>>::is_morphic());
181+
/// ```
182+
impl<T: TypeCharacteristics> TypeCharacteristics for RwLock<T> {
183+
fn is_morphic() -> bool {
184+
T::is_morphic()
185+
}
186+
187+
fn is_polymorphic() -> bool {
188+
T::is_polymorphic()
189+
}
190+
}
191+
192+
#[cfg(test)]
193+
mod tests {
194+
use super::*;
195+
use crate::fory::Fory;
196+
197+
#[test]
198+
fn test_rwlock_basic_serialization() {
199+
let fory = Fory::default();
200+
let rwlock = RwLock::new(42i32);
201+
202+
let serialized = fory.serialize(&rwlock).unwrap();
203+
let deserialized: RwLock<i32> = fory.deserialize(&serialized).unwrap();
204+
205+
assert_eq!(*deserialized.read().unwrap(), 42);
206+
}
207+
208+
#[test]
209+
fn test_rwlock_string_serialization() {
210+
let fory = Fory::default();
211+
let rwlock = RwLock::new(String::from("Hello, RwLock!"));
212+
213+
let serialized = fory.serialize(&rwlock).unwrap();
214+
let deserialized: RwLock<String> = fory.deserialize(&serialized).unwrap();
215+
216+
assert_eq!(*deserialized.read().unwrap(), "Hello, RwLock!");
217+
}
218+
219+
#[test]
220+
fn test_rwlock_vec_serialization() {
221+
let fory = Fory::default();
222+
let rwlock = RwLock::new(vec![1, 2, 3, 4, 5]);
223+
224+
let serialized = fory.serialize(&rwlock).unwrap();
225+
let deserialized: RwLock<Vec<i32>> = fory.deserialize(&serialized).unwrap();
226+
227+
assert_eq!(*deserialized.read().unwrap(), vec![1, 2, 3, 4, 5]);
228+
}
229+
230+
#[test]
231+
fn test_rwlock_type_characteristics() {
232+
// RwLock<i32> should be morphic
233+
assert!(RwLock::<i32>::is_morphic());
234+
assert!(!RwLock::<i32>::is_polymorphic());
235+
236+
// RwLock<String> should be morphic
237+
assert!(RwLock::<String>::is_morphic());
238+
assert!(!RwLock::<String>::is_polymorphic());
239+
240+
// RwLock<Vec<i32>> should be morphic
241+
assert!(RwLock::<Vec<i32>>::is_morphic());
242+
assert!(!RwLock::<Vec<i32>>::is_polymorphic());
243+
}
244+
}

0 commit comments

Comments
 (0)