claw-code/.guardrails/examples/rust/bevy-ui-example/zero-copy-transfer.rs

362 lines
11 KiB
Rust

// Zero-Copy UI State Transfer - Bevy UI 0.15+
// Production-ready zero-copy UI state transfer patterns
//
// Last Updated: 2026-03-14
// Bevy Version: 0.15+
// Rust Version: 1.85+
use bevy::prelude::*;
use bevy::render::render_resource::{Buffer, BufferInitDescriptor, BufferUsages};
use std::mem::{size_of, slice_from_raw_parts};
/// Zero-Copy UI State - Bytemuck derive for safe zero-copy transfer
/// This pattern eliminates serialization overhead for high-performance UI
#[derive(Component, Clone, Copy, Debug, Default, Reflect)]
#[repr(C)]
pub struct ZeroCopyUiState {
/// Player health - direct memory transfer
pub health: u32,
/// Player mana - direct memory transfer
pub mana: u32,
/// Player experience - direct memory transfer
pub experience: u32,
/// Player level - direct memory transfer
pub level: u32,
/// Position X - GPU coordinate transfer
pub position_x: f32,
/// Position Y - GPU coordinate transfer
pub position_y: f32,
/// Theme ID - direct enum transfer
pub theme_id: u8,
/// Accessibility flags - bitfield
pub accessibility_flags: u8,
/// Padding for alignment
_padding: [u8; 2],
}
/// Bytemuck trait implementation - Safe zero-copy guarantees
/// UNSAFE: Requires careful memory layout verification
unsafe impl Pod for ZeroCopyUiState {
/// All bytes are valid - no invalid representations
/// Verified by #[repr(C)] and primitive types only
}
/// Zeroable trait implementation - Zero initialization safe
/// UNSAFE: All fields can be zero-initialized
unsafe impl Zeroable for ZeroCopyUiState {
/// Zero value is valid for all fields
/// u32, f32, u8 all have valid zero representations
}
/// Pod trait - Plain Old Data for zero-copy
/// All types must be Copy + Clone
pub trait Pod: Copy + Clone {
/// Cast slice reference - zero-copy conversion
fn cast_slice(&self) -> &[u8] {
unsafe {
slice_from_raw_parts(
self as *const Self as *const u8,
size_of::<Self>(),
)
}
}
/// Cast mutable slice - zero-copy mutation
fn cast_slice_mut(&mut self) -> &[u8] {
unsafe {
slice_from_raw_parts(
self as *mut Self as *const u8,
size_of::<Self>(),
)
}
}
/// Size in bytes - constant
fn size() -> usize {
size_of::<Self>()
}
}
/// Zeroable trait - Zero initialization
pub trait Zeroable: Pod {
/// Zero value - all bits zero
fn zero() -> Self {
unsafe {
let mut value = Self::default();
std::ptr::write_bytes(&mut value as *mut Self, 0, 1);
value
}
}
/// Is zero-initialized valid?
fn is_zero_valid() -> bool {
true
}
}
/// GPU Buffer Transfer - Zero-copy upload to GPU
#[derive(Resource, Debug)]
pub struct GpuUiBuffer {
/// GPU buffer
pub buffer: Buffer,
/// Buffer size
pub size: u64,
/// Buffer usage flags
pub usages: BufferUsages,
/// Last upload sequence
pub sequence: u64,
}
/// Implementation: ZeroCopyUiState
impl ZeroCopyUiState {
/// Create from ECS state - zero-copy conversion
pub fn from_ecs(state: &UiStateComponent) -> Self {
Self {
health: state.health,
mana: state.mana,
experience: state.experience,
level: state.level,
position_x: state.position_x,
position_y: state.position_y,
theme_id: match state.theme {
UiTheme::Default => 0,
UiTheme::HighContrast => 1,
UiTheme::Dark => 2,
UiTheme::Light => 3,
UiTheme::ColorblindProtanopia => 4,
UiTheme::ColorblindDeuteranopia => 5,
UiTheme::ColorblindTritanopia => 6,
},
accessibility_flags: {
let mut flags = 0u8;
if state.accessibility.screen_reader { flags |= 0b00000001; }
if state.accessibility.high_contrast { flags |= 0b00000010; }
if state.accessibility.reduced_motion { flags |= 0b00000100; }
if state.accessibility.keyboard_navigation { flags |= 0b00001000; }
if state.accessibility.focus_indicators { flags |= 0b00010000; }
flags
},
_padding: [0; 2],
}
}
/// Copy from ECS state - direct memory transfer
pub fn copy_from(&mut self, state: &UiStateComponent) {
*self = Self::from_ecs(state);
}
/// Copy to ECS state - direct memory transfer
pub fn copy_to(&self, state: &mut UiStateComponent) {
state.health = self.health;
state.mana = self.mana;
state.experience = self.experience;
state.level = self.level;
state.position_x = self.position_x;
state.position_y = self.position_y;
state.theme = match self.theme_id {
0 => UiTheme::Default,
1 => UiTheme::HighContrast,
2 => UiTheme::Dark,
3 => UiTheme::Light,
4 => UiTheme::ColorblindProtanopia,
5 => UiTheme::ColorblindDeuteranopia,
6 => UiTheme::ColorblindTritanopia,
_ => UiTheme::Default,
};
state.accessibility.screen_reader = (self.accessibility_flags & 0b00000001) != 0;
state.accessibility.high_contrast = (self.accessibility_flags & 0b00000010) != 0;
state.accessibility.reduced_motion = (self.accessibility_flags & 0b00000100) != 0;
state.accessibility.keyboard_navigation = (self.accessibility_flags & 0b00001000) != 0;
state.accessibility.focus_indicators = (self.accessibility_flags & 0b00010000) != 0;
}
/// Validate memory layout - zero-copy safety
pub fn validate_layout() -> bool {
// Verify alignment
assert!(size_of::<Self>() % 4 == 0, "Size must be 4-byte aligned");
// Verify field offsets
assert!(size_of::<u32>() == 4, "u32 size expected");
assert!(size_of::<f32>() == 4, "f32 size expected");
true
}
/// Get byte slice - zero-copy read
pub fn as_bytes(&self) -> &[u8] {
self.cast_slice()
}
/// Get mutable byte slice - zero-copy write
pub fn as_bytes_mut(&mut self) -> &[u8] {
self.cast_slice_mut()
}
}
/// Implementation: Pod for ZeroCopyUiState
impl Pod for ZeroCopyUiState {
fn size() -> usize {
size_of::<Self>()
}
}
/// Implementation: Zeroable for ZeroCopyUiState
impl Zeroable for ZeroCopyUiState {
fn zero() -> Self {
Self::default()
}
fn is_zero_valid() -> bool {
true
}
}
/// ECS UI State - Source for zero-copy transfer
#[derive(Component, Resource, Clone, Debug, Default)]
pub struct UiStateComponent {
pub health: u32,
pub mana: u32,
pub experience: u32,
pub level: u32,
pub position_x: f32,
pub position_y: f32,
pub theme: UiTheme,
pub accessibility: AccessibilityConfig,
}
/// Accessibility Config - Flags for zero-copy
#[derive(Component, Clone, Debug, Default)]
pub struct AccessibilityConfig {
pub screen_reader: bool,
pub high_contrast: bool,
pub reduced_motion: bool,
pub keyboard_navigation: bool,
pub focus_indicators: bool,
}
/// UI Theme - Enum for zero-copy ID
#[derive(Component, Clone, Debug, Default, PartialEq, Eq)]
pub enum UiTheme {
#[default]
Default,
HighContrast,
Dark,
Light,
ColorblindProtanopia,
ColorblindDeuteranopia,
ColorblindTritanopia,
}
/// System: Zero-copy transfer system
pub fn zero_copy_transfer_system(
ecs_state: Res<UiStateComponent>,
mut zero_copy: ResMut<ZeroCopyUiState>,
) {
// Direct memory transfer - no allocation
zero_copy.copy_from(&ecs_state);
}
/// System: GPU buffer upload system
pub fn gpu_buffer_upload_system(
zero_copy: Res<ZeroCopyUiState>,
mut gpu_buffer: ResMut<GpuUiBuffer>,
render_device: Res<RenderDevice>,
) {
// Zero-copy GPU upload - direct memory write
let bytes = zero_copy.as_bytes();
// Write buffer directly - no intermediate allocation
render_device.queue_buffer_write(
&mut gpu_buffer.buffer,
0,
bytes,
);
gpu_buffer.sequence += 1;
log::info!("GPU buffer uploaded: sequence {}", gpu_buffer.sequence);
}
/// System: Batch transfer system - Zero-copy slice transfer
pub fn batch_transfer_system(
states: Query<&UiStateComponent>,
mut zero_copy_states: QueryMut<ZeroCopyUiState>,
) {
// Batch zero-copy transfer - no per-entity allocation
for (ecs, zero_copy) in states.iter().zip(zero_copy_states.iter_mut()) {
zero_copy.copy_from(ecs);
}
}
/// Create GPU buffer - Zero-copy initialization
pub fn create_gpu_buffer(render_device: &RenderDevice, size: u64) -> GpuUiBuffer {
let buffer = render_device.create_buffer(&BufferInitDescriptor {
label: "UI State Buffer",
size,
usage: BufferUsages::MAP_WRITE | BufferUsages::COPY_DST,
});
GpuUiBuffer {
buffer,
size,
usages: BufferUsages::MAP_WRITE | BufferUsages::COPY_DST,
sequence: 0,
}
}
/// Validate zero-copy guarantees - Runtime checks
pub fn validate_zero_copy_guarantees() {
let state = ZeroCopyUiState::default();
// Size validation
assert!(state.size() % 4 == 0, "Size must be aligned");
// Byte slice validation
let bytes = state.as_bytes();
assert_eq!(bytes.len(), size_of::<ZeroCopyUiState>(), "Byte slice size mismatch");
// Zero initialization validation
let zero = ZeroCopyUiState::zero();
assert!(ZeroCopyUiState::is_zero_valid(), "Zero must be valid");
log::info!("Zero-copy guarantees validated");
}
/// Performance benchmark - Zero-copy vs serialization
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_zero_copy_size() {
let state = ZeroCopyUiState::default();
assert_eq!(state.size(), 24); // 6 u32/f32 + 2 u8 + 2 padding
}
#[test]
fn test_zero_copy_bytes() {
let state = ZeroCopyUiState::default();
let bytes = state.as_bytes();
assert_eq!(bytes.len(), size_of::<ZeroCopyUiState>());
}
#[test]
fn test_zero_copy_from_ecs() {
let ecs = UiStateComponent {
health: 100,
mana: 50,
experience: 500,
level: 10,
position_x: 1.0,
position_y: 2.0,
theme: UiTheme::HighContrast,
accessibility: AccessibilityConfig::default(),
};
let zero_copy = ZeroCopyUiState::from_ecs(&ecs);
assert_eq!(zero_copy.health, 100);
assert_eq!(zero_copy.theme_id, 1);
}
#[test]
fn test_zero_copy_layout() {
assert!(ZeroCopyUiState::validate_layout());
}
}