Crates.io | the-newtype |
lib.rs | the-newtype |
version | 0.1.1 |
source | src |
created_at | 2023-02-12 21:37:12.702876 |
updated_at | 2023-02-22 21:24:39.546512 |
description | The Newtype trait |
homepage | https://github.com/smmoosavi/the-newtype |
repository | https://github.com/smmoosavi/the-newtype |
max_upload_size | |
id | 783528 |
size | 9,097 |
Newtype
traitSometimes you want to wrap a type in a newtype, but you want the newtype implements the same traits as the wrapped type. The Newtype
trait helps you to implement the traits of the wrapped type for the newtype automatically.
When you define a trait, you can support the Newtype
trait and any type that implements the Newtype
trait will automatically implement your trait.
use the_newtype::Newtype;
use derive_more::AsRef;
pub trait MyTrait {
fn my_method(&self) -> String;
}
impl<T> MyTrait for T
where
T: Newtype + AsRef<T::Inner>,
T::Inner: MyTrait,
{
fn my_method(&self) -> String {
self.as_ref().my_method()
}
}
// Now we can use the `MyTrait` trait for the newtype.
struct Foo;
impl MyTrait for Foo {
fn my_method(&self) -> String {
"foo".to_string()
}
}
#[derive(AsRef)]
struct Bar(Foo);
impl Newtype for Bar {
type Inner = Foo;
}
fn main() {
let bar = Bar(Foo);
assert_eq!(bar.my_method(), "foo");
}
You can use the Newtype
trait when you want to wrap a type in a newtype and you want the newtype implements ALL the newtype-supported traits of the wrapped type. If you need some traits, you should implement them manually and avoid using the Newtype
trait.
The Newtype
trait is not a good solution for the following cases:
Fancy
trait will implement the Awesome
trait). only one general implementation for each trait is possible. You can't use the Newtype
trait in this case.use the_newtype::Newtype;
trait Fancy {
fn fancy_method(&self) -> String;
}
// it's ok to implement the `Fancy` trait for the `Newtype` trait
impl<T> Fancy for T
where
T: Newtype + AsRef<T::Inner>,
T::Inner: Fancy,
{
fn fancy_method(&self) -> String {
self.as_ref().fancy_method()
}
}
trait Awesome {
fn awesome_method(&self) -> String;
}
// every type that implements the `Fancy` trait will implement the `Awesome` trait
// it's not possible to implement the `Awesome` trait for the `Newtype` trait
impl<T> Awesome for T
where
T: Fancy,
{
fn awesome_method(&self) -> String {
let fancy = self.fancy_method();
format!("{} is awesome!", fancy)
}
}
derive_more
and Newtype
macrosYou can use the derive_more
crate to implement the AsRef
, AsMut
, and Into
traits for the newtype. And you can use the Newtype
macro to implement the Newtype
trait for the newtype.
use the_newtype::Newtype;
use derive_more::AsRef;
#[derive(AsRef, Newtype)]
struct Bar(String);
&self
If you want to implement a trait for &self
, you can use the AsRef
trait.
use the_newtype::Newtype;
trait MyTrait {
fn my_method(&self) -> String;
}
impl<T> MyTrait for T
where
T: Newtype + AsRef<T::Inner>,
T::Inner: MyTrait,
{
fn my_method(&self) -> String {
self.as_ref().my_method()
}
}
&mut self
If you want to implement a trait for &mut self
, you can use the AsMut
trait.
use the_newtype::Newtype;
trait MyTrait {
fn my_method(&mut self) -> String;
}
impl<T> MyTrait for T
where
T: Newtype + AsMut<T::Inner>,
T::Inner: MyTrait,
{
fn my_method(&mut self) -> String {
self.as_mut().my_method()
}
}
self
If you want to implement a trait for self
, you can use the Into
trait.
use the_newtype::Newtype;
trait MyTrait {
fn my_method(self) -> String;
}
impl<T> MyTrait for T
where
T: Newtype + Into<T::Inner>,
T::Inner: MyTrait,
{
fn my_method(self) -> String {
self.into().my_method()
}
}
self
If you want to implement a trait without self
, no extra trait is needed.
use the_newtype::Newtype;
trait MyTrait {
fn my_method() -> String;
}
impl<T> MyTrait for T
where
T: Newtype,
T::Inner: MyTrait,
{
fn my_method() -> String {
T::Inner::my_method()
}
}
self
, &self
or &mut self
If you want to implement a trait for self
, &self
or &mut self
, you can use the Into
, AsRef
or AsMut
traits together.
use the_newtype::Newtype;
trait MyTrait {
fn my_method(&self) -> String;
fn my_method_mut(&mut self) -> String;
}
impl<T> MyTrait for T
where
T: Newtype + AsRef<T::Inner> + AsMut<T::Inner>,
T::Inner: MyTrait,
{
fn my_method(&self) -> String {
self.as_ref().my_method()
}
fn my_method_mut(&mut self) -> String {
self.as_mut().my_method_mut()
}
}
[dependencies]
the-newtype = "0.1"