use crate::{SharedBox, SharedVec, SharedVecMut};
pub trait Scope {
type Shared;
fn create_shared(&mut self) -> Self::Shared;
fn set_from_shared(&mut self, shared: Self::Shared);
fn scope<T>(&mut self, f: impl FnOnce(&mut Self::Shared) -> T) -> T {
let mut shared = self.create_shared();
let ret = f(&mut shared);
self.set_from_shared(shared);
ret
}
fn scope_async<T>(
&mut self,
f: impl AsyncFnOnce(&mut Self::Shared) -> T,
) -> impl Future<Output = T> {
async {
let mut shared = self.create_shared();
let ret = f(&mut shared).await;
self.set_from_shared(shared);
ret
}
}
}
impl<T> Scope for Vec<T> {
type Shared = SharedVec<T>;
fn create_shared(&mut self) -> Self::Shared {
let v = core::mem::take(self);
SharedVec::from_vec(v)
}
fn set_from_shared(&mut self, shared: Self::Shared) {
*self = if let Ok(v) = shared.try_into_vec() {
v
} else {
panic!("Failed to convert SharedVec to Vec");
}
}
}
impl<T: Default + ?Sized> Scope for Box<T> {
type Shared = SharedBox<T>;
fn create_shared(&mut self) -> Self::Shared {
let b = core::mem::take(self);
SharedBox::from_box(b)
}
fn set_from_shared(&mut self, shared: Self::Shared) {
*self = if let Ok(b) = shared.try_into_box() {
b
} else {
panic!("Failed to convert SharedBox to Box");
}
}
}
pub struct VecShareMut<'a, T>(pub &'a mut Vec<T>);
impl<'a, T> Scope for VecShareMut<'a, T> {
type Shared = SharedVecMut<T>;
fn create_shared(&mut self) -> Self::Shared {
let v = core::mem::take(self.0);
SharedVecMut::from_vec(v)
}
fn set_from_shared(&mut self, shared: Self::Shared) {
*self.0 = if let Ok(v) = shared.try_into_vec() {
v
} else {
panic!("Failed to convert SharedVecMut to Vec");
};
}
}
macro_rules! impl_for_tuple_body {
(
$($types:ident),*
;
$($numbers:tt),*
) => {
type Shared = ( $( $types::Shared ),* ,);
fn create_shared(&mut self) -> Self::Shared {
($( self.$numbers.create_shared() ),* ,)
}
fn set_from_shared(&mut self, shared: Self::Shared) {
$(
self.$numbers.set_from_shared(shared.$numbers)
);*;
}
};
}
macro_rules! impl_for_tuple {
(
$($types:ident),*
;
$($numbers:tt),*
) => {
#[cfg_attr(docsrs, doc(hidden))]
impl< $( $types: Scope ),* > Scope for ( $(&mut $types),* ,) {
impl_for_tuple_body!($($types),*; $($numbers),*);
}
};
}
#[cfg_attr(docsrs, doc(fake_variadic))]
#[cfg_attr(
docsrs,
doc = "This trait is implemented for tuples up to 8 items long."
)]
impl<T1: Scope> Scope for (&mut T1,) {
impl_for_tuple_body!(T1;0);
}
impl_for_tuple!(T1, T2; 0, 1);
impl_for_tuple!(T1, T2, T3; 0, 1, 2);
impl_for_tuple!(T1, T2, T3, T4; 0, 1, 2, 3);
impl_for_tuple!(T1, T2, T3, T4, T5; 0, 1, 2, 3, 4);
impl_for_tuple!(T1, T2, T3, T4, T5, T6; 0, 1, 2, 3, 4, 5);
impl_for_tuple!(T1, T2, T3, T4, T5, T6, T7; 0, 1, 2, 3, 4, 5, 6);
impl_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8; 0, 1, 2, 3, 4, 5, 6, 7);