ostd_pod_macros/lib.rs
1// SPDX-License-Identifier: MPL-2.0
2
3#![doc = include_str!("../README.md")]
4
5use proc_macro::TokenStream;
6
7mod pod_derive;
8mod pod_union;
9
10/// An attribute macro that replaces `#[derive(Pod)]` with the corresponding zerocopy traits.
11#[proc_macro_attribute]
12pub fn derive(attrs: TokenStream, input: TokenStream) -> TokenStream {
13 pod_derive::expand_derive(attrs, input)
14}
15
16/// An attribute macro that enables safe usage of unions as POD types.
17///
18/// Rust's built-in unions cannot directly derive `zerocopy::IntoBytes` because unions require
19/// field-by-field initialization and access. The `#[pod_union]` macro solves this by
20/// transforming a union into a safe wrapper struct.
21///
22/// # Implementation details
23///
24/// When you write:
25///
26/// ```rust
27/// use ostd_pod_macros::pod_union;
28///
29/// #[repr(C)]
30/// #[pod_union]
31/// #[derive(Clone, Copy)]
32/// pub union Data {
33/// value: u64,
34/// bytes: [u8; 4],
35/// }
36/// ```
37///
38/// The `#[pod_union]` macro internally generates something equivalent to:
39///
40/// ```rust
41/// use ostd_pod::array_helper::{ArrayFactory, ArrayManufacture, U64Array};
42/// use ostd_pod::{FromBytes, FromZeros, Immutable, IntoBytes, KnownLayout, Pod};
43///
44/// // Internal private union
45/// #[repr(C)]
46/// #[derive(FromBytes, KnownLayout, Immutable)]
47/// union __Data__ {
48/// value: u64,
49/// bytes: [u8; 4],
50/// }
51///
52/// // Public wrapper struct that provides safe access
53/// #[repr(transparent)]
54/// #[derive(FromBytes, KnownLayout, Immutable, IntoBytes)]
55/// pub struct Data(<ArrayFactory<
56/// { align_of::<__Data__>() },
57/// { size_of::<__Data__>() / (align_of::<__Data__>()) },
58/// > as ArrayManufacture>::Array);
59///
60/// impl Data {
61/// // Field accessor methods
62/// pub fn value(&self) -> &u64 {
63/// u64::ref_from_bytes(&self.0.as_bytes()[..8]).unwrap()
64/// }
65/// pub fn value_mut(&mut self) -> &mut u64 {
66/// u64::mut_from_bytes(&mut self.0.as_mut_bytes()[..8]).unwrap()
67/// }
68/// pub fn bytes(&self) -> &[u8; 4] {
69/// <[u8; 4]>::ref_from_bytes(&self.0.as_bytes()[..4]).unwrap()
70/// }
71/// pub fn bytes_mut(&mut self) -> &mut [u8; 4] {
72/// <[u8; 4]>::mut_from_bytes(&mut self.0.as_mut_bytes()[..4]).unwrap()
73/// }
74///
75/// // Initializer methods
76/// pub fn new_value(value: u64) -> Self {
77/// let mut slf = Self::new_zeroed();
78/// *slf.value_mut() = value;
79/// slf
80/// }
81/// pub fn new_bytes(bytes: [u8; 4]) -> Self {
82/// let mut slf = Self::new_zeroed();
83/// *slf.bytes_mut() = bytes;
84/// slf
85/// }
86/// }
87/// ```
88#[proc_macro_attribute]
89pub fn pod_union(_attr: TokenStream, item: TokenStream) -> TokenStream {
90 let input = syn::parse_macro_input!(item as syn::DeriveInput);
91 pod_union::expand_pod_union(input).into()
92}