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

Alorel / macroific-rs / 11355108785

15 Oct 2024 10:06PM UTC coverage: 82.378%. First build
11355108785

Pull #14

github

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

474 of 517 new or added lines in 16 files covered. (91.68%)

1150 of 1396 relevant lines covered (82.38%)

45.34 hits per line

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

98.23
/modules/macroific-core/src/elements/module_prefix.rs
1
//! A `const`-table module prefix, e.g. `::your_crate::__private`.
2

3
use std::ops::{Deref, Index};
4
use std::{array, fmt};
5

6
use crate::core_ext::*;
7
use proc_macro2::{Ident, TokenStream};
8
use quote::{ToTokens, TokenStreamExt};
9
use syn::Token;
10

11
/// Prefix for [`::core::option::Option`].
12
pub const OPTION: ModulePrefix<'static, 3> = ModulePrefix::new(["core", "option", "Option"]);
13

14
/// Prefix for [`::core::result::Result`].
15
pub const RESULT: ModulePrefix<'static, 3> = ModulePrefix::new(["core", "result", "Result"]);
16

17
/// A `const`-table module prefix, e.g. `::your_crate::__private`.
18
///
19
/// ```
20
/// # use macroific_core::elements::*;
1✔
21
/// # use syn::parse_quote;
22
/// # use quote::{quote, ToTokens};
23
/// #
24
/// let prefixed = ModulePrefix::new(["foo", "bar"]);
25
/// let prefixed_stream = prefixed.to_token_stream().to_string();
1✔
26
/// assert_eq!(prefixed_stream, ":: foo :: bar");
1✔
27
///
1✔
28
/// let unprefixed = prefixed.with_leading_sep(false);
29
/// let unprefixed_stream = unprefixed.to_token_stream().to_string();
1✔
30
/// assert_eq!(unprefixed_stream, "foo :: bar");
1✔
31
///
1✔
32
/// // Display is also implemented
33
/// assert_eq!(prefixed.to_string(), prefixed_stream);
34
/// assert_eq!(unprefixed.to_string(), unprefixed_stream);
1✔
35
/// ```
1✔
36
#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
1✔
37
#[cfg(feature = "module-prefix")]
38
pub struct ModulePrefix<'a, const LEN: usize> {
39
    path: [&'a str; LEN],
40
    leading_sep: bool,
41
}
42

43
/// A chained [`ModulePrefix`] separated by `::`.
44
#[cfg(feature = "module-prefix")]
45
pub struct Chain<A, B> {
46
    a: A,
47
    b: B,
48
}
49

50
impl<'a, const LEN: usize> ModulePrefix<'a, LEN> {
51
    /// Create a new `ModulePrefix` from a slice of segments.
52
    #[inline]
53
    #[must_use]
54
    pub const fn new(segments: [&'a str; LEN]) -> Self {
6✔
55
        Self {
6✔
56
            path: segments,
6✔
57
            leading_sep: true,
6✔
58
        }
6✔
59
    }
6✔
60

61
    /// `true` (default) will include the leading `::`, `false` will omit it.
62
    #[inline]
63
    #[must_use]
64
    pub const fn with_leading_sep(mut self, leading_sep: bool) -> Self {
1✔
65
        self.leading_sep = leading_sep;
1✔
66
        self
1✔
67
    }
1✔
68
}
69

70
impl<'a, const LEN: usize> IntoIterator for ModulePrefix<'a, LEN> {
71
    type Item = &'a str;
72
    type IntoIter = array::IntoIter<&'a str, LEN>;
73

74
    #[inline]
75
    fn into_iter(self) -> Self::IntoIter {
876✔
76
        self.path.into_iter()
876✔
77
    }
876✔
78
}
79

80
impl<'a, const LEN: usize> ToTokens for ModulePrefix<'a, LEN> {
81
    fn to_tokens(&self, tokens: &mut TokenStream) {
874✔
82
        let mut iter = self.into_iter();
874✔
83

874✔
84
        if !self.leading_sep {
874✔
85
            if let Some(first) = iter.next() {
1✔
86
                tokens.append(Ident::create(first));
1✔
87
            } else {
1✔
NEW
88
                return;
×
89
            }
90
        }
873✔
91

92
        let sep = <Token![::]>::default();
874✔
93

94
        for segment in iter {
3,474✔
95
            sep.to_tokens(tokens);
2,600✔
96
            tokens.append(Ident::create(segment));
2,600✔
97
        }
2,600✔
98
    }
874✔
99
}
100

101
impl<'a, const LEN: usize> fmt::Display for ModulePrefix<'a, LEN> {
102
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2✔
103
        let mut iter = self.into_iter();
2✔
104
        let Some(first) = iter.next() else {
2✔
NEW
105
            return Ok(());
×
106
        };
107

108
        if self.leading_sep {
2✔
109
            f.write_str(":: ")?;
1✔
110
            f.write_str(first)?;
1✔
111
        } else {
112
            f.write_str(first)?;
1✔
113
        }
114

115
        for item in iter {
4✔
116
            f.write_str(" :: ")?;
2✔
117
            f.write_str(item)?;
2✔
118
        }
119

120
        Ok(())
2✔
121
    }
2✔
122
}
123

