Stable type_eq (#2150)
* stable type eq * whoops, wrong section * satiate clippy * remove extraneous comment * explain * bonus inline
This commit is contained in:
parent
e7e820868c
commit
c1a55982b6
@ -95,7 +95,6 @@ rustversion = "1.0"
|
|||||||
libafl_derive = { version = "0.12.0", optional = true, path = "../libafl_derive" }
|
libafl_derive = { version = "0.12.0", optional = true, path = "../libafl_derive" }
|
||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
|
|
||||||
rustversion = "1.0"
|
|
||||||
tuple_list = { version = "0.1.3" }
|
tuple_list = { version = "0.1.3" }
|
||||||
hashbrown = { version = "0.14", features = ["serde", "ahash"], default-features = false, optional = true } # A faster hashmap, nostd compatible
|
hashbrown = { version = "0.14", features = ["serde", "ahash"], default-features = false, optional = true } # A faster hashmap, nostd compatible
|
||||||
xxhash-rust = { version = "0.8.5", features = ["xxh3"], optional = true } # xxh3 hashing for rust
|
xxhash-rust = { version = "0.8.5", features = ["xxh3"], optional = true } # xxh3 hashing for rust
|
||||||
|
@ -6,6 +6,7 @@ use alloc::{borrow::Cow, vec::Vec};
|
|||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use core::{
|
use core::{
|
||||||
any::{type_name, TypeId},
|
any::{type_name, TypeId},
|
||||||
|
cell::Cell,
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem::transmute,
|
mem::transmute,
|
||||||
@ -23,40 +24,37 @@ use crate::HasLen;
|
|||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use crate::Named;
|
use crate::Named;
|
||||||
|
|
||||||
/// Returns if the type `T` is equal to `U`
|
/// Returns if the type `T` is equal to `U`, ignoring lifetimes.
|
||||||
/// From <https://stackoverflow.com/a/60138532/7658998>
|
#[inline] // this entire call gets optimized away :)
|
||||||
#[rustversion::nightly]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
|
|
||||||
// Helper trait. `VALUE` is false, except for the specialization of the
|
|
||||||
// case where `T == U`.
|
|
||||||
trait TypeEq<U: ?Sized> {
|
|
||||||
const VALUE: bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default implementation.
|
|
||||||
impl<T: ?Sized, U: ?Sized> TypeEq<U> for T {
|
|
||||||
default const VALUE: bool = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specialization for `T == U`.
|
|
||||||
impl<T: ?Sized> TypeEq<T> for T {
|
|
||||||
const VALUE: bool = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
<T as TypeEq<U>>::VALUE
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns if the type `T` is equal to `U`
|
|
||||||
/// As this relies on [`type_name`](https://doc.rust-lang.org/std/any/fn.type_name.html#note) internally,
|
|
||||||
/// there is a chance for collisions.
|
|
||||||
/// Use `nightly` if you need a perfect match at all times.
|
|
||||||
#[rustversion::not(nightly)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
|
pub fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
|
||||||
type_name::<T>() == type_name::<U>()
|
// decider struct: hold a cell (which we will update if the types are unequal) and some
|
||||||
|
// 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<'a, T: ?Sized, U: ?Sized> Clone for W<'a, 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
|
||||||
|
#[allow(clippy::mismatching_type_param_order)]
|
||||||
|
impl<'a, T: ?Sized> Copy for W<'a, 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
|
||||||
@ -453,10 +451,6 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Match for a name and return the value
|
/// Match for a name and return the value
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
/// This operation may not be 100% accurate with Rust stable, see the notes for [`type_eq`]
|
|
||||||
/// (in `nightly`, it uses [specialization](https://stackoverflow.com/a/60138532/7658998)).
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub trait MatchName {
|
pub trait MatchName {
|
||||||
/// Match for a name and return the borrowed value
|
/// Match for a name and return the borrowed value
|
||||||
|
Loading…
x
Reference in New Issue
Block a user