# Logical State
Logical state is the part of an item that is:
* Implementor / user definable
* Controllable by automation
* Deterministic
## Uses
There are three uses of logical state:
1. Representing current state.
2. Representing goal state.
3. Computing state difference.
```rust ,ignore
let params = data.params();
// `dest` references the actual item that is being managed.
// e.g. calculate content hash of actual file being written to.
let state_current = params.dest().read();
// `src` references the *specification* of what the item is intended to be.
// e.g. retrieve content hash from a source file.
let state_goal = params.src().read();
// We can only compute the `diff` when both `src` and `dest` are available.
let state_diff = state_goal - state_current;
```
## Discovery Constraints
In an item's parameters, there must be the following categories of information:
* `src`: information of what the item should be, or where to look up that information.
Thus, `src` is a reference to where to look up `state_goal`.
* `dest`: reference to where the actual item should be.
`dest` is a reference to where to push `state_current`.
Both `src` and `dest` may reference resources that are ensured by predecessor items. Meaning sometimes `state_goal` and `state_current` cannot be discovered because they rely on the predecessors' completions.
### Examples
* A list of files in a zip file cannot be read, if the zip file is not downloaded.
* A file on a server cannot be read, if the server doesn't exist.
* A server cannot have a domain name assigned to it, if the server doesn't exist.
### Implications
* If `dest` is not available, then `state_current` may simply be "does not exist".
* If `src` is not available, and we want to show `state_goal` that is not just "we can't look it up", then `src` must be defined in terms of something readable during discovery.
* If that is not possible, or is too expensive, then one or more of the following has to be chosen:
1. `Item::state_goal` functions have to always cater for `src` not being available.
It incurs mental effort to always cater for `src` not being available – i.e. implementing an item would need knowledge beyond itself.
2. the `peace` framework defaults to not running `state_current_fn` for items that have a logical dependency on things that `Item::apply_check` returns `ExecRequired`
For this to work, when the current state is requested, `peace` will:
1. For each non-parent item, run `state_current`, `state_goal`, `state_diff`, and `apply_check`.
2. If `apply_check` returns `ApplyCheck::ExecNotRequired`, then successor items can be processed as well.
3. `state_current` could return `Result<Option<Status>, E>`:
+ `Ok(None)`: State cannot be discovered, likely because predecessor hasn't run
+ `Ok(Some(State<_, _>))`: State cannot be discovered.
+ `Err(E)`: An error happened when discovering state.
May be difficult to distinguish some cases from `Ok(None)`, e.g. failed to connect to server, is it because the server doesn't exist, or because the address is incorrect.
Should we have two `state_current`s? Or pass in whether it's being called from `Discover` vs `Ensure` – i.e. some information that says "err when failing to connect because the predecessor has been ensured".
<!-- -->
Option 2 may be something we have to do anyway – we will not be able to provide current state to run `Item::apply` for successors for the same reason.
Option 3 may coexist with option 2.
**Note:** State discovery may be expensive, so it is important to be able to show a stored copy of what is discovered.