#[derive(DeriveMessage)]
{
// Attributes available to this derive:
#[photon]
}
Expand description
Derive macro that generates a Pod-compatible wire struct from a domain struct.
Given a struct with bool, Option<numeric>, usize/isize, and
#[repr(u8)] enum fields, generates {Name}Wire plus From conversions.
Structs without enum fields get safe From impls in both directions;
structs with enum fields get From<Domain> for Wire (safe) and
Wire::into_domain() (unsafe). Requires the derive feature.
#[derive(photon_ring::DeriveMessage)]
struct Order { price: f64, side: Side, filled: bool, tag: Option<u32> }
// Generates: OrderWire, From<Order> for OrderWire, From<OrderWire> for OrderDerive a Pod-compatible wire struct with From conversions.
Given a struct with fields that may include bool, Option<numeric>,
usize/isize, and #[repr(u8)] enums, generates:
{Name}Wire— a#[repr(C)] Clone + Copystruct with all fields converted to Pod-safe types, plusunsafe impl Pod.From<Name> for {Name}Wire— converts the domain struct to wire.{Name}Wire::into_domain(self) -> Name— converts the wire struct back. This is anunsafemethod for structs containing enum fields (since the enum discriminant is not validated), or a safeFromimpl for structs without enum fields.
§Field type mappings
| Source type | Wire type | To wire | From wire |
|---|---|---|---|
f32, f64, u8..u128, i8..i128 | same | passthrough | passthrough |
usize | u64 | as u64 | as usize |
isize | i64 | as i64 | as isize |
bool | u8 | if v { 1 } else { 0 } | v != 0 |
Option<T> (T: unsigned ≤64-bit) | X_value: u64, X_has: u8 | Some(v) => (v as u64, 1), None => (0, 0) | has != 0 => Some(value as T), else None |
Option<T> (T: signed ≤64-bit) | X_value: i64, X_has: u8 | Some(v) => (v as i64, 1), None => (0, 0) | has != 0 => Some(value as T), else None |
Option<u128> | X_value: u128, X_has: u8 | Some(v) => (v, 1), None => (0, 0) | has != 0 => Some(value), else None |
Option<i128> | X_value: u128, X_has: u8 | Some(v) => (v as u128, 1), None => (0, 0) | has != 0 => Some(value as i128), else None |
Option<usize> | X_value: u64, X_has: u8 | Some(v) => (v as u64, 1), None => (0, 0) | has != 0 => Some(value as usize), else None |
Option<isize> | X_value: i64, X_has: u8 | Some(v) => (v as i64, 1), None => (0, 0) | has != 0 => Some(value as isize), else None |
Option<f32> | X_value: u32, X_has: u8 | Some(v) => (v.to_bits(), 1), None => (0, 0) | has != 0 => Some(f32::from_bits(value)), else None |
Option<f64> | X_value: u64, X_has: u8 | Some(v) => (v.to_bits(), 1), None => (0, 0) | has != 0 => Some(f64::from_bits(value)), else None |
[T; N] (T: Pod) | same | passthrough | passthrough |
#[photon(as_enum)] field: E | u8 | v as u8 | transmute(v) (unsafe) |
§Enum fields
Enum fields must be annotated with #[photon(as_enum)] to opt in
to the u8 wire encoding. Without this attribute, unrecognized types
produce a compile error. The enum must have #[repr(u8)] — the macro
emits a compile-time size_of check to enforce this.
Enum fields are stored as raw u8 on the wire. Converting back requires
that the byte holds a valid discriminant. Because the macro cannot verify
enum variants at compile time, structs with enum fields generate an
unsafe fn into_domain(self) -> DomainType method on the wire struct
instead of a safe From impl. Callers must ensure enum fields contain
valid discriminants (which is always the case when the wire data was
produced by a valid domain value via From<Domain> for Wire).
§Example
#[repr(u8)]
#[derive(Clone, Copy)]
enum Side { Buy = 0, Sell = 1 }
#[derive(photon_ring::Message)]
struct Order {
price: f64,
qty: u32,
#[photon(as_enum)]
side: Side,
filled: bool,
tag: Option<u32>,
}
// Generates: OrderWire, From<Order> for OrderWire,
// OrderWire::into_domain (unsafe, due to enum field)