1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
#![deny(missing_docs)] //! # Quack - Duck typing traits //! //! [Duck typing](https://en.wikipedia.org/wiki/Duck_typing) is a method //! where code works when certain methods and properties are present, //! instead of requiring a certain type. //! //! ### Design //! //! An duck typing abstraction is composed from the following building blocks: //! //! - Get properties (implements the `Get` trait) //! - Set properties (implements the `Set` trait) //! - Actions (implements the `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. //! //! ### Example //! //! ```rust //! extern crate quack; //! //! use quack::*; //! //! #[derive(Copy, Clone, Debug)] //! pub struct Tire {pub winter: bool} //! //! #[derive(Debug, Clone)] //! 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 { //! get_set LeftFrontTire(self.tires[0]), //! get_set RightFrontTire(self.tires[1]), //! get_set LeftBackTire(self.tires[2]), //! get_set RightBackTire(self.tires[3]), //! } //! } //! //! pub struct ShiftToWinterTires; //! impl Action<ShiftToWinterTires> for Car { //! type Result = (); //! fn action(&mut self, _: ShiftToWinterTires) -> () { //! for i in 0..4 {self.tires[i].winter = true} //! } //! } //! //! pub struct ShiftToSummerTires; //! impl Action<ShiftToSummerTires> for Car { //! type Result = (); //! fn action(&mut self, _: ShiftToSummerTires) -> () { //! for i in 0..4 {self.tires[i].winter = false} //! } //! } //! //! // Implement trait on top of duck type object. //! pub trait GenericCar: //! GetSet<LeftFrontTire> + //! GetSet<RightFrontTire> + //! GetSet<LeftBackTire> + //! GetSet<RightBackTire> + //! Action<ShiftToSummerTires> + //! Action<ShiftToWinterTires> //! { //! fn left_front_tire(&self) -> Tire {Get::<LeftFrontTire>::get(self).0} //! fn right_front_tire(&self) -> Tire {Get::<RightFrontTire>::get(self).0} //! fn left_back_tire(&self) -> Tire {Get::<LeftBackTire>::get(self).0} //! fn right_back_tire(&self) -> Tire {Get::<RightBackTire>::get(self).0} //! //! 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<T> GenericCar for T where T: //! GetSet<LeftFrontTire> + //! GetSet<RightFrontTire> + //! GetSet<LeftBackTire> + //! GetSet<RightBackTire> + //! Action<ShiftToSummerTires> + //! Action<ShiftToWinterTires> //! {} //! //! 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()); //! } //! ``` mod refcell; /// Get property. pub trait Get<T> { /// Gets property value. fn get(&self) -> T; } /// Set property. pub trait Set<T> { /// Sets property value. fn set(&mut self, val: T); } /// An auto implemented trait for get/set properties. pub trait GetSet<T>: Get<T> + Set<T> {} impl<T, U> GetSet<T> for U where U: Get<T> + Set<T> {} /// Represents an action on objects. pub trait Action<T> { /// The action result type. type Result; /// Performs action on object. fn action(&mut self, val: T) -> Self::Result; } /// Helper macro for simple get/set properties. /// /// This macro supports 4 different syntaxes: /// /// 1. Get/set property e.g. `quack!{get_set X(self.x) for Foo}` /// 2. Get property e.g. `quack!{get X(self.x) for Foo}` /// 3. Set property e.g. `quack!{set X(self.x) for Foo}` /// 4. Multiple properties e.g. `quack!{for Foo {get X(self.x), get Y(self.y)}}` #[macro_export] macro_rules! quack { (get_set $prop:ident ( $($code:tt)* ) for $Self:ty) => { quack!(get $prop($($code)*) for $Self); quack!(set $prop($($code)*) for $Self); }; (set $prop:ident ( self . $($code:tt)* ) for $Self:ty) => { impl Set<$prop> for $Self { #[inline(always)] fn set(&mut self, val: $prop) {self.$($code)* = val.0} } }; (set $prop:ident ( self [ $($code:tt)* ] ) for $Self:ty) => { impl Set<$prop> for $Self { #[inline(always)] fn set(&mut self, val: $prop) {self[$($code)*] = val.0} } }; (get $prop:ident ( self . $($code:tt)* ) for $Self:ty) => { impl Get<$prop> for $Self { #[inline(always)] fn get(&self) -> $prop {$prop(self.$($code)*)} } }; (get $prop:ident ( self [ $($code:tt)* ] ) for $Self:ty) => { impl Get<$prop> for $Self { #[inline(always)] fn get(&self) -> $prop {$prop(self[$($code)*])} } }; ( for $Self:ty { $($cmd:tt $get_set_prop:ident ( $($get_set:tt)* )),* $(,)? } ) => { $(quack!($cmd $get_set_prop($($get_set)*) for $Self);)* } }