├── .gitignore ├── .travis.yml ├── Cargo.toml ├── README.md └── src ├── impls.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *~ 3 | *# 4 | *.o 5 | *.so 6 | *.swp 7 | *.dylib 8 | *.dSYM 9 | *.dll 10 | *.rlib 11 | *.dummy 12 | *.exe 13 | *-test 14 | /doc/ 15 | /target/ 16 | /examples/* 17 | !/examples/*.rs 18 | Cargo.lock 19 | 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "modifier" 4 | version = "0.1.0" 5 | authors = ["Jonathan Reem "] 6 | description = "Fluid chaining APIs for both mutable ownership types." 7 | readme = "README.md" 8 | repository = "https://github.com/reem/rust-modifier" 9 | license = "MIT" 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust-Modifier 2 | 3 | > Chaining APIs for both `self -> Self` and `&mut self` methods. 4 | 5 | ## Example 6 | 7 | ```rust 8 | let mut thing = Thing { x: 6 }; 9 | thing.set_mut(ModifyX(8)); 10 | assert_eq!(thing.x, 8); 11 | 12 | let thing = thing.set(ModifyX(9)); 13 | assert_eq!(thing.x, 9); 14 | ``` 15 | 16 | ## Overview 17 | 18 | Rust-modifier allows you to define modifiers just once, then 19 | use them through both `set` and `set_mut`, allowing downstream 20 | users the ability to use whichever API is most convenient. 21 | 22 | Additionally, rust-modifier allows users to define their own 23 | modifiers, arbitrarily extending the utility of existing types. 24 | 25 | ## LICENSE 26 | 27 | MIT 28 | 29 | -------------------------------------------------------------------------------- /src/impls.rs: -------------------------------------------------------------------------------- 1 | /// Some implementations for chains of tuples. 2 | /// 3 | /// FIXME(reem): Move generation of this to a build script. 4 | 5 | use Modifier; 6 | 7 | impl Modifier for (M1,) 8 | where M1: Modifier { 9 | fn modify(self, x: &mut X) { 10 | self.0.modify(x); 11 | } 12 | } 13 | 14 | impl Modifier for (M1, M2) 15 | where M1: Modifier, 16 | M2: Modifier { 17 | fn modify(self, x: &mut X) { 18 | self.0.modify(x); 19 | self.1.modify(x); 20 | } 21 | } 22 | 23 | impl Modifier for (M1, M2, M3) 24 | where M1: Modifier, 25 | M2: Modifier, 26 | M3: Modifier { 27 | fn modify(self, x: &mut X) { 28 | self.0.modify(x); 29 | self.1.modify(x); 30 | self.2.modify(x); 31 | } 32 | } 33 | 34 | impl Modifier for (M1, M2, M3, M4) 35 | where M1: Modifier, 36 | M2: Modifier, 37 | M3: Modifier, 38 | M4: Modifier { 39 | fn modify(self, x: &mut X) { 40 | self.0.modify(x); 41 | self.1.modify(x); 42 | self.2.modify(x); 43 | self.3.modify(x); 44 | } 45 | } 46 | 47 | impl Modifier for (M1, M2, M3, M4, M5) 48 | where M1: Modifier, 49 | M2: Modifier, 50 | M3: Modifier, 51 | M4: Modifier, 52 | M5: Modifier { 53 | fn modify(self, x: &mut X) { 54 | self.0.modify(x); 55 | self.1.modify(x); 56 | self.2.modify(x); 57 | self.3.modify(x); 58 | self.4.modify(x); 59 | } 60 | } 61 | 62 | impl Modifier for (M1, M2, M3, M4, M5, M6) 63 | where M1: Modifier, 64 | M2: Modifier, 65 | M3: Modifier, 66 | M4: Modifier, 67 | M5: Modifier, 68 | M6: Modifier { 69 | fn modify(self, x: &mut X) { 70 | self.0.modify(x); 71 | self.1.modify(x); 72 | self.2.modify(x); 73 | self.3.modify(x); 74 | self.4.modify(x); 75 | self.5.modify(x); 76 | } 77 | } 78 | 79 | impl Modifier for Option 80 | where M: Modifier { 81 | fn modify(self, x: &mut X) { 82 | match self { 83 | Some(m) => m.modify(x), 84 | None => (), 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs, warnings)] 2 | 3 | //! Overloadable modification through both owned and mutable references 4 | //! to a type with minimal code duplication. 5 | 6 | /// Allows use of the implemented type as an argument to Set::set. 7 | /// 8 | /// This allows types to be used for ad-hoc overloading of Set::set 9 | /// to perform complex updates to the parameter of Modifier. 10 | pub trait Modifier { 11 | /// Modify `F` with self. 12 | fn modify(self, &mut F); 13 | } 14 | 15 | /// A trait providing the set and set_mut methods for all types. 16 | /// 17 | /// Simply implement this for your types and they can be used 18 | /// with modifiers. 19 | pub trait Set { 20 | /// Modify self using the provided modifier. 21 | #[inline(always)] 22 | fn set>(mut self, modifier: M) -> Self where Self: Sized { 23 | modifier.modify(&mut self); 24 | self 25 | } 26 | 27 | /// Modify self through a mutable reference with the provided modifier. 28 | #[inline(always)] 29 | fn set_mut>(&mut self, modifier: M) -> &mut Self { 30 | modifier.modify(self); 31 | self 32 | } 33 | } 34 | 35 | mod impls; 36 | 37 | #[cfg(test)] 38 | mod test { 39 | pub use super::*; 40 | 41 | pub struct Thing { 42 | x: usize 43 | } 44 | 45 | pub struct BiggerThing { 46 | first: usize, 47 | second: usize 48 | } 49 | 50 | impl Set for Thing {} 51 | impl Set for BiggerThing {} 52 | 53 | pub struct ModifyX(usize); 54 | pub struct ModifyFirst(usize); 55 | pub struct ModifySecond(usize); 56 | 57 | impl Modifier for ModifyX { 58 | fn modify(self, thing: &mut Thing) { 59 | thing.x = self.0; 60 | } 61 | } 62 | 63 | impl Modifier for ModifyFirst { 64 | fn modify(self, bigger_thing: &mut BiggerThing) { 65 | bigger_thing.first = self.0; 66 | } 67 | } 68 | 69 | impl Modifier for ModifySecond { 70 | fn modify(self, bigger_thing: &mut BiggerThing) { 71 | bigger_thing.second = self.0; 72 | } 73 | } 74 | 75 | #[test] 76 | fn test_set_and_set_mut() { 77 | let mut thing = Thing { x: 6 }; 78 | thing.set_mut(ModifyX(8)); 79 | assert_eq!(thing.x, 8); 80 | 81 | let thing = thing.set(ModifyX(9)); 82 | assert_eq!(thing.x, 9); 83 | } 84 | 85 | #[test] 86 | fn test_optional_modifier() { 87 | let get_mod = |b| if b { Some(ModifyX(5)) } else { None }; 88 | let thing = Thing { x: 8 }.set(get_mod(false)); 89 | assert_eq!(thing.x, 8); 90 | 91 | let thing = thing.set(get_mod(true)); 92 | assert_eq!(thing.x, 5); 93 | } 94 | 95 | #[test] 96 | fn test_tuple_chains() { 97 | let thing = Thing { x: 8 }.set((ModifyX(5), ModifyX(112))); 98 | assert_eq!(thing.x, 112); 99 | } 100 | 101 | #[test] 102 | fn test_tuple_different_fields() { 103 | let bigger_thing = BiggerThing { first: 1, second: 2}.set((ModifyFirst(10), ModifySecond(12))); 104 | assert_eq!(bigger_thing.first, 10); 105 | assert_eq!(bigger_thing.second, 12); 106 | } 107 | } 108 | 109 | --------------------------------------------------------------------------------