Skip to main content

mdbx_proc/
lib.rs

1#![feature(proc_macro_span)]
2
3extern crate proc_macro;
4use proc_macro::{token_stream::IntoIter, TokenStream};
5use std::collections::HashMap;
6use std::fmt::Write;
7use std::iter::IntoIterator;
8
9#[derive(Debug)]
10struct Cls {
11  cls: String,
12  map: HashMap<String, String>,
13}
14
15impl Cls {
16  fn new(t: &impl ToString) -> Self {
17    Cls {
18      cls: t.to_string(),
19      map: HashMap::new(),
20    }
21  }
22}
23
24fn parse(mut iter: IntoIter) -> Vec<Cls> {
25  let mut vec = vec![];
26  if let Some(t) = iter.next() {
27    let mut cls = Cls::new(&t);
28    let span = t.span().start();
29    let mut line = span.line;
30    let mut indent_base = span.column;
31    let mut key = String::new();
32    let mut is_key = true;
33    for t in iter {
34      let span = t.span().start();
35      if span.line != line {
36        line = span.line;
37        let column = span.column;
38        if column <= indent_base {
39          vec.push(cls);
40          cls = Cls::new(&t);
41          indent_base = column;
42          is_key = false;
43        } else {
44          key = t.to_string();
45          cls.map.insert(key.clone(), "".into());
46          is_key = true;
47        }
48      } else if is_key {
49        cls.map.insert(
50          key.clone(),
51          cls.map.get(&key).unwrap().to_owned() + &t.to_string(),
52        );
53      }
54    }
55    vec.push(cls);
56  }
57  vec
58}
59
60const ONE: &str = "One";
61const DUP: &str = "Dup";
62
63const LITTLE_ENDIAN: bool = cfg!(target_endian = "little");
64
65macro_rules! _static {
66  ($x:ident) => {
67    if ["Bin", "Str"].contains(&$x.as_str()) {
68      $x = format!("{}<'static>", $x);
69    }
70  };
71}
72
73#[proc_macro]
74pub fn mdbx(input: TokenStream) -> TokenStream {
75  let env;
76  let mut iter = input.into_iter();
77  let mut code = String::new();
78
79  if let Some(t) = iter.next() {
80    env = t.to_string();
81    let vec = parse(iter);
82    for i in vec {
83      let map = i.map;
84
85      macro_rules! get {
86        ($key: ident) => {
87          get!($key, "mdbx::r#type::Bin<'static>")
88        };
89        ($key: ident, $default: expr) => {
90          map
91            .get(stringify!($key))
92            .map_or($default, String::as_str)
93            .to_string()
94        };
95      }
96
97      let mut key = get!(key);
98      let mut val = get!(val);
99
100      let flag = &get!(flag, "DB_DEFAULTS");
101      let mut flag = flag.split('|').collect::<Vec<&str>>();
102
103      let kind = if flag.contains(&"DUPSORT") { DUP } else { ONE };
104
105      if key == "u32" || key == "u64" || key == "usize" {
106        flag.push("INTEGERKEY");
107      } else if ["u16", "u128", "i16", "i32", "i64", "i128", "isize"].contains(&key.as_str()) {
108        if LITTLE_ENDIAN {
109          flag.push("REVERSEKEY");
110        }
111      } else {
112        _static!(key)
113      };
114
115      _static!(val);
116
117      if kind == DUP
118        && [
119          "usize", "u128", "u64", "u32", "u16", "u8", "isize", "i128", "i64", "i32", "i16", "i8",
120        ]
121        .contains(&val.as_str())
122      {
123        flag.push("DUPFIXED");
124        if val == "u32" || val == "u64" || val == "usize" {
125          flag.push("INTEGERDUP")
126        } else if LITTLE_ENDIAN {
127          flag.push("REVERSEDUP");
128        }
129      }
130
131      flag.sort_unstable();
132      flag.dedup();
133
134      let flag = flag
135        .into_iter()
136        .map(|x| format!("mdbx::flag::DB::MDBX_{x}"))
137        .collect::<Vec<String>>()
138        .join("|");
139
140      //println!("{} flag {}", i.cls,flag.replace("mdbx::flag::DB::",""));
141
142      writeln!(
143        &mut code,
144        "mdbx::Db!({env},{},mdbx::db::kind::{kind},{key},{val},{flag});\n",
145        i.cls
146      )
147      .unwrap();
148    }
149  }
150
151  //println!("{code}");
152  let code: TokenStream = code.parse().unwrap();
153  code
154}