[−][src]Derive Macro dispose_derive::Dispose
#[derive(Dispose)] { // Attributes available to this derive: #[dispose] }
Add trivial Dispose
support to a struct or enum where the contained values implement
Dispose
or DisposeWith<W>
.
This macro is designed to reduce the boilerplate for writing custom containers housing
Dispose
or DisposeWith
resources.
The #[dispose]
attribute
Examples
Here's a dead-simple example:
use dispose::{prelude::*, Disposable}; struct MyResource { important_stuff: String, } impl Dispose for MyResource { fn dispose(self) { println!("disposing {:?}", self.important_stuff); } } struct MyOtherResource { handle: u32, } impl Dispose for MyOtherResource { fn dispose(self) { println!("releasing handle {}", self.handle) } } // The derive macro makes it trivial to implement Dispose on a container type for these // resources. #[derive(Dispose)] struct MyContainer { res: MyResource, other: MyOtherResource, } impl MyContainer { fn new(important_stuff: impl Into<String>, handle: u32) -> Disposable<Self> { let important_stuff = important_stuff.into(); Self { res: MyResource { important_stuff }, other: MyOtherResource { handle }, }.into() } } { let container = MyContainer::new("foobar", 27); // Do some stuff with container here... } // This prints: // disposing "foobar" // releasing handle 27
Here's a more real-world example, using the gfx-hal crate:
use gfx_hal::{prelude::*, Backend, device::Device}; // First, some setup - since this is non-trivial, the macro can't help here. struct Buffer<B: Backend>(B::Buffer); struct Memory<B: Backend>(B::Memory); impl<B: Backend> DisposeWith<&B::Device> for Buffer<B> { fn dispose_with(self, dev: &B::Device) { unsafe { dev.destroy_buffer(self.0) } } } impl<B: Backend> DisposeWith<&B::Device> for Memory<B> { fn dispose_with(self, dev: &B::Device) { unsafe { dev.free_memory(self.0) } } } /// A single buffer with its own device memory allocation. #[derive(Dispose)] struct SingleBuffer<'a, B: Backend> { #[dispose(ignore)] dev: &'a B::Device, #[dispose(with = .dev)] buf: Buffer<B>, #[dispose(with = .dev)] mem: Memory<B>, } impl<'a, B: Backend> SingleBuffer<'a, B> { fn new(dev: &'a B::Device, buf: Buffer<B>, mem: Memory<B>) -> Disposable<Self> { Self { dev, buf, mem }.into() } } /// A set of buffers sharing a single memory allocation. #[derive(Dispose)] struct MultiBuffer<'a, B: Backend> { #[dispose(ignore)] dev: &'a B::Device, #[dispose(with = .dev)] bufs: Vec<Buffer<B>>, #[dispose(with = .dev)] mem: Memory<B>, } impl<'a, B: Backend> MultiBuffer<'a, B> { fn new( dev: &'a B::Device, bufs: impl IntoIterator<Item = Buffer<B>>, mem: Memory<B>, ) -> Disposable<Self> { Self { dev, bufs: bufs.into_iter().collect(), mem, }.into() } } // Acquire a device here. // Now we can create and manage a container for a single buffer... let buf = SingleBuffer::new( a_device, create_buffer(a_device), alloc_memory(a_device), ); // ...or multiple buffers, with allocation sharing. // And, there's no excessive copies of a_device stored in memory! let bufs = MultiBuffer::new( a_device, (0..16).into_iter().map(|_| create_buffer(a_device)), alloc_memory(a_device), ); // Draw cool things with the buffers here...