giftwrap/
lib.rs

1extern crate proc_macro;
2use harled::{Error, Kind};
3use proc_macro::TokenStream;
4
5//TODO noWrap/wrapDepth -> giftwrap(noWrap/wrapDepth) in docs
6
7#[macro_use]
8mod wrap;
9#[macro_use]
10mod unwrap;
11
12pub(crate) mod attrib;
13
14/// Derve macro for `From<T>` where `T` is the inner type(s) of your struct or enum.
15///
16/// Using `#[giftwrap(wrapDepth = n)]` `From` is derived for every type in the chain, which is useful for
17/// types such as `Box<T>` and `Arc<Mutex<T>>`. Setting wrapDepth to 0 will derive for all inner
18/// types. Default depth is 1.
19///
20/// Any enum variant annotated with `#[giftwrap(noWrap = true)]` will be ignored.
21///
22/// # Example
23/// ```ignore
24/// use std::sync::{Arc, Mutex};
25/// use giftwrap::Wrap;
26///
27/// #[derive(Wrap)]
28/// enum SomeEnum {
29///     Number(i64),
30///     Text(String),
31///     #[giftwrap(wrapDepth = 0)]
32///     DeepVariant(Arc<Mutex<bool>>),
33///     #[giftwrap(noWrap = true)]
34///     Real(f64),
35/// }
36///
37/// //would generate
38/// impl From<i64> for SomeEnum {
39///     fn from(f: i64) -> Self {
40///         SomeEnum::Number(f)
41///     }
42/// }
43///
44/// impl From<String> for SomeEnum {
45///     fn from(f: String) -> Self {
46///         SomeEnum::Text(f)
47///     }
48/// }
49///
50/// impl From<Arc<Mutex<bool>>> for SomeEnum {
51///     fn from(f: Arc<Mutex<bool>>) -> Self {
52///         SomeEnum::DeepVariant(f)
53///     }
54/// }
55///
56/// impl From<Mutex<bool>> for SomeEnum {
57///     fn from(f: Mutex<bool>) -> Self {
58///         SomeEnum::DeepVariant(Arc::<_>::from(f))
59///     }
60/// }
61///
62/// impl From<bool> for SomeEnum {
63///     fn from(f: bool) -> Self {
64///         SomeEnum::DeepVariant(Arc::<_>::from(Mutex::<_>::from(f)))
65///     }
66/// }
67/// ```
68#[proc_macro_derive(Wrap, attributes(giftwrap))]
69pub fn derive_wrap(input: TokenStream) -> TokenStream {
70    let wrap: Result<wrap::Derive, _> = harled::parse(input);
71    match wrap.map_err(|e| match e {
72        Error::Unsupported(Kind::Union, span) => wrap::Error::For(span, "Union").into(),
73        Error::Syn(syn) => syn,
74        _ => unreachable!(),
75    }) {
76        Ok(wrap) => wrap.derive().into(),
77        Err(syn) => syn.to_compile_error().into(),
78    }
79}
80
81/// Derve macro for `impl From<S> for T` and `impl TryFrom<E> for T` for structs (`S`) and enums (`E`) where `T` is the inner type(s).
82///
83/// Any enum variant annotated with `#[giftwrap(noUnwrap = true)]` will be ignored.
84///
85/// # Example
86/// ```ignore
87/// use std::convert::TryFrom;
88/// use giftwrap::Unwrap;
89///
90/// #[derive(Unwrap)]
91/// enum SomeEnum {
92///     Number(i64),
93///     Text(String),
94///     #[giftwrap(noUnwrap = true)]
95///     Real(f64),
96/// }
97///
98/// //would generate
99/// impl TryFrom<SomeEnum> for i64 {
100///     type Error = &'static str;
101///
102///     fn try_from(f: SomeEnum) -> Self {
103///         match f {
104///             SomeEnum::Number(v) => v,
105///             SomeEnum::Text(_) => "Cannot convert SomeEnum::Text into i64",
106///             //...
107///         }
108///     }
109/// }
110///
111/// impl TryFrom<SomeEnum> for String {
112///     type Error = &'static str;
113///
114///     fn try_from(f: SomeEnum) -> Self {
115///         match f {
116///             SomeEnum::Text(v) => v,
117///             SomeEnum::Number(_) => "Cannot convert SomeEnum::Number into String",
118///             //...
119///         }
120///     }
121/// }
122/// ```
123#[proc_macro_derive(Unwrap, attributes(giftwrap))]
124pub fn derive_unwrap(input: TokenStream) -> TokenStream {
125    let unwrap: Result<unwrap::Derive, _> = harled::parse(input);
126    match unwrap.map_err(|e| match e {
127        Error::Unsupported(Kind::Union, span) => unwrap::Error::For(span, "Union").into(),
128        Error::Syn(syn) => syn,
129        _ => unreachable!(),
130    }) {
131        Ok(unwrap) => unwrap.derive().into(),
132        Err(syn) => syn.to_compile_error().into(),
133    }
134}
135
136pub(crate) enum GetFieldError {
137    Unit(proc_macro2::Span),
138    NotSingle(proc_macro2::Span),
139}
140
141pub(crate) fn get_field(fields: &syn::Fields) -> Result<&syn::Field, GetFieldError> {
142    use syn::spanned::Spanned;
143    match fields {
144        syn::Fields::Named(f) => {
145            if f.named.len() != 1 {
146                Err(GetFieldError::NotSingle(f.brace_token.span))
147            } else {
148                Ok(f.named.first().unwrap())
149            }
150        }
151        syn::Fields::Unnamed(f) => {
152            if f.unnamed.len() != 1 {
153                Err(GetFieldError::NotSingle(f.paren_token.span))
154            } else {
155                Ok(f.unnamed.first().unwrap())
156            }
157        }
158        syn::Fields::Unit => Err(GetFieldError::Unit(fields.span())),
159    }
160}