1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
use super::Device;
/// The `AnyDevice` type: a pointer to a `Device<A>` for any backend `A`.
use crate::hal_api::HalApi;
use std::any::Any;
use std::fmt;
use std::sync::Arc;
/// A pointer to a `Device<A>`, for any backend `A`.
///
/// Any `AnyDevice` is just like an `Arc<Device<A>>`, except that the
/// `A` type parameter is erased. To access the `Device`, you must
/// downcast to a particular backend with the \[`downcast_ref`\] or
/// \[`downcast_clone`\] methods.
pub struct AnyDevice(Arc<dyn Any + 'static>);
impl AnyDevice {
/// Return an `AnyDevice` that holds an owning `Arc` pointer to `device`.
pub fn new<A: HalApi>(device: Arc<Device<A>>) -> AnyDevice {
AnyDevice(device)
}
/// If `self` is an `Arc<Device<A>>`, return a reference to the
/// device.
pub fn downcast_ref<A: HalApi>(&self) -> Option<&Device<A>> {
self.0.downcast_ref::<Device<A>>()
}
/// If `self` is an `Arc<Device<A>>`, return a clone of that.
pub fn downcast_clone<A: HalApi>(&self) -> Option<Arc<Device<A>>> {
// `Arc::downcast` returns `Arc<T>`, but requires that `T` be `Sync` and
// `Send`, and this is not the case for `Device` in wasm builds.
//
// But as far as I can see, `Arc::downcast` has no particular reason to
// require that `T` be `Sync` and `Send`; the steps used here are sound.
if (self.0).is::<Device<A>>() {
// Get an owned Arc.
let clone = self.0.clone();
// Turn the `Arc`, which is a pointer to an `ArcInner` struct, into
// a pointer to the `ArcInner`'s `data` field. Carry along the
// vtable from the original `Arc`.
let raw_erased: *const (dyn Any + 'static) = Arc::into_raw(clone);
// Remove the vtable, and supply the concrete type of the `data`.
let raw_typed: *const Device<A> = raw_erased.cast::<Device<A>>();
// Convert the pointer to the `data` field back into a pointer to
// the `ArcInner`, and restore reference-counting behavior.
let arc_typed: Arc<Device<A>> = unsafe {
// Safety:
// - We checked that the `dyn Any` was indeed a `Device<A>` above.
// - We're calling `Arc::from_raw` on the same pointer returned
// by `Arc::into_raw`, except that we stripped off the vtable
// pointer.
// - The pointer must still be live, because we've borrowed `self`,
// which holds another reference to it.
// - The format of a `ArcInner<dyn Any>` must be the same as
// that of an `ArcInner<Device<A>>`, or else `AnyDevice::new`
// wouldn't be possible.
Arc::from_raw(raw_typed)
};
Some(arc_typed)
} else {
None
}
}
}
impl fmt::Debug for AnyDevice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("AnyDevice")
}
}
#[cfg(send_sync)]
unsafe impl Send for AnyDevice {}
#[cfg(send_sync)]
unsafe impl Sync for AnyDevice {}