• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Alorel / macroific-rs / 11197184821

05 Oct 2024 11:43PM CUT coverage: 81.468%. First build
11197184821

Pull #14

github

web-flow
Merge c8342d59b into 697e66c3a
Pull Request #14: v2

430 of 476 new or added lines in 16 files covered. (90.34%)

1099 of 1349 relevant lines covered (81.47%)

46.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.56
/modules/macroific-macro/src/attr_parse/parse_option.rs
1
use proc_macro2::Span;
2
use syn::{Attribute, DeriveInput, Token};
3

4
use macroific_attr_parse::AttributeOptions;
5
use macroific_attr_parse::__private::decode_attr_options_field;
6
use macroific_core::core_ext::MacroificCoreIdentExt;
7
use macroific_core::elements::{GenericImpl, ModulePrefix};
8

9
use super::{
10
    Delimiter, Fields, Generics, Group, Ident, ParseStream, Render, ToTokens, TokenStream, RESULT,
11
};
12
use super::{ATTR_NAME, BASE, PRIVATE};
13
use ::syn::parse::Parse;
14
use quote::{quote, TokenStreamExt};
15

16
struct Options {
17
    from_parse: bool,
18
}
19

20
impl AttributeOptions for Options {
21
    fn from_iter(_: Span, attributes: impl IntoIterator<Item = Attribute>) -> syn::Result<Self> {
5✔
22
        let mut from_parse = None;
5✔
23

24
        for attr in attributes {
7✔
25
            attr.parse_nested_meta(|meta| {
2✔
26
                if meta.path.is_ident("from_parse") {
2✔
27
                    decode_attr_options_field(&mut from_parse, &meta.path, meta.input)
2✔
28
                } else {
29
                    Ok(())
×
30
                }
31
            })?;
2✔
32
        }
33

34
        Ok(Self {
5✔
35
            from_parse: from_parse.unwrap_or(false),
5✔
36
        })
5✔
37
    }
5✔
38
}
39

40
impl Render for ParseOptionDerive {
41
    const TRAIT_NAME: &'static str = "ParseOption";
42

43
    #[inline]
44
    fn generics(&self) -> &Generics {
8✔
45
        &self.as_ref().generics
8✔
46
    }
8✔
47

48
    #[inline]
49
    fn ident(&self) -> &Ident {
8✔
50
        &self.as_ref().ident
8✔
51
    }
8✔
52

53
    fn fields(&self) -> &Fields {
3✔
54
        match self {
3✔
55
            Self::Base(_, fields) => fields,
3✔
56
            Self::FromParse(_) => {
NEW
57
                unreachable!("`fields` inapplicable for `FromParse`")
×
58
            }
59
        }
60
    }
3✔
61

NEW
62
    fn render_empty_body(ending: Option<Group>) -> TokenStream {
×
NEW
63
        quote! {
×
NEW
64
            #[inline]
×
NEW
65
            fn from_stream(_: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
×
NEW
66
                #RESULT::Ok(Self #ending)
×
NEW
67
            }
×
NEW
68
        }
×
NEW
69
    }
×
70
}
71

72
impl AsRef<ParseOptionCommonData> for ParseOptionDerive {
73
    fn as_ref(&self) -> &ParseOptionCommonData {
16✔
74
        match self {
16✔
75
            Self::Base(c, _) | Self::FromParse(c) => c,
16✔
76
        }
16✔
77
    }
16✔
78
}
79

80
pub enum ParseOptionDerive {
81
    Base(ParseOptionCommonData, Fields),
82
    FromParse(ParseOptionCommonData),
83
}
84

85
pub struct ParseOptionCommonData {
86
    ident: Ident,
87
    generics: Generics,
88
}
89

90
impl Parse for ParseOptionDerive {
91
    fn parse(input: ParseStream) -> ::syn::Result<Self> {
5✔
92
        let DeriveInput {
93
            ident,
5✔
94
            generics,
5✔
95
            data,
5✔
96
            attrs,
5✔
97
            ..
98
        } = input.parse()?;
5✔
99

100
        let opts = Options::from_iter_named(ATTR_NAME, Span::call_site(), attrs)?;
5✔
101
        let common = ParseOptionCommonData { ident, generics };
5✔
102

5✔
103
        Ok(if opts.from_parse {
5✔
104
            Self::FromParse(common)
2✔
105
        } else {
106
            Self::Base(common, data.try_into()?)
3✔
107
        })
108
    }
5✔
109
}
110

