use std::cell::UnsafeCell;
use std::marker::{PhantomData, PhantomPinned};
use std::panic::{RefUnwindSafe, UnwindSafe};
use supply::want::*;
use supply::Want;
use ty_tag::lifetime_list::{LifetimeList, L0, L1};
use ty_tag::{ReifySelf, ReifySized, TagTypeId};
#[allow(unused)]
struct NoAuto<'a>(
PhantomData<(*const u8, PhantomPinned, &'a mut u8, UnsafeCell<u8>)>,
str,
);
const _: () = {
struct Test<'a>(NoAuto<'a>);
impl<'a, T> WantFor<T> for Test<'a> {
fn fulfill(&mut self, _value: T) {
unimplemented!()
}
fn is_satisfied(&self) -> bool {
unimplemented!()
}
}
};
const _: () = {
struct Test<'a>(NoAuto<'a>);
impl<'a, L: LifetimeList> Want<L> for Test<'a> {
fn try_for_id(&mut self, _tag_type_id: TagTypeId<L>) -> Option<ErasedWantFor<'_, L>> {
unimplemented!()
}
fn is_satisfied(&self) -> bool {
unimplemented!()
}
}
struct Other;
impl Want for Other {
fn try_for_id(&mut self, _tag_type_id: TagTypeId<L0>) -> Option<ErasedWantFor<'_, L0>> {
unimplemented!()
}
fn is_satisfied(&self) -> bool {
unimplemented!()
}
}
fn test() {
fn assert<'r, T: Want<L0>>() {}
assert::<Other>();
}
};
struct MockWant(i8);
impl<L: LifetimeList> Want<L> for MockWant {
fn try_for_id(&mut self, tag_type_id: TagTypeId<L>) -> Option<ErasedWantFor<'_, L>> {
if tag_type_id == TagTypeId::of::<i8>() || tag_type_id == TagTypeId::of::<f32>() {
Some(ErasedWantFor::new::<i8>(self))
} else {
None
}
}
fn is_satisfied(&self) -> bool {
self.0 > 0
}
}
impl WantFor<i8> for MockWant {
fn fulfill(&mut self, value: i8) {
self.0 += value;
}
fn is_satisfied(&self) -> bool {
self.0 > 0
}
}
#[test]
#[allow(unused)]
fn can_call_dyn_methods() {
fn assert_call_provide_value<T: ReifySelf<L>, L: LifetimeList>(
want: &mut dyn Want<L>,
value: T,
) {
want.provide_value(value);
}
fn assert_call_provide_tag<T: ReifySized<L>, L: LifetimeList>(
want: &mut dyn Want<L>,
value: T::Reified,
) {
want.provide_tag::<T>(value);
}
fn assert_call_provide<F, T: ReifySized<L>, L: LifetimeList>(want: &mut dyn Want<L>, f: F)
where
F: FnOnce() -> T::Reified,
{
want.provide::<T, F>(f);
}
fn assert_call_provide_with<C, F, T: ReifySized<L>, L: LifetimeList>(
want: &mut dyn Want<L>,
ctx: C,
f: F,
) where
F: FnOnce(C) -> T::Reified,
{
want.provide_with::<T, C, F>(ctx, f);
}
fn assert_call_try_for<T, L: LifetimeList>(want: &mut dyn Want<L>)
where
T: ReifySized<L>,
{
want.try_for::<T>();
}
}
#[test]
fn want_try_for() {
let mut mock = MockWant(0);
let want: &mut dyn Want = &mut mock;
assert!(want.try_for::<u8>().is_none());
let want_for = want.try_for::<i8>().unwrap();
assert!(!want_for.is_satisfied());
want_for.fulfill(123);
assert!(want_for.is_satisfied());
want_for.fulfill(-124);
assert!(!want_for.is_satisfied());
assert!(want.try_for::<f32>().is_none());
assert_eq!(mock.0, -1);
}
#[test]
fn want_provide_with() {
let mut mock = MockWant(0);
let want: &mut dyn Want = &mut mock;
assert_eq!(
want.provide_with::<u8, String, _>(String::from("hello"), |_| unimplemented!())
.as_deref(),
Some("hello")
);
assert!(!want.is_satisfied());
assert_eq!(
want.provide_with::<i8, String, _>(String::from("hello"), |ctx| {
assert_eq!(ctx, "hello");
42
})
.as_deref(),
None
);
assert!(want.is_satisfied());
assert_eq!(
want.provide_with::<f32, String, _>(String::from("hello"), |_| { unimplemented!() })
.as_deref(),
Some("hello")
);
assert_eq!(mock.0, 42);
}
#[test]
fn want_provide() {
let mut mock = MockWant(0);
let want: &mut dyn Want = &mut mock;
let want = want.provide::<u8, _>(|| unimplemented!());
assert!(!want.is_satisfied());
let want = want.provide::<i8, _>(|| 101);
assert!(want.is_satisfied());
want.provide::<f32, _>(|| unimplemented!());
assert!(want.is_satisfied());
assert_eq!(mock.0, 101);
}
#[test]
fn want_tag() {
let mut mock = MockWant(0);
let want: &mut dyn Want = &mut mock;
let want = want.provide_tag::<u8>(5);
assert!(!want.is_satisfied());
let want = want.provide_tag::<i8>(6);
assert!(want.is_satisfied());
want.provide_tag::<f32>(1.234);
assert!(want.is_satisfied());
assert_eq!(mock.0, 6);
}
#[test]
fn want_value() {
let mut mock = MockWant(0);
let want: &mut dyn Want = &mut mock;
let want = want.provide_value::<u8>(8);
assert!(!want.is_satisfied());
let want = want.provide_value::<i8>(16);
assert!(want.is_satisfied());
want.provide_value::<f32>(0.1234);
assert!(want.is_satisfied());
assert_eq!(mock.0, 16);
}
const _: () = {
#[allow(clippy::extra_unused_lifetimes)]
fn _with_l<'u, L: LifetimeList>() {
fn assert_auto<T: Unpin + Sized>() {}
assert_auto::<ErasedWantFor<'u, L>>();
trait AmbiguousIfImpl<A> {
fn some_item() {}
}
impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
{
struct Invalid;
impl<T: ?Sized + RefUnwindSafe> AmbiguousIfImpl<Invalid> for T {}
}
{
struct Invalid;
impl<T: ?Sized + Send> AmbiguousIfImpl<Invalid> for T {}
}
{
struct Invalid;
impl<T: ?Sized + Sync> AmbiguousIfImpl<Invalid> for T {}
}
{
struct Invalid;
impl<T: ?Sized + UnwindSafe> AmbiguousIfImpl<Invalid> for T {}
}
let _ = <ErasedWantFor<'u, L> as AmbiguousIfImpl<_>>::some_item;
}
};
const _: () = {
#[allow(clippy::extra_unused_lifetimes)]
fn assert_can_call_new_and_downcast<'u, T: ReifySized<L>, U: ReifySized<L>, L: LifetimeList>(
want_for: &'u mut dyn WantFor<T::Reified>,
) -> &'u mut dyn WantFor<U::Reified> {
let erased: ErasedWantFor<'u, L> = ErasedWantFor::new::<T>(want_for);
let Ok(down): Result<&'u mut dyn WantFor<U::Reified>, ErasedWantFor<'u, L>> =
erased.downcast::<U>()
else {
panic!()
};
down
}
};
#[test]
fn erased_want_for_new_then_downcast() {
let mut want = MockWant(0);
let want_for: &mut dyn WantFor<i8> = (&mut want as &mut dyn Want).try_for::<i8>().unwrap();
let erased: ErasedWantFor<L1> = ErasedWantFor::new::<i8>(want_for);
let Err(erased) = erased.downcast::<u8>() else {
panic!()
};
let Err(erased) = erased.downcast::<f32>() else {
panic!()
};
let Ok(downcasted): Result<&mut dyn WantFor<i8>, _> = erased.downcast::<i8>() else {
panic!()
};
downcasted.fulfill(100);
assert_eq!(want.0, 100);
}
const _: () = {
fn auto_send<L: LifetimeList, T: ReifySized<L>>()
where
T::SizedReified: Send,
{
fn assert_auto<T: Send>() {}
assert_auto::<WantOne<L, T>>();
}
fn auto_sync<L: LifetimeList, T: ReifySized<L>>()
where
T::SizedReified: Sync,
{
fn assert_auto<T: Sync>() {}
assert_auto::<WantOne<L, T>>();
}
fn auto_unpin<L: LifetimeList, T: ReifySized<L>>()
where
T::SizedReified: Unpin,
{
fn assert_auto<T: Unpin>() {}
assert_auto::<WantOne<L, T>>();
}
fn auto_ref_unwind<L: LifetimeList, T: ReifySized<L>>()
where
T::SizedReified: RefUnwindSafe,
{
fn assert_auto<T: RefUnwindSafe>() {}
assert_auto::<WantOne<L, T>>();
}
fn auto_unwind<L: LifetimeList, T: ReifySized<L>>()
where
T::SizedReified: UnwindSafe,
{
fn assert_auto<T: UnwindSafe>() {}
assert_auto::<WantOne<L, T>>();
}
fn assert_new<L: LifetimeList, T: ReifySized<L>>(value: Option<T::Reified>) -> WantOne<L, T> {
WantOne::<L, T>::new(value)
}
fn assert_into_inner<L: LifetimeList, T: ReifySized<L>>(
erased: WantOne<L, T>,
) -> Option<T::Reified> {
erased.into_inner()
}
};
#[test]
fn tagged_option_new_then_into_inner() {
let tagged = WantOne::<L0, f32>::new(Some(1.234));
assert_eq!(tagged.into_inner(), Some(1.234));
}
#[test]
fn tagged_option_default() {
let tagged = WantOne::<L0, f32>::default();
assert_eq!(tagged.into_inner(), None);
}
#[test]
fn tagged_option_try_for_id() {
let mut tagged = WantOne::<L0, f32>::default();
let want: &mut dyn Want = &mut tagged;
assert!(want.try_for_id(TagTypeId::of::<f64>()).is_none());
let _want_for = want.try_for_id(TagTypeId::of::<f32>()).unwrap();
}
#[test]
fn tagged_option_is_satisfied() {
let mut tagged = WantOne::<L0, f32>::default();
let want: &mut dyn Want = &mut tagged;
assert!(!want.is_satisfied());
let mut tagged = WantOne::<L0, f32>::new(Some(1.234));
let want: &mut dyn Want<L0> = &mut tagged;
assert!(want.is_satisfied());
}
#[test]
fn tagged_option_fulfill() {
let mut tagged = WantOne::<L0, f32>::default();
let want: &mut dyn Want = &mut tagged;
let want_for = want.try_for_id(TagTypeId::of::<f32>()).unwrap();
let Ok(want_for) = want_for.downcast::<f32>() else {
panic!()
};
want_for.fulfill(0.56);
assert_eq!(tagged.into_inner(), Some(0.56));
}
#[test]
fn tagged_option_want_for_is_satisfied() {
let mut tagged = WantOne::<L0, f32>::default();
let want: &mut dyn Want = &mut tagged;
let want_for = want.try_for_id(TagTypeId::of::<f32>()).unwrap();
let Ok(want_for) = want_for.downcast::<f32>() else {
panic!()
};
assert!(!want_for.is_satisfied());
want_for.fulfill(0.56);
assert!(want_for.is_satisfied());
}
const _: () = {
trait AmbiguousIfImpl<A> {
fn some_item() {}
}
impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
{
struct Invalid;
impl<T: ?Sized + RefUnwindSafe> AmbiguousIfImpl<Invalid> for T {}
}
{
struct Invalid;
impl<T: ?Sized + Send> AmbiguousIfImpl<Invalid> for T {}
}
{
struct Invalid;
impl<T: ?Sized + Sync> AmbiguousIfImpl<Invalid> for T {}
}
{
struct Invalid;
impl<T: ?Sized + Unpin> AmbiguousIfImpl<Invalid> for T {}
}
{
struct Invalid;
impl<T: ?Sized + UnwindSafe> AmbiguousIfImpl<Invalid> for T {}
}
{
struct Invalid;
impl<T: Sized> AmbiguousIfImpl<Invalid> for T {}
}
let _ = <NoAuto as AmbiguousIfImpl<_>>::some_item;
};