I recently ran into an issue where I wanted to use Any
for slices. However, it only allows 'static
types (based on what I read, this is because you get the same TypeId
regardless of lifetimes).
I came up with this workaround which I think is safe:
use std::{
any::{Any, TypeId},
marker::PhantomData,
};
#[derive(Clone, Debug)]
pub struct AnySlice<'a> {
tid: TypeId,
len: usize,
ptr: *const (),
marker: PhantomData<&'a ()>,
}
impl<'a> AnySlice<'a> {
pub fn from_slice(s: &'a [T]) -> Self {
Self {
len: s.len(),
ptr: s.as_ptr() as *const (),
tid: TypeId::of::(),
marker: PhantomData,
}
}
pub fn as_slice(&self) -> Option<&'a [T]> {
if TypeId::of::() != self.tid {
return None;
}
Some(unsafe { std::slice::from_raw_parts(self.ptr as *const T, self.len) })
}
pub fn is(&self) -> bool {
TypeId::of::() == self.tid
}
}
edit: Unfortunately it seems like Lemmy insists on mangling the code block. See the playground link below.
T: Any
ensures T
is also 'static
. The lifetime is preserved with PhantomData
. Here’s a playground link with some simple tests and a mut version: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=3116a404c28317c46dbba6ed6824c8a9
It seems to pass Miri, including the mut version (which requires a bit more care to ensure there can only be one mutable reference). Any problems with doing this?
Thanks for the reply. Unfortunately, I could just use
Any
for that sinceVec
is'static
as long as the items are (and I don’t think you could useanyvec
if the tiems weren’t static).I asked in the Rust Discord channels and it seems like my approach is fine. Even the mutable version is okay and doesn’t need to be unsafe if it returns the reference with
self
’s lifetime.Then maybe publish it as a mini-crate (e.g.
any-slice
), ideally with a link to the discussion that proves that it is sound.