Crates.io | mwt |
lib.rs | mwt |
version | 0.4.3 |
source | src |
created_at | 2021-12-24 03:18:09.167599 |
updated_at | 2022-07-28 20:00:47.306182 |
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!