Skip to main content

percore_derive/
lib.rs

1// Copyright 2026 The percore Authors.
2// This project is dual-licensed under Apache 2.0 and MIT terms.
3// See LICENSE-APACHE and LICENSE-MIT for details.
4
5use proc_macro::TokenStream;
6use quote::quote;
7use syn::{ItemStatic, parse_macro_input};
8
9/// Marks the variable as percore, creating an instance for each core.
10///
11/// This replaces the static with a `percore::derive::LinkedPerCore` of the same name and places it
12/// in the `percore` linker section. The static's symbol is the base address of the per-core variable
13/// and can be used to access it from assembly.
14///
15/// # Example
16///
17/// ```
18/// use percore::{ExceptionLock, derive::percore};
19/// use core::cell::RefCell;
20///
21/// #[percore]
22/// static VARIABLE: ExceptionLock<RefCell<u64>> = ExceptionLock::new(RefCell::new(1));
23/// ```
24#[proc_macro_attribute]
25pub fn percore(_attr: TokenStream, item: TokenStream) -> TokenStream {
26    let static_item = parse_macro_input!(item as ItemStatic);
27
28    let attrs = &static_item.attrs;
29    let vis = &static_item.vis;
30    let name = &static_item.ident;
31    let ty = &static_item.ty;
32    let expr = &static_item.expr;
33
34    quote! {
35        #[cfg_attr(any(target_os = "none", target_os = "linux", target_os = "android", target_os = "fuchsia", target_os = "psp", target_os = "freebsd", target_os = "openbsd"), unsafe(link_section = "percore"))]
36        #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), unsafe(link_section = "__DATA,__percore"))]
37        #(#attrs)*
38        #vis static #name: percore::derive::LinkedPerCore<#ty> = const {
39            let value = #expr;
40            unsafe { percore::derive::LinkedPerCore::new(value) }
41        };
42    }
43    .into()
44}