196: Rewrite builder in the readme r=MaikKlein a=MaikKlein



Co-authored-by: Maik Klein <maikklein@googlemail.com>
Co-authored-by: Benjamin Saunders <ben.e.saunders@gmail.com>
This commit is contained in:
bors[bot] 2019-03-22 12:03:11 +00:00
commit 775a7d035d
3 changed files with 1267 additions and 6 deletions

View file

@ -72,15 +72,46 @@ let desc_alloc_info = vk::DescriptorSetAllocateInfo {
}; };
``` ```
### Builder pattern ### Builder pattern
```Rust ```Rust
let pipeline_vertex_input_state_create_info = vk::PipelineVertexInputStateCreateInfo::builder() // We lose all lifetime information when we call `.build()`. Be carefull!
.vertex_binding_descriptions(&Vertex::binding_descriptions()) let queue_info = [vk::DeviceQueueCreateInfo::builder()
.vertex_attribute_descriptions(&Vertex::attribute_descriptions()).build(); .queue_family_index(queue_family_index)
.queue_priorities(&priorities)
.build()];
// We don't need to call build here because builders implement `Deref`.
let device_create_info = vk::DeviceCreateInfo::builder()
.queue_create_infos(&queue_info)
.enabled_extension_names(&device_extension_names_raw)
.enabled_features(&features);
let device: Device = instance
.create_device(pdevice, &device_create_info, None)
.unwrap();
``` ```
Builders implement `Deref` targeting their corresponding Vulkan struct, so references to builders can be passed directly Builders have an explicit lifetime, and are marked as `#[repr(transparent)]`.
to Vulkan functions. This is encouraged as doing so allows Rust to check the lifetimes of captured objects are valid, ```Rust
whereas calling `build` discards lifetime information, making inadvertent use-after-free errors more likely. #[repr(transparent)]
pub struct DeviceCreateInfoBuilder<'a> {
inner: DeviceCreateInfo,
marker: ::std::marker::PhantomData<&'a ()>,
}
impl<'a> DeviceCreateInfoBuilder<'a> {
//...
pub fn queue_create_infos(
mut self,
queue_create_infos: &'a [DeviceQueueCreateInfo],
) -> DeviceCreateInfoBuilder<'a> {...}
//...
```
Every reference has to live as long as the builder itself. Builders implement `Deref` targeting their corresponding Vulkan struct, so references to builders can be passed directly
to Vulkan functions.
Calling `.build()` will **discard** that lifetime because Vulkan structs use raw pointers internally. This should be avoided as much as possible because this can easily lead to dangling pointers. If `.build()` has to be called, it should be called as late as possible. [Lifetimes of temporaries](https://doc.rust-lang.org/reference/expressions.html#temporary-lifetimes) are extended to the enclosing statement, ensuring they are valid for the duration of a Vulkan call occurring in the same statement.
### Pointer chains ### Pointer chains

File diff suppressed because it is too large Load diff

View file

@ -1726,6 +1726,9 @@ pub fn derive_setters(
#next_function #next_function
/// Calling build will **discard** all the lifetime information. Only call this if
/// necessary! Builders implement `Deref` targeting their corresponding Vulkan struct,
/// so references to builders can be passed directly to Vulkan functions.
pub fn build(self) -> #name { pub fn build(self) -> #name {
self.inner self.inner
} }