Skip to main content

sort_macro/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use proc_macro::*;
4use Spacing::*;
5use tt_path::TtPath;
6
7fn stream<I>(iter: I) -> TokenStream
8where I: IntoIterator<Item = TokenTree>,
9{
10    TokenStream::from_iter(iter)
11}
12
13fn span_setter(span: Span) -> impl Fn(TokenTree) -> TokenTree {
14    move |mut tt| {
15        tt.set_span(span);
16        tt
17    }
18}
19
20fn err(msg: &str, span: Span) -> TokenStream {
21    let s = span_setter(span);
22    stream([
23        s(Punct::new(':', Joint).into()),
24        s(Punct::new(':', Joint).into()),
25        s(Ident::new("core", span).into()),
26        s(Punct::new(':', Joint).into()),
27        s(Punct::new(':', Joint).into()),
28        s(Ident::new("compile_error", span).into()),
29        s(Punct::new('!', Joint).into()),
30        s(Group::new(Delimiter::Brace, stream([
31            s(Literal::string(msg).into()),
32        ])).into()),
33    ])
34}
35
36struct Sorter {
37    key: TtPath,
38    prefix: TokenStream,
39    tokens: Vec<TokenTree>,
40    args: Group,
41}
42impl Sorter {
43    fn finish(self) -> TokenStream {
44        let mut args = self.args.stream().into_iter().collect::<Vec<_>>();
45        args.sort_by_key(|tt| {
46            self.key.apply(tt.clone())
47                .into_iter()
48                .filter_map(Result::ok)
49                .map(|it| it.to_string())
50                .collect::<Vec<_>>()
51        });
52        args.splice(..0, self.prefix);
53
54        let mut sorted_args = Group::new(self.args.delimiter(), TokenStream::from_iter(args));
55        sorted_args.set_span(self.args.span());
56
57        self.tokens.into_iter()
58            .chain([sorted_args.into()])
59            .collect()
60    }
61}
62
63#[doc = include_str!("../README.md")]
64#[proc_macro]
65pub fn sort_in(tokens: TokenStream) -> TokenStream {
66    let mut tokens = tokens.into_iter().collect::<Vec<_>>();
67    let Some(args) = tokens.pop() else {
68        return err("must input a `()` `{}` `[]`", Span::call_site());
69    };
70    let TokenTree::Group(args) = args else {
71        return err("last token must is group", args.span());
72    };
73
74    let mut prefix = TokenStream::new();
75    let mut key = TtPath::from_tokens(&mut None.into_iter().peekable()).unwrap();
76
77    if let Some(TokenTree::Group(first)) = tokens.first()
78        && first.delimiter() == Delimiter::Bracket
79    {
80        let iter = &mut first.stream().into_iter().peekable();
81        match TtPath::from_tokens(iter) {
82            Ok(tt_path) => key = tt_path,
83            Err(e) => return err(e.msg(), e.span()),
84        }
85        if let Some(peek) = iter.peek() {
86            return err("unexpected key token", peek.span());
87        }
88        tokens.remove(0);
89    }
90
91    if let Some(TokenTree::Group(first)) = tokens.first()
92        && first.delimiter() == Delimiter::Brace
93    {
94        prefix = first.stream();
95        tokens.remove(0);
96    }
97
98    Sorter { key, prefix, tokens, args }.finish()
99}