# tspawn
[](https://crates.io/crates/tspawn)
[](https://docs.rs/tspawn)
[](#license)
`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.
## Features
- **Thread-safe shared state**: Built on `parking_lot::RwLock` for better performance than `std::sync::RwLock`
- **Convenient cloning**: Clone the wrapper without explicit `Arc::clone()` calls
- **Async task macros**: Powerful `tspawn!` macro for spawning tokio tasks with automatic cloning
- **Multiple access patterns**: Support for read-only, write-only, and mixed access patterns
- **No poisoning**: Uses `parking_lot` which doesn't have lock poisoning
- **Zero-cost abstractions**: Minimal overhead over manual `Arc<RwLock<T>>` usage
## Installation
Add this to your `Cargo.toml`:
```toml
[dependencies]
tspawn = "0.1"
tokio = { version = "1.0", features = ["full"] }
```
## Quick Start
```rust
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(())
}
```
## Core Types
### `A<T>` - The Main Wrapper
`A<T>` is a thread-safe wrapper around `Arc<RwLock<T>>` that provides convenient methods for accessing and modifying shared data:
```rust
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
```rust
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?;
```
### Complex Scenarios
```rust
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?;
```
## Advanced Usage
### Working with Complex Types
```rust
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
name: "Alice".to_string(),
score: 100,
});
});
// Read user data
if let Some(user) = users.read().get("alice") {
println!("User: {}, Score: {}", user.name, user.score);
}
```
### Integration with async/await
```rust
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;
}
```
## API Reference
### `A<T>` Methods
- `new(value: T) -> Self` - Create a new wrapper
- `get() -> T` - Get a clone of the inner value (requires `T: Clone`)
- `set(value: T)` - Set a new value
- `update<F>(f: F)` - Update the value using a closure
- `read() -> RwLockReadGuard<'_, T>` - Get a read guard
- `write() -> RwLockWriteGuard<'_, T>` - Get a write guard
- `from_inner(Arc<RwLock<T>>) -> Self` - Create from existing Arc<RwLock<T>>
- `into_inner(self) -> Arc<RwLock<T>>` - Convert back to Arc<RwLock<T>>
### `tspawn!` Macro Variants
- `tspawn!(var, { code })` - Clone the wrapper into the task
- `tspawn!(ref var, { code })` - Read access within the task
- `tspawn!(mut var, { code })` - Write access within the task
- `tspawn!(ref var1, ref var2, { code })` - Multiple read access
- `tspawn!(mut var1, ref var2, { code })` - Mixed access patterns
- And more combinations for up to 3 variables
## Performance
`tspawn` uses `parking_lot::RwLock` instead of `std::sync::RwLock` for better performance:
- **Faster lock operations**: `parking_lot` is typically 2-3x faster
- **No poisoning overhead**: Simpler error handling
- **Better fairness**: More predictable scheduling between readers and writers
- **Smaller memory footprint**: More efficient lock implementation
## Examples
See the [`examples/`](examples/) directory for more comprehensive examples:
- [Basic usage](examples/basic.rs)
- [Multiple tasks](examples/multiple_tasks.rs)
- [Complex data structures](examples/complex_types.rs)
## Requirements
- Rust 1.70 or later
- `tokio` runtime for async functionality
## Contributing
We welcome contributions! Please feel free to submit issues or pull requests on [GitHub](https://github.com/modeckrus/tspawn).
### Development
```bash
# 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
```
## License
This project is licensed under either of
- [Apache License, Version 2.0](LICENSE-APACHE)
- [MIT License](LICENSE-MIT)
at your option.
## Acknowledgments
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.