Skip to main content

sort_macro/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use proc_macro::*;
4use Spacing::*;
5
6fn stream<I>(iter: I) -> TokenStream
7where I: IntoIterator<Item = TokenTree>,
8{
9    TokenStream::from_iter(iter)
10}
11
12fn span_setter(span: Span) -> impl Fn(TokenTree) -> TokenTree {
13    move |mut tt| {
14        tt.set_span(span);
15        tt
16    }
17}
18
19fn err(msg: &str, span: Span) -> TokenStream {
20    let s = span_setter(span);
21    stream([
22        s(Punct::new(':', Joint).into()),
23        s(Punct::new(':', Joint).into()),
24        s(Ident::new("core", span).into()),
25        s(Punct::new(':', Joint).into()),
26        s(Punct::new(':', Joint).into()),
27        s(Ident::new("compile_error", span).into()),
28        s(Punct::new('!', Joint).into()),
29        s(Group::new(Delimiter::Brace, stream([
30            s(Literal::string(msg).into()),
31        ])).into()),
32    ])
33}
34
35struct Sorter {
36    _key: (),
37    prefix: TokenStream,
38    tokens: Vec<TokenTree>,
39    args: Group,
40}
41impl Sorter {
42    fn finish(self) -> TokenStream {
43        let mut args = self.args.stream().into_iter().collect::<Vec<_>>();
44        args.sort_by_key(|tt| tt.to_string());
45        args.splice(..0, self.prefix);
46
47        let mut sorted_args = Group::new(self.args.delimiter(), TokenStream::from_iter(args));
48        sorted_args.set_span(self.args.span());
49
50        self.tokens.into_iter()
51            .chain([sorted_args.into()])
52            .collect()
53    }
54}
55
56// TODO sort_in!([1.2] {@branch} foo!())
57
58#[doc = include_str!("../README.md")]
59#[proc_macro]
60pub fn sort_in(tokens: TokenStream) -> TokenStream {
61    let mut tokens = tokens.into_iter().collect::<Vec<_>>();
62    let Some(args) = tokens.pop() else {
63        return err("must input a `()` `{}` `[]`", Span::call_site());
64    };
65    let TokenTree::Group(args) = args else {
66        return err("last token must is group", args.span());
67    };
68
69    let mut prefix = TokenStream::new();
70
71    if let Some(TokenTree::Group(first)) = tokens.first()
72        && first.delimiter() == Delimiter::Brace
73    {
74        prefix = first.stream();
75        tokens.remove(0);
76    }
77
78    Sorter { _key: (), prefix, tokens, args }.finish()
79}