| Crates.io | tspawn |
| lib.rs | tspawn |
| version | 0.1.0 |
| created_at | 2025-06-16 17:13:14.519707+00 |
| updated_at | 2025-06-16 17:13:14.519707+00 |
| description | A thread-safe wrapper around Arc |
| homepage | https://github.com/modeckrus/tspawn |
| repository | https://github.com/modeckrus/tspawn |
| max_upload_size | |
| id | 1714543 |
| size | 66,435 |
tspawn is a Rust library that provides a thread-safe wrapper around Arc<RwLock<T>> with convenient cloning semantics and powerful async task spawning macros. It simplifies working with shared mutable state in concurrent and asynchronous Rust applications.
parking_lot::RwLock for better performance than std::sync::RwLockArc::clone() callstspawn! macro for spawning tokio tasks with automatic cloningparking_lot which doesn't have lock poisoningArc<RwLock<T>> usageAdd this to your Cargo.toml:
[dependencies]
tspawn = "0.1"
tokio = { version = "1.0", features = ["full"] }
use tspawn::{A, tspawn};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a shared counter
let counter = A::new(0);
// Spawn a task that increments the counter
tspawn!(mut counter, {
*counter += 1;
println!("Counter incremented to: {}", *counter);
}).await?;
// Read the final value
println!("Final counter value: {}", counter.get());
Ok(())
}
A<T> - The Main WrapperA<T> is a thread-safe wrapper around Arc<RwLock<T>> that provides convenient methods for accessing and modifying shared data:
use tspawn::A;
let data = A::new(42);
// Read access
let value = data.get(); // Returns a clone of the inner value
let guard = data.read(); // Returns a read guard
// Write access
data.set(100); // Set a new value
data.update(|x| *x += 1); // Update using a closure
let mut guard = data.write(); // Returns a write guard
tspawn! MacroThe tspawn! macro simplifies spawning tokio tasks with shared state. It automatically clones the necessary data and provides different access patterns:
use tspawn::{A, tspawn};
let data = A::new(vec![1, 2, 3]);
// Read-only access
tspawn!(ref data, {
println!("Data length: {}", data.len());
}).await?;
// Write access
tspawn!(mut data, {
data.push(4);
println!("Added element, new length: {}", data.len());
}).await?;
// Clone access (moves the cloned wrapper)
tspawn!(data, {
let value = data.get();
println!("Current value: {:?}", value);
}).await?;
use tspawn::{A, tspawn};
let x = A::new(10);
let y = A::new(20);
// Multiple read access
tspawn!(ref x, ref y, {
println!("Sum: {}", *x + *y);
}).await?;
// Mixed access patterns
tspawn!(mut x, ref y, {
*x += *y;
println!("x updated to: {}", *x);
}).await?;
use tspawn::{A, tspawn};
let a = A::new(5);
let b = A::new(10);
let c = A::new(15);
// Three variables with mixed access
tspawn!(mut a, ref b, c, {
*a = *b + *c.read();
println!("Updated a: {}", *a);
}).await?;
use tspawn::A;
use std::collections::HashMap;
#[derive(Clone)]
struct UserData {
name: String,
score: i32,
}
let users = A::new(HashMap::<String, UserData>::new());
// Add a user
users.update(|map| {
map.insert("alice".to_string(), UserData {
name: "Alice".to_string(),
score: 100,
});
});
// Read user data
if let Some(user) = users.read().get("alice") {
println!("User: {}, Score: {}", user.name, user.score);
}
use tspawn::{A, tspawn};
async fn process_data(data: A<Vec<i32>>) {
tspawn!(mut data, {
data.sort();
data.reverse();
println!("Processed data: {:?}", *data);
}).await.unwrap();
}
#[tokio::main]
async fn main() {
let numbers = A::new(vec![3, 1, 4, 1, 5, 9]);
process_data(numbers).await;
}
A<T> Methodsnew(value: T) -> Self - Create a new wrapperget() -> T - Get a clone of the inner value (requires T: Clone)set(value: T) - Set a new valueupdate<F>(f: F) - Update the value using a closureread() -> RwLockReadGuard<'_, T> - Get a read guardwrite() -> RwLockWriteGuard<'_, T> - Get a write guardfrom_inner(Arc<RwLock<T>>) -> Self - Create from existing Arc<RwLockinto_inner(self) -> Arc<RwLock<T>> - Convert back to Arc<RwLocktspawn! Macro Variantstspawn!(var, { code }) - Clone the wrapper into the tasktspawn!(ref var, { code }) - Read access within the tasktspawn!(mut var, { code }) - Write access within the tasktspawn!(ref var1, ref var2, { code }) - Multiple read accesstspawn!(mut var1, ref var2, { code }) - Mixed access patternstspawn uses parking_lot::RwLock instead of std::sync::RwLock for better performance:
parking_lot is typically 2-3x fasterSee the examples/ directory for more comprehensive examples:
tokio runtime for async functionalityWe welcome contributions! Please feel free to submit issues or pull requests on GitHub.
# Clone the repository
git clone https://github.com/modeckrus/tspawn.git
cd tspawn
# Run tests
cargo test
# Run examples
cargo run --example basic
# Check formatting
cargo fmt --check
# Run clippy
cargo clippy
This project is licensed under either of
at your option.
This library is inspired by common patterns in Rust async programming and aims to reduce boilerplate when working with shared mutable state across tokio tasks.