diff options
-rw-r--r-- | tests/movable.rs | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/tests/movable.rs b/tests/movable.rs new file mode 100644 index 0000000..f702979 --- /dev/null +++ b/tests/movable.rs @@ -0,0 +1,58 @@ +//! Tests of "moving" a holder. +//! +//! We cannot move the actual holders themselves but we can move owned handles +//! (Box, Rc, etc) to them. + +use std::cell::Cell; +use std::rc::Rc; + +use selfref::Holder; +use selfref::opaque; + +struct Foo<'this> { + foo: Cell<Option<&'this Foo<'this>>>, +} + +struct FooKey; + +opaque! { + impl Opaque for FooKey { + type Kind<'this> = Foo<'this>; + } +} + +fn create_holder() -> Holder<'static, FooKey> { + Holder::new_with(|builder| builder.build(Foo { + foo: Cell::new(None), + })) +} + +#[test] +fn move_box() { + // this is UB without the !Unpin hack + // same goes for any pinned container that has &mut's to it. + let b1 = Box::pin(create_holder()); + b1.as_ref().operate_in(|foo| { + foo.foo.set(Some(foo.get_ref())); + }); + let b2 = b1; + b2.as_ref().operate_in(|foo| { + // check that we can access the self-reference + assert!(foo.foo.get().unwrap().foo.get().is_some()); + }); +} + +#[test] +fn move_rc() { + // this is perfectly fine without the !Unpin hack! + // any container that behaves like a shared ref is fine for this. + let b1 = Rc::pin(create_holder()); + b1.as_ref().operate_in(|foo| { + foo.foo.set(Some(foo.get_ref())); + }); + let b2 = b1; + b2.as_ref().operate_in(|foo| { + // check that we can access the self-reference + assert!(foo.foo.get().unwrap().foo.get().is_some()); + }); +} |