# `#[gpu_struct]` — GPU-Safe Struct Macro
The `#[gpu_struct]` attribute macro transforms ordinary Rust structs into GPU-ABI-compatible host-side representations, ensuring correct memory layout for CUDA, Metal, and future OpenCL kernel parameter passing.
## Quick Start
```rust
use prgpu::gpu_struct;
#[gpu_struct]
pub struct MyParams {
pub time: f32,
pub intensity: f32,
pub enabled: bool, // automatically mapped to u32 for GPU ABI
}
```
This generates:
- `#[repr(C, align(N))]` with the correct GPU alignment
- `bytemuck::Pod` + `bytemuck::Zeroable` derives (when possible)
- `Clone`, `Copy`, `Debug` derives
- `SIZE` and `ALIGN` constants on the impl block
- `enabled_bool()` helper method for the `bool → u32` field
- Compile-time const assertions verifying size and alignment
- Explicit padding fields (when `bytemuck` or `pad` is enabled) so every byte is defined
## Attribute Options
| `targets(cuda, metal)` | `cuda, metal` | Target GPU backends for layout rules |
| `align = N` | auto | Force minimum alignment to N bytes (must be power of 2) |
| `bytemuck = bool` | `true` | Auto-derive `bytemuck::Pod` + `bytemuck::Zeroable` |
| `pad` | `false` | Inject explicit padding fields even without bytemuck |
| `allow_vec3` | `false` | Allow `[f32; 3]`, `[u32; 3]`, `[i32; 3]` arrays |
| `allow_bool` | `true` | Allow `bool` fields (mapped to `u32`) |
| `debug_layout` | `false` | Emit `FIELD_OFFSET` constants and field offset assertions |
| `emit_offsets` | `false` | Emit `FIELD_OFFSET` constants (same as debug_layout but without assertions) |
| `strict` | `false` | Reject `bool`, `f64`, and other questionable types |
## Supported Field Types
### Scalars
| `u8`, `i8` | 1 | 1 |
| `u16`, `i16` | 2 | 2 |
| `u32`, `i32`, `f32` | 4 | 4 |
| `u64`, `i64`, `f64` | 8 | 8 |
| `bool` | 4 (as `u32`) | 4 |
### Vector Types
| `Vec2` | 8 | 8 | `{ x: f32, y: f32 }` |
| `Vec3` | 16 | 16 | `{ x: f32, y: f32, z: f32, _pad: u32 }` |
`Vec2` and `Vec3` are recognized only from trusted paths: `Vec2`, `crate::Vec2`, `crate::types::Vec2`, `crate::types::maths::Vec2`, `prgpu::Vec2`, `prgpu::types::Vec2`, `prgpu::types::maths::Vec2` (and the same for `Vec3`).
### Arrays
Fixed-size arrays of supported types: `[f32; 4]`, `[[f32; 4]; 4]`, etc.
By default, `[f32; 3]`, `[u32; 3]`, and `[i32; 3]` are **rejected** because their GPU ABI is ambiguous (3×4 = 12 bytes without padding vs. Vec3's 16 bytes with padding). Use `Vec3` instead, or enable `allow_vec3` if you truly want the unpadded 12-byte layout.
### Nested Structs
Other `#[gpu_struct]`-annotated structs and built-in types like `Transform` are allowed as nested fields, but you must annotate them with `#[gpu_nested]`:
```rust
#[gpu_struct]
pub struct Inner {
pub x: f32,
pub y: f32,
}
#[gpu_struct]
pub struct Outer {
#[gpu_nested]
pub inner: Inner,
pub z: f32,
}
```
When a struct contains `#[gpu_nested]` fields, `bytemuck::Pod` cannot be derived automatically (the macro can't verify the nested type has no implicit padding), so only `Clone`, `Copy`, `Debug` are derived.
## Bool → u32 Mapping
GPU kernels don't have a standard `bool` type. By default, `#[gpu_struct]` maps `bool` fields to `u32` on the host side:
```rust
#[gpu_struct]
pub struct Params {
pub enabled: bool, // becomes `enabled: u32` in the transformed struct
}
// Access the bool value:
let p = Params { enabled: 1u32 };
assert!(p.enabled_bool()); // true
let p2 = Params { enabled: 0u32 };
assert!(!p2.enabled_bool()); // false
```
In `strict` mode, `bool` is rejected entirely — use `u32` explicitly.
## Rejected Types
| `usize`, `isize` | Platform-dependent size (32 or 64 bit) |
| `Vec<T>`, `Box<T>`, etc. | Heap-allocated, not GPU-safe |
| `&T`, `&mut T` | References don't make sense in GPU memory |
| Tuples `(A, B)` | No stable ABI layout |
| `other::Vec3` | Not a trusted path — use `prgpu::Vec3` |
## Compile-Time Guarantees
The macro emits const assertions that fail at compile time if the generated struct doesn't match the expected layout:
```rust
const _: () = {
assert!(core::mem::size_of::<MyStruct>() == EXPECTED);
assert!(core::mem::align_of::<MyStruct>() == EXPECTED);
};
```
With `debug_layout`, field offset assertions are also emitted:
```rust
const _: () = {
assert!(core::mem::offset_of!(MyStruct, field) == EXPECTED_OFFSET);
};
```
## Padding Field Injection
When `bytemuck = true` (default) or `pad` is enabled, the macro injects explicit padding fields so that `bytemuck::Pod` can be derived (Pod requires every byte of the struct to be defined):
```rust
#[gpu_struct]
pub struct MixedAlignment {
pub x: u32, // offset 0, size 4
pub b: u8, // offset 4, size 1
pub y: u32, // offset 8, size 4 (3 bytes padding at offset 5-7)
}
// Transformed to:
#[repr(C, align(4))]
pub struct MixedAlignment {
pub x: u32,
pub b: u8,
#[doc(hidden)]
_prgpu_pad_0: [u8; 3],
pub y: u32,
#[doc(hidden)]
_prgpu_pad_tail: [u8; 0], // no tail padding needed here
}
```
When `bytemuck = false` and `pad` is not set, no padding fields are injected — the struct relies on `#[repr(C)]`'s implicit padding. This is simpler but means `bytemuck::Pod` cannot be derived.
## Interaction with `kernel_params!`
The `#[gpu_struct]` macro is designed to coexist with the existing `kernel_params!` macro. Over time, `kernel_params!` will be updated to recognize `#[gpu_struct]`-annotated types and use their `SIZE`/`ALIGN` constants directly.