use alloc::{borrow::ToOwned, boxed::Box};
use core::fmt::Debug;
use ouroboros::self_referencing;
#[self_referencing]
struct TraitObject {
data: Box<dyn Debug>,
#[borrows(data)]
dref: &'this dyn Debug,
}
#[self_referencing]
struct BoxAndRef {
data: i32,
#[borrows(data)]
dref: &'this i32,
}
#[self_referencing]
struct BoxAndMutRef {
data: i32,
#[borrows(mut data)]
dref: &'this mut i32,
}
#[self_referencing(no_doc)]
struct ChainedAndUndocumented {
data: i32,
#[borrows(data)]
ref1: &'this i32,
#[borrows(ref1)]
ref2: &'this &'this i32,
}
#[self_referencing]
struct BoxCheckWithLifetimeParameter<'t> {
external_data: &'t (),
#[borrows(external_data)]
self_reference: &'this &'t (),
}
#[self_referencing]
struct AutoDetectCovarianceOnFieldsWithoutThis {
data: (),
unrelated_data: Box<i32>,
#[borrows(data)]
self_reference: &'this (),
}
#[self_referencing]
struct TemplateMess<'d, A, B: 'static, C: 'static>
where
A: ?Sized,
B: 'static,
C: 'static,
{
external: &'d A,
data1: B,
#[borrows(data1)]
data2: &'this C,
data3: B,
#[borrows(mut data3)]
data4: &'this mut C,
}
#[self_referencing]
#[derive(Debug, PartialEq, Eq)]
struct DeriveCompilesOk<T: 'static> {
data: T,
#[borrows(data)]
dref: &'this T,
}
#[test]
fn box_and_ref() {
let bar = BoxAndRefBuilder {
data: 12,
dref_builder: |data| data,
}
.build();
assert!(bar.with_dref(|dref| **dref) == 12);
drop(bar);
}
#[cfg(all(not(feature = "miri"), feature = "std"))]
#[tokio::test]
async fn async_new() {
let bar = BoxAndRefAsyncBuilder {
data: 12,
dref_builder: |data| Box::pin(async move { data }),
}
.build()
.await;
assert!(bar.with_dref(|dref| **dref) == 12);
drop(bar);
}
#[cfg(all(not(feature = "miri"), feature = "std"))]
#[tokio::test]
async fn async_try_new() {
let bar = BoxAndRefAsyncTryBuilder {
data: 12,
dref_builder: |data| Box::pin(async move { Result::<_, ()>::Ok(data) }),
}
.try_build()
.await
.unwrap();
assert!(bar.with_dref(|dref| **dref) == 12);
drop(bar);
}
#[cfg(all(not(feature = "miri"), feature = "std"))]
#[tokio::test]
async fn async_try_new_err() {
let result = BoxAndRefAsyncTryBuilder {
data: 12,
dref_builder: |_data| Box::pin(async move { Err(56u64) }),
}
.try_build()
.await;
if let Err(56) = result {
} else {
panic!("Test failed.");
}
}
#[test]
fn try_new() {
let bar = BoxAndRefTryBuilder {
data: 12,
dref_builder: |data| Result::<_, ()>::Ok(data),
}
.try_build()
.unwrap();
assert!(bar.with_dref(|dref| **dref) == 12);
drop(bar);
}
#[test]
fn try_new_err() {
let result = BoxAndRefTryBuilder {
data: 12,
dref_builder: |_data| Err(56),
}
.try_build();
if let Err(56) = result {
} else {
panic!("Test failed.");
}
}
#[test]
fn try_new_recover_heads() {
let result = BoxAndRefTryBuilder {
data: 12,
dref_builder: |_data| Err(56),
}
.try_build_or_recover();
if let Err((56, heads)) = result {
assert!(heads.data == 12);
} else {
panic!("Test failed.");
}
}
#[test]
fn into_heads() {
let bar = BoxAndRefBuilder {
data: 12,
dref_builder: |data| data,
}
.build();
assert!(bar.into_heads().data == 12);
}
#[test]
fn box_and_mut_ref() {
let mut bar = BoxAndMutRefBuilder {
data: 12,
dref_builder: |data| data,
}
.build();
assert!(bar.with_dref(|dref| **dref) == 12);
bar.with_dref_mut(|dref| **dref = 34);
assert!(bar.with_dref(|dref| **dref) == 34);
}
const STATIC_INT: i32 = 456;
#[test]
fn self_reference_with() {
let mut bar = BoxAndRef::new(123, |b| b);
bar.with_dref(|dref| {
assert_eq!(**dref, 123);
});
bar.with_dref_mut(|dref| {
*dref = &STATIC_INT;
});
assert_eq!(**bar.borrow_dref(), STATIC_INT);
bar.with_mut(|fields| {
*fields.dref = fields.data;
});
assert_eq!(**bar.borrow_dref(), 123);
}
#[test]
fn single_lifetime() {
#[self_referencing]
struct Struct<'a> {
external: &'a str,
#[borrows(external)]
internal: &'this &'a str,
}
let external = "Hello world!".to_owned();
let instance = Struct::new(&external, |field_ref| field_ref);
drop(instance.borrow_external());
drop(instance.borrow_internal());
drop(instance);
}
#[test]
fn double_lifetime() {
#[self_referencing]
struct Struct<'a, 'b: 'a> {
external: &'a str,
external2: &'b str,
#[borrows(external, external2)]
internal: &'this &'b str,
}
}
#[cfg(not(feature = "miri"))]
#[rustversion::stable(1.62)]
mod compile_tests {
#[test]
fn fails_ok() {
let t = trybuild::TestCases::new();
t.compile_fail("src/fail_tests/*.rs");
}
}
#[allow(dead_code)]
mod test_hygiene {
mod std {}
mod core {}
struct Copy;
struct Send;
struct Sync;
struct Sized;
struct Drop;
struct Fn;
struct FnMut;
struct FnOnce;
struct Result;
struct Ok;
struct Err;
struct Option;
struct Some;
struct None;
fn drop() {}
#[ouroboros::self_referencing]
struct BoxAndRef {
data: i32,
#[borrows(data)]
dref: &'this i32,
}
}