Crates.io | temporary_enum_delegate_0_3_0 |
lib.rs | temporary_enum_delegate_0_3_0 |
version | 0.3.0 |
source | src |
created_at | 2023-02-17 05:01:01.593693 |
updated_at | 2023-02-17 05:01:01.593693 |
description | Provides trait delegation functionality for enums and structs |
homepage | |
repository | https://gitlab.com/Sean-McConnachie/temporary_enum_delegate_0.3.0.git |
max_upload_size | |
id | 787258 |
size | 31,300 |
This is an unpublished version (with bugs) forked from enum_delegate (revision f99967517e925f9630735836fb1601747df9c71d
).
The original authors are Reinis Mazeiks, 50U10FCA7. This crate is to resolve dependency conflicts in another crate concurrent_tor
. Since that crate depends on enum_delegate ^= "0.3.0"
,
this is a temporary upload of enum_delegate
.
Provides trait delegation functionality for enums and structs.
Note: Name contains enum_*
part due to historical reasons. It is not limited to enums.
[dependencies]
enum_delegate = "0.4"
use enum_delegate::delegate;
#[delegate(for(LastName))]
trait AsStr {
fn as_str(&self) -> &str;
}
impl AsStr for String {
fn as_str(&self) -> &str {
self
}
}
#[delegate(derive(AsStr))]
struct FirstName(String);
#[delegate]
struct LastName {
name: String,
}
#[delegate(derive(AsStr))]
enum Name {
First(FirstName),
Last(LastName),
}
fn main() {
let name = Name::First(FirstName("John".to_string()));
assert_eq!(name.as_str(), "John");
let name = Name::Last(LastName {
name: "Doe".to_string(),
});
assert_eq!(name.as_str(), "Doe");
}
Crate provides several definitions:
delegate
macro - derives trait on a new-type struct or enum, invoking it on its inner type.Convert
trait - converts enum or struct to type represents "any of its variant".#[delegate]
expansion on typeImplements Convert
trait to enum/struct, which allows to convert it to "any of its variant" type.
#[delegate]
enum Name {
First(FirstName),
Last {
name: LastName,
},
}
Note: Example is simplified for readability.
impl Convert for Name {
type Output = Either<FirstName, LastName>;
fn convert(self) -> Self::Output {
match self {
Name::First(first_name) => Either::Left(first_name),
Name::Last { name } => Either::Right(name),
}
}
}
#[delegate]
expansion on traitImplements the trait for any type that implements Convert
trait, which "any variant" implements target trait.
I.e. each method in generated impl
convert self
to "any of its variant" and invokes target trait method on it.
#[delegate]
trait AsStr {
fn as_str(&self) -> &str;
}
Note: Example is simplified for readability.
// Implementation for "any variant of enum or struct" type.
impl<L: AsStr, R: AsStr> AsStr for Either<L, R> {
fn as_str(&self) -> &str {
match self {
Either::Left(left) => left.as_str(),
Either::Right(right) => right.as_str(),
}
}
}
// Implementation for any type that implements `Convert` trait.
impl<T> AsStr for T
where
T: Convert,
T::Output: AsStr,
{
fn as_str(&self) -> &str {
let this = self.convert(); // convert type to "any of its variant".
this.as_str() // call the method.
}
}
#[delegate]
macro attribute.Self
trait/method bounds except marker traits like Sized
, Send
or Sync
are not supported yet.#[delegate(for(Enum<Generics>))]
supports only concrete generic types.Rust mechanism for dynamic dispatch using trait objects, which adds runtime overhead.
trait AsStr {
fn as_str(&self) -> &str;
}
impl AsStr for String {
fn as_str(&self) -> &str {
self
}
}
struct FirstName(String);
impl AsStr for FirstName {
fn as_str(&self) -> &str {
&self.0
}
}
fn do_something_with_string(s: &dyn AsStr) {
println!("{}", s.as_str());
}
fn main() {
let name = "John".to_string();
do_something_with_string(&name);
let name = FirstName(name);
do_something_with_string(&name);
}
enum_delegate
was highly inspired by enum_dispatch crate. It provides similar functionality, but has more limitations:
enum_dispatch
between crates is impossible due to limitations of its design.Derive a method to return a borrowed pointer to the inner value, cast to a trait object, using enum_derive::EnumInnerAsTrait
.
Slower though, more similar to Dynamic dispatch.