Simplify provider api to improve llvm ir

This commit is contained in:
Jane Losare-Lusby
2024-06-10 12:37:32 -07:00
parent a3167859f2
commit 6e3134972e

View File

@@ -404,9 +404,9 @@ fn request_by_type_tag<'a, I>(err: &'a (impl Error + ?Sized)) -> Option<I::Reifi
where
I: tags::Type<'a>,
{
let mut tagged = TaggedOption::<'a, I>(None);
let mut tagged = Tagged { tag_id: TypeId::of::<I>(), value: TaggedOption::<'a, I>(None) };
err.provide(tagged.as_request());
tagged.0
tagged.value.0
}
///////////////////////////////////////////////////////////////////////////////
@@ -507,16 +507,9 @@ where
///
#[unstable(feature = "error_generic_member_access", issue = "99301")]
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
pub struct Request<'a>(dyn Erased<'a> + 'a);
pub struct Request<'a>(Tagged<dyn Erased<'a> + 'a>);
impl<'a> Request<'a> {
/// Create a new `&mut Request` from a `&mut dyn Erased` trait object.
fn new<'b>(erased: &'b mut (dyn Erased<'a> + 'a)) -> &'b mut Request<'a> {
// SAFETY: transmuting `&mut (dyn Erased<'a> + 'a)` to `&mut Request<'a>` is safe since
// `Request` is repr(transparent).
unsafe { &mut *(erased as *mut dyn Erased<'a> as *mut Request<'a>) }
}
/// Provide a value or other type with only static lifetimes.
///
/// # Examples
@@ -940,27 +933,28 @@ pub(crate) mod tags {
#[repr(transparent)]
pub(crate) struct TaggedOption<'a, I: tags::Type<'a>>(pub Option<I::Reified>);
impl<'a, I: tags::Type<'a>> TaggedOption<'a, I> {
impl<'a, I: tags::Type<'a>> Tagged<TaggedOption<'a, I>> {
pub(crate) fn as_request(&mut self) -> &mut Request<'a> {
Request::new(self as &mut (dyn Erased<'a> + 'a))
let erased = self as &mut Tagged<dyn Erased<'a> + 'a>;
// SAFETY: transmuting `&mut Tagged<dyn Erased<'a> + 'a>` to `&mut Request<'a>` is safe since
// `Request` is repr(transparent).
unsafe { &mut *(erased as *mut Tagged<dyn Erased<'a>> as *mut Request<'a>) }
}
}
/// Represents a type-erased but identifiable object.
///
/// This trait is exclusively implemented by the `TaggedOption` type.
unsafe trait Erased<'a>: 'a {
/// The `TypeId` of the erased type.
fn tag_id(&self) -> TypeId;
unsafe trait Erased<'a>: 'a {}
unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> {}
struct Tagged<E: ?Sized> {
tag_id: TypeId,
value: E,
}
unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> {
fn tag_id(&self) -> TypeId {
TypeId::of::<I>()
}
}
impl<'a> dyn Erased<'a> + 'a {
impl<'a> Tagged<dyn Erased<'a> + 'a> {
/// Returns some reference to the dynamic value if it is tagged with `I`,
/// or `None` otherwise.
#[inline]
@@ -968,9 +962,9 @@ impl<'a> dyn Erased<'a> + 'a {
where
I: tags::Type<'a>,
{
if self.tag_id() == TypeId::of::<I>() {
if self.tag_id == TypeId::of::<I>() {
// SAFETY: Just checked whether we're pointing to an I.
Some(unsafe { &*(self as *const Self).cast::<TaggedOption<'a, I>>() })
Some(&unsafe { &*(self as *const Self).cast::<Tagged<TaggedOption<'a, I>>>() }.value)
} else {
None
}
@@ -983,9 +977,12 @@ impl<'a> dyn Erased<'a> + 'a {
where
I: tags::Type<'a>,
{
if self.tag_id() == TypeId::of::<I>() {
// SAFETY: Just checked whether we're pointing to an I.
Some(unsafe { &mut *(self as *mut Self).cast::<TaggedOption<'a, I>>() })
if self.tag_id == TypeId::of::<I>() {
Some(
// SAFETY: Just checked whether we're pointing to an I.
&mut unsafe { &mut *(self as *mut Self).cast::<Tagged<TaggedOption<'a, I>>>() }
.value,
)
} else {
None
}