Skip to main content

astrelis_render/
extension.rs

1//! Extension traits for low-level wgpu access.
2//!
3//! This module provides traits that allow accessing the underlying wgpu types
4//! from the Astrelis wrapper types. Use these when you need raw wgpu access
5//! for advanced use cases not covered by the high-level API.
6//!
7//! # Example
8//!
9//! ```ignore
10//! use astrelis_render::{GraphicsContext, AsWgpu};
11//!
12//! let ctx = GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
13//!
14//! // Access raw wgpu device via inherent methods
15//! let device: &wgpu::Device = ctx.device();
16//! let queue: &wgpu::Queue = ctx.queue();
17//!
18//! // Create custom wgpu resources
19//! let buffer = device.create_buffer(&wgpu::BufferDescriptor {
20//!     label: Some("Custom Buffer"),
21//!     size: 1024,
22//!     usage: wgpu::BufferUsages::UNIFORM,
23//!     mapped_at_creation: false,
24//! });
25//! ```
26
27use std::sync::Arc;
28
29use crate::{
30    ComputePass, FrameContext, Framebuffer, GraphicsContext, RenderPass, WindowContext,
31};
32
33// =============================================================================
34// Core Extension Traits
35// =============================================================================
36
37/// Access the underlying wgpu type (immutable).
38///
39/// Implement this trait to expose the underlying wgpu type for advanced access.
40pub trait AsWgpu {
41    /// The underlying wgpu type.
42    type WgpuType;
43
44    /// Get a reference to the underlying wgpu type.
45    fn as_wgpu(&self) -> &Self::WgpuType;
46}
47
48/// Access the underlying wgpu type (mutable).
49///
50/// Implement this trait to expose mutable access to the underlying wgpu type.
51pub trait AsWgpuMut: AsWgpu {
52    /// Get a mutable reference to the underlying wgpu type.
53    fn as_wgpu_mut(&mut self) -> &mut Self::WgpuType;
54}
55
56/// Consume and return the underlying wgpu type.
57///
58/// Implement this trait when ownership of the wgpu type can be transferred.
59pub trait IntoWgpu {
60    /// The underlying wgpu type.
61    type WgpuType;
62
63    /// Consume self and return the underlying wgpu type.
64    fn into_wgpu(self) -> Self::WgpuType;
65}
66
67// =============================================================================
68// AsWgpu Implementations
69// =============================================================================
70
71impl AsWgpu for GraphicsContext {
72    type WgpuType = wgpu::Device;
73
74    fn as_wgpu(&self) -> &Self::WgpuType {
75        self.device()
76    }
77}
78
79impl AsWgpu for Arc<GraphicsContext> {
80    type WgpuType = wgpu::Device;
81
82    fn as_wgpu(&self) -> &Self::WgpuType {
83        self.device()
84    }
85}
86
87impl AsWgpu for FrameContext {
88    type WgpuType = wgpu::CommandEncoder;
89
90    fn as_wgpu(&self) -> &Self::WgpuType {
91        self.encoder.as_ref().expect("FrameContext encoder already taken - ensure finish() wasn't called early")
92    }
93}
94
95impl AsWgpuMut for FrameContext {
96    fn as_wgpu_mut(&mut self) -> &mut Self::WgpuType {
97        self.encoder.as_mut().expect("FrameContext encoder already taken - ensure finish() wasn't called early")
98    }
99}
100
101impl<'a> AsWgpu for RenderPass<'a> {
102    type WgpuType = wgpu::RenderPass<'static>;
103
104    fn as_wgpu(&self) -> &Self::WgpuType {
105        self.pass.as_ref().expect("RenderPass already consumed - ensure it wasn't dropped early")
106    }
107}
108
109impl<'a> AsWgpuMut for RenderPass<'a> {
110    fn as_wgpu_mut(&mut self) -> &mut Self::WgpuType {
111        self.pass.as_mut().expect("RenderPass already consumed - ensure it wasn't dropped early")
112    }
113}
114
115impl<'a> AsWgpu for ComputePass<'a> {
116    type WgpuType = wgpu::ComputePass<'static>;
117
118    fn as_wgpu(&self) -> &Self::WgpuType {
119        self.pass.as_ref().expect("ComputePass already consumed - ensure it wasn't dropped early")
120    }
121}
122
123impl<'a> AsWgpuMut for ComputePass<'a> {
124    fn as_wgpu_mut(&mut self) -> &mut Self::WgpuType {
125        self.pass.as_mut().expect("ComputePass already consumed - ensure it wasn't dropped early")
126    }
127}
128
129impl AsWgpu for Framebuffer {
130    type WgpuType = wgpu::Texture;
131
132    fn as_wgpu(&self) -> &Self::WgpuType {
133        self.color_texture()
134    }
135}
136
137impl AsWgpu for WindowContext {
138    type WgpuType = wgpu::Surface<'static>;
139
140    fn as_wgpu(&self) -> &Self::WgpuType {
141        &self.surface
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    // Note: These tests require a GPU context, so they're integration tests.
150    // Here we just test that the traits compile correctly.
151
152    #[test]
153    fn test_trait_object_safety() {
154        // Ensure the core traits can be used as trait objects where applicable
155        fn _takes_as_wgpu<T: AsWgpu>(_: &T) {}
156        fn _takes_as_wgpu_mut<T: AsWgpuMut>(_: &mut T) {}
157        fn _takes_into_wgpu<T: IntoWgpu>(_: T) {}
158    }
159}