extruct_macros/
lib.rs

1use proc_macro::TokenStream;
2
3#[cfg(any(feature = "extruct_from", doc))]
4mod extruct_from;
5#[cfg(any(feature = "fields", doc))]
6mod fields;
7mod utils;
8
9/// A derive macro implements the [`Fields`](trait.Fields.html) trait for a struct.
10///
11/// [`Fields`] can annotate a named struct, a unit struct or an empty unnamed
12/// (tuple-like) struct, including generic structs.
13/// It collects names of the fields from the struct definition and represents
14/// them as a list of string literals accessible through [`Fields::fields()`](trait.Fields.html#tymethod.fields).
15///
16/// ```rust
17/// # use extruct_core as extruct;
18/// # use extruct::Fields;
19/// # use extruct_macros::Fields;
20/// #[derive(Fields)]
21/// struct NamedStruct {
22///     one: String,
23///     two: u32,
24///     three: char,
25/// }
26/// assert_eq!(NamedStruct::fields(), ["one", "two", "three"]);
27/// ```
28#[cfg(any(feature = "fields", doc))]
29#[proc_macro_derive(Fields)]
30pub fn get_struct_fields(item: TokenStream) -> TokenStream {
31    match fields::parse(item.into()) {
32        Ok(ast) => {
33            let model = fields::analyze(ast);
34            let code = fields::codegen(model);
35
36            code.into()
37        }
38        Err(err) => err.to_compile_error().into(),
39    }
40}
41
42/// An attribute macro implements the [`std::convert::From`](https://doc.rust-lang.org/std/convert/trait.From.html)
43/// trait for an annotated non-generic named struct using a "superstruct" specified as
44/// the attribute parameter as a source type and the [`ExtructedFrom`](trait.ExtructedFrom.html)
45/// marker trait that indicates that struct fields populated during conversion from
46/// superstruct all have same names in both structs.
47///
48/// [`extruct_from`](macro@extruct_from) accepts a single parameter which is a non-generic type name referring
49/// to a named struct.
50///
51/// ```rust
52/// # use extruct_core as extruct;
53/// # use extruct::ExtructedFrom;
54/// # use extruct_macros::extruct_from;
55/// struct SuperStruct {
56///     one_field: String,
57///     another_field: u32,
58///     and_one_more: char,
59/// }
60///
61/// #[extruct_from(SuperStruct)]
62/// struct SubStruct {
63///     and_one_more: String,
64/// }
65///
66/// fn convert_preserving_names<T, S>(sup: S) -> T
67/// where
68///     T: ExtructedFrom<S>
69/// {
70///     sup.into()
71/// }
72///
73/// let sup = SuperStruct {
74///     one_field: "str".to_owned(),
75///     another_field: 1135,
76///     and_one_more: 'x',
77/// };
78///
79/// let sub: SubStruct = convert_preserving_names(sup);
80/// ```
81#[cfg(any(feature = "extruct_from", doc))]
82#[proc_macro_attribute]
83pub fn extruct_from(attr: TokenStream, item: TokenStream) -> TokenStream {
84    match extruct_from::parse(attr.into(), item.into()) {
85        Ok(ast) => {
86            let model = extruct_from::analyze(ast);
87            let code = extruct_from::codegen(model);
88
89            code.into()
90        }
91        Err(err) => err.to_compile_error().into(),
92    }
93}