1 stable release
new 1.1.0 | Apr 13, 2025 |
---|
#79 in No standard library
89 downloads per month
24KB
407 lines
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:
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:
Name | Type | Default | Description |
---|---|---|---|
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[^runtime_match_order]. |
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:
#[_]
[^match_default] - Direct match:
#[matches(1)]
. - Joins:
#[matches(0|1)]
- Guards:
#[1 | _ if { i.set(i.get() + 1); false }]
The following attributes are available:
Name | Type | Default | Description |
---|---|---|---|
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 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 toMyType<T>
,From
should be implemented with the generic types:impl<T> From<MyType<T>> for Enum
.
- If
- Allow doc support to override the
From::from
documentation allowing specification of, for example, pre-conditions / assumptions. - 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 aMatcher
, 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)
Major items
- 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, whereT
represents thevalue_type
. - The default range should be checked in compile time.
- Using the runtime interface should return a
Result<Self>
. Returning an "IncompleteRangeError" if invallid.
- In case a
- The ranges should span $(-\infty, \infty)$ when no
- 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 ani32
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.
- For example a
- 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 anint32
and the attribute is something likeFoo(i32)
. The value should be injected into foo.- The same should be done for runtime-matching.
Example of Matched
enum:
[^match_default]: There is an intention to add a try_from
returning an Option<Self>
.
It is recommended to use this once added and chaining the Option
with .or_default
.
Allowing for more idiomatic default construction.
[^runtime_match_order]: When using the runtime configurable match options, the Matcher 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.
Dependencies
~1–1.6MB
~28K SLoC