static_atom_build/
lib.rs

1#![deny(warnings)]
2
3use std::collections::HashMap;
4use std::error;
5use std::fmt;
6use std::io::Write;
7use std::result;
8use std::str;
9
10use heck::SnakeCase;
11use itertools::Itertools;
12
13type Result<T> = result::Result<T, Box<error::Error>>;
14
15struct ByteStrDisplay<'a>(&'a [u8]);
16
17impl<'a> fmt::Display for ByteStrDisplay<'a> {
18    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
19        if let Ok(s) = str::from_utf8(self.0) {
20            write!(f, "b{:?}", s)
21        } else {
22            write!(f, "&[{}]", itertools::join(self.0, ", "))
23        }
24    }
25}
26
27fn generate_inner<W: Write>(writer: &mut W, lower_name: &str, atoms: Vec<(&[u8], &str)>) -> Result<()> {
28    for (_prefix_byte, atoms) in &atoms.into_iter().group_by(|&(s, _)| s[0]) {
29        let mut atoms = atoms.collect_vec();
30        let mut prefix = Vec::new();
31
32        let s = loop {
33            let &(bytes, s) = atoms.first().unwrap();
34
35            let prefix_byte = if let Some(&b) = bytes.first() {
36                b
37            } else {
38                break Some(s);
39            };
40
41            if atoms.iter().all(|(s, _)| s[0] == prefix_byte) {
42                prefix.push(prefix_byte);
43                for (s, _) in atoms.iter_mut() {
44                    *s = &s[1..];
45                }
46            } else {
47                break None;
48            }
49        };
50
51        writeln!(
52            writer,
53            "if let Some(s) = s.expect({prefix}) {{",
54            prefix = ByteStrDisplay(&prefix[..])
55        )?;
56
57        if let Some(s) = s {
58            write!(writer, "Ok({lower_name}!({s:?}))", lower_name = lower_name, s = s)?;
59        } else {
60            generate_inner(writer, lower_name, atoms)?;
61        }
62
63        write!(writer, "}} else ")?;
64    }
65
66    writeln!(writer, "{{ Err(()) }}")?;
67    Ok(())
68}
69
70pub fn generate<W: Write>(
71    mut writer: W,
72    mod_name: &str,
73    name: &str,
74    atoms: Vec<&str>,
75    visitors: Vec<&str>,
76) -> Result<()> {
77    let mod_name = if mod_name.is_empty() {
78        String::new()
79    } else {
80        mod_name.to_owned() + "::"
81    };
82
83    let lower_name = name.to_snake_case();
84    let visitors = visitors
85        .into_iter()
86        .map(|visitor| (visitor, visitor.to_snake_case()))
87        .collect_vec();
88
89    let mut by_len = HashMap::new();
90    for &s in atoms.iter() {
91        let bytes = s.as_bytes();
92        by_len.entry(bytes.len()).or_insert_with(Vec::new).push((bytes, s));
93    }
94
95    writeln!(
96        writer,
97        "\
98        #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
99        pub enum {name} {{",
100        name = name
101    )?;
102
103    for (index, &s) in atoms.iter().enumerate() {
104        writeln!(writer, "_{index}, // {s:?}", index = index, s = s)?;
105    }
106
107    writeln!(
108        writer,
109        "\
110        }}
111
112        #[doc(hide)]
113        pub mod _{lower_name}_types {{",
114        lower_name = lower_name
115    )?;
116
117    for (index, &s) in atoms.iter().enumerate() {
118        writeln!(
119            writer,
120            "\
121            #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
122            pub struct _{index}; // {s:?}",
123            index = index,
124            s = s
125        )?;
126    }
127
128    writeln!(
129        writer,
130        "\
131        }}
132
133        #[macro_export]
134        macro_rules! {lower_name} {{",
135        lower_name = lower_name
136    )?;
137    for (index, &s) in atoms.iter().enumerate() {
138        writeln!(
139            writer,
140            "({s:?}) => {{ $crate::{mod_name}{name}::_{index} }};",
141            mod_name = mod_name,
142            name = name,
143            index = index,
144            s = s
145        )?;
146    }
147
148    writeln!(
149        writer,
150        "\
151        }}
152
153        #[macro_export]
154        macro_rules! {lower_name}_type {{",
155        lower_name = lower_name
156    )?;
157
158    for (index, &s) in atoms.iter().enumerate() {
159        writeln!(
160            writer,
161            "({s:?}) => {{ $crate::{mod_name}_{lower_name}_types::_{index} }};",
162            mod_name = mod_name,
163            lower_name = lower_name,
164            index = index,
165            s = s
166        )?;
167    }
168
169    writeln!(
170        writer,
171        "\
172         }}
173
174         impl ::std::str::FromStr for {name} {{
175            type Err = ();
176
177            #[allow(unused_variables)]
178            fn from_str(s: &str) -> ::std::result::Result<Self, ()> {{
179                use ::static_atom::Expect;
180
181                let s = s.as_bytes();
182                match s.len() {{",
183        name = name
184    )?;
185
186    for (len, mut atoms) in by_len.into_iter().sorted_by_key(|&(len, _)| len) {
187        writeln!(writer, "{len} => {{", len = len)?;
188        atoms.sort_by_key(|&(bytes, _)| bytes);
189        generate_inner(&mut writer, &lower_name, atoms)?;
190        writeln!(writer, "}}")?;
191    }
192
193    writeln!(
194        writer,
195        "\
196                _ => Err(())
197                }}
198            }}
199        }}
200
201        impl {name} {{
202            pub fn as_str(&self) -> &'static str {{
203                match self {{",
204        name = name
205    )?;
206
207    for &s in atoms.iter() {
208        writeln!(writer, "{lower_name}!({s:?}) => {s:?},", lower_name = lower_name, s = s)?;
209    }
210
211    writeln!(
212        writer,
213        "\
214                }}
215            }}"
216    )?;
217
218    for &(visitor, ref lower_visitor) in visitors.iter() {
219        writeln!(
220            writer,
221            "\
222            pub fn visit_{lower_visitor}<V: {visitor}Visitor>(self, visitor: V) -> V::Value {{
223                match self {{",
224            visitor = visitor,
225            lower_visitor = lower_visitor,
226        )?;
227
228        for s in atoms.iter() {
229            writeln!(
230                writer,
231                "{lower_name}!({s:?}) => visitor.visit::<{lower_name}_type!({s:?})>(),",
232                lower_name = lower_name,
233                s = s,
234            )?;
235        }
236
237        writeln!(
238            writer,
239            "\
240                }}
241            }}"
242        )?;
243    }
244
245    writeln!(
246        writer,
247        "\
248        }}
249
250        impl From<{name}> for usize {{
251            fn from(token: {name}) -> Self {{
252                match token {{",
253        name = name
254    )?;
255
256    for (index, &s) in atoms.iter().enumerate() {
257        writeln!(
258            writer,
259            "{lower_name}!({s:?}) => {index},",
260            lower_name = lower_name,
261            index = index,
262            s = s
263        )?;
264    }
265
266    writeln!(
267        writer,
268        "\
269                }}
270            }}
271        }}
272
273        impl ::static_atom::TryFrom<usize> for {name} {{
274            type Err = ();
275
276            fn try_from(n: usize) -> Result<Self, ()> {{
277                match n {{",
278        name = name
279    )?;
280
281    for (index, &s) in atoms.iter().enumerate() {
282        writeln!(
283            writer,
284            "{index} => Ok({lower_name}!({s:?})),",
285            lower_name = lower_name,
286            index = index,
287            s = s
288        )?;
289    }
290
291    writeln!(
292        writer,
293        "\
294                    _ => Err(()),
295                }}
296            }}
297        }}"
298    )?;
299
300    #[cfg(feature = "serde")]
301    {
302        writeln!(
303            writer,
304            "\
305            impl ::serde::Serialize for {name} {{
306                fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {{
307                    self.as_str().serialize(serializer)
308                }}
309            }}
310
311            impl<'de> ::serde::Deserialize<'de> for {name} {{
312                fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {{
313                    use serde::de::Error;
314
315                    <&str>::deserialize(deserializer).and_then(|s| {{
316                        s.parse().map_err(|()| Error::custom(format!(\"can't parse {{}} as {name}\", s)))
317                    }})
318                }}
319            }}",
320            name = name
321        )?;
322    }
323
324    let where_mapping = atoms
325        .iter()
326        .map(|&s| {
327            format!(
328                "M: ::static_atom::Mapping<{lower_name}_type!({s:?})>",
329                lower_name = lower_name,
330                s = s
331            )
332        })
333        .join("\n,");
334
335    writeln!(
336        writer,
337        "\
338        impl ::std::fmt::Debug for {name} {{
339            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {{
340                write!(f, \"{lower_name}!({{}})\", self.as_str())
341            }}
342        }}
343
344        impl ::std::fmt::Display for {name} {{
345            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {{
346                f.write_str(self.as_str())
347            }}
348        }}
349
350        #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
351        pub struct {name}Map<T>([Option<T>; {len}]);
352        
353        impl<T> {name}Map<T> {{
354            pub fn new() -> Self {{
355                {name}Map(Default::default())
356            }}
357        }}
358        
359        impl<T> ::static_atom::AtomMap for {name}Map<T> {{
360            type Key = {name};
361            type Value = T;
362        
363            fn entry(&self, key: {name}) -> &Option<T> {{
364                &self.0[usize::from(key)]
365            }}
366        
367            fn entry_mut(&mut self, key: {name}) -> &mut Option<T> {{
368                &mut self.0[usize::from(key)]
369            }}
370        
371            fn entries(&self) -> &[Option<T>] {{
372                &self.0
373            }}
374        
375            fn entries_mut(&mut self) -> &mut [Option<T>] {{
376                &mut self.0
377            }}
378        }}
379
380        impl<T> ::std::iter::FromIterator<({name}, T)> for {name}Map<T> {{
381            fn from_iter<I: ::std::iter::IntoIterator<Item = ({name}, T)>>(iter: I) -> Self {{
382                let mut map = {name}Map::new();
383                for (key, value) in iter {{
384                    map.0[usize::from(key)] = Some(value);
385                }}
386
387                map
388            }}
389        }}
390
391        pub struct Typed{name}Map<M>
392        where {where_mapping}
393        {{",
394        lower_name = lower_name,
395        name = name,
396        len = atoms.len(),
397        where_mapping = where_mapping
398    )?;
399
400    for (index, &s) in atoms.iter().enumerate() {
401        writeln!(
402            writer,
403            "_{index}: Option<<M as ::static_atom::Mapping<{lower_name}_type!({s:?})>>::Value>,",
404            index = index,
405            lower_name = lower_name,
406            s = s
407        )?;
408    }
409
410    writeln!(
411        writer,
412        "\
413        }}
414
415        impl<M> Typed{name}Map<M>
416        where {where_mapping}
417        {{
418            pub fn new() -> Self {{
419                Typed{name}Map {{",
420        name = name,
421        where_mapping = where_mapping
422    )?;
423
424    for (index, &s) in atoms.iter().enumerate() {
425        writeln!(writer, "_{index}: None, // {s:?}", index = index, s = s)?;
426    }
427
428    writeln!(
429        writer,
430        "\
431                }}
432            }}
433        }}
434
435        impl<M> ::static_atom::TypedAtomMap<M> for Typed{name}Map<M>
436        where {where_mapping}
437        {{
438            fn entry<A>(&self) -> &Option<<M as ::static_atom::Mapping<A>>::Value>
439            where
440                M: ::static_atom::Mapping<A>,
441                A: 'static,
442            {{
443                use std::any::TypeId;
444                use std::mem;
445
446                let id = TypeId::of::<A>();",
447        name = name,
448        where_mapping = where_mapping
449    )?;
450
451    for (index, &s) in atoms.iter().enumerate() {
452        write!(
453            writer,
454            "\
455            if id == TypeId::of::<{lower_name}_type!({s:?})>() {{
456                unsafe {{ mem::transmute(&self._{index}) }}
457            }} else ",
458            lower_name = lower_name,
459            index = index,
460            s = s
461        )?;
462    }
463
464    writeln!(
465        writer,
466        "\
467                {{
468                    unreachable!()
469                }}
470            }}
471
472            fn entry_mut<A>(&mut self) -> &mut Option<<M as ::static_atom::Mapping<A>>::Value>
473            where
474                M: ::static_atom::Mapping<A>,
475                A: 'static,
476            {{
477                use std::any::TypeId;
478                use std::mem;
479
480                let id = TypeId::of::<A>();"
481    )?;
482
483    for (index, &s) in atoms.iter().enumerate() {
484        write!(
485            writer,
486            "\
487            if id == TypeId::of::<{lower_name}_type!({s:?})>() {{
488                unsafe {{ mem::transmute(&mut self._{index}) }}
489            }} else ",
490            lower_name = lower_name,
491            index = index,
492            s = s
493        )?;
494    }
495
496    writeln!(
497        writer,
498        "\
499                {{
500                    unreachable!()
501                }}
502            }}
503        }}"
504    )?;
505
506    Ok(())
507}