#[macro_export]
macro_rules! with {
(mut $obj:expr => $($body:tt)*) => ({
let mut obj = $obj;
$crate::with!(@parse obj $($body)*);
obj
});
($obj:expr => $($body:tt)*) => ({
let obj = $obj;
$crate::with!(@parse obj $($body)*);
obj
});
(@parse $obj:ident) => ();
(@parse $obj:ident . $method:ident ( $($args:expr),* ) $($tail:tt)*) => {
$obj.$method($($args),*);
$crate::with!(@parse $obj $($tail)*)
};
(@parse $obj:ident let $var:pat = . $method:ident ( $($args:expr),* ) ; $($tail:tt)*) => {
let $var = $obj.$method($($args),*);
$crate::with!(@parse $obj $($tail)*)
};
(@parse $obj:ident $var:ident = . $method:ident ( $($args:expr),* ) ; $($tail:tt)*) => {
$var = $obj.$method($($args),*);
$crate::with!(@parse $obj $($tail)*)
};
(@parse $obj:ident $exp:expr ; $($tail:tt)*) => {
$exp;
$crate::with!(@parse $obj $($tail)*)
}
}
#[cfg(test)]
mod tests {
use std::cell::Cell;
#[derive(Debug, PartialEq, Eq)]
struct Foo(Cell<i32>);
impl Foo {
fn new(val: i32) -> Self {
Foo(Cell::new(val))
}
fn get_val(&self) -> i32 {
self.0.get()
}
fn set_val(&self, val: i32) {
self.0.set(val)
}
fn add(&self, n: i32) {
self.0.set(self.0.get() + n)
}
fn mul(&self, n: i32) {
self.0.set(self.0.get() * n)
}
}
#[test]
fn basic() {
let a;
let foo = with! {
Foo::new(0) =>
.set_val(10)
.mul(2)
a = .get_val();
.add(1)
let n = .get_val();
assert_eq!(n, 21);
.mul(2)
};
assert_eq!(a, 20);
assert_eq!(foo.get_val(), 42);
}
#[test]
fn mutable() {
let vec = with! {
mut Vec::new() =>
.push(1)
.push(42)
.push(-13)
let l = .len();
assert_eq!(l, 3);
};
assert_eq!(vec, [1, 42, -13]);
}
#[test]
fn nested() {
let vec = with! {
mut Vec::new() =>
.push(with!{
Foo::new(3) =>
})
.push(with!{
Foo::new(0) =>
.set_val(10)
.add(3)
})
};
assert_eq!(vec, [Foo::new(3), Foo::new(13)]);
}
}