This library is a slightly more convenient version of derive
for newtype pattern.
=> See also Deriving via
Basic Usage
#[derive(DerivingVia)]
and then write the #[deriving]
attribute on struct and list the trait you want to derive in it.
simple
Derives From<i32> for D
and Display for D
.
#[derive(DerivingVia)]
#[deriving(From, Display)]
pub struct D(i32);
with generics
#[derive(DerivingVia)]
#[deriving(From, Display)]
pub struct D<T: Display>(T);
with newtype pattern
If you have more than one field, specify #[underlying]
for one. Note that the other fields require default initialisation by the Default
trait.
#[derive(DerivingVia)]
#[deriving(From, Display)]
pub struct Test<T>(#[underlying] i32, std::marker::PhantomData<T>);
Syntax
Derive DerivingVia
and list the traits you want to derive in the #[deriving]
attribute.
#[derive(DerivingVia)]
#[deriving(<Derive>...)]
struct Target(Base);
The syntax of <Derive>
is defined as follows.
Derive := <Trait> | <Trait>(via: <Type>)
Deriving Via
Using the deriving via feature, it is possible to generate derives from the impl of a base of a multi-layered wrapped type.
DerivingVia
uses transitive type coercion for type conversion. All newtypes must be dereferenceable to the underlying type. Therefore, DerivingVia
automatically generates a Deref
trait.
Example
use deriving_via::DerivingVia;
#[derive(DerivingVia)]
pub struct A(i32);
#[derive(DerivingVia)]
pub struct B(A);
#[derive(DerivingVia)]
#[deriving(Display(via: i32))]
pub struct C(B);
fn main() {
let c = C(B(A(42)));
println!("{c}"); // 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).
Example
use std::fmt::Display;
use deriving_via::DerivingVia;
#[derive(DerivingVia)]
#[deriving(From)]
pub struct A(i32);
#[derive(DerivingVia)]
#[deriving(From)]
pub struct B(A);
#[derive(DerivingVia)]
#[deriving(From, Add(via: i32), Display(via: i32))]
#[transitive(i32 -> A -> B -> C)]
pub struct C(B);
fn main() {
let c = C(B(A(42))) + C(B(A(42)));
println!("{c}");
}
Available Derives
struct Base(Underlying);
#[derive(DerivingVia)]
#[deriving(<Derive>)]
struct Target(Base);
- fmt
Display
- requires:
Base: Display
or(via = <Type>) and Type: Display
- requires:
- ops
Eq
- requires:
Base: Eq
or(via = <Type>) and Type: Eq
- requires:
Ord
- requires:
Base: Ord
or(via = <Type>) and Type: Ord
- requires:
Add
-lile (Add, Sub)- requires:
Base: From<Underlying>
- limitations: one hop or
#[transitive]
- requires:
Mul
-like (Mul, Div)- requires:
Base: From<Underlying>
- limitations: one hop or
#[transitive]
- requires:
Arithmetic
(Add, Sub, Mul, Div)- requires:
Base: From<Underlying>
- limitations: one hop or
#[transitive]
- requires:
Index
- requires:
Base: Index
or(via = <Type>) and Type: Index
- requires:
IndexMut
- requires:
Base: IndexMut
or(via = <Type>) and Type: IndexMut
- requires:
DerefMut
- requires:
Base: DerefMut
or(via = <Type>) and Type: DerefMut
- requires:
- hash
Hash
- requires:
Base: Hash
or(via = <Type>) and Type: Hash
- requires:
- serde
Serialize
- requires:
Base: Serialize
or(via = <Type>) and Type: Serialize
- requires:
Deserialize
- requires:
Base: Deserialize
or(via = <Type>) and Type: Deserialize
- requires:
- convert
AsRef
AsMut
FromIterator
- requires:
(via: <ItemType>)
- requires:
IntoIterator
- requires:
Base: IntoIterator
or(via: <Type>), Type: IntoIterator
- requires:
Into
- requires:
Base: Into<Underlying>
- limitations: one hop or
#[transitive]
- requires:
From
- limitations: one hop or
#[transitive]
- limitations: one hop or
TryFrom
- requires:
Base: From<Underlying>
- limitations: one hop or
#[transitive]
- requires:
FromStr
- requires:
Base: From<Underlying>
- limitations: one hop or
#[transitive]
- requires:
- impls
- Iter
- requires:
Base: IntoIterator and Base dereferenceable to slice
or(via: <Type>), Type: IntoIterator and Type dereferenceable to slice
- requires:
- Iter
Caveat
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