Simple shared types for multi-threaded programs
This library simplifies a number of shared-object patterns that are used in multi-threaded programs such as web-servers. The traditional Rust shared object patterns tend to be somewhat version, for example:
```rust
let object = "123".to_string(); let shared = Arc::new(Mutex::new(object)); shared.lock().expect("Mutex was poisoned"); ```
The [SharedRW
] object hides the complexity of managing Arc<Mutex<T>>
or Arc<RwLock<T>>
behind a single interface:
```rust
let object = "123".tostring(); let shared = SharedRW::new(object); shared.lockread(); ```
By default, a [SharedRW
] object uses Arc<RwLock<T>>
under the hood, but you can choose the synchronization primitive at
construction time. The [SharedRW
] object erases the underlying primitive and you can use them interchangeably:
```rust
fn useshared(shared: SharedRW
let shared = SharedRW::new("123".tostring()); useshared(shared); let shared = SharedRW::newwithtype("123".tostring(), Implementation::Mutex); useshared(shared); ```
Managing the poison state of synchronization primitives can be challenging as well. Rust will poison a Mutex
or RwLock
if you
hold a lock while a panic!
occurs.
The SharedRW
type allows you to specify a [PoisonPolicy
] at construction time. By default, if a synchronization
primitive is poisoned, the SharedRW
will panic!
on access. This can be configured so that poisoning is ignored:
```rust
let shared = SharedRW::newwithpolicy("123".to_string(), PoisonPolicy::Ignore); ```
The [Shared
] object is similar to Rust's [std::sync::Arc
], but adds the ability to project.
Both [Shared
] and [SharedRW
] allow projection into the underlying type. Projection can be used to select
either a subset of a type, or to cast a type to a trait.
Note that projections are always linked to the root object!
Casting:
```rust
let shared = SharedRW::new("123".tostring());
let sharedasref: SharedRW
Subset of a struct/tuple:
```rust
struct Foo { tuple: (String, usize) }
let shared = SharedRW::new(Foo::default());
let shared_string: SharedRW
shared_string.lock_write() += "hello, world"; assert_eq!(shared.lock_read().tuple.0, "hello, world"); assert_eq!(sharedstring.lockread(), "hello, world"); ```
Both [Shared
] and [SharedRW
] support unsized types, but due to current limitations in the language (see [std::ops::CoerceUnsized
] for details),
you need to construct them in special ways.
Unsized traits are supported, but you will either need to specify Send + Sync
in the shared type, or [project_cast!
] the object:
```rust
// In this form, Send + Sync
are visible in the shared type
let boxed: Box
// In this form, Send + Sync
are erased via projection
let shared = SharedRW::new("123".tostring());
let sharedasref: SharedRW
Unsized slices are supported using a box:
```rust
let boxed: Box<[i32]> = Box::new([1, 2, 3]); let shared: SharedRW<[i32]> = SharedRW::from_box(boxed); ```