1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//! Derive/attribute macros for simics-api
#![deny(clippy::unwrap_used)]
#![deny(missing_docs)]
#![forbid(unsafe_code)]
use attr_value::{
from_attr_value_dict_impl, from_attr_value_list_impl, into_attr_value_dict_impl,
into_attr_value_list_impl,
};
use class::{class_derive_impl, class_impl};
use conf_object::{as_conf_object_impl, from_conf_object_impl};
use exception::simics_exception_impl;
use init::simics_init_impl;
use interface::interface_impl;
use proc_macro::TokenStream;
mod attr_value;
mod class;
mod conf_object;
mod exception;
mod init;
mod interface;
#[allow(non_snake_case)]
#[proc_macro_derive(IntoAttrValueList, attributes(attr_value))]
/// Derive Macro for implementing conversion into an `AttrValue` list, where each struct
/// field's value is an entry in the heterogeneous list.
///
/// # Arguments
///
/// At the field level (i.e. on each field of a struct deriving this attribute), the
/// following attributes are supported:
///
/// * `#[attr_value(skip)]` - Do not include this field in the conversion.
/// * `#[attr_value(fallible)]` - If the field type does not implement `Into<AttrValue>`,
/// use its implementation of `TryInto<AttrValue>` instead. Whether this flag is necessary
/// cannot be automatically determined by this macro, so it must be specified manually.
pub fn IntoAttrValueList(input: TokenStream) -> TokenStream {
into_attr_value_list_impl(input)
}
#[allow(non_snake_case)]
#[proc_macro_derive(IntoAttrValueDict, attributes(attr_value))]
/// Derive Macro for implementing conversion into an `AttrValue` dictionary, where each
/// struct field's key, value pair is an entry in the dictionary.
///
/// # Arguments
///
/// At the field level (i.e. on each field of a struct deriving this attribute), the
/// following attributes are supported:
///
/// * `#[attr_value(skip)]` - Do not include this field in the conversion.
/// * `#[attr_value(fallible)]` - If the field type does not implement `Into<AttrValue>`,
/// use its implementation of `TryInto<AttrValue>` instead. Whether this flag is necessary
/// cannot be automatically determined by this macro, so it must be specified manually.
pub fn IntoAttrValueDict(input: TokenStream) -> TokenStream {
into_attr_value_dict_impl(input)
}
#[allow(non_snake_case)]
#[proc_macro_derive(FromAttrValueList, attributes(attr_value))]
/// Derive Macro for implementing conversion from an `AttrValue` list into a struct, where
/// each entry in the list is a struct field's value.
///
/// # Arguments
///
/// At the field level (i.e. on each field of a struct deriving this attribute), the
/// following attributes are supported:
///
/// * `#[attr_value(fallible)]` - If the field type does not implement `From<AttrValue>`,
/// use its implementation of `TryFrom<AttrValue>` instead. Whether this flag is necessary
/// cannot be automatically determined by this macro, so it must be specified manually.
pub fn FromAttrValueList(input: TokenStream) -> TokenStream {
from_attr_value_list_impl(input)
}
#[allow(non_snake_case)]
#[proc_macro_derive(FromAttrValueDict, attributes(attr_value))]
/// Derive Macro for implementing conversion from an `AttrValue` dict into a struct, where
/// each key, value pair in the dict is a struct field's name, value pair.
///
/// # Arguments
///
/// At the field level (i.e. on each field of a struct deriving this attribute), the
/// following attributes are supported:
///
/// * `#[attr_value(fallible)]` - If the field type does not implement `From<AttrValue>`,
/// use its implementation of `TryFrom<AttrValue>` instead. Whether this flag is necessary
/// cannot be automatically determined by this macro, so it must be specified manually.
pub fn FromAttrValueDict(input: TokenStream) -> TokenStream {
from_attr_value_dict_impl(input)
}
#[allow(non_snake_case)]
#[proc_macro_derive(Class, attributes(class))]
/// Derive macro for implementing the `Class` trait for the annotated type
pub fn Class(input: TokenStream) -> TokenStream {
class_derive_impl(input)
}
#[proc_macro_attribute]
/// Attribute macro for declaring a Simics class for a Rust struct type
pub fn class(args: TokenStream, input: TokenStream) -> TokenStream {
class_impl(args, input)
}
#[allow(non_snake_case)]
#[proc_macro_derive(AsConfObject, attributes(conf_object))]
/// Derive macro for implementing conversion to raw `ConfObject` pointers.
/// This macro implements the `AsConfObject` trait for the annotated type.
pub fn AsConfObject(input: TokenStream) -> TokenStream {
as_conf_object_impl(input)
}
#[allow(non_snake_case)]
#[proc_macro_derive(FromConfObject, attributes(conf_object))]
/// Derive macro for implementing conversion from raw `ConfObject` pointers.
/// This macro implements the `FromConfObject` trait for the annotated type.
///
/// # Arguments
///
/// At the item level (i.e. on the struct deriving this attribute), the following
/// attributes are supported:
///
/// * `#[conf_object(skip_from)]` - Skip also implementing `From<*_ ConfObject>` which is the
/// default behavior.
pub fn FromConfObject(input: TokenStream) -> TokenStream {
from_conf_object_impl(input)
}
#[proc_macro_attribute]
/// Marks a function as being a SIMICS API that can throw exceptions in called FFI APIs.
///
/// A SIMICS exception can be generated by most APIs. This macro makes the function
/// private, wraps it, and adds the requisite code to check for and report exceptions.
/// `clear_exception` should *not* be called inside the wrapped function. `last_error`
/// may be called, however, as any exceptions will be cleared after the wrapped function
/// returns.
///
/// # Examples
///
/// Add the `#[simics_exception]` attribute to a function which calls a SIMICS API that can throw
/// exceptions. The function will be wrapped and the requisite code to check for and report
/// exceptions will be added.
///
/// ```rust,ignore
/// #[simics_exception]
/// pub fn write_byte(physical_memory: *mut ConfObject, physical_addr: u64, byte: u8) {
/// unsafe { SIM_write_byte(physical_memory, physical_addr, byte) };
/// }
/// ```
///
/// This expands to:
///
/// ```rust,ignore
/// fn _write_byte(physical_memory: *mut ConfObject, physical_addr: u64, byte: u8) {
/// unsafe { SIM_write_byte(physical_memory, physical_addr, byte) };
/// }
///
/// pub fn write_byte(physical_memory: *mut ConfObject, physical_addr: u64, byte: u8) -> Result<()> {
/// let res = _write_byte(physical_memory, physical_addr, byte);
///
/// match simics::get_pending_exception() {
/// SimException::SimExc_No_Exception => Ok(()),
/// exception => {
/// clear_exception();
/// Err(Error::from(exception))
/// }
/// }
/// }
/// ```
pub fn simics_exception(args: TokenStream, input: TokenStream) -> TokenStream {
simics_exception_impl(args, input)
}
#[proc_macro_attribute]
/// Mark a function as being the initializer of a Simics module.
///
/// This function will be called on module load and should be used to initialize the
/// module. This macro will add the requisite
/// code to call the function on module load.
pub fn simics_init(args: TokenStream, input: TokenStream) -> TokenStream {
simics_init_impl(args, input)
}
#[proc_macro_attribute]
/// Declare a struct implementation as a SIMICS API interface.
///
/// This macro will add the requisite code to implement the interface which allows
/// methods in the impl to be called
/// from Simics scripts in Python or the Simics language.
pub fn interface(args: TokenStream, input: TokenStream) -> TokenStream {
interface_impl(args, input)
}