| Crates.io | mwt |
| lib.rs | mwt |
| version | 0.4.3 |
| created_at | 2021-12-24 03:18:09.167599+00 |
| updated_at | 2022-07-28 20:00:47.306182+00 |
| description | proc macros for generating mut and non-mut methods without duplicating code |
| homepage | https://github.com/phi-fell/mwt |
| repository | https://github.com/phi-fell/mwt |
| max_upload_size | |
| id | 502518 |
| size | 21,935 |
Generate mut and non-mut versions of the same function without duplicating code!
mwt provides two mostly identical macros: mwt and maybe_mut
mwt looks for mwt in identifiers, and looks for types like &Mwt<T>maybe_mut does the same for maybe_mut and &MaybeMut<T>both let you put #[if_mut] and #[not_mut] before blocks to have conditionally present sections.
they also have a mwt() and maybe_mut() function* respectively for things like return &mwt(self.0)
both also let you pass an argument ignore_self e.g. #[mwt::maybe_mut(ignore_self)] to stop mwt from messing with the &self (or &mut self) parameter. stripping mut from &mut self is the default because taking &T<self> is a parse error, and most of the time this is the desired behavior (at least for my use cases).
there isn't currently a way to handle functions of the form _ref/_mut but one may be added in the future (maybe rwf which becomes either ref or mut?)
*Not actually a function, but the proc macro looks for it being used like a function call
mwt lets you write:
use mwt::mwt;
struct SomeStruct {
a_vector: Vec<SomeStruct>,
}
impl SomeStruct {
#[mwt]
fn my_mwt_accessor(&mut self) -> &Mwt<SomeStruct> {
let mut a = 0;
a = a + 1;
let b = &mwt(a);
#[if_mut] {
println!("Hello from my_mut_accessor()!");
}
#[not_mut] {
println!("Hello from my_accessor()!");
}
self.a_vector.get_mwt(0).unwrap()
}
}
which results in two functions:
impl SomeStruct {
fn my_accessor(&self) -> &SomeStruct {
let mut a = 0;
a = a + 1;
let b = &a;
println!("Hello from my_accessor()!");
self.a_vector.get(0).unwrap()
}
fn my_mut_accessor(&mut self) -> &mut SomeStruct {
let mut a = 0;
a = a + 1;
let b = &mut a;
println!("Hello from my_mut_accessor()!");
self.a_vector.get_mut(0).unwrap()
}
}
e.g.
#[mwt::mwt]
fn my_mwt_method(&'a mut self, other_param: i32) -> &Mwt<bool> {
#[if_mut] {
//code for only the mut version of the function
let i = 0;
}
#[not_mut] {
// code for only the non-mut version of the function
let i= 1;
}
// do something with i
self.get_mwt_flag_by_index(i)
}
Basically write the mutable version of your function, but for identifiers, replace mut with mwt and for types replace &mut T with &Mwt<T>
You can also use Mwt in types e.g. MyMwtType becomes MyMutType and MyType
Alternatively you can use mwt::maybe_mut if you feel that's more readable. example:
#[mwt::maybe_mut]
pub fn get_maybe_mut<T: 'static + Component>(&mut self) -> Option<&MaybeMut<T>> {
// use #[if_mut]{} and #[not_mut]{} for conditional behavior
// or for cases where mwt isn't powerful enough yet
// like .as_ref() vs .as_mut()
#[if_mut] { println!("if_mut"); }
#[not_mut] { println!("not_mut"); }
// use &MaybeMut<T> for &mut types
let map: &MaybeMut<HashMap<TypeId,Box<dyn Component>>>
// and &maybe_mut(...) for taking mut references
= &maybe_mut(self.components);
// use _maybe_mut_ in function calls, etc.
map.get_maybe_mut(&TypeId::of::<T>())
.and_then(|c| c.cast_maybe_mut::<T>())
}
results in two functions:
pub fn get_<T: 'static + Component>(& self) -> Option<&T> {
println!("not_mut");
let map: &HashMap<TypeId,Box<dyn Component>> = &self.components;
map.get(&TypeId::of::<T>()).and_then(|c| c.cast::<T>())
}
pub fn get_mut<T: 'static + Component>(&mut self) -> Option<&mut T> {
println!("if_mut");
let map: &mut HashMap<TypeId,Box<dyn Component>> = &mut self.components;
map.get_mut(&TypeId::of::<T>()).and_then(|c| c.cast_mut::<T>())
}
mwt::mwt basically just replaces the function with two copies (i.e. a non-mut and mut version) and does a few things on those:
&Mwt<T> with &T and &mut T respectivelymwt(expr) with expr and mut expr respectively#[not_mut]{...} and the non-mut version strips any occurrences of #[if_mut]{...} (the ones that aren't stripped have their braces removed, so be aware of that)MwtAlt<First, Second> is replaced with either First or Second in the mut and non-mut versions respectivelymwt::maybe_mut is identical just with different strings.
(Mwt -> MaybeMut, mwt -> maybe_mut, MwtAlt -> MutOrElse)
Please file an issue or submit a pull request!