//! Tests for the want module API. /* use std::cell::UnsafeCell; use std::marker::{PhantomData, PhantomPinned}; use std::panic::{RefUnwindSafe, UnwindSafe}; use supply::lt_list::{Lt0, Lt1, LtList}; use supply::tag::{ReifySized, TagOf, TagTypeId}; use supply::want::*; #[allow(unused)] struct NoAuto<'a>( PhantomData<(*const u8, PhantomPinned, &'a mut u8, UnsafeCell)>, str, ); // WantFor const _: () = { struct Test<'a>(NoAuto<'a>); // Doesn't require any extra traits. impl<'a, L: LtList, T: ReifySized> WantFor for Test<'a> { fn fulfill(&mut self, _value: T::Reified) { unimplemented!() } fn is_satisfied(&self) -> bool { unimplemented!() } } }; // Want const _: () = { struct Test<'a>(NoAuto<'a>); // Doesn't require any extra traits. impl<'r, 'a, L: LtList> Want<'r, L> for Test<'a> { fn try_for_id( &mut self, _tag_type_id: TagTypeId>, ) -> Option>> { unimplemented!() } fn is_satisfied(&self) -> bool { unimplemented!() } } struct Other; impl<'r> Want<'r> for Other { fn try_for_id( &mut self, _tag_type_id: TagTypeId>, ) -> Option>> { unimplemented!() } fn is_satisfied(&self) -> bool { unimplemented!() } } // The default L is Lt0. fn test() { fn assert<'r, T: Want<'r, Lt0>>() {} assert::(); } }; struct MockWant<'r>(i8, PhantomData<&'r ()>); impl<'r, L: LtList + 'r> Want<'r, L> for MockWant<'r> { fn try_for_id( &mut self, tag_type_id: TagTypeId>, ) -> Option>> { // We return on i8 and we return the wrong one on f32 for testing. if tag_type_id == TagTypeId::of::() || tag_type_id == TagTypeId::of::() { Some(ErasedWantFor::new::>(self)) } else { None } } fn is_satisfied(&self) -> bool { self.0 > 0 } } impl<'r> WantFor> for MockWant<'r> { fn fulfill(&mut self, value: i8) { self.0 += value; } fn is_satisfied(&self) -> bool { self.0 > 0 } } // Callable for all possible types. // fn can_call_dyn_methods() { // fn assert_call_provide_value<'r, T: Tagged, L: LtList>( // want: &mut dyn Want<'r, L>, // value: >>::SizedReified, // ) where // T::Tag: ReifySized, SizedReified = T>, // { // want.provide_value::(value); // } // // fn assert_call_provide_tag<'r, T: Tagged, L: LtList>( // want: &mut dyn Want<'r, L>, // value: >>::SizedReified, // ) where // T::Tag: ReifySized>, // { // want.provide_tag::(value); // } // // fn assert_call_provide<'r, F, T: Tagged, L: LtList>(want: &mut dyn Want<'r, L>, f: F) // where // T::Tag: ReifySized>, // F: FnOnce() -> >>::SizedReified, // { // want.provide::(f); // } // // fn assert_call_provide_with<'r, C, F, T: Tagged, L: LtList>( // want: &mut dyn Want<'r, L>, // ctx: C, // f: F, // ) where // T::Tag: ReifySized>, // F: FnOnce(C) -> >>::SizedReified, // { // want.provide_with::(ctx, f); // } // // fn assert_call_try_for<'r, T, L: LtList>(want: &mut dyn Want<'r, L>) // where // T: ReifySized>, // { // want.try_for::(); // } // } #[test] fn want_try_for() { let mut mock = MockWant(0, PhantomData); // The methods are on the trait object because thats how it will be used // in Provider. let want: &mut dyn Want = &mut mock; // If we request for a type the mock doesn't support we get None. assert!(want.try_for::().is_none()); // We can get a WantFor that is not satisfied. let want_for = want.try_for::().unwrap(); assert!(!want_for.is_satisfied()); // We can fulfill the want and make it satisfied. want_for.fulfill(123); assert!(want_for.is_satisfied()); // The mock allows resetting the state and the satisfied reflects that. want_for.fulfill(-124); assert!(!want_for.is_satisfied()); // If a want returns a bad WantFor it just gets ignored by try_for. assert!(want.try_for::().is_none()); // The want's internal state was set right. assert_eq!(mock.0, -1); } #[test] fn want_provide_with() { let mut mock = MockWant(0, PhantomData); let want: &mut dyn Want = &mut mock; // Providing a type that the want doesn't care about returns the context we gave. // The closure is also not run. assert_eq!( want.provide_with::(String::from("hello"), |_| unimplemented!()) .as_deref(), Some("hello") ); assert!(!want.is_satisfied()); // Providing a wanted value satisfies it. assert_eq!( want.provide_with::(String::from("hello"), |ctx| { assert_eq!(ctx, "hello"); 42 }) .as_deref(), None ); assert!(want.is_satisfied()); // Providing a value where the want is wrong does nothing. assert_eq!( want.provide_with::(String::from("hello"), |_| { unimplemented!() }) .as_deref(), Some("hello") ); assert_eq!(mock.0, 42); } #[test] fn want_provide() { let mut mock = MockWant(0, PhantomData); let want: &mut dyn Want = &mut mock; // Providing a type that the want doesn't care about returns the context we gave. // The closure is also not run. let want = want.provide::(|| unimplemented!()); assert!(!want.is_satisfied()); // Providing a wanted value satisfies it. let want = want.provide::(|| 101); assert!(want.is_satisfied()); // Providing a value where the want is wrong does nothing. want.provide::(|| unimplemented!()); assert!(want.is_satisfied()); assert_eq!(mock.0, 101); } #[test] fn want_tag() { let mut mock = MockWant(0, PhantomData); let want: &mut dyn Want = &mut mock; // Providing a type that the want doesn't care about returns the context we gave. let want = want.provide_tag::(5); assert!(!want.is_satisfied()); // Providing a wanted value satisfies it. let want = want.provide_tag::(6); assert!(want.is_satisfied()); // Providing a value where the want is wrong does nothing. want.provide_tag::(1.234); assert!(want.is_satisfied()); assert_eq!(mock.0, 6); } #[test] fn want_value() { let mut mock = MockWant(0, PhantomData); let want: &mut dyn Want = &mut mock; // Providing a type that the want doesn't care about returns the context we gave. let want = want.provide_value::(8); assert!(!want.is_satisfied()); // Providing a wanted value satisfies it. let want = want.provide_value::(16); assert!(want.is_satisfied()); // Providing a value where the want is wrong does nothing. want.provide_value::(0.1234); assert!(want.is_satisfied()); assert_eq!(mock.0, 16); } // ErasedWantFor const _: () = { #[allow(clippy::extra_unused_lifetimes)] fn _with_l<'u, L: LtList>() { // ErasedWantFor only implements Unpin (because a &mut T is always Unpin) // and is Sized. fn assert_auto() {} assert_auto::>(); // All the other auto traits can't be implemented because we don't // know what the T in the &mut T is. trait AmbiguousIfImpl { fn some_item() {} } impl AmbiguousIfImpl<()> for T {} { struct Invalid; impl AmbiguousIfImpl for T {} } { struct Invalid; impl AmbiguousIfImpl for T {} } { struct Invalid; impl AmbiguousIfImpl for T {} } { struct Invalid; impl AmbiguousIfImpl for T {} } let _ = as AmbiguousIfImpl<_>>::some_item; } // Lt's LtList properties are tested above. }; // const _: () = { // // Can call new and the downcast with any type. // #[allow(clippy::extra_unused_lifetimes)] // fn assert_can_call_new_and_downcast<'u, L: LtList, T: ReifySized, U: ReifySized>( // want_for: &'u mut dyn WantFor, // ) -> &'u mut dyn WantFor { // let erased: ErasedWantFor<'u, L> = ErasedWantFor::new::(want_for); // // let Ok(down): Result<&'u mut dyn WantFor, ErasedWantFor<'u, L>> = erased.downcast() // else { // panic!() // }; // // down // } // }; // // #[test] // fn erased_want_for_new_then_downcast() { // let mut want = MockWant(0, PhantomData); // // let want_for: &mut dyn WantFor = (&mut want as &mut dyn Want).try_for::().unwrap(); // // // Erase the i8 from the type. // let erased: ErasedWantFor = ErasedWantFor::new(want_for); // // // Downcasting to the wrong type is not allowed. // let Err(erased) = erased.downcast::() else { // panic!() // }; // let Err(erased) = erased.downcast::() else { // panic!() // }; // // // We can downcast to the real type and then use the WantFor. // let Ok(downcasted): Result<&mut dyn WantFor, _> = erased.downcast::() else { // panic!() // }; // // downcasted.fulfill(100); // // assert_eq!(want.0, 100); // } // TaggedOption const _: () = { fn auto_send<'r, L: LtList, T: ReifySized>>() where T::SizedReified: Send, { fn assert_auto() {} assert_auto::>(); } fn auto_sync<'r, L: LtList, T: ReifySized>>() where T::SizedReified: Sync, { fn assert_auto() {} assert_auto::>(); } fn auto_unpin<'r, L: LtList, T: ReifySized>>() where T::SizedReified: Unpin, { fn assert_auto() {} assert_auto::>(); } fn auto_ref_unwind<'r, L: LtList, T: ReifySized>>() where T::SizedReified: RefUnwindSafe, { fn assert_auto() {} assert_auto::>(); } fn auto_unwind<'r, L: LtList, T: ReifySized>>() where T::SizedReified: UnwindSafe, { fn assert_auto() {} assert_auto::>(); } // Always implements Default, Want, and WantFor // fn with_t<'r, L: LtList, T: ReifySized>>() { // fn assert_traits< // 'r, // T: Default + Want<'r, L> + WantFor, // U: ReifySized>, // L: LtList, // >() { // } // assert_traits::<'r, TaggedOption<'r, L, T>, T, L>(); // } // Has new function. fn assert_new<'r, L: LtList, T: ReifySized>>( value: Option, ) -> WantOne<'r, L, T> { WantOne::<'r, L, T>::new(value) } // Has into_inner function. fn assert_into_inner<'r, L: LtList, T: ReifySized>>( erased: WantOne<'r, L, T>, ) -> Option { erased.into_inner() } }; #[test] fn tagged_option_new_then_into_inner() { let tagged = WantOne::::new(Some(1.234)); // The state given to new is kept. assert_eq!(tagged.into_inner(), Some(1.234)); } #[test] fn tagged_option_default() { let tagged = WantOne::::default(); // Default state is without a value. assert_eq!(tagged.into_inner(), None); } #[test] fn tagged_option_try_for_id() { let mut tagged = WantOne::::default(); let want: &mut dyn Want = &mut tagged; // Doesn't give other WantFor. assert!(want.try_for_id(TagTypeId::of::()).is_none()); // Tested later. let _want_for = want.try_for_id(TagTypeId::of::()).unwrap(); } #[test] fn tagged_option_is_satisfied() { let mut tagged = WantOne::::default(); let want: &mut dyn Want = &mut tagged; assert!(!want.is_satisfied()); let mut tagged = WantOne::::new(Some(1.234)); let want: &mut dyn Want = &mut tagged; assert!(want.is_satisfied()); } #[test] fn tagged_option_fulfill() { let mut tagged = WantOne::::default(); let want: &mut dyn Want = &mut tagged; let want_for = want.try_for_id(TagTypeId::of::()).unwrap(); let Ok(want_for) = want_for.downcast::() 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::::default(); let want: &mut dyn Want = &mut tagged; let want_for = want.try_for_id(TagTypeId::of::()).unwrap(); let Ok(want_for) = want_for.downcast::() else { panic!() }; assert!(!want_for.is_satisfied()); want_for.fulfill(0.56); // The satisfaction can be checked on the want_for directly. assert!(want_for.is_satisfied()); } // Check that NoAuto doesn't implement any of the auto traits. const _: () = { trait AmbiguousIfImpl { fn some_item() {} } impl AmbiguousIfImpl<()> for T {} { struct Invalid; impl AmbiguousIfImpl for T {} } { struct Invalid; impl AmbiguousIfImpl for T {} } { struct Invalid; impl AmbiguousIfImpl for T {} } { struct Invalid; impl AmbiguousIfImpl for T {} } { struct Invalid; impl AmbiguousIfImpl for T {} } { struct Invalid; impl AmbiguousIfImpl for T {} } let _ = >::some_item; }; */