makepad_live_id_macros/
lib.rs

1use proc_macro::{TokenStream};
2
3use makepad_micro_proc_macro::{TokenBuilder, TokenParser, error};
4
5const LIVE_ID_SEED:u64 = 0xd6e8_feb8_6659_fd93;
6
7const fn from_bytes(seed:u64, id_bytes: &[u8], start: usize, end: usize) -> u64 {
8    let mut x = seed;
9    let mut i = start;
10    while i < end {
11        x = x.overflowing_add(id_bytes[i] as u64).0;
12        x ^= x >> 32;
13        x = x.overflowing_mul(0xd6e8_feb8_6659_fd93).0;
14        x ^= x >> 32;
15        x = x.overflowing_mul(0xd6e8_feb8_6659_fd93).0;
16        x ^= x >> 32;
17        i += 1;
18    }
19    // mark high bit as meaning that this is a hash id
20    (x & 0x7fff_ffff_ffff_ffff) | 0x8000_0000_0000_0000
21}
22
23const fn from_str_unchecked(id_str: &str) -> u64 {
24    let bytes = id_str.as_bytes();
25    from_bytes(LIVE_ID_SEED, bytes, 0, bytes.len())
26}
27
28mod derive_from_live_id;
29use crate::derive_from_live_id::*;
30
31#[proc_macro] 
32pub fn live_id(item: TokenStream) -> TokenStream {
33    let mut tb = TokenBuilder::new(); 
34    let v = item.to_string();
35    let id = from_str_unchecked(&v);
36    tb.add("LiveId (").suf_u64(id).add(")");
37    tb.end()
38}
39
40#[proc_macro] 
41pub fn some_id(item: TokenStream) -> TokenStream {
42    let mut tb = TokenBuilder::new(); 
43    let v = item.to_string();
44    let id = from_str_unchecked(&v);
45    tb.add("Some(LiveId (").suf_u64(id).add("))");
46    tb.end()
47}
48
49#[proc_macro] 
50pub fn id(item: TokenStream) -> TokenStream {
51    let mut tb = TokenBuilder::new(); 
52    let mut parser = TokenParser::new(item);
53    fn parse(parser:&mut TokenParser, tb:&mut TokenBuilder)->Result<(),TokenStream>{
54        tb.add("&[");
55        loop{
56            // if its a {} insert it as code
57            if parser.open_paren(){
58                tb.stream(Some(parser.eat_level()));
59                tb.add(",");
60            }
61            else{
62                let ident = parser.expect_any_ident()?;
63                let id = from_str_unchecked(&ident);
64                tb.add("LiveId (").suf_u64(id).add("),");
65            }
66                
67            if parser.eat_eot(){
68                tb.add("]");
69                return Ok(())
70            }
71            parser.expect_punct_alone('.')?
72        }
73    }
74    if let Err(e) = parse(&mut parser, &mut tb){
75        return e
76    };
77    tb.end()
78}
79
80#[proc_macro] 
81pub fn ids(item: TokenStream) -> TokenStream {
82    let mut tb = TokenBuilder::new(); 
83    let mut parser = TokenParser::new(item);
84    fn parse(parser:&mut TokenParser, tb:&mut TokenBuilder)->Result<(),TokenStream>{
85        tb.add("&[");
86        'outer: loop{
87            tb.add("&[");
88            loop{
89                let ident = parser.expect_any_ident()?;
90                let id = from_str_unchecked(&ident);
91                tb.add("LiveId (").suf_u64(id).add("),");
92                if parser.eat_eot(){
93                    tb.add("]");
94                    break 'outer
95                }
96                if parser.eat_punct_alone(','){
97                    tb.add("]");
98                    break
99                }
100                parser.expect_punct_alone('.')?
101            }
102            tb.add(",");
103            if parser.eat_eot(){
104                break;
105            }
106        }
107        tb.add("]");
108        Ok(())
109    }
110    if let Err(e) = parse(&mut parser, &mut tb){
111        return e
112    };
113    tb.end()
114}
115
116
117// absolutely a very bad idea but lets see if we can do this.
118#[proc_macro]
119pub fn live_id_num(item: TokenStream) -> TokenStream {
120    let mut tb = TokenBuilder::new(); 
121
122    let mut parser = TokenParser::new(item);
123    if let Some(name) = parser.eat_any_ident() {
124        if !parser.eat_punct_alone(','){
125            return error("please add a number")
126        }
127        // then eat the next bit
128        let arg = parser.eat_level();
129        let id = from_str_unchecked(&name);
130        tb.add("LiveId::from_num(").suf_u64(id).add(",").stream(Some(arg)).add(")");
131        tb.end()
132    }
133    else{
134        parser.unexpected()
135    }
136}
137
138#[proc_macro]
139pub fn id_lut(item: TokenStream) -> TokenStream {
140    let mut tb = TokenBuilder::new(); 
141
142    let mut parser = TokenParser::new(item);
143    if let Some(name) = parser.eat_any_ident() {
144        tb.add("LiveId::from_str_with_lut(").string(&name).add(").unwrap()");
145        tb.end()
146    }
147    else if let Some(punct) = parser.eat_any_punct(){
148        tb.add("LiveId::from_str_with_lut(").string(&punct).add(").unwrap()");
149        tb.end()
150    }
151    else{
152        parser.unexpected()
153    }
154}
155
156#[proc_macro_derive(FromLiveId)]
157pub fn derive_from_live_id(input: TokenStream) -> TokenStream {
158    derive_from_live_id_impl(input)
159}