Crates.io | hereditary |
lib.rs | hereditary |
version | 0.1.0 |
source | src |
created_at | 2023-07-28 21:49:48.407479 |
updated_at | 2023-07-28 21:49:48.407479 |
description | Procedural macros for emulating OOP Inheritance in Rust |
homepage | |
repository | https://github.com/datapture/hereditary |
max_upload_size | |
id | 928911 |
size | 198,526 |
Procedural macros for emulating OOP Inheritance in Rust, by extending the trait functionality in structs based on their composition (as they contain instances of other types that implement the desired functionality).
Hereditary
generates the boilerplate of trait implementations for the composited struct,
by Forwarding the
required methods that wrap the functionality already implemented in the contained instances referenced by its struct fields.
Currently, Hereditary
support 2 kinds of delegation:
#[forward_trait(submember)]
on trait implementations.#[derive(Forwarding)]
on the composited struct, it derives the trait implementation
on the struct field (designated by attribute #[forward_derive(Trait)]
).Note
Learn more in the documentation page here https://docs.rs/hereditary
Hereditary
tools are essentially zero-cost abstractions. They doesn't require runtime structures for holding trait type information.
All the work it's done by macros and code generation.inner-type
interfaces for the new-type
. By using this technique Rust programmers
avoid the problems of incorporating new behaviour of existing foreign types, bypassing the
Orphan Rule for traits.Install in your repository:
cargo add hereditary
Insert hereditary
macros in your code:
mod animal {
// Attribute macro for generating trait info
#[hereditary::trait_info]
pub trait Cannis {
fn bark(&self)-> String;
fn sniff(&self)-> bool;
}
#[hereditary::trait_info]
pub trait Bird {
fn sing(&self) -> String;
fn fly(&mut self, elevation:f64) -> f64;
}
}
// Heritance for an hybrid animal
#[derive(hereditary::Forwarding)]
struct KimeraSphinx
{
#[forward_derive(animal::Cannis)] // full implementation of Cannis
dogpart:Bulldog,
birdpart:Seagull
}
// Combining existing trait implementation from Seagull instance
#[hereditary::forward_trait(birdpart)]
impl animal::Bird for KimeraSphinx
{
fn sing(&self) -> String
{
self.dogpart.bark()
}
}
// -- Subcomponent implementations -- //
struct Bulldog { position:f64 }
impl animal::Cannis for Bulldog {
//... Cannis methods ...
}
struct Seagull { elevation:f64 }
impl animal::Bird for Seagull {
//... Bird methods ...
}
fn main() {
// Instance kimera
let mut kimera = KimeraSphinx::new();
// A dogs that flies.
assert_eq!(kimera.fly(50f64), 50f64);
assert_eq!(kimera.bark(), kimera.sing()); // It barks instead of singing
assert_eq!(kimera.sniff(), true);
}
Hereditary
would incurr in longer compilation processes.trait_info
generated macros
aren't imported automatically as same as their corresponding traits. That's why they need to be referenced with the full path
in the forwarding attributes (animal::Bird
), instead of just Bird
. This is a known issue related with declarative macros and the scope rules for
their visibibility, as they have special needs when exporting them as module symbols.Apache 2.0
Authors: Francisco Leon