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
#![cfg_attr(feature = "nightly", feature(proc_macro_diagnostic))]

extern crate proc_macro;

#[macro_use]
extern crate lazy_static;

use options::MockAttrOptionsBuilder;
use proc_macro::TokenStream;
use proc_macro2::Span;
use syn::parse_macro_input;

mod codegen;
mod options;
mod type_manip;
mod error;
#[cfg(feature="debug")] mod debug;
mod id_gen;
mod util;
mod diagnostics;

use crate::codegen::{mock_impl, mocked_impl, register_types_impl};
use diagnostics::{Diagnostic, Level};

fn emit_error(err: syn::Error) {
    Diagnostic::spanned(err.span().unstable(), Level::Error, err.to_string()).emit();
}

/// Implementation `#[mocked]` attribute — main entry point of library.
/// Attribute may be used on trait, extern module, struct and impl block.
/// This itself is a thin wrapper around `mocked_impl` where actual work is done.
#[proc_macro_attribute]
pub fn mocked(attr: TokenStream, input: TokenStream) -> TokenStream {
    let opts_span = Span::call_site();

    let mut opts_builder = MockAttrOptionsBuilder::default();
    let opts_parser = syn::meta::parser(|meta| opts_builder.parse_arg(meta));
    parse_macro_input!(attr with opts_parser);
    let opts = match opts_builder.build() {
        Ok(opts) => opts,
        Err(err) => {
            emit_error(err.into());
            return proc_macro2::TokenStream::new().into();
        }
    };

    match mocked_impl(input.into(), opts_span, &opts) {
        Ok(tokens) => tokens,
        Err(err) => {
            emit_error(err);
            proc_macro2::TokenStream::new()
        },
    }
    .into()
}

#[proc_macro]
pub fn mock(input: TokenStream) -> TokenStream {
    match mock_impl(input.into()) {
        Ok(tokens) => tokens,
        Err(err) => {
            emit_error(err);
            proc_macro2::TokenStream::new()
        }
    }
    .into()
}

#[proc_macro]
pub fn register_types(input: TokenStream) -> TokenStream {
    match register_types_impl(input.into()) {
        Ok(tokens) => tokens,
        Err(err) => {
            emit_error(err);
            proc_macro2::TokenStream::new()
        }
    }
    .into()
}