Skip to main content

photon_ring_derive/
lib.rs

1// Copyright 2026 Photon Ring Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4//! Derive macro for [`photon_ring::Pod`].
5//!
6//! ```ignore
7//! #[derive(photon_ring::Pod)]
8//! struct Quote {
9//!     price: f64,
10//!     volume: u32,
11//! }
12//! ```
13//!
14//! This generates `#[repr(C)]`, `#[derive(Clone, Copy)]`, and
15//! `unsafe impl photon_ring::Pod for Quote {}` — with a compile-time
16//! check that every field type implements `Pod`.
17
18use proc_macro::TokenStream;
19use quote::quote;
20use syn::{parse_macro_input, Data, DeriveInput, Fields};
21
22/// Derive `Pod` for a struct.
23///
24/// Requirements:
25/// - Must be a struct (not enum or union).
26/// - All fields must implement `Pod`.
27/// - The struct will be given `#[repr(C)]` semantics (the macro adds
28///   `Clone` and `Copy` derives and the `unsafe impl Pod`).
29///
30/// # Example
31///
32/// ```ignore
33/// #[derive(photon_ring::Pod)]
34/// struct Tick {
35///     price: f64,
36///     volume: u32,
37///     _pad: u32,
38/// }
39/// ```
40#[proc_macro_derive(Pod)]
41pub fn derive_pod(input: TokenStream) -> TokenStream {
42    let input = parse_macro_input!(input as DeriveInput);
43    let name = &input.ident;
44    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
45
46    // Only structs are supported
47    let fields = match &input.data {
48        Data::Struct(s) => match &s.fields {
49            Fields::Named(f) => f.named.iter().collect::<Vec<_>>(),
50            Fields::Unnamed(f) => f.unnamed.iter().collect::<Vec<_>>(),
51            Fields::Unit => vec![],
52        },
53        _ => {
54            return syn::Error::new_spanned(&input.ident, "Pod can only be derived for structs")
55                .to_compile_error()
56                .into();
57        }
58    };
59
60    // Generate compile-time assertions that every field is Pod
61    let field_assertions = fields.iter().map(|f| {
62        let ty = &f.ty;
63        quote! {
64            const _: () = {
65                fn _assert_pod<T: photon_ring::Pod>() {}
66                fn _check() { _assert_pod::<#ty>(); }
67            };
68        }
69    });
70
71    let expanded = quote! {
72        // Compile-time field checks
73        #(#field_assertions)*
74
75        // Safety: all fields verified to be Pod via compile-time assertions above.
76        // The derive macro only applies to structs, and Pod requires that every
77        // bit pattern is valid — which holds when all fields are Pod.
78        unsafe impl #impl_generics photon_ring::Pod for #name #ty_generics #where_clause {}
79    };
80
81    TokenStream::from(expanded)
82}