124
/// # Example
125
///
126
/// ```
127
/// # use macroific_core::elements::ModulePrefix;
1✔
128
/// #
129
/// fn accept_str_slice(_: &[&str]) {}
130
///
1✔
131
/// let prefix = ModulePrefix::new(["foo", "bar"]);
132
/// accept_str_slice(&prefix); // derefs fine
1✔
133
/// ```
1✔
134
impl<'a, const LEN: usize> Deref for ModulePrefix<'a, LEN> {
1✔
135
    type Target = [&'a str];
136

137
    #[inline]
138
    fn deref(&self) -> &Self::Target {
1✔
139
        &self.path
1✔
140
    }
1✔
141
}
142

143
/// # Example
144
///
145
/// ```
146
/// # use macroific_core::elements::ModulePrefix;
1✔
147
/// #
148
/// let prefix = ModulePrefix::new(["foo", "bar"]);
149
/// assert_eq!(&prefix[0], "foo");
1✔
150
/// assert_eq!(&prefix[1], "bar");
1✔
151
/// ```
1✔
152
impl<'a, const LEN: usize> Index<usize> for ModulePrefix<'a, LEN> {
1✔
153
    type Output = str;
154

155
    #[inline]
156
    fn index(&self, index: usize) -> &Self::Output {
2✔
157
        self.path[index]
2✔
158
    }
2✔
159
}
160

161
impl<const LEN: usize> ModulePrefix<'_, LEN> {
162
    /// Chain the path with another segment - typically an [`Ident`], [`Path`](syn::Path), or
163
    /// another [`ModulePrefix`] or [`Chain`].
164
    ///
165
    /// # Example
166
    ///
167
    /// ```
168
    /// # use macroific_core as macroific;
1✔
169
    /// # use macroific::core_ext::*;
170
    /// # use macroific::elements::ModulePrefix;
171
    /// # use syn::{DeriveInput, parse_quote};
172
    /// # use proc_macro2::{Ident, TokenStream};
173
    /// # use quote::quote;
174
    /// #
175
    /// const MAIN_MODULE: ModulePrefix<'static, 2> = ModulePrefix::new(["my_crate", "some_module"]);
176
    ///
177
    /// // Simplified view of a macro
178
    /// fn parse() -> DeriveInput {
179
    ///   parse_quote!(struct Foo(u8);) // would be an actual token stream in a derive macro
1✔
180
    /// }
1✔
181
    ///
1✔
182
    /// # //noinspection RsConstantConditionIf
183
    /// fn to_tokens(input: DeriveInput) -> TokenStream {
184
    ///   const SOME_CONDITION: bool = true;
1✔
185
    ///   const ANOTHER_CONDITION: bool = false;
186
    ///
187
    ///   let submodule = MAIN_MODULE.chain(Ident::create(if SOME_CONDITION {
188
    ///     "foo"
1✔
189
    ///   } else {
1✔
190
    ///     "bar"
191
    ///   }));
192
    ///
193
    ///   let trait_name = submodule.chain(Ident::create(if ANOTHER_CONDITION {
194
    ///     "Qux"
1✔
195
    ///   } else {
196
    ///     "Baz"
197
    ///   }));
1✔
198
    ///
199
    ///   // Implement some imaginary trait forwarding
200
    ///   let ident = &input.ident;
201
    ///   quote! {
1✔
202
    ///     impl #trait_name for #ident {
1✔
203
    ///       fn exec(self) {
1✔
204
    ///         #trait_name::exec(self.inner);
1✔
205
    ///       }
1✔
206
    ///     }
1✔
207
    ///   }
1✔
208
    /// }
1✔
209
    ///
1✔
210
    /// let input = parse();
211
    /// let output = to_tokens(input);
1✔
212
    ///
1✔
213
    /// assert_eq!(output.to_string(), "impl :: my_crate :: some_module :: foo :: Baz for Foo { fn exec (self) { :: my_crate :: some_module :: foo :: Baz :: exec (self . inner) ; } }");
1✔
214
    /// ```
1✔
215
    ///
1✔
216
    /// Output in a bit more readable format:
217
    ///
218
    #[cfg_attr(doctest, doc = " ````no_test")]
219
    /// ```
220
    /// impl ::my_crate::some_module::foo::Baz for Foo {
221
    ///     fn exec(self) {
222
    ///         ::my_crate::some_module::foo::Baz::exec(self.inner);
223
    ///     }
224
    /// }
225
    /// ````
226
    pub const fn chain<T>(self, next_segment: T) -> Chain<Self, T>
1✔
227
    where
1✔
228
        T: ToTokens,
1✔
229
    {
1✔
230
        Chain {
1✔
231
            a: self,
1✔
232
            b: next_segment,
1✔
233
        }
1✔
234
    }
1✔
235
}
236

237
impl<A, B> Chain<A, B> {
238
    /// Chain the path further. See [`ModulePrefix::chain`].
239
    pub const fn chain<C>(self, next_segment: C) -> Chain<Self, C>
1✔
240
    where
1✔
241
        C: ToTokens,
1✔
242
    {
1✔
243
        Chain {
1✔
244
            a: self,
1✔
245
            b: next_segment,
1✔
246
        }
1✔
247
    }
1✔
248
}
249

250
impl<A: ToTokens, B: ToTokens> ToTokens for Chain<A, B> {
251
    fn to_tokens(&self, tokens: &mut TokenStream) {
4✔
252
        self.a.to_tokens(tokens);
4✔
253
        <Token![::]>::default().to_tokens(tokens);
4✔
254
        self.b.to_tokens(tokens);
4✔
255
    }
4✔
256
}
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