# Making Decisions

A decider connects a state with the decision made on it.

To create one, call `Decider::new` with an asynchronous closure that receives the command and the current state, and returns the events to write:

```rust
fn acquire_book() -> Decider<AcquireBook, Book, DomainError> {
  Decider::new(|command: AcquireBook, book: Book| async move {
    if book.is_acquired {
      return Err(DomainError::new(format!("{} has already been acquired", command.book)));
    }

    Ok(vec![BookEvent::Acquired(BookAcquired {
      title: command.title,
      author: command.author,
      isbn: command.isbn,
    })])
  })
}
```

The types of the command, the state, and the error are taken from the closure and from what it returns, so a decider bound with `let` names none of them, while a function that returns one names them in its return type, as above. The events are variants of the enum of the state, so **a decider can only return events that the state has a rule for**. `Decider::new` returns a `Decider`, whose `decide` method decides on a command, given the state, with the closure you handed over.

The closure takes the command and the state by value rather than by reference, so that its future can be sent across threads, which a web server needs. **It is asynchronous, so that it can load what else it needs to decide**, such as the state of another subject (see **[Loading States](/docs/architecturekit/rust/loading-states)**).

To refuse a command, return an error. `DomainError` refuses it with a message, which `DomainError::new` takes, for example from `format!`, and which is exactly what its `Display` shows. **It belongs to the category `Category::Domain`** (see **[Handling Errors](/docs/architecturekit/rust/handling-errors)**).

To let a caller or a test tell a refusal apart from the others, define an error type of your own, such as an enum with one variant per refusal. It implements `Categorized`, whose `category` method names `Category::Domain`, so that the kit tells the refusal apart from a failure, for example one while the decider loads what else it needs:

```rust
#[derive(Debug, PartialEq)]
enum BookRefused {
  AlreadyAcquired(Subject),
}

impl fmt::Display for BookRefused {
  fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    match self {
      Self::AlreadyAcquired(book) => write!(formatter, "{book} has already been acquired"),
    }
  }
}

impl std::error::Error for BookRefused {}

impl Categorized for BookRefused {
  fn category(&self) -> Option<Category> {
    Some(Category::Domain)
  }
}

fn acquire_book() -> Decider<AcquireBook, Book, BookRefused> {
  Decider::new(|command: AcquireBook, book: Book| async move {
    if book.is_acquired {
      return Err(BookRefused::AlreadyAcquired(command.book));
    }

    Ok(vec![BookEvent::Acquired(BookAcquired {
      title: command.title,
      author: command.author,
      isbn: command.isbn,
    })])
  })
}
```

A caller then matches the variant, as in `ExecuteError::Decider(BookRefused::AlreadyAcquired(_))` (see **[Handling Errors](/docs/architecturekit/rust/handling-errors)**), and a test compares the error with `then_failed`, which is why it derives `PartialEq` and `Debug` (see **[Expecting Rejections](/docs/architecturekit/rust/testing-deciders#expecting-rejections)**). `Display` and `Error` let it be logged and handed on with `?`.

A decider may check several rules:

```rust
fn borrow_book() -> Decider<BorrowBook, Book, DomainError> {
  Decider::new(|command: BorrowBook, book: Book| async move {
    if !book.is_acquired {
      return Err(DomainError::new(format!("{} does not exist", command.book)));
    }
    if book.is_borrowed {
      return Err(DomainError::new(format!("{} is already borrowed", command.book)));
    }

    Ok(vec![BookEvent::Borrowed(BookBorrowed {
      borrowed_by: command.reader_id,
      borrowed_until: command.borrowed_until,
    })])
  })
}
```

If there is nothing to do, return no events. A decider that never refuses names its error type all the same, here in the return type, or with `Decider::<_, _, DomainError>::new` for one bound with `let`:

```rust
fn return_book() -> Decider<ReturnBook, Book, DomainError> {
  Decider::new(|_: ReturnBook, book: Book| async move {
    if !book.is_borrowed {
      return Ok(Vec::new());
    }

    Ok(vec![BookEvent::Returned(BookReturned {})])
  })
}
```
