use super::*;
#[cfg(feature = "std")]
use std::string::String;
struct SelfRefTest<T, U: ?Sized + PointerRecomposition> {
t_ref: SelfRef<U, i8>,
t: T,
}
fn id<T>(t: &mut T) -> &mut T {
t
}
impl<T, U: ?Sized + PointerRecomposition> SelfRefTest<T, U> {
pub fn new(t: T, f: fn(&mut T) -> &mut U) -> Self {
let mut this = Self {
t,
t_ref: SelfRef::null(),
};
this.t_ref.set(f(&mut this.t)).unwrap();
this
}
pub fn t(&self) -> &T {
&self.t
}
pub fn t_mut(&mut self) -> &mut T {
&mut self.t
}
pub fn t_ref(&mut self) -> &U {
unsafe {
self.t_ref
.get_ref_from_base_unchecked(self as *const _ as *const u8)
}
}
#[allow(unused)]
pub fn t_ref_mut(&mut self) -> &mut U {
let base = self as *mut _ as *mut u8;
unsafe { self.t_ref.get_mut_from_base_unchecked(base) }
}
}
#[inline(never)]
fn block_opt<T>(x: T) -> T {
x
}
#[test]
fn simple_test() {
let mut s = SelfRefTest {
t: "Hello World",
t_ref: SelfRef::null(),
};
s.t_ref.set(&mut s.t).unwrap();
assert_eq!(*s.t(), "Hello World");
assert_eq!(*s.t_ref(), "Hello World");
}
#[test]
fn simple_move() {
let mut s = SelfRefTest {
t: "Hello World",
t_ref: SelfRef::null(),
};
s.t_ref.set(&mut s.t).unwrap();
assert_eq!(*s.t(), "Hello World");
assert_eq!(*s.t_ref(), "Hello World");
let mut s = block_opt(s);
assert_eq!(*s.t(), "Hello World");
assert_eq!(*s.t_ref(), "Hello World");
}
#[test]
fn simple_move_after_init() {
let mut s = SelfRefTest::new("Hello World", id);
assert_eq!(*s.t(), "Hello World");
assert_eq!(*s.t_ref(), "Hello World");
let mut s = block_opt(s);
assert_eq!(*s.t(), "Hello World");
assert_eq!(*s.t_ref(), "Hello World");
}
#[test]
fn swap() {
let mut s = SelfRefTest::new("Hello World", id);
let mut x = SelfRefTest::new("Killer Move", id);
assert_eq!(*s.t(), "Hello World");
assert_eq!(*x.t(), "Killer Move");
assert_eq!(*s.t_ref(), "Hello World");
assert_eq!(*x.t_ref(), "Killer Move");
std::mem::swap(&mut s, &mut x);
assert_eq!(*s.t(), "Killer Move");
assert_eq!(*x.t(), "Hello World");
assert_eq!(*s.t_ref(), "Killer Move");
assert_eq!(*x.t_ref(), "Hello World");
}
#[test]
fn aliasing() {
let mut s = SelfRefTest::new("Hello World", id);
*s.t_mut() = "Killer Move";
assert_eq!(*s.t(), "Killer Move");
assert_eq!(*s.t_ref(), "Killer Move");
}
#[test]
fn sub_str() {
#[inline(never)]
fn get_move(s: SelfRefTest<[u8; 5], [u8]>) {
let mut s = s;
assert_eq!(*s.t(), [0, 1, 2, 3, 4]);
assert_eq!(*s.t_ref(), [2, 3, 4]);
}
let mut s = SelfRefTest::new([0, 1, 2, 3, 4], |x| &mut x[2..]);
assert_eq!(*s.t(), [0, 1, 2, 3, 4]);
assert_eq!(*s.t_ref(), [2, 3, 4]);
get_move(s);
}
#[cfg(feature = "std")]
#[test]
fn equality_tracks_metadata() {
let left = SelfRefTest::new([0, 1, 2, 3, 4], |x| &mut x[..]);
let right = SelfRefTest::new([0, 1, 2, 3, 4], |x| &mut x[1..]);
assert_eq!(
left.t_ref,
SelfRefTest::new([9, 8, 7, 6, 5], |x| &mut x[..]).t_ref
);
assert_ne!(left.t_ref, right.t_ref);
}
#[cfg(feature = "std")]
#[test]
fn from_parts_restores_pointer() {
let mut node = SelfRefTest::new([5, 6, 7, 8, 9], |x| &mut x[1..]);
let (stored_offset, stored_components) = node
.t_ref
.parts_if_ready()
.expect("pointer should be ready");
node.t_ref = SelfRef::from_parts(stored_offset, stored_components);
assert!(node.t_ref.is_ready());
assert_eq!(*node.t_ref(), [6, 7, 8, 9]);
}
#[cfg(feature = "std")]
#[test]
fn try_accessors() {
struct Wrapper {
cell: SelfRefCell<String, i16>,
}
let wrapper = Wrapper {
cell: SelfRefCell::new(String::from("alive")).unwrap(),
};
assert_eq!(wrapper.cell.try_get().map(|value| value.len()), Some(5));
}
#[test]
fn check_copy() {
fn is_copy<T: Copy>() {}
#[allow(unused, path_statements)]
fn check<T: ?Sized + PointerRecomposition, I: Offset>() {
is_copy::<SelfRef<T, I>>;
}
}
#[cfg(feature = "nightly")]
mod nightly {
use super::*;
#[derive(Debug)]
struct TestStruct {
value: u32,
}
#[test]
fn check_trait_object_simple() {
let mut s = SelfRefTest::new(TestStruct { value: 42 }, |x| unsafe {
TraitObject::from_mut(x as &mut dyn std::fmt::Debug)
});
assert_eq!(s.t().value, 42);
#[cfg(feature = "std")]
{
let debug_str = format!("{:?}", s.t_ref().as_ref());
assert!(debug_str.contains("42"));
}
}
#[test]
fn check_trait_object_after_move() {
let mut s = SelfRefTest::new(TestStruct { value: 42 }, |x| unsafe {
TraitObject::from_mut(x as &mut dyn std::fmt::Debug)
});
assert_eq!(s.t().value, 42);
#[cfg(feature = "std")]
{
let debug_str = format!("{:?}", s.t_ref().as_ref());
assert!(debug_str.contains("42"));
}
#[inline(never)]
fn force_move<T>(t: T) -> T {
t
}
let mut s = force_move(s);
assert_eq!(s.t().value, 42);
#[cfg(feature = "std")]
{
let debug_str = format!("{:?}", s.t_ref().as_ref());
assert!(debug_str.contains("42"));
}
}
#[test]
#[cfg(feature = "std")]
fn check_trait_object_after_move_heap() {
let mut s = SelfRefTest::new(TestStruct { value: 42 }, |x| unsafe {
TraitObject::from_mut(x as &mut dyn std::fmt::Debug)
});
assert_eq!(s.t().value, 42);
#[cfg(feature = "std")]
{
let debug_str = format!("{:?}", s.t_ref().as_ref());
assert!(debug_str.contains("42"));
}
let mut s = Box::new(s);
assert_eq!(s.t().value, 42);
#[cfg(feature = "std")]
{
let debug_str = format!("{:?}", s.t_ref().as_ref());
assert!(debug_str.contains("42"));
}
}
}