Better type_eq (#2946)
* typeid that doesn't suck * actually, that's not const! * format, move phantomdata to alloc feature block * a --------- Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
This commit is contained in:
parent
abe955137f
commit
83d88546d3
@ -120,6 +120,7 @@ strum = "0.26.3"
|
|||||||
strum_macros = "0.26.4"
|
strum_macros = "0.26.4"
|
||||||
toml = "0.8.19" # For parsing the injections toml file
|
toml = "0.8.19" # For parsing the injections toml file
|
||||||
typed-builder = "0.20.0" # Implement the builder pattern at compiletime
|
typed-builder = "0.20.0" # Implement the builder pattern at compiletime
|
||||||
|
typeid = "1.0.0" # Safe type_eq that doesn't rely on std specialization
|
||||||
uuid = { version = "1.10.0", features = ["serde", "v4"] }
|
uuid = { version = "1.10.0", features = ["serde", "v4"] }
|
||||||
which = "6.0.3"
|
which = "6.0.3"
|
||||||
windows = "0.59.0"
|
windows = "0.59.0"
|
||||||
|
@ -122,6 +122,7 @@ rustversion = { workspace = true }
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
libafl_derive = { workspace = true, default-features = true, optional = true }
|
libafl_derive = { workspace = true, default-features = true, optional = true }
|
||||||
static_assertions = { workspace = true }
|
static_assertions = { workspace = true }
|
||||||
|
typeid = { workspace = true }
|
||||||
|
|
||||||
tuple_list = { version = "0.1.3" }
|
tuple_list = { version = "0.1.3" }
|
||||||
hashbrown = { workspace = true, features = [
|
hashbrown = { workspace = true, features = [
|
||||||
|
@ -6,9 +6,10 @@ use alloc::{borrow::Cow, vec::Vec};
|
|||||||
use core::{
|
use core::{
|
||||||
any::type_name,
|
any::type_name,
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
|
marker::PhantomData,
|
||||||
ops::{Deref, DerefMut, Index, IndexMut},
|
ops::{Deref, DerefMut, Index, IndexMut},
|
||||||
};
|
};
|
||||||
use core::{any::TypeId, cell::Cell, marker::PhantomData, mem::transmute};
|
use core::{any::TypeId, mem::transmute};
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -21,36 +22,9 @@ use crate::HasLen;
|
|||||||
use crate::Named;
|
use crate::Named;
|
||||||
|
|
||||||
/// Returns if the type `T` is equal to `U`, ignoring lifetimes.
|
/// Returns if the type `T` is equal to `U`, ignoring lifetimes.
|
||||||
#[inline] // this entire call gets optimized away :)
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
|
pub fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
|
||||||
// decider struct: hold a cell (which we will update if the types are unequal) and some
|
typeid::of::<T>() == typeid::of::<U>()
|
||||||
// phantom data using a function pointer to allow for Copy to be implemented
|
|
||||||
struct W<'a, T: ?Sized, U: ?Sized>(&'a Cell<bool>, PhantomData<fn() -> (&'a T, &'a U)>);
|
|
||||||
|
|
||||||
// default implementation: if the types are unequal, we will use the clone implementation
|
|
||||||
impl<T: ?Sized, U: ?Sized> Clone for W<'_, T, U> {
|
|
||||||
#[inline]
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
// indicate that the types are unequal
|
|
||||||
// unfortunately, use of interior mutability (Cell) makes this not const-compatible
|
|
||||||
// not really possible to get around at this time
|
|
||||||
self.0.set(false);
|
|
||||||
W(self.0, self.1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// specialized implementation: Copy is only implemented if the types are the same
|
|
||||||
#[expect(clippy::mismatching_type_param_order)]
|
|
||||||
impl<T: ?Sized> Copy for W<'_, T, T> {}
|
|
||||||
|
|
||||||
let detected = Cell::new(true);
|
|
||||||
// [].clone() is *specialized* in core.
|
|
||||||
// Types which implement copy will have their copy implementations used, falling back to clone.
|
|
||||||
// If the types are the same, then our clone implementation (which sets our Cell to false)
|
|
||||||
// will never be called, meaning that our Cell's content remains true.
|
|
||||||
let res = [W::<T, U>(&detected, PhantomData)].clone();
|
|
||||||
res[0].0.get()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrow each member of the tuple
|
/// Borrow each member of the tuple
|
||||||
@ -955,8 +929,6 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
#[expect(unused_qualifications)] // for type name tests
|
|
||||||
fn test_type_eq() {
|
fn test_type_eq() {
|
||||||
// An alias for equality testing
|
// An alias for equality testing
|
||||||
type OwnedMutSliceAlias<'a> = OwnedMutSlice<'a, u8>;
|
type OwnedMutSliceAlias<'a> = OwnedMutSlice<'a, u8>;
|
||||||
@ -976,15 +948,6 @@ mod test {
|
|||||||
// test weirder lifetime things
|
// test weirder lifetime things
|
||||||
assert!(type_eq::<OwnedMutSlice<u8>, OwnedMutSlice<u8>>());
|
assert!(type_eq::<OwnedMutSlice<u8>, OwnedMutSlice<u8>>());
|
||||||
assert!(!type_eq::<OwnedMutSlice<u8>, OwnedMutSlice<u32>>());
|
assert!(!type_eq::<OwnedMutSlice<u8>, OwnedMutSlice<u32>>());
|
||||||
|
|
||||||
assert!(type_eq::<
|
|
||||||
OwnedMutSlice<u8>,
|
|
||||||
crate::ownedref::OwnedMutSlice<u8>,
|
|
||||||
>());
|
|
||||||
assert!(!type_eq::<
|
|
||||||
OwnedMutSlice<u8>,
|
|
||||||
crate::ownedref::OwnedMutSlice<u32>,
|
|
||||||
>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user