# Deadlocker
Dealocker is a crate that aims to eliminate deadlocks in a builder-pattern
inspired manner
---
The main feature of the crate is the derive macro which will do a number of
things:
1. Create one struct for each combination of locks that may be held
2. Create a struct for holding references to the locks in the original struct
3. Allow the locker struct to chain methods to specify desired locks in any
order
4. Implement a final lock method on the locker struct which will lock the
desired locks in a deterministic order, eliminating deadlocks caused by
out-of-order acquisition of locks
## Example
```rust
use deadlocker::Locker;
use std::sync::{Arc, Mutex};
type Foo = Vec<usize>;
type Bar = usize;
type Baz = u8;
#[derive(Locker)]
pub struct MyStruct {
#[result]
pub foo: Arc<Mutex<Foo>>,
#[result]
pub bar: Arc<Mutex<Bar>>,
#[result]
pub baz: Arc<Mutex<Baz>>,
}
pub fn main() {
let mut my_struct = MyStruct {
foo: Arc::new(Mutex::new(Vec::new())),
bar: Arc::new(Mutex::new(0)),
baz: Arc::new(Mutex::new(0)),
};
{
let mut lock = my_struct
.locker()
.baz()
.foo()
.lock()
.expect("Mutex was poisoned");
lock.foo.push(1);
**lock.baz = 1;
}
{
let lock = my_struct
.locker()
.bar()
.foo()
.baz()
.lock()
.expect("Mutex was poisoned");
println!("Foo: {:?}", **lock.foo);
println!("Bar: {:?}", **lock.bar);
println!("Baz: {:?}", **lock.baz);
}
}
```
## Attributes
Each field may be annotated with a number of attributes to modify the behaviour
of the derive macro. The effects are noted below, and examples are provided in
the [examples directory](examples)
### outer_type
Indicates what is to be the outer type, i.e. what is the locking part, as
opposed to the [inner_type](#inner_type). This is the complement to [inner_type](#inner_type), it
only makes sense to specify one of them, and [inner_type](#inner_type) takes precedence.
It is specified using a regex with a single capture group where the
[inner_type](#inner_type) is supposed to be. Specifying the outer type is mostly useful
when the inner type is long and complex.
```rust
#[outer_type = "Arc<Mutex<(.*)>>"]
```
Note that this is by default set to the above, meaning that if your field
conforms to the pattern you needn't specify anything. See the
[basic example](examples/basic_example) for more.
### inner_type
Indicates what is the be the inner type, i.e. what is being guarded by the lock.
This is the complement to [outer_type](#outer_type), it only makes sense to specify one of
them, and this takes precedence over [outer_type](#outer_type)
```rust
#[inner_type = "usize"]
```
### async_lock
Marks the lock as async, this causes the final `lock` method in a chain
containing an `async_lock` marked field to become asynchronous as well. This
does not affect other locks in the struct, so the final `lock` method needn't be
asynchronous just because some of the locks are.
```rust
#[async_lock]
```
### lock_method
Indicates how to get at the [inner_type](#inner_type) from the lock. For
`std::sync::Mutex` this is `lock()`, and for `tokio::sync::Mutex` it is
`lock().await`. Note the omission of the leading period, as well as the trailing
semicolon.
```rust
#[lock_method = "lock()"]
```
For synchronous locks this defaults to `lock()`, and to `lock().await` for
asynchronous ones, meaning most people won't have to specify this.
### result
Marks the lock as yielding a result over its guard, rather than the guard
directly. This is true for `std::sync::Mutex` but not for `tokio::sync::Mutex`.
This causes the final `lock` method in a chain containing a `result` marked
field to return a result, with the normally returned struct embedded in its `Ok`
variant.
```rust
#[result]
```
### include
Indicates that this field should be included in the locker struct. The presence
of a single field marked as such implies that no field without such a mark should
be included. Useful if you have a large state struct where only a small portion
are locks. This overrides any [exclude](#exclude) attribute.
```rust
#[include]
```
### exclude
Indicates that this field should not be included in the locker struct. Useful if
you have a large state struct where most of the fields are locked.
```rust
#[exclude]
```