111
impl ParseOptionDerive {
112
    #[inline]
113
    fn to_tokens_from_parse(&self) -> TokenStream {
2✔
114
        let mut tokens = self.impl_generics();
2✔
115

2✔
116
        // Impl body
2✔
117
        tokens.append(Group::new(
2✔
118
            Delimiter::Brace,
2✔
119
            quote! {
2✔
120
                #[inline]
2✔
121
                fn from_stream(stream: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
2✔
122
                    #PRIVATE::decode_parse_option_from_parse(stream)
2✔
123
                }
2✔
124
            },
2✔
125
        ));
2✔
126

2✔
127
        tokens
2✔
128
    }
2✔
129

130
    #[inline]
131
    fn to_tokens_base(&self) -> TokenStream {
3✔
132
        let fields = match self.named_fields() {
3✔
133
            Ok(fields) => fields,
3✔
134
            Err(delim) => return self.render_empty(delim),
×
135
        };
136

137
        let mut tokens = self.impl_generics();
3✔
138

139
        let fn_body = Group::new(Delimiter::Brace, {
3✔
140
            let indexed_fields = super::indexed_fields(fields);
3✔
141

3✔
142
            let matches = indexed_fields.clone()
3✔
143
                .map(move |(option_var_name, field)| {
98✔
144
                    let mut stream = field.resolved_label().into_token_stream();
98✔
145
                    <Token![=>]>::default().to_tokens(&mut stream);
98✔
146

98✔
147
                    stream.append(Group::new(
98✔
148
                        Delimiter::Brace,
98✔
149
                        quote! { #PRIVATE::decode_parse_option_field(&mut #option_var_name, ident, value_source) },
98✔
150
                    ));
98✔
151

98✔
152
                    stream
98✔
153
                });
98✔
154

3✔
155
            let mut out = super::nones(fields);
3✔
156

3✔
157
            out.append_all(quote! {
3✔
158
                // Provided ident, but no value, then continued to provide the next ident
3✔
159
                if !parse.peek(::syn::Token![,]) {
3✔
160
                    for result in #PRIVATE::iterate_option_meta(parse)? {
3✔
161
                        let (ident, value_source) = result?;
3✔
162

3✔
163
                        match ::std::string::ToString::to_string(&ident).as_str() {
3✔
164
                            #(#matches)*
3✔
165
                            other => return #RESULT::Err(::syn::Error::new(::syn::spanned::Spanned::span(&ident), ::std::format!("Unrecognised attribute: `{}`", other))),
3✔
166
                        }?;
3✔
167

3✔
168
                    }
3✔
169
                }
3✔
170
            });
3✔
171

172
            RESULT.to_tokens(&mut out);
3✔
173
            <Token![::]>::default().to_tokens(&mut out);
3✔
174
            out.append(Ident::create("Ok"));
3✔
175

3✔
176
            out.append(Group::new(Delimiter::Parenthesis, {
3✔
177
                let mut out = <Token![Self]>::default().into_token_stream();
3✔
178
                let unwraps = super::unwraps(
3✔
179
                    indexed_fields,
3✔
180
                    &quote! {
3✔
181
                        ::proc_macro2::Span::call_site()
3✔
182
                    },
3✔
183
                );
3✔
184
                out.append(unwraps);
3✔
185
                out
3✔
186
            }));
3✔
187

3✔
188
            out
3✔
189
        });
3✔
190

3✔
191
        // Impl body
3✔
192
        tokens.append(Group::new(Delimiter::Brace, {
3✔
193
            let mut signature = quote! {
3✔
194
                fn from_stream(parse: ::syn::parse::ParseStream) -> ::syn::Result<Self>
3✔
195
            };
3✔
196
            signature.append(fn_body);
3✔
197
            signature
3✔
198
        }));
3✔
199

3✔
200
        GenericImpl::new(self.generics())
3✔
201
            .with_trait(ModulePrefix::new(["syn", "parse", "Parse"]))
3✔
202
            .with_target(self.ident())
3✔
203
            .to_tokens(&mut tokens);
3✔
204

3✔
205
        tokens.append(Group::new(
3✔
206
            Delimiter::Brace,
3✔
207
            quote! {
3✔
208
                #[inline]
3✔
209
                fn parse(parse: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
3✔
210
                    #BASE::ParseOption::from_stream(parse)
3✔
211
                }
3✔
212
            },
3✔
213
        ));
3✔
214

3✔
215
        tokens
3✔
216
    }
3✔
217
}
218

219
impl ToTokens for ParseOptionDerive {
NEW
220
    fn to_tokens(&self, _: &mut TokenStream) {
×
NEW
221
        unimplemented!("Use to_token_stream")
×
222
    }
223

224
    fn to_token_stream(&self) -> TokenStream {
5✔
225
        match self {
5✔
226
            Self::FromParse(_) => self.to_tokens_from_parse(),
2✔
227
            Self::Base(_, _) => self.to_tokens_base(),
3✔
228
        }
229
    }
5✔
230
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc