riscv_macros/lib.rs
1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput};
4
5mod riscv;
6
7/// Attribute-like macro that implements the traits of the `riscv-pac` crate for a given enum.
8///
9/// As these traits are unsafe, the macro must be called with the `unsafe` keyword followed by the trait name.
10/// In this way, we warn callers that they must comply with the requirements of the trait.
11///
12/// The trait name must be one of `ExceptionNumber`, `CoreInterruptNumber`, `ExternalInterruptNumber`,
13/// `PriorityNumber`, or `HartIdNumber`.
14///
15/// # Note
16///
17/// Crates using this macro must depend on the `riscv` crate, as the generated code references it.
18///
19/// If the `rt` feature is enabled, the generated code may also include the necessary runtime support
20/// for interrupt and exception handling. Thus, the calling crate must also depend on the `riscv-rt` crate.
21///
22/// # Safety
23///
24/// The struct to be implemented must comply with the requirements of the specified trait.
25///
26/// # Example
27///
28/// ```rust,ignore,no_run
29/// use riscv::*;
30///
31/// #[repr(usize)]
32/// #[pac_enum(unsafe ExceptionNumber)]
33/// #[derive(Clone, Copy, Debug, Eq, PartialEq)]
34/// enum Exception {
35/// E1 = 1,
36/// E3 = 3,
37/// }
38///
39/// assert_eq!(Exception::E1.number(), 1);
40/// assert_eq!(Exception::E3.number(), 3);
41///
42/// assert_eq!(Exception::from_number(1), Ok(Exception::E1));
43/// assert_eq!(Exception::from_number(2), Err(2));
44/// assert_eq!(Exception::from_number(3), Ok(Exception::E3));
45///
46/// assert_eq!(Exception::MAX_EXCEPTION_NUMBER, 3);
47///```
48#[proc_macro_attribute]
49pub fn pac_enum(attr: TokenStream, item: TokenStream) -> TokenStream {
50 let input = parse_macro_input!(item as DeriveInput);
51 let pac_enum = riscv::PacEnumItem::new(&input);
52
53 let attr = parse_macro_input!(attr as riscv::PacTrait);
54
55 let trait_impl = pac_enum.impl_trait(&attr);
56 quote! {
57 #input
58 #(#trait_impl)*
59 }
60 .into()
61}