| Crates.io | shared-container |
| lib.rs | shared-container |
| version | 0.3.0 |
| created_at | 2025-07-14 09:22:42.972649+00 |
| updated_at | 2025-10-06 12:04:48.616237+00 |
| description | A unified abstraction for shared data access in both multi-threaded and single-threaded environments |
| homepage | |
| repository | https://github.com/edc-studio/shared-container |
| max_upload_size | |
| id | 1751424 |
| size | 95,263 |
Type-safe shared data access for multi-threaded, async, and single-threaded environments.
shared-container provides type-safe abstractions for shared data access across different runtime environments:
Arc<RwLock<T>> on native platformsRc<RefCell<T>>Arc<tokio::sync::RwLock<T>>Version 0.3 introduces type-level separation between sync and async, eliminating runtime surprises and providing explicit error handling.
Shared<T>) and async (AsyncShared<T>)Result<_, AccessError> instead of Option or panicsAdd this to your Cargo.toml:
[dependencies]
shared-container = "0.3"
use shared_container::{Shared, SyncAccess};
// Create a new container
let container = Shared::new(42);
// Read access
let guard = container.read().unwrap();
assert_eq!(*guard, 42);
drop(guard);
// Write access
let mut guard = container.write().unwrap();
* guard = 100;
drop(guard);
// Clone the container (both point to the same data)
let container2 = container.clone();
// Get a cloned value
let value = container.get_cloned().unwrap();
assert_eq!(value, 100);
Enable the async feature:
[dependencies]
shared-container = { version = "0.3.0", features = ["async"] }
use shared_container::{AsyncShared, AsyncAccess};
async fn example() {
let container = AsyncShared::new(42);
// Async read access
let guard = container.read_async().await;
assert_eq!(*guard, 42);
drop(guard);
// Async write access
let mut guard = container.write_async().await;
*guard = 100;
drop(guard);
// Clone works the same
let container2 = container.clone();
// Get cloned value asynchronously
let value = container.get_cloned_async().await;
assert_eq!(value, 100);
}
use shared_container::{Shared, SyncAccess};
#[derive(Debug, Clone)]
struct User {
id: u64,
name: String,
}
let container = Shared::new(User {
id: 1,
name: "Alice".to_string(),
});
// Modify the user
let mut guard = container.write().unwrap();
guard.name = "Bob".to_string();
drop(guard);
// Get a snapshot
let user_snapshot = container.get_cloned().unwrap();
println!("User: {:?}", user_snapshot);
use shared_container::{Shared, SyncAccess};
let container = Shared::new(42);
let weak = container.downgrade();
// Try to upgrade
if let Some(strong) = weak.upgrade() {
let guard = strong.read().unwrap();
println ! ("Value: {}", * guard);
} else {
println ! ("Value was dropped");
}
// After dropping all strong references
drop(container);
assert!(weak.upgrade().is_none());
The new API uses AccessError enum for explicit error handling:
use shared_container::{Shared, SyncAccess, AccessError};
let container = Shared::new(42);
match container.read() {
Ok(guard) => println ! ("Value: {}", * guard),
Err(AccessError::Poisoned) => println ! ("Lock was poisoned"),
Err(AccessError::BorrowConflict) => println ! ("Already borrowed"),
Err(AccessError::UnsupportedMode) => println ! ("Wrong container type"),
}
Poisoned: Lock was poisoned by a panic (multi-threaded only)BorrowConflict: Borrow rules violated (WebAssembly RefCell only)UnsupportedMode: Operation not supported for this container typeFor generic code that needs to work with both sync and async containers:
use shared_container::{SharedAny, Shared, SyncAccess, AccessError};
fn process_container(container: SharedAny<i32>) {
match container.read() {
Ok(guard) => println!("Sync read: {}", *guard),
Err(AccessError::UnsupportedMode) => {
println!("This is an async container, use read_async() instead");
}
Err(e) => println!("Error: {}", e),
}
}
let sync_container: SharedAny<i32> = Shared::new(42).into();
process_container(sync_container);
| Platform | Backend | Notes |
|---|---|---|
| Native (multi-threaded) | Arc<std::sync::RwLock<T>> |
Can be poisoned by panics |
| WebAssembly | Rc<RefCell<T>> |
Borrow checking at runtime |
| Async (Tokio) | Arc<tokio::sync::RwLock<T>> |
Requires async feature |
async: Enables AsyncShared<T> and async trait methods (requires tokio)std-sync (default): Legacy support for SharedContainer with std sync primitivestokio-sync: Legacy support for SharedContainer with tokio primitives (deprecated)wasm-sync: Legacy support for forcing WebAssembly backendVersion 0.3 introduces breaking changes with a clearer, type-safe API. The old SharedContainer<T> is deprecated but
still available.
| Old (0.2.x) | New (0.3.x) |
|---|---|
SharedContainer::new(v) (std-sync) |
Shared::new(v) |
SharedContainer::new(v) (tokio-sync) |
AsyncShared::new(v) with async feature |
container.read() → Option<Guard> |
container.read() → Result<Guard, AccessError> |
container.write() → Option<Guard> |
container.write() → Result<Guard, AccessError> |
container.read_async().await |
container.read_async().await (same) |
Before (0.2.x):
use shared_container::SharedContainer;
let container = SharedContainer::new(42);
if let Some(guard) = container.read() {
println ! ("{}", * guard);
}
After (0.3.x):
use shared_container::{Shared, SyncAccess};
let container = Shared::new(42);
match container.read() {
Ok(guard) => println ! ("{}", * guard),
Err(e) => eprintln! ("Error: {}", e),
}
For async code with tokio:
Before (0.2.x with tokio-sync):
use shared_container::SharedContainer;
let container = SharedContainer::new(42);
let guard = container.read_async().await;
After (0.3.x with async feature):
use shared_container::{AsyncShared, AsyncAccess};
let container = AsyncShared::new(42);
let guard = container.read_async().await;
# Run all tests with default features
cargo test
# Run tests with async support
cargo test --features async
# Run all tests
cargo test --all-features
This project is licensed under the MIT License - see the LICENSE file for details.