Derive Macro dispose::Dispose [−][src]
#[derive(Dispose)]
{
// Attributes available to this derive:
#[dispose]
}
Expand description
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
The #[dispose] attribute available to types deriving Dispose provides four options for
decorating fields: ignore, with, iter, and iter_with.
#[dispose(ignore)]is the simplest option. It disables generating a.dispose()call for the field it decorates.#[dispose(with = <expr>)]changes the.dispose()call to a.dispose_with(...)call that is provided with a value determined by<expr>.exprcan take one of two forms:.membfor a member access intoself, or any other Rust expression, which will be token-pasted into thedispose_withcall as-is.#[dispose(iter)]changes the.dispose()call to.dispose_iter(), for types that implementDisposeIteratorrather thanDispose.#[dispose(iter_with = <expr>)]changes the.dispose()call to.dispose_iter_with(...), behaving similarly to both#[dispose(iter)]and#[dispose(with = <expr>)].
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 27Here’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...