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
//! This crate provides shared macros to:
//!
//! - clone structs asynchronously
//! - create an ockam node and access its `Context`
//! - write some node-related tests
//!
#![deny(
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unused_import_braces,
unused_qualifications,
warnings
)]
//! Procedural macros for use with Ockam.
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, ItemFn};
mod async_try_clone_derive;
mod internals;
mod message_derive;
mod node_attribute;
mod node_test_attribute;
mod vault_test_attribute;
/// Implements the [`AsyncTryClone`](https://docs.rs/ockam_core/latest/ockam_core/traits/trait.AsyncTryClone.html) trait for a type.
///
/// The macro supports the following attributes:
///
/// - `#[async_try_clone(crate = "...")]`: specify a path to the crate that
/// will be used to import the items required by the macro. This can be
/// helpful when using the macro from an internal `ockam` crate. Defaults
/// to `ockam`.
///
/// Example of use:
///
/// ```ignore
/// #[derive(ockam::AsyncTryClone)]
/// #[async_try_clone(crate = "ockam")]
/// pub struct MyStruct {
/// a: u32,
/// }
/// ```
#[proc_macro_derive(AsyncTryClone, attributes(async_try_clone))]
pub fn async_try_clone_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
async_try_clone_derive::expand(input)
.unwrap_or_else(to_compile_errors)
.into()
}
/// Implements the [`Message`](https://docs.rs/ockam_core/latest/ockam_core/trait.Message.html) trait for a type.
///
/// Example of use:
///
/// ```ignore
/// #[derive(ockam::Message, Deserialize, Serialize)]
/// pub struct MyStruct {
/// a: u32,
/// }
/// ```
#[proc_macro_derive(Message)]
pub fn message_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
message_derive::expand(input).unwrap_or_else(to_compile_error)
}
/// Marks an async function to be run in an ockam node.
///
/// The `#[node]` macro transform an async input main function into a regular
/// output main function that sets up an ockam node and executes the body of
/// the input function inside the node.
///
/// The macro supports the following attributes:
///
/// - `#[ockam::node(crate = "...")]`: specify a path to the crate that will be
/// used to import the items required by the macro. This can be helpful
/// when using the macro from an internal `ockam` crate. Defaults to
/// `ockam`.
///
/// - #[ockam::node(no_main)]: by default, this macro executes the provided
/// function within the standard entry point function `main`. If your target
/// device doesn't support this entry point, use this argument to execute the
/// input function within your own entry point as a separate function.
///
/// Example of use:
///
/// ```ignore
/// #[ockam::node]
/// async fn main(mut ctx: ockam::Context) -> ockam::Result<()> {
/// ctx.stop().await
/// }
/// ```
#[proc_macro_attribute]
pub fn node(args: TokenStream, item: TokenStream) -> TokenStream {
let input_fn = syn::parse_macro_input!(item as ItemFn);
node_attribute::expand(input_fn, &args.into())
.unwrap_or_else(to_compile_errors)
.into()
}
/// Marks an async test function to be run in an ockam node.
///
/// It transforms an async input function into a test output function that sets
/// up an ockam node and executes the body of the input function inside the
/// node.
///
/// The macro supports the following attributes:
///
/// - `#[ockam::test(crate = "...")]`: specify a path to the crate that will be
/// used to import the items required by the macro. This can be helpful
/// when using the macro from an internal `ockam` crate. Defaults to
/// `ockam_node`.
///
/// - `#[ockam::test(timeout = 1000)]`: the macro executes the test with a
/// timeout interval (in milliseconds) to avoid blocking the test
/// indefinitely. If the test times out it will panic. Defaults to 30000 (30
/// seconds).
///
/// Example of use:
///
/// ```ignore
/// #[ockam::test]
/// async fn main(mut ctx: ockam::Context) -> ockam::Result<()> {
/// ctx.stop().await
/// }
/// ```
#[proc_macro_attribute]
pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
let input_fn = syn::parse_macro_input!(item as ItemFn);
node_test_attribute::expand(input_fn, &args.into())
.unwrap_or_else(to_compile_errors)
.into()
}
/// Expands to a test suite for a custom implementation of the vault traits.
///
/// The name of the test function must match one of the test functions
/// accompanying the traits definitions in the `ockam_vault::traits` module.
///
/// Example of use:
///
/// ```ignore
/// use ockam_vault::Vault;
///
/// fn new_vault() -> Vault {
/// Vault::default()
/// }
///
/// #[ockam_macros::vault_test]
/// fn hkdf() {}
/// ```
#[proc_macro_attribute]
pub fn vault_test(_attrs: TokenStream, item: TokenStream) -> TokenStream {
let input_fn = parse_macro_input!(item as ItemFn);
vault_test_attribute::expand(input_fn).unwrap_or_else(to_compile_error)
}
fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
let compile_errors = errors.iter().map(syn::Error::to_compile_error);
quote!(#(#compile_errors)*)
}
fn to_compile_error(error: syn::Error) -> TokenStream {
error.to_compile_error().into()
}