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}