|
| 1 | +use proc_macro::TokenStream; |
| 2 | + |
| 3 | +mod dcfg; |
| 4 | +mod ram; |
| 5 | + |
| 6 | +/// This attribute places the annotated function or static variable into the internal RAM |
| 7 | +/// of the ESP32 chip. |
| 8 | +/// |
| 9 | +/// # Possible issues with functions |
| 10 | +/// |
| 11 | +/// If a function is placed into RAM, the literals are not automatically placed into RAM as well: |
| 12 | +/// |
| 13 | +/// ```rust,ignore |
| 14 | +/// #[ram] |
| 15 | +/// fn gpio_isr_handler() -> usize { |
| 16 | +/// let s = "I am string still stored in flash"; |
| 17 | +/// } |
| 18 | +/// ``` |
| 19 | +/// |
| 20 | +/// To store the literal in flash, one could do |
| 21 | +/// ```rust,ignore |
| 22 | +/// #[ram] |
| 23 | +/// fn gpio_isr_handler() -> usize { |
| 24 | +/// #[ram] |
| 25 | +/// static _S: &str = "I am string still stored in flash"; |
| 26 | +/// let s = _S; |
| 27 | +/// } |
| 28 | +/// ``` |
| 29 | +/// |
| 30 | +/// # Possible issues with statics that reference data |
| 31 | +/// |
| 32 | +/// If the attribute is applied to a static variable that references some data, for example |
| 33 | +/// `#[ram] static MESSAGE: &str = "Error, invalid argument";` or `#[ram] static BUFFER: &[u8] = &[0]` |
| 34 | +/// the referenced data might not be placed into RAM. |
| 35 | +/// |
| 36 | +/// For byte string and string literals, the attribute will ensure that the referenced data is placed in |
| 37 | +/// RAM, but for arbitrary slices or references it is unable to do so. |
| 38 | +/// |
| 39 | +/// The first option is to declare an owned static array that is then referenced by the static variable, |
| 40 | +/// applying the ram attribute to both: |
| 41 | +/// |
| 42 | +/// ```rust,ignore |
| 43 | +/// #[ram] |
| 44 | +/// static BUFFER_DATA: [u8; 3] = [0, 1, 2]; |
| 45 | +/// #[ram] |
| 46 | +/// static BUFFER: &[u8] = &BUFFER_DATA; |
| 47 | +/// ``` |
| 48 | +/// |
| 49 | +/// or like this: |
| 50 | +/// |
| 51 | +/// ```rust,ignore |
| 52 | +/// #[ram] |
| 53 | +/// static BUFFER: &[u8] = { |
| 54 | +/// #[ram] |
| 55 | +/// static DATA: [u8; 3] = [0, 1, 2]; |
| 56 | +/// DATA.as_slice() |
| 57 | +/// }; |
| 58 | +/// ``` |
| 59 | +/// |
| 60 | +/// If the slice value is [`Copy`], the attribute can do this automatically: |
| 61 | +/// ```rust,ignore |
| 62 | +/// #[ram(copy)] |
| 63 | +/// static BUFFER: [u8; 3] = &[0, 1, 2]; |
| 64 | +/// ``` |
| 65 | +#[proc_macro_attribute] |
| 66 | +pub fn ram(args: TokenStream, input: TokenStream) -> TokenStream { |
| 67 | + ram::ram(args.into(), input.into()) |
| 68 | + .unwrap_or_else(|err| err.to_compile_error().into()) |
| 69 | + .into() |
| 70 | +} |
| 71 | + |
| 72 | +/// This attribute forwards its arguments to `cfg`, and if the `doc-cfg` feature of this |
| 73 | +/// crate is enabled, it will emit a `doc(cfg(...))` attribute as well. |
| 74 | +/// |
| 75 | +/// # Example |
| 76 | +/// |
| 77 | +/// For rustdoc to document that a piece of code is only available when a specific condition is met, |
| 78 | +/// one would have to write (because it is nightly-only): |
| 79 | +/// |
| 80 | +/// ```rust,ignore |
| 81 | +/// pub enum ZeroCrossMode { |
| 82 | +// PositionZero, |
| 83 | +// NegativeZero, |
| 84 | +// NegativePosition, |
| 85 | +// PositiveNegative, |
| 86 | +// #[cfg(esp_idf_version_at_least_5_4_0)] |
| 87 | +// #[cfg_attr(feature = "nightly", doc(cfg(esp_idf_version_at_least_5_4_0)))] |
| 88 | +// Invalid, |
| 89 | +// } |
| 90 | +/// ``` |
| 91 | +/// |
| 92 | +/// with this attribute, one can shorten it to: |
| 93 | +/// |
| 94 | +/// ```rust,ignore |
| 95 | +/// pub enum ZeroCrossMode { |
| 96 | +// PositionZero, |
| 97 | +// NegativeZero, |
| 98 | +// NegativePosition, |
| 99 | +// PositiveNegative, |
| 100 | +// #[dcfg(esp_idf_version_at_least_5_4_0)] |
| 101 | +// Invalid, |
| 102 | +// } |
| 103 | +/// ``` |
| 104 | +/// |
| 105 | +/// The macro will then expand to the following if the `doc-cfg` feature is enabled: |
| 106 | +/// |
| 107 | +/// ```rust,ignore |
| 108 | +/// pub enum ZeroCrossMode { |
| 109 | +/// PositionZero, |
| 110 | +/// NegativeZero, |
| 111 | +/// NegativePosition, |
| 112 | +/// PositiveNegative, |
| 113 | +/// #[cfg(esp_idf_version_at_least_5_4_0)] |
| 114 | +/// #[doc(cfg(esp_idf_version_at_least_5_4_0))] |
| 115 | +/// Invalid, |
| 116 | +/// } |
| 117 | +/// ``` |
| 118 | +/// |
| 119 | +/// and to the following if the `doc-cfg` feature is not enabled: |
| 120 | +/// |
| 121 | +/// ```rust,ignore |
| 122 | +/// pub enum ZeroCrossMode { |
| 123 | +/// PositionZero, |
| 124 | +/// NegativeZero, |
| 125 | +/// NegativePosition, |
| 126 | +/// PositiveNegative, |
| 127 | +/// #[cfg(esp_idf_version_at_least_5_4_0)] |
| 128 | +/// Invalid, |
| 129 | +/// } |
| 130 | +/// ``` |
| 131 | +#[proc_macro_attribute] |
| 132 | +pub fn dcfg(args: TokenStream, input: TokenStream) -> TokenStream { |
| 133 | + dcfg::dcfg(args.into(), input.into()) |
| 134 | + .unwrap_or_else(|err| err.to_compile_error().into()) |
| 135 | + .into() |
| 136 | +} |
0 commit comments