mod a;
pub use a::A;
#[macro_export]
macro_rules! tspawn {
($($input:tt)*) => {
$crate::tspawn_internal!(@parse [] [] $($input)*)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! tspawn_internal {
(@parse [$($clone:tt)*] [$($lock:tt)*] $body:block) => {{
$($clone)*
tokio::spawn({
$($lock)*
async move $body
})
}};
(@parse [$($clone:tt)*] [$($lock:tt)*] ref $var:ident, $($rest:tt)*) => {
$crate::tspawn_internal!(
@parse
[$($clone)* let $var = ::core::clone::Clone::clone(&$var);]
[$($lock)* let $var = $var.read();]
$($rest)*
)
};
(@parse [$($clone:tt)*] [$($lock:tt)*] mut $var:ident, $($rest:tt)*) => {
$crate::tspawn_internal!(
@parse
[$($clone)* let $var = ::core::clone::Clone::clone(&$var);]
[$($lock)* let mut $var = $var.write();]
$($rest)*
)
};
(@parse [$($clone:tt)*] [$($lock:tt)*] $var:ident, $($rest:tt)*) => {
$crate::tspawn_internal!(
@parse
[$($clone)* let $var = ::core::clone::Clone::clone(&$var);]
[$($lock)*]
$($rest)*
)
};
(@parse [$($clone:tt)*] [$($lock:tt)*] ref $var:ident $body:block) => {
$crate::tspawn_internal!(
@parse
[$($clone)* let $var = ::core::clone::Clone::clone(&$var);]
[$($lock)* let $var = $var.read();]
$body
)
};
(@parse [$($clone:tt)*] [$($lock:tt)*] mut $var:ident $body:block) => {
$crate::tspawn_internal!(
@parse
[$($clone)* let $var = ::core::clone::Clone::clone(&$var);]
[$($lock)* let mut $var = $var.write();]
$body
)
};
(@parse [$($clone:tt)*] [$($lock:tt)*] $var:ident $body:block) => {
$crate::tspawn_internal!(
@parse
[$($clone)* let $var = ::core::clone::Clone::clone(&$var);]
[$($lock)*]
$body
)
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_operations() {
let data = A::new(42);
assert_eq!(data.get(), 42);
data.set(100);
assert_eq!(data.get(), 100);
data.update(|x| *x += 1);
assert_eq!(data.get(), 101);
assert_eq!(data.geto(), Some(101));
}
#[test]
fn test_cloning() {
let original = A::new(vec![1, 2, 3]);
let cloned = original.clone();
assert_eq!(original.get(), vec![1, 2, 3]);
assert_eq!(cloned.get(), vec![1, 2, 3]);
original.update(|v| v.push(4));
assert_eq!(cloned.get(), vec![1, 2, 3, 4]);
}
#[test]
fn test_guards() {
let data = A::new(String::from("Hello"));
{
let guard = data.read();
assert_eq!(&*guard, "Hello");
}
{
let mut guard = data.write();
guard.push_str(", World!");
}
assert_eq!(data.get(), "Hello, World!");
}
#[test]
fn test_from_and_into_inner() {
use parking_lot::RwLock;
use std::sync::Arc;
let arc_lock = Arc::new(RwLock::new(42));
let data = A::from_inner(arc_lock);
assert_eq!(data.get(), 42);
let arc_lock = data.into_inner();
assert_eq!(*arc_lock.read(), 42);
}
#[tokio::test]
async fn test_tspawn_ref() {
let data = A::new(42);
tspawn!(ref data, {
assert_eq!(*data, 42);
})
.await
.unwrap();
}
#[tokio::test]
async fn test_tspawn_mut() {
let data = A::new(42);
tspawn!(mut data, {
*data += 10;
})
.await
.unwrap();
assert_eq!(data.get(), 52);
}
#[tokio::test]
async fn test_tspawn_clone() {
let data = A::new(42);
tspawn!(data, {
let value = data.get();
assert_eq!(value, 42);
data.set(100);
})
.await
.unwrap();
assert_eq!(data.get(), 100);
}
#[tokio::test]
async fn test_tspawn_multiple_ref() {
let x = A::new(10);
let y = A::new(20);
tspawn!(ref x, ref y, {
assert_eq!(*x + *y, 30);
})
.await
.unwrap();
}
#[tokio::test]
async fn test_tspawn_mixed_access() {
let x = A::new(10);
let y = A::new(20);
tspawn!(mut x, ref y, {
*x += *y;
})
.await
.unwrap();
assert_eq!(x.get(), 30);
assert_eq!(y.get(), 20);
}
#[tokio::test]
async fn test_concurrent_access() {
let data = A::new(0);
let mut handles = vec![];
for _ in 0..10 {
let data_clone = data.clone();
handles.push(tokio::spawn(async move {
data_clone.update(|x| *x += 1);
}));
}
for handle in handles {
handle.await.unwrap();
}
assert_eq!(data.get(), 10);
}
#[tokio::test]
async fn test_tspawn_variadic_patterns() {
let a = A::new(1);
tspawn!(a, {
assert_eq!(a.get(), 1);
})
.await
.unwrap();
tspawn!(ref a, {
assert_eq!(*a, 1);
})
.await
.unwrap();
tspawn!(mut a, {
*a += 1;
})
.await
.unwrap();
assert_eq!(a.get(), 2);
let b = A::new(10);
let c = A::new(20);
tspawn!(ref a, mut b, c, {
*b += *a;
let c_val = c.get();
assert_eq!(*b, 12);
assert_eq!(c_val, 20);
})
.await
.unwrap();
assert_eq!(b.get(), 12);
let d = A::new(30);
let e = A::new(40);
tspawn!(a, ref b, mut c, d, ref e, {
*c += *b + *e;
assert_eq!(*c, 72); assert_eq!(a.get(), 2);
assert_eq!(d.get(), 30);
})
.await
.unwrap();
assert_eq!(c.get(), 72);
}
#[tokio::test]
async fn test_tspawn_many_variables() {
let v0 = A::new(0);
let v1 = A::new(1);
let v2 = A::new(2);
let v3 = A::new(3);
let v4 = A::new(4);
let v5 = A::new(5);
let v6 = A::new(6);
let v7 = A::new(7);
tspawn!(v0, mut v1, ref v2, v3, ref v4, mut v5, v6, ref v7, {
*v1 += *v2 + *v4 + *v7; *v5 += v0.get() + v3.get() + v6.get(); })
.await
.unwrap();
assert_eq!(v1.get(), 14);
assert_eq!(v5.get(), 14);
}
}