This library is a slightly more convenient version of derive
for newtype pattern.
The library provides features such as Generalised Newtype Deriving, which allows methods of the base type of newtype to be invoked by transitive application of Deref
traits.
It also allows derives to be generated based on a specific base implementation using the Deriving Via feature.
=> See also Generalised derived instances for newtypes and Deriving via.
The Rust Reference says:
Deref should only be implemented for smart pointers to avoid confusion.
However, this is the only way to do it, as there is no mechanism such as Generalised Newtype Deriving available.
I consider it acceptable to use Deref
for the newtype pattern.
Please use this library if and only if you agree with this idea.
The DerivingVia
macro generates the Deref
trait.
Therefore, repeatedly dereferencing the receiver-type even if the method call is directly ineligible as a syntax.
In other words, if the type derives DerivingVia
, it can be treated as an UNDERLING TYPE.
This works for method calls in general. This is similar to what smart pointers do.
Types that derive DerivingVia
will behave as Smart Wrappers.
```rust
pub struct Foo(i32);
fn main() { let foo = Foo(42);
// This works because of Deref trait. // ToOwned trait is implemented for i32. // Foo is dereferenced to i32 and toowned for i32 is called. let i: i32 = foo.toowned(); } ```
Foo
desn't implement ToOwned
trait, but i32
implements ToOwned
trait.
foo.to_owned()
will deref if it doesn't work directly.
foo
is dereferenced to i32
and to_owned()
is called for i32
.
Using the deriving via feature, it is possible to generate derives from the impl of a specific base of a multi-layered wrapped type.
This example is not use Deriving Via feature.
```rust use std::fmt::Display;
use deriving_via::DerivingVia;
pub struct A(i32);
impl Display for A { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "A({})", self.0) } }
pub struct B(A);
fn main() { let b = B(A(42));
// b.to_string()
uses A::Display
impl (most nearest impl).
asserteq!(b.tostring(), "A(42)");
}
```
This example is use Deriving Via feature.
B
derives Display
trait from i32
impl.
```rust use std::fmt::Display;
use deriving_via::DerivingVia;
pub struct A(i32);
impl Display for A { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "A({})", self.0) } }
pub struct B(A);
fn main() { let b = B(A(42));
// b.to_string()
uses B::Display
impl directly.
asserteq!(b.tostring(), "42");
}
```
Deref
trait works transitive, but how we re-constructs a Self
type?
Unfortunately, no convenience mechanism exists in the language,
so it is necessary to teach how to revert using the #[transitive]
attribute.
Some trait require #[transitive]
attribute (see Available Derives section).
```rust use std::fmt::Display;
use deriving_via::DerivingVia;
pub struct A(i32);
pub struct B(A);
pub struct C(B);
fn main() { let c: C = C(B(A(42))) + C(B(A(42))); println!("{c}"); } ```
```rust struct Base(Underlying);
struct Target(Base); ```
Display
Base: Display
or (via = <Type>) and Type: Display
Eq
Base: Eq
or (via = <Type>) and Type: Eq
Ord
Base: Ord
or (via = <Type>) and Type: Ord
Add
-lile (Add, Sub)Base: From<Underlying>
#[transitive]
Mul
-like (Mul, Div)Base: From<Underlying>
#[transitive]
Arithmetic
(Add, Sub, Mul, Div)Base: From<Underlying>
#[transitive]
Index
Base: Index
or (via = <Type>) and Type: Index
IndexMut
Base: IndexMut
or (via = <Type>) and Type: IndexMut
DerefMut
Base: DerefMut
or (via = <Type>) and Type: DerefMut
Hash
Base: Hash
or (via = <Type>) and Type: Hash
Serialize
Base: Serialize
or (via = <Type>) and Type: Serialize
Deserialize
Base: Deserialize
or (via = <Type>) and Type: Deserialize
AsRef
AsMut
FromIterator
(via: <ItemType>)
IntoIterator
Base: IntoIterator
or (via: <Type>), Type: IntoIterator
Into
Base: Into<Underlying>
#[transitive]
From
#[transitive]
TryFrom
Base: From<Underlying>
#[transitive]
FromStr
Base: From<Underlying>
#[transitive]
Base: IntoIterator and Base dereferenceable to slice
or (via: <Type>), Type: IntoIterator and Type dereferenceable to slice
Base: Clone
or (via: <Type>), Type: Clone
DerivingVia using transitive case of Type Coercion. According to rumours, transitive Type Coercion is not fully supported yet.
See: https://doc.rust-lang.org/reference/type-coercions.html#coercion-types