Skip to main content

DeriveMessage

Derive Macro DeriveMessage 

Source
#[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 Order

Derive 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:

  1. {Name}Wire — a #[repr(C)] Clone + Copy struct with all fields converted to Pod-safe types, plus unsafe impl Pod.
  2. From<Name> for {Name}Wire — converts the domain struct to wire.
  3. {Name}Wire::into_domain(self) -> Name — converts the wire struct back. This is an unsafe method for structs containing enum fields (since the enum discriminant is not validated), or a safe From impl for structs without enum fields.

§Field type mappings

Source typeWire typeTo wireFrom wire
f32, f64, u8..u128, i8..i128samepassthroughpassthrough
usizeu64as u64as usize
isizei64as i64as isize
boolu8if v { 1 } else { 0 }v != 0
Option<T> (T: unsigned ≤64-bit)X_value: u64, X_has: u8Some(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: u8Some(v) => (v as i64, 1), None => (0, 0)has != 0 => Some(value as T), else None
Option<u128>X_value: u128, X_has: u8Some(v) => (v, 1), None => (0, 0)has != 0 => Some(value), else None
Option<i128>X_value: u128, X_has: u8Some(v) => (v as u128, 1), None => (0, 0)has != 0 => Some(value as i128), else None
Option<usize>X_value: u64, X_has: u8Some(v) => (v as u64, 1), None => (0, 0)has != 0 => Some(value as usize), else None
Option<isize>X_value: i64, X_has: u8Some(v) => (v as i64, 1), None => (0, 0)has != 0 => Some(value as isize), else None
Option<f32>X_value: u32, X_has: u8Some(v) => (v.to_bits(), 1), None => (0, 0)has != 0 => Some(f32::from_bits(value)), else None
Option<f64>X_value: u64, X_has: u8Some(v) => (v.to_bits(), 1), None => (0, 0)has != 0 => Some(f64::from_bits(value)), else None
[T; N] (T: Pod)samepassthroughpassthrough
#[photon(as_enum)] field: Eu8v as u8transmute(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)