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#[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}