Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/fsmaxb/static-option
A rust Option with compile time state tracking using const generics.
https://github.com/fsmaxb/static-option
Last synced: about 2 months ago
JSON representation
A rust Option with compile time state tracking using const generics.
- Host: GitHub
- URL: https://github.com/fsmaxb/static-option
- Owner: FSMaxB
- Created: 2021-10-29T12:48:58.000Z (about 3 years ago)
- Default Branch: master
- Last Pushed: 2023-09-25T10:42:36.000Z (over 1 year ago)
- Last Synced: 2024-10-14T17:23:03.183Z (3 months ago)
- Language: Rust
- Size: 73.2 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# static-option
`static-option` is a [rust](https://rust-lang.org) library that provides versions of `Option` and `Result` that track their state at compile time using const generic boolean parameters.
## Features
* Statically tracks if a `StaticOption` contains a value or a `StaticResult` is `ok` or `err` at compile time.
* Direct access to the contents of `StaticOption` and `StaticResult` if the type parameters guarantee that there is a value inside.
* Optimal memory layout using a union internally and exposing a safe interface so that you don't have to write `unsafe` yourself
* MSRV see `rust-version` in `Cargo.toml`
* All standard library functions and traits of `Option` and `Result` that can be reimplement for `StaticOption` and `StaticResult` are reimplemented. (if one is missing, open a GitHub issue about it)
* `#![no_std]`
* Conversion back to the standard `Option` and `Result` types.## Caveats
* Some methods from the standard library cannot be implemented on `StaticOption` and `StaticResult`
* Methods that mutably change the content from `some` -> `none`, `none` -> `some` or `ok` -> `error`, `error` -> `ok` respectively.
* Methods that require boolean logic between to const generic boolean type parameters, like `Option::xor` for example.
* `StaticOption` and `StaticResult` do not implement `Drop`, this is because they have no way to track if the content's have been dropped yet.
* If you aren't using any method taking owned `self` as parameter, you need to make sure to call `.drop()` manually.
* For that reason, bot `StaticOption` and `StaticResult` emit a warning if they aren't used, thanks to the `#[must_use]` attribute.## Example: Statically checked builder pattern
Example on how `StaticOption` can be used, implementing compile time checked builder pattern.
**NOTE:** If you actually want to use builders like that, I recommend the excellent [typed-builder](https://github.com/idanarye/rust-typed-builder) instead
```rust
use static_option::StaticOption;#[derive(Debug, PartialEq)]
struct Point {
x: f64,
y: f64,
}impl Point {
// Starts with both const generic type parameters as `false`
// (in other words: Neither `x` nor `y` having been set)
pub fn build() -> Builder {
Builder {
x: Default::default(),
y: Default::default(),
}
}
}// The X and Y const generic type parameters track at compile time which values have already been provided to the builder.
// The actual values are stored inside of `StaticOption`.
#[must_use = "Finish building with `.build()` if you don't use the `Builder` anymore."]
struct Builder {
x: StaticOption,
y: StaticOption,
}// Setting `x` is only possible on builders where the `X` type parameter is `false` and it will set it to `true`.
// (in other words: Where `x` hasn't been set yet)
impl Builder {
pub fn x(self, x: f64) -> Builder {
Builder {
x: x.into(),
y: self.y,
}
}
}// Setting `y` is only possible on builders where the `Y` type parameter is `false` and it will set it to `true`.
// (in other words: Where `y` hasn't been set yet)
impl Builder {
pub fn y(self, y: f64) -> Builder {
Builder {
x: self.x,
y: y.into(),
}
}
}// The `build` method is only available when both `X` and `Y` type parameters are `true`
// (in other words: When both `x` and `y` have been set)
impl Builder {
pub fn build(self) -> Point {
Point {
x: self.x.into_inner(),
y: self.y.into_inner(),
}
}
}let point = Point::build().x(1.0).y(2.0).build();
let point2 = Point::build().y(2.0).x(1.0).build();
let expected = Point { x: 1.0, y: 2.0 };assert_eq!(expected, point);
assert_eq!(point, point2);
```