Duck typing is a method where code works when certain methods and properties are present, instead of requiring a certain type.
An duck typing abstraction is composed from the following building blocks:
Get
trait)Set
trait)Action
trait)Is is common to declare a newtype for each property and action.
For example, declare pub struct X(pub f64);
for Get<X>
and Set<X>
.
The quack!
macro can be used to implement simple get/set properties.
Get
, Set
and Action
traits are auto implemented for &RefCell<T>
and Rc<RefCell<T>>
.
This simplifies working with dynamic borrowing in a single thread.
```rust extern crate quack;
use quack::*;
pub struct Tire {pub winter: bool}
pub struct Car {pub tires: [Tire; 4]}
pub struct LeftFrontTire(pub Tire); pub struct RightFrontTire(pub Tire); pub struct LeftBackTire(pub Tire); pub struct RightBackTire(pub Tire);
quack!{ for Car { getset LeftFrontTire(self.tires[0]), getset RightFrontTire(self.tires[1]), getset LeftBackTire(self.tires[2]), getset RightBackTire(self.tires[3]), } }
pub struct ShiftToWinterTires;
impl Action
pub struct ShiftToSummerTires;
impl Action
// Implement trait on top of duck type object.
pub trait GenericCar:
GetSet
fn set_left_front_tire(&mut self, val: Tire) {self.set(LeftFrontTire(val))}
fn set_right_front_tire(&mut self, val: Tire) {self.set(RightFrontTire(val))}
fn set_left_back_tire(&mut self, val: Tire) {self.set(LeftBackTire(val))}
fn set_right_back_tire(&mut self, val: Tire) {self.set(RightBackTire(val))}
fn shift_to_winter_tires(&mut self) {self.action(ShiftToWinterTires);}
fn shift_to_summer_tires(&mut self) {self.action(ShiftToSummerTires);}
}
// Auto implement GenericCar
.
impl
fn main() { let mut car = Car {tires: [Tire {winter: false}; 4]};
car.shift_to_winter_tires();
println!("{:?}", car);
car.set_left_front_tire(Tire {winter: false});
println!("Left front tire: {:?}", car.left_front_tire());
} ```