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
35    let mut parser = TokenParser::new(item);
36    if let Some(name) = parser.eat_any_ident() {
37        let id = from_str_unchecked(&name);
38        tb.add("LiveId (").suf_u64(id).add(")");
39        tb.end()
40    }
41    else if let Some(punct) = parser.eat_any_punct(){
42        let id = from_str_unchecked(&punct);
43        tb.add("LiveId (").suf_u64(id).add(")");
44        tb.end()
45    }
46    else if let Some(v) = parser.eat_literal(){
47        if let Ok(v) = v.to_string().parse::<u64>(){
48            tb.add("LiveId (").suf_u64(v).add(")");
49            return tb.end()
50        }
51        else{
52            parser.unexpected()
53        }
54    }
55    else{
56        parser.unexpected()
57    }
58}
59
60#[proc_macro] 
61pub fn id(item: TokenStream) -> TokenStream {
62    let mut tb = TokenBuilder::new(); 
63    let mut parser = TokenParser::new(item);
64    fn parse(parser:&mut TokenParser, tb:&mut TokenBuilder)->Result<(),TokenStream>{
65        tb.add("&[");
66        loop{
67            let ident = parser.expect_any_ident()?;
68            let id = from_str_unchecked(&ident);
69            tb.add("LiveId (").suf_u64(id).add("),");
70            if parser.eat_eot(){
71                tb.add("]");
72                return Ok(())
73            }
74            parser.expect_punct_alone('.')?
75        }
76    }
77    if let Err(e) = parse(&mut parser, &mut tb){
78        return e
79    };
80    tb.end()
81}
82
83#[proc_macro] 
84pub fn ids(item: TokenStream) -> TokenStream {
85    let mut tb = TokenBuilder::new(); 
86    let mut parser = TokenParser::new(item);
87    fn parse(parser:&mut TokenParser, tb:&mut TokenBuilder)->Result<(),TokenStream>{
88        tb.add("&[");
89        'outer: loop{
90            tb.add("&[");
91            loop{
92                let ident = parser.expect_any_ident()?;
93                let id = from_str_unchecked(&ident);
94                tb.add("LiveId (").suf_u64(id).add("),");
95                if parser.eat_eot(){
96                    tb.add("]");
97                    break 'outer
98                }
99                if parser.eat_punct_alone(','){
100                    tb.add("]");
101                    break
102                }
103                parser.expect_punct_alone('.')?
104            }
105            tb.add(",");
106            if parser.eat_eot(){
107                break;
108            }
109        }
110        tb.add("]");
111        Ok(())
112    }
113    if let Err(e) = parse(&mut parser, &mut tb){
114        return e
115    };
116    tb.end()
117}
118
119
120// absolutely a very bad idea but lets see if we can do this.
121#[proc_macro]
122pub fn live_id_num(item: TokenStream) -> TokenStream {
123    let mut tb = TokenBuilder::new(); 
124
125    let mut parser = TokenParser::new(item);
126    if let Some(name) = parser.eat_any_ident() {
127        if !parser.eat_punct_alone(','){
128            return error("please add a number")
129        }
130        // then eat the next bit
131        let arg = parser.eat_level();
132        let id = from_str_unchecked(&name);
133        tb.add("LiveId::from_num(").suf_u64(id).add(",").stream(Some(arg)).add(")");
134        tb.end()
135    }
136    else{
137        parser.unexpected()
138    }
139}
140
141#[proc_macro]
142pub fn id_lut(item: TokenStream) -> TokenStream {
143    let mut tb = TokenBuilder::new(); 
144
145    let mut parser = TokenParser::new(item);
146    if let Some(name) = parser.eat_any_ident() {
147        tb.add("LiveId::from_str_with_lut(").string(&name).add(").unwrap()");
148        tb.end()
149    }
150    else if let Some(punct) = parser.eat_any_punct(){
151        tb.add("LiveId::from_str_with_lut(").string(&punct).add(").unwrap()");
152        tb.end()
153    }
154    else{
155        parser.unexpected()
156    }
157}
158
159#[proc_macro_derive(FromLiveId)]
160pub fn derive_from_live_id(input: TokenStream) -> TokenStream {
161    derive_from_live_id_impl(input)
162}