rust-derivative
rust-derivative copied to clipboard
Deref support.
Describe the bug The Rust Pattern of wrapping one type in another was suggested to me as a solution of working with reference counting.
struct RcA(a-sys::A);
pub struct A(Rc<RcA>);
The Deref
trait would remove .0
from all over the place. The point is to implement Drop
for RcA
such that the destructor for a-sys::A
would be called. My target is ash/Vulkan.
A real world example: Much of the boilerplate is hidden inside macros, so only the unique parts are shown.
impl<T> Device<T> {
pub fn new(
instance: Instance<T>,
physical_device: vk::PhysicalDevice,
create_info: &vk::DeviceCreateInfo,
user: T,
) -> Result<Self> {
let inner = unsafe { instance.create_device(physical_device, create_info, None) }
.context(VkCreateDevice {})?;
let acceleration_structure_fn = AccelerationStructure::new(&**instance, &inner);
let ray_tracing_fn = RayTracingPipeline::new(&**instance, &inner);
Ok(Self(Rc::new(RcDevice {
inner,
instance,
acceleration_structure_fn,
ray_tracing_fn,
user,
})))
}
}
pub struct RcDevice<T> {
pub inner: VkDevice,
pub instance: Instance<T>,
pub acceleration_structure_fn: AccelerationStructure,
pub ray_tracing_fn: RayTracingPipeline,
pub user: T,
}
impl<T> Deref for RcDevice<T> {
type Target = VkDevice;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> Drop for RcDevice<T> {
fn drop(&mut self) {
unsafe {
self.inner.destroy_device(None);
};
}
}
impl<T> Fence<T> {
pub fn new(device: Device<T>, create_info: &vk::FenceCreateInfo, user: T) -> Result<Self> {
Ok(Self(Rc::new(RcFence {
inner: unsafe { device.create_fence(create_info, None) }.context(VkCreateFence {})?,
device,
user,
})))
}
}
pub struct RcFence<T> {
pub inner: vk::Fence,
pub device: Device<T>,
pub user: T,
}
impl<T> Drop for RcFence<T> {
fn drop(&mut self) {
unsafe {
self.device.inner.destroy_fence(**self, None);
};
}
}
Fence
and CommandBuffer
https://gitlab.com/cheako/ash-tray-rs/-/blob/c9a1ea4db239fca214f0cea09030096fc0390c3b/src/vk_helper.rs#L598-925 are two extremes and DescriptoSet
is a complex example as well.
Expected behavior
macro_rules! vk_subinner_types {
($($t:ident)*) => ($(
concat_idents::concat_idents! (RcName = Rc, $t {
impl<T> Deref for RcName<T> {
type Target = vk::$t;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
});
)*)
}
macro_rules! vk_inner_types {
($($t:ident)*) => ($(
concat_idents::concat_idents! (RcName = Rc, $t {
impl<T> Deref for $t<T> {
type Target = RcName<T>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
});
)*)
}
Most of the types(notably Device
and Fence
from above) are defined with this macro:
macro_rules! vk_tuple_types {
($($t:ident)*) => ($(
concat_idents::concat_idents! (RcName = Rc, $t {
#[derive(Derivative)]
#[derivative(Clone(bound=""))]
pub struct $t<T> (pub Rc<RcName<T>>);
impl<T> Deref for $t<T> {
type Target = RcName<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
});
)*)
}
A keen eye would have noticed that Device
has a one-of Deref
, actually two types like that. It's because "use ash::Device as VkDevice" != "use ash::vk; vk::Device"
Version (please complete the following information):
rustup --version
cargo --version
rustc --version
$ exit
rustup 1.24.3 (ce5817a94 2021-05-31)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.56.0-nightly (ad02dc46b 2021-08-26)`
cargo 1.56.0-nightly (e96bdb0c3 2021-08-17)
rustc 1.56.0-nightly (ad02dc46b 2021-08-26)
- Version of
derivative
:2.2.0
Additional context
I also do a lot of testing with CI and it's obviously not easy to run the above --version
script. Though I need that information as well, so if you look at https://gitlab.com/cheako/ash-tray-rs/-/pipelines and https://gitlab.com/cheako/hazel-rs/-/pipelines you'll get more examples of version info and resulting errors. Thought I don't believe you'll find errors there, even for the fixed errors because generic is not Clone
where I don't think I pushed any.
Also note that I'd love any criticism of this code, it often keeps me up at night wondering if this code is any good... And now I can add wondering if it's too much Golf.