anymap/src/any.rs
Chris Morgan 0a1c85f865 no_std support
I’m quite pleased with how this has turned out.

Given the stability-despite-instability of hashbrown (that the API
surface we’re depending on hasn’t changed since 0.1.1), and the
deliberate altered SemVer guarantees for it, it was very tempting
to leave the hashbrown range open, `version = ">=0.1.1"` or at least
`version = ">=0.1.1, <1"`, but for some reason or other I ended up
deciding not to. I’m still of two minds about it, really.
2022-01-26 00:16:15 +11:00

108 lines
3.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use core::fmt;
use core::any::Any;
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
#[doc(hidden)]
pub trait CloneToAny {
/// Clone `self` into a new `Box<dyn CloneAny>` object.
fn clone_to_any(&self) -> Box<dyn CloneAny>;
}
impl<T: Any + Clone> CloneToAny for T {
#[inline]
fn clone_to_any(&self) -> Box<dyn CloneAny> {
Box::new(self.clone())
}
}
macro_rules! impl_clone {
($t:ty) => {
impl Clone for Box<$t> {
#[inline]
fn clone(&self) -> Box<$t> {
// SAFETY: this dance is to reapply any Send/Sync marker. Im not happy about this
// approach, given that I used to do it in safe code, but then came a dodgy
// future-compatibility warning where_clauses_object_safety, which is spurious for
// auto traits but still super annoying (future-compatibility lints seem to mean
// your bin crate needs a corresponding allow!). Although I explained my plight¹
// and it was all explained and agreed upon, no action has been taken. So I finally
// caved and worked around it by doing it this way, which matches whats done for
// core::any², so its probably not *too* bad.
//
// ¹ https://github.com/rust-lang/rust/issues/51443#issuecomment-421988013
// ² https://github.com/rust-lang/rust/blob/e7825f2b690c9a0d21b6f6d84c404bb53b151b38/library/alloc/src/boxed.rs#L1613-L1616
let clone: Box<dyn CloneAny> = (**self).clone_to_any();
let raw: *mut dyn CloneAny = Box::into_raw(clone);
unsafe { Box::from_raw(raw as *mut $t) }
}
}
impl fmt::Debug for $t {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad(stringify!($t))
}
}
}
}
#[allow(missing_docs)] // Bogus warning (its not public outside the crate), ☹
pub trait UncheckedAnyExt: Any {
unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T;
unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T;
unsafe fn downcast_unchecked<T: Any>(self: Box<Self>) -> Box<T>;
}
#[doc(hidden)]
/// A trait for the conversion of an object into a boxed trait object.
pub trait IntoBox<A: ?Sized + UncheckedAnyExt>: Any {
/// Convert self into the appropriate boxed form.
fn into_box(self) -> Box<A>;
}
macro_rules! implement {
($base:ident, $(+ $bounds:ident)*) => {
impl UncheckedAnyExt for dyn $base $(+ $bounds)* {
#[inline]
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
&*(self as *const Self as *const T)
}
#[inline]
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
&mut *(self as *mut Self as *mut T)
}
#[inline]
unsafe fn downcast_unchecked<T: 'static>(self: Box<Self>) -> Box<T> {
Box::from_raw(Box::into_raw(self) as *mut T)
}
}
impl<T: $base $(+ $bounds)*> IntoBox<dyn $base $(+ $bounds)*> for T {
#[inline]
fn into_box(self) -> Box<dyn $base $(+ $bounds)*> {
Box::new(self)
}
}
}
}
implement!(Any,);
implement!(Any, + Send);
implement!(Any, + Send + Sync);
/// [`Any`], but with cloning.
///
/// Every type with no non-`'static` references that implements `Clone` implements `CloneAny`.
/// See [`core::any`] for more details on `Any` in general.
pub trait CloneAny: Any + CloneToAny { }
impl<T: Any + Clone> CloneAny for T { }
implement!(CloneAny,);
implement!(CloneAny, + Send);
implement!(CloneAny, + Send + Sync);
impl_clone!(dyn CloneAny);
impl_clone!(dyn CloneAny + Send);
impl_clone!(dyn CloneAny + Send + Sync);