1extern crate deq_core;
2extern crate proc_macro;
3extern crate quote;
4extern crate syn;
5use proc_macro::TokenStream;
6use quote::quote;
7use syn::{parse::Parser, parse_macro_input, DeriveInput};
8
9#[proc_macro_derive(Transaction)]
11pub fn transaction_macro_derive(input: TokenStream) -> TokenStream {
12 let ast = syn::parse(input).unwrap();
15
16 impl_transaction_macro(&ast)
18}
19
20#[proc_macro_attribute]
25pub fn transaction_fields(_args: TokenStream, input: TokenStream) -> TokenStream {
26 let mut ast = parse_macro_input!(input as DeriveInput);
27 match &mut ast.data {
28 syn::Data::Struct(ref mut struct_data) => {
29 match &mut struct_data.fields {
30 syn::Fields::Named(fields) => {
31 fields.named.push(
32 syn::Field::parse_named
33 .parse2(quote! { pub transaction_data: TransactionData<Self> })
34 .unwrap(),
35 );
36 }
37 _ => (),
38 }
39
40 return quote! {
41 #ast
42 }
43 .into();
44 }
45 _ => panic!("`transactions_fields` must be used with structs"),
46 }
47}
48
49fn impl_transaction_macro(ast: &syn::DeriveInput) -> TokenStream {
50 let name = &ast.ident;
51 let gen = quote! {
52 impl Transaction for #name {
53 fn begin(&mut self) {
54 self.transaction_data.t.push(self.clone());
55 }
56
57 fn commit(&mut self) -> Result<(), TransactionError> {
58 match self.transaction_data.t.pop() {
59 Some(_) => Ok(()),
60 None => Err(TransactionError::new(TransactionErrorType::TransactionNotStarted))
61 }
62 }
63
64 fn revert(&mut self) -> Result<(), TransactionError> {
65 match self.transaction_data.t.pop() {
66 Some(prev) => {
67 *self = prev;
68 return Ok(());
69 },
70 None => Err(TransactionError::new(TransactionErrorType::TransactionNotStarted))
71 }
72 }
73
74 fn len(&self) -> usize {
75 self.transaction_data.t.len()
76 }
77 }
78 };
79 gen.into()
80}