// 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::(), ) } } /// 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::(), ) } } /// Size in bytes - constant fn size() -> usize { size_of::() } } /// 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::() % 4 == 0, "Size must be 4-byte aligned"); // Verify field offsets assert!(size_of::() == 4, "u32 size expected"); assert!(size_of::() == 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::() } } /// 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, mut zero_copy: ResMut, ) { // 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, mut gpu_buffer: ResMut, render_device: Res, ) { // 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, ) { // 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::(), "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::()); } #[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()); } }