#![doc = include_str!("../README.md")]
#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
#![no_std]
#![cfg_attr(not(test), warn(
missing_debug_implementations,
missing_docs,
//trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
//unused_results
))]
#![cfg_attr(test, deny(
missing_debug_implementations,
missing_docs,
//trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_must_use,
//unused_results
))]
#![cfg_attr(
test,
deny(
bad_style,
dead_code,
improper_ctypes,
non_shorthand_field_patterns,
overflowing_literals,
path_statements,
patterns_in_fns_without_body,
unconditional_recursion,
unused,
unused_allocation,
unused_comparisons,
unused_parens,
while_true
)
)]
#[cfg(feature = "std")]
#[macro_use]
extern crate std;
#[cfg(feature = "alloc")]
#[doc(hidden)]
pub extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::{borrow::Cow, vec::Vec};
use core::{any::TypeId, mem::transmute};
#[cfg(feature = "alloc")]
use core::{
any::type_name,
fmt::{Debug, Formatter},
marker::PhantomData,
ops::{Deref, DerefMut, Index, IndexMut},
};
#[cfg(feature = "alloc")]
use libafl_core::Named;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub use tuple_list::{TupleList, tuple_list, tuple_list_type};
#[cfg(feature = "alloc")]
use crate::seal::StackedExtract;
#[must_use]
pub fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
typeid::of::<T>() == typeid::of::<U>()
}
pub trait SplitBorrow<'a> {
type SplitBorrowResult;
type SplitBorrowMutResult;
fn borrow(&'a self) -> Self::SplitBorrowResult;
fn borrow_mut(&'a mut self) -> Self::SplitBorrowMutResult;
}
impl<'a> SplitBorrow<'a> for () {
type SplitBorrowResult = ();
type SplitBorrowMutResult = ();
fn borrow(&'a self) -> Self::SplitBorrowResult {}
fn borrow_mut(&'a mut self) -> Self::SplitBorrowMutResult {}
}
impl<'a, Head, Tail> SplitBorrow<'a> for (Head, Tail)
where
Head: 'a,
Tail: SplitBorrow<'a>,
{
type SplitBorrowResult = (Option<&'a Head>, Tail::SplitBorrowResult);
type SplitBorrowMutResult = (Option<&'a mut Head>, Tail::SplitBorrowMutResult);
fn borrow(&'a self) -> Self::SplitBorrowResult {
(Some(&self.0), self.1.borrow())
}
fn borrow_mut(&'a mut self) -> Self::SplitBorrowMutResult {
(Some(&mut self.0), self.1.borrow_mut())
}
}
#[cfg(feature = "alloc")]
pub trait IntoVec<T> {
fn into_vec_reversed(self) -> Vec<T>
where
Self: Sized,
{
let mut ret = self.into_vec();
ret.reverse();
ret
}
fn into_vec(self) -> Vec<T>;
}
#[cfg(feature = "alloc")]
impl<T> IntoVec<T> for () {
#[inline]
fn into_vec(self) -> Vec<T> {
Vec::new()
}
}
pub trait HasConstLen {
const LEN: usize;
}
impl HasConstLen for () {
const LEN: usize = 0;
}
impl<Head, Tail> HasConstLen for (Head, Tail)
where
Tail: HasConstLen,
{
const LEN: usize = 1 + Tail::LEN;
}
pub trait MatchFirstType {
fn match_first_type<T: 'static>(&self) -> Option<&T>;
fn match_first_type_mut<T: 'static>(&mut self) -> Option<&mut T>;
}
impl MatchFirstType for () {
fn match_first_type<T: 'static>(&self) -> Option<&T> {
None
}
fn match_first_type_mut<T: 'static>(&mut self) -> Option<&mut T> {
None
}
}
impl<Head, Tail> MatchFirstType for (Head, Tail)
where
Head: 'static,
Tail: MatchFirstType,
{
fn match_first_type<T: 'static>(&self) -> Option<&T> {
if TypeId::of::<T>() == TypeId::of::<Head>() {
unsafe { (&raw const self.0 as *const T).as_ref() }
} else {
self.1.match_first_type::<T>()
}
}
fn match_first_type_mut<T: 'static>(&mut self) -> Option<&mut T> {
if TypeId::of::<T>() == TypeId::of::<Head>() {
unsafe { (&raw mut self.0 as *mut T).as_mut() }
} else {
self.1.match_first_type_mut::<T>()
}
}
}
pub trait ExtractFirstRefType {
fn take<'a, T: 'static>(self) -> (Option<&'a T>, Self);
}
impl ExtractFirstRefType for () {
fn take<'a, T: 'static>(self) -> (Option<&'a T>, Self) {
tuple_list!(None)
}
}
impl<Head, Tail> ExtractFirstRefType for (Option<&Head>, Tail)
where
Head: 'static,
Tail: ExtractFirstRefType,
{
fn take<'a, T: 'static>(mut self) -> (Option<&'a T>, Self) {
if TypeId::of::<T>() == TypeId::of::<Head>() {
let r = self.0.take();
(unsafe { transmute::<Option<&Head>, Option<&T>>(r) }, self)
} else {
let (r, tail) = self.1.take::<T>();
(r, (self.0, tail))
}
}
}
impl<Head, Tail> ExtractFirstRefType for (Option<&mut Head>, Tail)
where
Head: 'static,
Tail: ExtractFirstRefType,
{
fn take<'a, T: 'static>(mut self) -> (Option<&'a T>, Self) {
if TypeId::of::<T>() == TypeId::of::<Head>() {
let r = self.0.take();
(
unsafe { transmute::<Option<&mut Head>, Option<&T>>(r) },
self,
)
} else {
let (r, tail) = self.1.take::<T>();
(r, (self.0, tail))
}
}
}
pub trait ExtractFirstRefMutType {
fn take<'a, T: 'static>(self) -> (Option<&'a mut T>, Self);
}
impl ExtractFirstRefMutType for () {
fn take<'a, T: 'static>(self) -> (Option<&'a mut T>, Self) {
tuple_list!(None)
}
}
impl<Head, Tail> ExtractFirstRefMutType for (Option<&mut Head>, Tail)
where
Head: 'static,
Tail: ExtractFirstRefMutType,
{
fn take<'a, T: 'static>(mut self) -> (Option<&'a mut T>, Self) {
if TypeId::of::<T>() == TypeId::of::<Head>() {
let r = self.0.take();
(
unsafe { transmute::<Option<&mut Head>, Option<&mut T>>(r) },
self,
)
} else {
let (r, tail) = self.1.take::<T>();
(r, (self.0, tail))
}
}
}
pub trait SplitBorrowExtractFirstType<'a> {
type SplitBorrowResult: ExtractFirstRefType;
type SplitBorrowMutResult: ExtractFirstRefType + ExtractFirstRefMutType;
fn borrow(&'a self) -> Self::SplitBorrowResult;
fn borrow_mut(&'a mut self) -> Self::SplitBorrowMutResult;
}
impl<'a> SplitBorrowExtractFirstType<'a> for () {
type SplitBorrowResult = ();
type SplitBorrowMutResult = ();
fn borrow(&'a self) -> Self::SplitBorrowResult {}
fn borrow_mut(&'a mut self) -> Self::SplitBorrowMutResult {}
}
impl<'a, Head, Tail> SplitBorrowExtractFirstType<'a> for (Head, Tail)
where
Head: 'static,
Tail: SplitBorrowExtractFirstType<'a>,
{
type SplitBorrowResult = (Option<&'a Head>, Tail::SplitBorrowResult);
type SplitBorrowMutResult = (Option<&'a mut Head>, Tail::SplitBorrowMutResult);
fn borrow(&'a self) -> Self::SplitBorrowResult {
(Some(&self.0), self.1.borrow())
}
fn borrow_mut(&'a mut self) -> Self::SplitBorrowMutResult {
(Some(&mut self.0), self.1.borrow_mut())
}
}
pub trait MatchType {
fn match_type<T: 'static, FN: FnMut(&T)>(&self, f: &mut FN);
fn match_type_mut<T: 'static, FN: FnMut(&mut T)>(&mut self, f: &mut FN);
}
impl MatchType for () {
fn match_type<T: 'static, FN: FnMut(&T)>(&self, _: &mut FN) {}
fn match_type_mut<T: 'static, FN: FnMut(&mut T)>(&mut self, _: &mut FN) {}
}
impl<Head, Tail> MatchType for (Head, Tail)
where
Head: 'static,
Tail: MatchType,
{
fn match_type<T: 'static, FN: FnMut(&T)>(&self, f: &mut FN) {
if TypeId::of::<T>() == TypeId::of::<Head>() {
f(unsafe { (&raw const self.0 as *const T).as_ref() }.unwrap());
}
self.1.match_type::<T, FN>(f);
}
fn match_type_mut<T: 'static, FN: FnMut(&mut T)>(&mut self, f: &mut FN) {
if TypeId::of::<T>() == TypeId::of::<Head>() {
f(unsafe { (&raw mut self.0 as *mut T).as_mut() }.unwrap());
}
self.1.match_type_mut::<T, FN>(f);
}
}
#[cfg(feature = "alloc")]
pub trait NamedTuple {
fn name(&self, index: usize) -> Option<&Cow<'static, str>>;
fn names(&self) -> Vec<Cow<'static, str>>;
}
#[cfg(feature = "alloc")]
impl NamedTuple for () {
fn name(&self, _index: usize) -> Option<&Cow<'static, str>> {
None
}
fn names(&self) -> Vec<Cow<'static, str>> {
Vec::new()
}
}
#[cfg(feature = "alloc")]
impl<Head, Tail> NamedTuple for (Head, Tail)
where
Head: Named,
Tail: NamedTuple,
{
fn name(&self, index: usize) -> Option<&Cow<'static, str>> {
if index == 0 {
Some(self.0.name())
} else {
self.1.name(index - 1)
}
}
fn names(&self) -> Vec<Cow<'static, str>> {
let first = self.0.name().clone();
let mut last = self.1.names();
last.insert(0, first);
last
}
}
#[cfg(feature = "alloc")]
pub trait MatchName {
#[deprecated = "Use `.handle` and either `.get` (fallible access) or `[]` (infallible access) instead"]
fn match_name<T>(&self, name: &str) -> Option<&T>;
#[deprecated = "Use `.handle` and either `.get` (fallible access) or `[]` (infallible access) instead"]
fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T>;
}
#[cfg(feature = "alloc")]
impl MatchName for () {
fn match_name<T>(&self, _name: &str) -> Option<&T> {
None
}
fn match_name_mut<T>(&mut self, _name: &str) -> Option<&mut T> {
None
}
}
#[cfg(feature = "alloc")]
#[expect(deprecated)]
impl<Head, Tail> MatchName for (Head, Tail)
where
Head: Named,
Tail: MatchName,
{
fn match_name<T>(&self, name: &str) -> Option<&T> {
if type_eq::<Head, T>() && name == self.0.name() {
unsafe { (&raw const self.0 as *const T).as_ref() }
} else {
self.1.match_name::<T>(name)
}
}
fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T> {
if type_eq::<Head, T>() && name == self.0.name() {
unsafe { (&raw mut self.0 as *mut T).as_mut() }
} else {
self.1.match_name_mut::<T>(name)
}
}
}
#[cfg(feature = "alloc")]
pub trait Handled: Named {
fn handle(&self) -> Handle<Self> {
Handle {
name: Named::name(self).clone(),
phantom: PhantomData,
}
}
}
#[cfg(feature = "alloc")]
impl<N> Handled for N where N: Named {}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg(feature = "alloc")]
pub struct Handle<T: ?Sized> {
name: Cow<'static, str>,
#[cfg_attr(feature = "serde", serde(skip))]
phantom: PhantomData<T>,
}
#[cfg(feature = "alloc")]
impl<T: ?Sized> Handle<T> {
#[must_use]
pub fn new(name: Cow<'static, str>) -> Self {
Self {
name,
phantom: PhantomData,
}
}
#[must_use]
pub fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
#[cfg(feature = "alloc")]
impl<T> Clone for Handle<T> {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
phantom: PhantomData,
}
}
}
#[cfg(feature = "alloc")]
impl<T> Debug for Handle<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Handle")
.field("name", self.name())
.field("type", &type_name::<T>())
.finish()
}
}
#[cfg(feature = "alloc")]
pub trait MatchNameRef {
fn get<T>(&self, rf: &Handle<T>) -> Option<&T>;
fn get_mut<T>(&mut self, rf: &Handle<T>) -> Option<&mut T>;
}
#[cfg(feature = "alloc")]
pub trait GetAll<HandleTuple> {
type GetAllResult<'a>
where
Self: 'a;
type GetAllMutResult<'a>
where
Self: 'a;
fn get_all(&self, handles: HandleTuple) -> Self::GetAllResult<'_>;
fn get_all_mut(&mut self, handles: HandleTuple) -> Self::GetAllMutResult<'_>;
}
#[cfg(feature = "alloc")]
#[expect(deprecated)]
impl<M> MatchNameRef for M
where
M: MatchName,
{
fn get<T>(&self, rf: &Handle<T>) -> Option<&T> {
self.match_name::<T>(&rf.name)
}
fn get_mut<T>(&mut self, rf: &Handle<T>) -> Option<&mut T> {
self.match_name_mut::<T>(&rf.name)
}
}
#[cfg(feature = "alloc")]
impl<Head, Tail> GetAll<()> for (Head, Tail)
where
(Head, Tail): MatchNameRef,
{
type GetAllResult<'a>
= ()
where
Self: 'a;
type GetAllMutResult<'a>
= ()
where
Self: 'a;
fn get_all(&self, _handles: ()) -> Self::GetAllResult<'_> {}
fn get_all_mut(&mut self, _handles: ()) -> Self::GetAllMutResult<'_> {}
}
pub trait InnerBorrowMut {
type Borrowed<'a>
where
Self: 'a;
fn inner_borrow_mut(&mut self) -> Self::Borrowed<'_>;
}
#[cfg(feature = "alloc")]
mod seal {
use libafl_core::Named;
use tuple_list::tuple_list;
use crate::{Handle, InnerBorrowMut, Merge, type_eq};
impl<Head, Tail> InnerBorrowMut for (Head, Tail)
where
Tail: InnerBorrowMut,
{
type Borrowed<'a>
= (&'a mut Head, Tail::Borrowed<'a>)
where
Self: 'a;
fn inner_borrow_mut(&mut self) -> Self::Borrowed<'_> {
(&mut self.0, self.1.inner_borrow_mut())
}
}
impl InnerBorrowMut for () {
type Borrowed<'a>
= ()
where
Self: 'a;
fn inner_borrow_mut(&mut self) -> Self::Borrowed<'_> {}
}
pub trait StackedExtract<'a, Handles, Visited> {
type Result;
fn extract(self, handles: Handles, visited: Visited) -> Self::Result;
}
impl<'a, T, HTail, Visited> StackedExtract<'a, (&Handle<T>, HTail), Visited> for ()
where
Visited: StackedExtract<'a, HTail, ()>,
T: 'a,
{
type Result = (Option<&'a mut T>, Visited::Result);
fn extract(self, handles: (&Handle<T>, HTail), visited: Visited) -> Self::Result {
(None, visited.extract(handles.1, ()))
}
}
impl<U, Visited> StackedExtract<'_, (), Visited> for U {
type Result = ();
fn extract(self, _handles: (), _visited: Visited) -> Self::Result {}
}
impl<'a, T, HTail, Head, Tail, Visited> StackedExtract<'a, (&Handle<T>, HTail), Visited>
for (&'a mut Head, Tail)
where
Head: Named,
Tail: for<'b> StackedExtract<
'a,
(&'b Handle<T>, HTail),
<Visited as Merge<(&'a mut Head, ())>>::MergeResult,
Result = (
Option<&'a mut T>,
<<Visited as Merge<Tail>>::MergeResult as StackedExtract<'a, HTail, ()>>::Result,
),
>,
Visited: Merge<(&'a mut Head, ())>,
Visited: Merge<Tail>,
<Visited as Merge<Tail>>::MergeResult: StackedExtract<'a, HTail, ()>,
T: 'a,
{
type Result = (
Option<&'a mut T>,
<<Visited as Merge<Tail>>::MergeResult as StackedExtract<'a, HTail, ()>>::Result,
);
fn extract(self, handles: (&Handle<T>, HTail), visited: Visited) -> Self::Result {
if type_eq::<Head, T>() && &handles.0.name == self.0.name() {
(
unsafe { (core::ptr::from_mut(self.0) as *mut T).as_mut() },
visited.merge(self.1).extract(handles.1, ()),
)
} else {
self.1.extract(handles, visited.merge(tuple_list!(self.0)))
}
}
}
}
#[cfg(feature = "alloc")]
impl<'b, Head, Tail, T, HandleTail> GetAll<(&'b Handle<T>, HandleTail)> for (Head, Tail)
where
(Head, Tail): MatchNameRef + GetAll<HandleTail> + InnerBorrowMut,
for<'a> <(Head, Tail) as InnerBorrowMut>::Borrowed<'a>:
StackedExtract<'a, (&'b Handle<T>, HandleTail), ()>,
T: 'static,
{
type GetAllResult<'a>
= (
Option<&'a T>,
<(Head, Tail) as GetAll<HandleTail>>::GetAllResult<'a>,
)
where
Self: 'a;
type GetAllMutResult<'a>
= <<(Head, Tail) as InnerBorrowMut>::Borrowed<'a> as StackedExtract<
'a,
(&'b Handle<T>, HandleTail),
(),
>>::Result
where
Self: 'a;
fn get_all(&self, handles: (&Handle<T>, HandleTail)) -> Self::GetAllResult<'_> {
let (head_handle, tail_handles) = handles;
let head_result = self.get(head_handle);
let tail_result = <(Head, Tail) as GetAll<HandleTail>>::get_all(self, tail_handles);
(head_result, tail_result)
}
fn get_all_mut(&mut self, handles: (&'b Handle<T>, HandleTail)) -> Self::GetAllMutResult<'_> {
self.inner_borrow_mut().extract(handles, ())
}
}
#[cfg(feature = "alloc")]
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct RefIndexable<RM, M>(RM, PhantomData<M>);
#[cfg(feature = "alloc")]
impl<RM, M> From<RM> for RefIndexable<RM, M>
where
RM: Deref<Target = M>,
{
fn from(value: RM) -> Self {
RefIndexable(value, PhantomData)
}
}
#[cfg(feature = "alloc")]
impl<RM, M> Deref for RefIndexable<RM, M>
where
RM: Deref<Target = M>,
{
type Target = RM::Target;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "alloc")]
impl<RM, M> DerefMut for RefIndexable<RM, M>
where
RM: DerefMut<Target = M>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(feature = "alloc")]
impl<T, RM, M> Index<&Handle<T>> for RefIndexable<RM, M>
where
RM: Deref<Target = M>,
M: MatchName,
{
type Output = T;
fn index(&self, index: &Handle<T>) -> &Self::Output {
let Some(e) = self.get(index) else {
panic!("Could not find entry matching {index:?}")
};
e
}
}
#[cfg(feature = "alloc")]
impl<T, RM, M> IndexMut<&Handle<T>> for RefIndexable<RM, M>
where
RM: DerefMut<Target = M>,
M: MatchName,
{
fn index_mut(&mut self, index: &Handle<T>) -> &mut Self::Output {
let Some(e) = self.get_mut(index) else {
panic!("Could not find entry matching {index:?}")
};
e
}
}
pub trait Prepend<T> {
#[must_use]
fn prepend(self, value: T) -> (T, Self);
}
impl<Tail, T> Prepend<T> for Tail {
fn prepend(self, value: T) -> (T, Self) {
(value, self)
}
}
pub trait Append<T>
where
Self: Sized,
{
#[must_use]
fn append(self, value: T) -> (Self, T);
}
impl<Head, T> Append<T> for Head {
fn append(self, value: T) -> (Self, T) {
(self, value)
}
}
pub trait Merge<T> {
type MergeResult;
#[must_use]
fn merge(self, value: T) -> Self::MergeResult;
}
impl<T> Merge<T> for () {
type MergeResult = T;
fn merge(self, value: T) -> Self::MergeResult {
value
}
}
impl<Head, Tail, T> Merge<T> for (Head, Tail)
where
Tail: Merge<T>,
{
type MergeResult = (Head, Tail::MergeResult);
fn merge(self, value: T) -> Self::MergeResult {
let (head, tail) = self;
(head, tail.merge(value))
}
}
pub trait MappingFunctor<T> {
type Output;
fn apply(&mut self, from: T) -> Self::Output;
}
pub trait Map<M> {
type MapResult;
fn map(self, mapper: M) -> Self::MapResult;
}
impl<Head, Tail, M> Map<M> for (Head, Tail)
where
M: MappingFunctor<Head>,
Tail: Map<M>,
{
type MapResult = (M::Output, Tail::MapResult);
fn map(self, mut mapper: M) -> Self::MapResult {
let head = mapper.apply(self.0);
(head, self.1.map(mapper))
}
}
impl<M> Map<M> for () {
type MapResult = ();
fn map(self, _mapper: M) -> Self::MapResult {}
}
#[macro_export]
macro_rules! tuple_for_each {
($fn_name:ident, $trait_name:path, $tuple_name:ident, $body:expr) => {
mod $fn_name {
pub trait ForEach {
fn for_each(&self);
}
impl ForEach for () {
fn for_each(&self) {}
}
impl<Head, Tail> ForEach for (Head, Tail)
where
Head: $trait_name,
Tail: tuple_list::TupleList + ForEach,
{
#[allow(clippy::redundant_closure_call)] fn for_each(&self) {
($body)(&self.0);
self.1.for_each();
}
}
}
{
use $fn_name::*;
$tuple_name.for_each();
};
};
}
#[macro_export]
macro_rules! tuple_for_each_mut {
($fn_name:ident, $trait_name:path, $tuple_name:ident, $body:expr) => {
mod $fn_name {
pub trait ForEachMut {
fn for_each_mut(&mut self);
}
impl ForEachMut for () {
fn for_each_mut(&mut self) {}
}
impl<Head, Tail> ForEachMut for (Head, Tail)
where
Head: $trait_name,
Tail: tuple_list::TupleList + ForEachMut,
{
#[allow(clippy::redundant_closure_call)] fn for_each_mut(&mut self) {
($body)(&mut self.0);
self.1.for_each_mut();
}
}
}
{
use $fn_name::*;
$tuple_name.for_each_mut();
};
};
}
#[macro_export]
macro_rules! map_tuple_list_type {
($Tuple:ty, $Mapper:ty) => {
<$Tuple as $crate::Map<$Mapper>>::MapResult
};
}
#[macro_export]
macro_rules! merge_tuple_list_type {
($Type1:ty) => {
$Type1
};
($Type1:ty, $Type2:ty) => {
<$Type1 as $crate::Merge<$Type2>>::MergeResult
};
($Type1:ty, $Type2:ty, $( $rest:ty ),+) => {
merge_tuple_list_type!(
<$Type1 as $crate::Merge<$Type2>>::MergeResult,
$( $rest ),+
)
};
}
#[cfg(test)]
mod test {
use core::marker::PhantomData;
#[cfg(feature = "alloc")]
use ownedref::OwnedMutSlice;
use tuple_list::{tuple_list, tuple_list_type};
use crate::{Map, MappingFunctor, Merge, type_eq};
#[test]
fn test_type_eq_simple() {
assert!(type_eq::<u64, u64>());
assert!(!type_eq::<u64, usize>());
}
#[test]
fn test_type_eq() {
type OwnedMutSliceAlias<'a> = OwnedMutSlice<'a, u8>;
#[expect(clippy::extra_unused_lifetimes)]
fn test_lifetimes<'a, 'b>() {
assert!(type_eq::<OwnedMutSlice<'a, u8>, OwnedMutSlice<'b, u8>>());
assert!(type_eq::<OwnedMutSlice<'static, u8>, OwnedMutSlice<'a, u8>>());
assert!(type_eq::<OwnedMutSlice<'a, u8>, OwnedMutSlice<'b, u8>>());
assert!(type_eq::<OwnedMutSlice<'a, u8>, OwnedMutSlice<'static, u8>>());
assert!(!type_eq::<OwnedMutSlice<'a, u8>, OwnedMutSlice<'b, i8>>());
}
assert!(type_eq::<OwnedMutSlice<u8>, OwnedMutSliceAlias>());
test_lifetimes();
assert!(type_eq::<OwnedMutSlice<u8>, OwnedMutSlice<u8>>());
assert!(!type_eq::<OwnedMutSlice<u8>, OwnedMutSlice<u32>>());
}
#[test]
fn test_mapper() {
struct W<T>(T);
struct ExampleMapper<P>(PhantomData<P>);
impl<T, P> MappingFunctor<T> for ExampleMapper<P> {
type Output = W<T>;
fn apply(&mut self, from: T) -> Self::Output {
W(from)
}
}
struct A;
struct B;
struct C;
type OrigType = tuple_list_type!(A, B, C);
type MappedType = map_tuple_list_type!(OrigType, ExampleMapper<usize>);
let orig: OrigType = tuple_list!(A, B, C);
let _mapped: MappedType = orig.map(ExampleMapper(PhantomData::<usize>));
}
#[test]
fn test_merge() {
struct A;
struct B;
struct C;
struct D;
struct E;
type Lhs = tuple_list_type!(A, B, C);
type Rhs = tuple_list_type!(D, E);
type Merged = merge_tuple_list_type!(Lhs, Rhs);
type IndividuallyMergedPre = merge_tuple_list_type!(
tuple_list_type!(A),
tuple_list_type!(B),
tuple_list_type!(C),
Rhs
);
type IndividuallyMergedPost =
merge_tuple_list_type!(Lhs, tuple_list_type!(D), tuple_list_type!(E));
type MergedCloned = merge_tuple_list_type!(Merged);
let lhs: Lhs = tuple_list!(A, B, C);
let rhs: Rhs = tuple_list!(D, E);
let merged: Merged = lhs.merge(rhs);
let merged: IndividuallyMergedPre = merged;
let merged: IndividuallyMergedPost = merged;
#[allow(clippy::no_effect_underscore_binding)]
let _merged: MergedCloned = merged;
}
#[test]
#[cfg(feature = "std")]
fn test_macros() {
let mut t = tuple_list!(1, "a");
tuple_for_each!(f1, core::fmt::Display, t, |x| {
println!("{x}");
});
tuple_for_each_mut!(f2, core::fmt::Display, t, |x| {
println!("{x}");
});
}
#[cfg(feature = "alloc")]
mod get_all {
use alloc::{
borrow::Cow,
string::{String, ToString as _},
};
use tuple_list::{tuple_list, tuple_list_type};
use crate::{GetAll as _, Handle, Handled as _, MatchNameRef, Named};
#[derive(Debug, PartialEq)]
struct MyHandled(String, Cow<'static, str>);
impl Named for MyHandled {
fn name(&self) -> &Cow<'static, str> {
&self.1
}
}
impl MyHandled {
fn new(name: &str) -> Self {
Self(name.to_string(), Cow::Owned(name.to_string()))
}
}
#[expect(clippy::type_complexity)]
fn get_tuple() -> (
tuple_list_type!(MyHandled, MyHandled, MyHandled),
(Handle<MyHandled>, Handle<MyHandled>, Handle<MyHandled>),
) {
let a = MyHandled::new("a");
let a_handle = a.handle();
let b = MyHandled::new("b");
let b_handle = b.handle();
let c = MyHandled::new("c");
let c_handle = c.handle();
(tuple_list!(a, b, c), (a_handle, b_handle, c_handle))
}
#[test]
fn test_get_all_empty() {
let (tuple, _handles) = get_tuple();
#[expect(clippy::let_unit_value)]
let recovered = tuple.get_all(tuple_list!());
#[allow(clippy::unit_cmp)]
{
assert_eq!(recovered, ());
}
}
#[test]
fn test_get_all_one() {
let (tuple, handles) = get_tuple();
let tuple_list!(a_rec) = tuple.get_all(tuple_list!(&handles.0));
assert_eq!(a_rec, Some(&tuple.0));
}
#[test]
fn test_get_all_two() {
let (tuple, handles) = get_tuple();
let tuple_list!(a_rec, b_rec) = tuple.get_all(tuple_list!(&handles.0, &handles.1));
assert_eq!(a_rec, Some(&tuple.0));
assert_eq!(b_rec, Some(&tuple.1.0));
}
#[test]
fn test_get_all_all() {
let (tuple, handles) = get_tuple();
let tuple_list!(a_rec, b_rec, c_rec) =
tuple.get_all(tuple_list!(&handles.0, &handles.1, &handles.2));
assert_eq!(a_rec, Some(&tuple.0));
assert_eq!(b_rec, Some(&tuple.1.0));
assert_eq!(c_rec, Some(&tuple.1.1.0));
}
#[test]
fn test_get_all_reverse() {
let (tuple, handles) = get_tuple();
let tuple_list!(c_rec, b_rec, a_rec) =
tuple.get_all(tuple_list!(&handles.2, &handles.1, &handles.0));
assert_eq!(c_rec, Some(&tuple.1.1.0));
assert_eq!(b_rec, Some(&tuple.1.0));
assert_eq!(a_rec, Some(&tuple.0));
}
#[test]
fn test_get_all_mut_empty() {
let mut tuple = get_tuple().0;
#[expect(clippy::let_unit_value)]
let recovered = tuple.get_all_mut(tuple_list!());
#[allow(clippy::unit_cmp)]
{
assert_eq!(recovered, tuple_list!());
}
}
#[test]
fn test_get_all_mut_one() {
let (mut tuple, handles) = get_tuple();
let recovered = tuple.get_all_mut(tuple_list!(&handles.0));
let tuple_list!(a_rec) = recovered;
a_rec.unwrap().0.push_str("_modified_a");
assert_eq!(tuple.get(&handles.0).unwrap().0, "a_modified_a");
}
#[test]
fn test_get_all_mut_two() {
let (mut tuple, handles) = get_tuple();
let tuple_list!(a_rec, b_rec) = tuple.get_all_mut(tuple_list!(&handles.0, &handles.1));
a_rec.unwrap().0.push_str("_modified_a");
b_rec.unwrap().0.push_str("_modified_b");
assert_eq!(tuple.get(&handles.0).unwrap().0, "a_modified_a");
assert_eq!(tuple.get(&handles.1).unwrap().0, "b_modified_b");
}
#[test]
fn test_get_all_mut_all() {
let (mut tuple, handles) = get_tuple();
let tuple_list!(a_rec, b_rec, c_rec) =
tuple.get_all_mut(tuple_list!(&handles.0, &handles.1, &handles.2));
a_rec.unwrap().0.push_str("_modified_a");
b_rec.unwrap().0.push_str("_modified_b");
c_rec.unwrap().0.push_str("_modified_c");
assert_eq!(tuple.get(&handles.0).unwrap().0, "a_modified_a");
assert_eq!(tuple.get(&handles.1).unwrap().0, "b_modified_b");
assert_eq!(tuple.get(&handles.2).unwrap().0, "c_modified_c");
}
#[test]
fn test_get_all_mut_reverse() {
let (mut tuple, handles) = get_tuple();
let tuple_list!(c_rec, b_rec, a_rec) =
tuple.get_all_mut(tuple_list!(&handles.2, &handles.1, &handles.0));
c_rec.unwrap().0.push_str("_modified_c");
b_rec.unwrap().0.push_str("_modified_b");
a_rec.unwrap().0.push_str("_modified_a");
assert_eq!(tuple.get(&handles.0).unwrap().0, "a_modified_a");
assert_eq!(tuple.get(&handles.1).unwrap().0, "b_modified_b");
assert_eq!(tuple.get(&handles.2).unwrap().0, "c_modified_c");
}
#[test]
fn test_get_all_mut_unsafe() {
let (mut tuple, handles) = get_tuple();
let handle_1 = handles.0;
let handle_1_clone = handle_1.clone();
let tuple_list!(rec_1, rec_1_clone) =
tuple.get_all_mut(tuple_list!(&handle_1, &handle_1_clone));
assert!(rec_1.is_some());
assert!(rec_1_clone.is_none());
}
#[test]
fn test_preserve_order() {
let a = MyHandled::new("a");
let a_handle = a.handle();
let b = MyHandled::new("a"); let b_handle = b.handle();
let mut tuple = tuple_list!(a, b);
let tuple_list!(_rec_a, rec_b) = tuple.get_all_mut(tuple_list!(&a_handle, &b_handle));
rec_b.unwrap().0 = "b".to_string();
let tuple_list!(a, b) = tuple;
assert_eq!(a.0, "a");
assert_eq!(b.0, "b");
}
}
}