# Matched Enum
Rust allows you to specify integer values for enumerations which make it easy to convert integers to enums.
However, such luxary does not exist for complex patterns like range-based matching.
This library aims to add such functionality.
It will respect the option to assign integer values to enumartion allowing idiomatic derives from `Ord` for comparisons.
While allowing for enumerations to be derived from ranges.
This conversion is achieved through the `From` trait.
For example:
```rust
use matched_enums::Matched;
#[derive(Matched, PartialEq, Debug)]
#[matched_enum(value_type=i32)]
enum Signature {
#[matches(1..)]
Positive,
#[matches(..=-1)]
Negative,
#[matches(0..1)]
Zero,
}
assert_eq!(Signature::from(-42), Signature::Negative);
assert_eq!(Signature::from(0), Signature::Zero);
assert_eq!(Signature::from(451), Signature::Positive);
```
> **NOTE**: Checkout the [examples] for more detailed and complex examples.
## Features
This library offers the following features:
- `runtime_configurable`: Allows the creation of runtime configurable structures.
## Attributes
After deriving from `Matched`, the following macros are available.
### Enum macros
This library uses the following macros:
#### `#[derive(Matched, ..)]`
When enabled allows the use of the other macros.
#### `#[matched_enum(..)]`
Configure the behavior of the macro using key-value pairs (configured using `key=value`).
The following keys are available:
| `allow_runtime_configurable` | Boolean Literal | `false` | If the `runtime_configurable` feature is enabled, it will generate a struct with a `Matcher` postfix. For example: `enum Foo` will have `struct FooMatcher`. This matcher, holds binary predicates for each enumeration. Defaulting to the normal matcher. |
| `use_partial` | Boolean Literal | `false` | When used, implements `TryFrom` instead of `From`. The implementation will use the `_` matcher after all other statements to return an error if it failed. This means it can only be used if the input is only partially covered. |
| `value_type` \| `value_types` | Any type or array of types | `i32` | Specify the type used from which the enum can be constructed. |
### Attribute macros
#### `matches(..)`
Indicates the criteria for matching a specific enum attribute as well as some configuration options passed as key-value pairs.
Arguments should match the pattern `matches(<match-arm>[[,<attribute>=value]..])`.
The `match-arm` can be any [`MatchArm`]. Some examples:
- Default: `#[_]`
- Direct match: `#[matches(1)]`.
- Joins: `#[matches(0|1)]`
- Guards: `#[1 | _ if { i.set(i.get() + 1); false }]`
The following attributes are available:
| `bind` | Any type | `None` | Binds the current match arm to the provided type. |
## Design Decisions
If you are curious about certain decisions that have shaped this package over time.
Please check out the [design-decisions](./doc/design_decisions.md) as this contains such detailed information.
## TODO
A list of tasks that still need to achieved.
These items are ordered arbitrarily and have no importance in their order.
> **NOTE**: These issues are not yet tracked in git as most have been defined since the start before it was hosted online.
### Minor items
- [ ] Allow support for additional allowing construction from templated types.
- If `value_type` is set to `MyType<T>`, `From` should be implemented with the generic types: `impl<T> From<MyType<T>> for Enum`.
- [ ] Add tags to the main `Cargo.toml` to find this easier (proc-macro, enum, match, etc.)
- [ ] Add a `precedence` attribute to matches which, optionally, allows one to specify the order of match priority without relying on enum declarations (if desired).
- [ ] Add support for a `DefaultMatcher` as an alias to a `Matcher`, making it easier to use.
- [ ] Ensure the that unbound match attributes (i.e. without typebind) are used as the default attribute across all other types (i.e. acting as a 'default' argument).
- [ ] Add support for more typing options in the matcher. For example a tuple, slice, etc.: <https://docs.rs/syn/latest/syn/enum.Type.html>
- [ ] Add an example with a multiple matchers of generic types. (i.e. explain the need for the turbo fish, see [templated_type](./src/tests/multiple_value_types/templated_type.rs))
- [x] Add tests for situations that should not be compilable.
### Major items
- [x] Add support for runtime changeable ranges.
- [ ] The ranges should span $(-\infty, \infty)$ when no `allow_incomplete` is provided, else it is accepted.
- [ ] In case a `value_type` has been specified, it must span $[T_{MIN}, T_{MAX}]$ instead, where `T` represents the `value_type`.
- [ ] The default range should be checked in compile time.
- [x] Using the runtime interface should return a `Result<Self>`. Returning an "IncompleteRangeError" if invallid.
- [ ] Allow partial matching to happen on a per-type basis instead of on a general basis
- For example a `uint8` should be fully matchable, but an `i32` should have partial matching.
- The current situation, where `allow_partial` dictates whether all type should be matched partially or fully, ought to be repurposed as the default.
- [ ] Allow value binding if needed. For example if an enum attribute can accept the same type as it is trying to convert from, it should be injected into the enum attribute. For example, if the `value_type` is an `int32` and the attribute is something like `Foo(i32)`. The value should be injected into foo.
- [ ] The same should be done for runtime-matching.
Example of `Matched` enum:
will go through all of the predicates linearly in a top-to-bottom order.
*If*, a wild card predicate is used *before* any of the other predicates,
the matcher will always go for the wild card.
[examples]: ./examples/