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
mod wrapper;

use proc_macro::TokenStream;
use syn::{DeriveInput, parse_macro_input};

/// ```
/// use dmutils_derive::wrapper;
/// use dmutils::*;
/// 
/// #[derive(Clone)]
/// struct NewPoint {
///     x: f64,
///     y: f64,
/// }
///
/// // the following two lines can be changed to
/// // `type Point = std::sync::Arc<NewPoint>`
/// // and the test still pass.
/// // This enables you to switch between "value type"
/// // and "reference type" without too many rewrites.
/// #[wrapper(ptr)]
/// struct Point(NewPoint);
///
/// let mut p: Point = NewPoint {
///     x: 2.0,
///     y: -1.5,
/// }.into();
///
/// assert_eq!(p.x, 2.0);
/// assert_eq!(p.y, -1.5);
///
/// p.mutate().x = 0.3;
/// assert_eq!(p.x, 0.3);
/// assert_eq!(p.y, -1.5);
/// ```
///
/// ```
/// use dmutils_derive::wrapper;
/// use dmutils::*;
/// use std::convert::TryFrom;
/// 
/// // misu = Make Illegal State Unpresentable
/// #[wrapper(misu)]
/// pub struct Pos(i32);
/// impl TryFrom<i32> for Pos {
///     type Error = String;
///
///     fn try_from(value: i32) -> Result<Self, Self::Error> {
///         if value > 0 {
///             Ok(Pos(value))
///         } else {
///             Err(format!("'{}' is not positive", value))
///         }
///     }
/// }
///
/// let pos = Pos::try_from(2).unwrap();
/// let _ref = pos.as_ref();
/// let _ref = &*pos;
/// let _back_to_primitive: i32 = pos.into();

#[proc_macro_attribute]
pub fn wrapper(attr: TokenStream, item: TokenStream) -> TokenStream {
    let derive_input = parse_macro_input!(item as DeriveInput);
    wrapper::new(attr, derive_input)
        .unwrap_or_else(|e| e.to_compile_error())
        .into()
}