tacit 0.1.2

Simple macro to make newtypes easier to create.
Documentation

![](https://img.shields.io/crates/v/tacit)

Simple newtype macro to create strong ID types over other types.

Make a strong ID out of a string:

```rust
tacit!(id1::Id1 -> String);
tacit!(id2::Id2 -> Arc<str>);
```

Try it with [ulid](https://crates.io/crates/ulid)

```rust
use ulid::Ulid;
tacit!(id::Id -> Ulid);
```

You can also write a doc comment for your tacits:
```rust
tacit!(
    /// My unique type!
    id::Id -> Ulid
);
```

Tacit works by generating two structs with the same name. The first part of
the macro, `id::Id` generates a struct in a module named `id`, like so:
```rust
mod id {
    #[derive(Clone, Copy, Debug...)]
    struct Id;
}
```

which then uses that type to make a type alias over the `Tacit` struct:

```rust
pub type Id = Tacit<Ulid, id::Id>;
```

The first generic argument is the *representation*, the actual data in the type.
The second argument is the *identifier*, which prevents Tacits of the same
representation to not compare with each other or allow them to be passed as
arguments to functions expecting different types.

While `Tacit`s of different types do not compare, they can convert between other
tacits that implement the same representation:
```rust
tacit!(a::A -> Ulid);
tacit!(b::B -> Ulid);
let a: A = Ulid::new().into();
let b: B = a.cast();
```

the `Tacit` struct implements a variety of traits when the representation
implements them. Below is a list of the following:
- `Clone`
- `Copy`
- `Debug`[1]
- `Display`[1]
- `Eq`
- `PartialEq`
- `Ord`
- `PartialOrd`
- `Hash`
- `From<R>` where `R` is the representation type.
- `FromStr` where `FromStr::Err` is `R::FromStr::Err`
- `serde::Serialize`[2]
- `serde::Deserialize`[2]

Note that, if the representation doesn't implement any of these, the Tacit won't
have it implemented either. You can still use types that don't implement these,
though, as they're implemented conditionally. This enables non-Copy types to
be Tacits, while also allowing Copy types to be Copyable.

Additionally, there are special `From<str>`/`From<String>` impls for `Arc<str>`
and `Rc<str>` as I couldn't find a good way to implements a generic `From<R>`
for types that encase other types like `Arc` does. I figured this was a
reasonable thing to hard-code since I'm essentially hardcoding over Rust's
string literal syntax.

[1] Tacit's display outputs are as follows:\
Given `tacit!(a::A -> Arc<str>)`:
- Debug: `Tacit(A, "abc")`
- Display: `A(abc)`

If you want the raw debug/display output without the tacit's name, call:
- `tacit.repr_debug()`
- `tacit.repr_str()`

Note that the automatically generated identifier implements the
`tacit::Identity` trait in order to display it's name. If you are not using an
automatically generated ID, ensure your identifier type implements `Identity`
as well, or else the entire `Tacit` cannot use `Debug` or `Display`. This seems
to be a limitation in Rust's trait system and one I can't find a way to
overcome, as ideally I'd like to simply only print the representation if the
identifier has no display.

[2] A note on `serde`: The Tacit will not serialize or deserialize *itself*,
it is a direct passthrough to the representation type. This means instead of
getting (from `tacit!(a::A -> u32)`):
```json
Tacit {
    repr: 123
}
```
You will instead simply get `123`. Keep this in mind when handling
serialization, as this essentially means Tacit will not help you out with
deserializing types.