1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
# shrinkwraprs [](https://gitlab.com/williamyaoh/shrinkwraprs/commits/master)
[](https://crates.io/crates/shrinkwraprs)
[](https://docs.rs/shrinkwraprs)
[](https://gitlab.com/williamyaoh/shrinkwraprs/blob/master/LICENSE)
Making wrapper types allows us to give more compile-time
guarantees about our code being correct:
```rust
// Now we can't mix up widths and heights; the compiler will yell at us!
struct Width(u64);
struct Height(u64);
```
But... they're kind of a pain to work with. If you ever need to get at
that wrapped `u64`, you need to constantly pattern-match back and forth
to wrap and unwrap the values.
`shrinkwraprs` aims to alleviate this pain by allowing you to derive
implementations of various conversion traits by deriving
`Shrinkwrap`.
## Functionality implemented
Currently, using `#[derive(Shrinkwrap)]` will derive the following traits
for all structs:
* `AsRef<InnerType>`
* `Borrow<InnerType>`
* `Deref<Target=InnerType>`
Additionally, using `#[shrinkwrap(mutable)]` will also
derive the following traits:
* `AsMut<InnerType>`
* `BorrowMut<InnerType>`
* `DerefMut<Target=InnerType>`
Finally, one more option is `#[shrinkwrap(transformers)]`, which will derive
some useful inherent functions for transforming the wrapped data:
* `fn transform<F>(&mut self, mut f: F) -> &mut Self where F: FnMut(&mut InnerType)`
* `fn siphon<F, T>(self, mut f: F) -> T where F: FnMut(InnerType) -> T`
...where `transform` makes it easy to chain updates on the inner value, and
`siphon` allows you to easily move out the inner value to produce a value
of a different type.
`transform` will have the same visibility as the inner field, which ensures that
`transform` doesn't leak the possibility of changing the inner value
(potentially in invariant-violating ways). `siphon` has the same visibility as
the struct itself, since it *doesn't* provide a direct way for callers to break
your data.
## Cool, how do I use it?
First, add `shrinkwraprs` as a dependency in your `Cargo.toml`:
```toml
[dependencies]
shrinkwraprs = "0.3.0"
```
Then, just slap a `#[derive(Shrinkwrap)]` on any structs you want
convenient-ified:
```rust
#[macro_use] extern crate shrinkwraprs;
#[derive(Shrinkwrap)]
struct Email(String);
fn main() {
let email = Email("chiya+snacks@natsumeya.jp".into());
let is_discriminated_email =
email.contains("+"); // Woohoo, we can use the email like a string!
/* ... */
}
```
If you have multiple fields, but there's only one field you want to be able
to deref/borrow as, mark it with `#[shrinkwrap(main_field)]`:
```rust
#[derive(Shrinkwrap)]
struct Email {
spamminess: f64,
#[shrinkwrap(main_field)] addr: String
}
#[derive(Shrinkwrap)]
struct CodeSpan(u32, u32, #[shrinkwrap(main_field)] Token);
```
If you also want to be able to modify the wrapped value directly,
add the attribute `#[shrinkwrap(mutable)]` as well:
```rust
#[derive(Shrinkwrap)]
#[shrinkwrap(mutable)]
struct InputBuffer {
buffer: String
}
...
let mut input_buffer = /* ... */;
input_buffer.push_str("some values");
...
```
|