newtypedecl 0.0.1

declarative newtype macro
Documentation

WARNING: until v0.1.0 this crate is in brainstorming phase, expect major breaking changes

The newtype pattern is a powerful idiom in Rust to use the type system to distinguish
between different uses of the same type.

<https://doc.rust-lang.org/rust-by-example/generics/new_types.html>

Unfortunally implementing the newtype pattern requires some boilerplate code.  This Crate
provides the [`newtype!`] declarative macro and traits to conveniently implement this
boilerplate code for you.

# How it works

We define newtypes as tuple structs with only one single data member. Thus it's type,
lifetimes, generics are all well known and can be reused when implementing member functions
and traits for the newtype instead typing repetive code. Think about it as code-completion at
compile time.

Additionally the user can define a invariant that must must hold at any time. This invariant
will be checked whenever a newtype is constructed and at some other (unspecified) places. This
invariant is a contract that must never be broken. Newtypes are not a refinement
type system, careless usage and trait implementations can lead to cases where the contract can
be possibly broken on misuse.

newtypedecl augments derive, where approbiate one can and should use derive. The newtype macro
addresses things that are commonly not covered by derive macros.

# Simple Example

The simplest case lets you use it like this:

```rust
#[macro_use]
use newtypedecl::newtype;

newtype! {
    /// Just a wrapper around a string
    pub struct Example(String);
}
```

Terminating a newtype with a semicolon will implement a preselected (opinionated) set of
methods and traits for it. See the [`newtype!`] macro docs for a list what this implements by
default.

# Control Block Example

When using a control block in braces instead the terminating semicolon after a the newtype
definiton we gain some DWIM superpowers:

```rust
#[macro_use]
use newtypedecl::*;

newtype! {
    /// The example from above with some more features
    #[derive(Debug, Hash, Clone)]
    pub struct Example(String){
        // invariant that must always be held
        invariant(value) {!value.is_empty()}
        // Define the traits and functions like above
        impl Deref + AsRef + Borrow + From;
        pub fn new;
        fn inner + into_inner + inner_mut;

        // More:
        // implementing Default takes a block of code that
        // returns something that can be converted `.into()` a inner value
        impl Default { "NULL" }
        // custom functions can be placed right here
        pub fn print_value(&self) {println!("{}", **self);}
    }
}

let example = Example::default();
assert_eq!(*example, "NULL");
example.print_value();
```

# Principles

The macro tries the most generic applicable form of methods and trait implementations. This
usually means that parameters are `impl Into` or `impl AsRef`. Future versions may introduce
dyn dispatch.

# Dangerous usage

Whenever a newtype is not only cosmetic but implements some contract which must be fulfilled
at any time, either by just documenting this or by adding invariants to the newtype there is a
danger that misuse breaks this contracts when a reference to the inner value is
reachable. This not only covers mutable references. Immutable references are subject
of this problem too when the inner value provides some kind of interior mutability.

The only way to address these problems is by being careful of what interfaces and traits a
newtype implement. This is not something this library can enforce, we only try to accomplish
this in a best-effort base and leave the actual decisions to the implementor.

When you want to be very safe then do not implement traits that expose a reference to the
inner. Only provide methods that do safe access and transformations.

## Panics

Constructing a newtype from a inner value can fail the invariant check. The 'try' forms
`try_new()` and `TryFrom` handle this and will return a runtime error in invariant
failure. Other forms that take a raw inner to be inserted into a newtype will panic in case
the invariant check fails. Thus users should not implement the traits and functions that
infallibly construct or alter a newtype when invariants are defined.

The invariant must holds at any time, never make the assumption it is ok to store an invalid
value not even temporaly.