1 #![recursion_limit = "256"]
2 extern crate proc_macro;
3 extern crate proc_macro2;
4 #[macro_use]
5 extern crate quote;
6
7 use proc_macro::TokenStream;
8 use proc_macro2::*;
9
10 use std::iter::FromIterator;
11
name_capital(name: &str) -> String12 fn name_capital(name: &str) -> String {
13 name.chars()
14 .enumerate()
15 .map(|(i, s)| {
16 if i == 0 {
17 s.to_uppercase().next().unwrap()
18 } else {
19 s
20 }
21 })
22 .collect()
23 }
24
25 #[proc_macro]
table(input: proc_macro::TokenStream) -> TokenStream26 pub fn table(input: proc_macro::TokenStream) -> TokenStream {
27 let input = proc_macro2::TokenStream::from(input);
28 let mut input_iter = input.into_iter();
29 let name = match input_iter.next() {
30 Some(TokenTree::Ident(id)) => id.to_string(),
31 _ => panic!("txn_table: first argument not an identifier"),
32 };
33 assert!(input_iter.next().is_none());
34 let name_capital = syn::Ident::new(&name_capital(&name), Span::call_site());
35 proc_macro::TokenStream::from(quote! {
36 type #name_capital;
37 })
38 }
39
40 #[proc_macro]
sanakirja_table_get(input: proc_macro::TokenStream) -> TokenStream41 pub fn sanakirja_table_get(input: proc_macro::TokenStream) -> TokenStream {
42 let input = proc_macro2::TokenStream::from(input);
43 let mut input_iter = input.into_iter();
44 let name = match input_iter.next() {
45 Some(TokenTree::Ident(id)) => id.to_string(),
46 _ => panic!("txn_table: first argument not an identifier"),
47 };
48 let name_get = syn::Ident::new(&format!("get_{}", name), Span::call_site());
49 let name = syn::Ident::new(&name, Span::call_site());
50 let key = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
51 let value = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
52 let error = next(&mut input_iter);
53 let error = if error.is_empty() {
54 quote! { Error }
55 } else {
56 proc_macro2::TokenStream::from_iter(error.into_iter())
57 };
58 proc_macro::TokenStream::from(quote! {
59 fn #name_get <'txn> (&'txn self, key: &#key, value: Option<&#value>) -> Result<Option<&'txn #value>, TxnErr<Self::#error>> {
60 match ::sanakirja::btree::get(&self.txn, &self.#name, key, value) {
61 Ok(Some((k, v))) if k == key => Ok(Some(v)),
62 Ok(_) => Ok(None),
63 Err(e) => {
64 error!("{:?}", e);
65 Err(TxnErr(SanakirjaError::PristineCorrupt))
66 }
67 }
68 }
69 })
70 }
71
72 #[proc_macro]
sanakirja_get(input: proc_macro::TokenStream) -> TokenStream73 pub fn sanakirja_get(input: proc_macro::TokenStream) -> TokenStream {
74 let input = proc_macro2::TokenStream::from(input);
75 let mut input_iter = input.into_iter();
76 let name = match input_iter.next() {
77 Some(TokenTree::Ident(id)) => id.to_string(),
78 _ => panic!("txn_table: first argument not an identifier"),
79 };
80 let name_capital = syn::Ident::new(&name_capital(&name), Span::call_site());
81 let name_get = syn::Ident::new(&format!("get_{}", name), Span::call_site());
82 let key = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
83 let value = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
84 let error = next(&mut input_iter);
85 let error = if error.is_empty() {
86 quote! { Error }
87 } else {
88 proc_macro2::TokenStream::from_iter(error.into_iter())
89 };
90 assert!(input_iter.next().is_none());
91 proc_macro::TokenStream::from(quote! {
92 fn #name_get<'txn>(&'txn self, db: &Self::#name_capital, key: &#key, value: Option<&#value>) -> Result<Option<&'txn #value>, TxnErr<Self::#error>> {
93 match ::sanakirja::btree::get(&self.txn, db, key, value) {
94 Ok(Some((k, v))) if k == key => Ok(Some(v)),
95 Ok(_) => Ok(None),
96 Err(e) => {
97 error!("{:?}", e);
98 Err(TxnErr(SanakirjaError::PristineCorrupt))
99 }
100 }
101 }
102 })
103 }
104
105 #[proc_macro]
table_get(input: proc_macro::TokenStream) -> TokenStream106 pub fn table_get(input: proc_macro::TokenStream) -> TokenStream {
107 let input = proc_macro2::TokenStream::from(input);
108 let mut input_iter = input.into_iter();
109 let name = match input_iter.next() {
110 Some(TokenTree::Ident(id)) => id.to_string(),
111 _ => panic!("txn_table: first argument not an identifier"),
112 };
113 let name_get = syn::Ident::new(&format!("get_{}", name), Span::call_site());
114 let key = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
115 let value = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
116 let error = next(&mut input_iter);
117 let error = if error.is_empty() {
118 quote! { Error }
119 } else {
120 proc_macro2::TokenStream::from_iter(error.into_iter())
121 };
122 assert!(input_iter.next().is_none());
123 proc_macro::TokenStream::from(quote! {
124 fn #name_get<'txn>(&'txn self, key: &#key, value: Option<&#value>) -> Result<Option<&'txn #value>, TxnErr<Self::#error>>;
125 })
126 }
127
128 #[proc_macro]
get(input: proc_macro::TokenStream) -> TokenStream129 pub fn get(input: proc_macro::TokenStream) -> TokenStream {
130 let input = proc_macro2::TokenStream::from(input);
131 let mut input_iter = input.into_iter();
132 let name = match input_iter.next() {
133 Some(TokenTree::Ident(id)) => id.to_string(),
134 _ => panic!("txn_table: first argument not an identifier"),
135 };
136 let name_capital = syn::Ident::new(&name_capital(&name), Span::call_site());
137 let name_get = syn::Ident::new(&format!("get_{}", name), Span::call_site());
138 let key = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
139 let value = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
140 let error = next(&mut input_iter);
141 let error = if error.is_empty() {
142 quote! { Error }
143 } else {
144 proc_macro2::TokenStream::from_iter(error.into_iter())
145 };
146 assert!(input_iter.next().is_none());
147 proc_macro::TokenStream::from(quote! {
148 fn #name_get<'txn>(&'txn self, db: &Self::#name_capital, key: &#key, value: Option<&#value>) -> Result<Option<&'txn #value>, TxnErr<Self::#error>>;
149 })
150 }
151
next(input_iter: &mut proc_macro2::token_stream::IntoIter) -> Vec<TokenTree>152 fn next(input_iter: &mut proc_macro2::token_stream::IntoIter) -> Vec<TokenTree> {
153 let mut result = Vec::new();
154 let mut is_first = true;
155 let mut level = 0;
156 loop {
157 match input_iter.next() {
158 Some(TokenTree::Punct(p)) => {
159 if p.as_char() == ',' {
160 if !is_first {
161 if level == 0 {
162 return result;
163 } else {
164 result.push(TokenTree::Punct(p))
165 }
166 }
167 } else if p.as_char() == '<' {
168 level += 1;
169 result.push(TokenTree::Punct(p))
170 } else if level > 0 && p.as_char() == '>' {
171 level -= 1;
172 result.push(TokenTree::Punct(p))
173 } else {
174 result.push(TokenTree::Punct(p))
175 }
176 }
177 Some(e) => {
178 result.push(e)
179 },
180 None => return result,
181 }
182 is_first = false
183 }
184 }
185
186 #[proc_macro]
cursor(input: proc_macro::TokenStream) -> TokenStream187 pub fn cursor(input: proc_macro::TokenStream) -> TokenStream {
188 cursor_(input, false, false, false)
189 }
190
191 #[proc_macro]
cursor_ref(input: proc_macro::TokenStream) -> TokenStream192 pub fn cursor_ref(input: proc_macro::TokenStream) -> TokenStream {
193 cursor_(input, false, false, true)
194 }
195
196 #[proc_macro]
iter(input: proc_macro::TokenStream) -> TokenStream197 pub fn iter(input: proc_macro::TokenStream) -> TokenStream {
198 cursor_(input, false, true, false)
199 }
200
201 #[proc_macro]
rev_cursor(input: proc_macro::TokenStream) -> TokenStream202 pub fn rev_cursor(input: proc_macro::TokenStream) -> TokenStream {
203 cursor_(input, true, false, false)
204 }
205
cursor_(input: proc_macro::TokenStream, rev: bool, iter: bool, borrow: bool) -> TokenStream206 fn cursor_(input: proc_macro::TokenStream, rev: bool, iter: bool, borrow: bool) -> TokenStream {
207 let input = proc_macro2::TokenStream::from(input);
208 let mut input_iter = input.into_iter();
209 let name = match input_iter.next() {
210 Some(TokenTree::Ident(id)) => id.to_string(),
211 _ => panic!("txn_table: first argument not an identifier"),
212 };
213 let capital = name_capital(&name);
214 let cursor_name = syn::Ident::new(&format!("{}Cursor", capital,), Span::call_site());
215 let name_capital = syn::Ident::new(&name_capital(&name), Span::call_site());
216 let name_iter = syn::Ident::new(&format!("iter_{}", name), Span::call_site());
217 let name_next = syn::Ident::new(&format!("cursor_{}_next", name), Span::call_site());
218 let name_prev = syn::Ident::new(&format!("cursor_{}_prev", name), Span::call_site());
219 let name_cursor = syn::Ident::new(
220 &format!("{}cursor_{}", if rev { "rev_" } else { "" }, name),
221 Span::call_site(),
222 );
223 let name_cursor_ref = syn::Ident::new(
224 &format!("{}cursor_{}_ref", if rev { "rev_" } else { "" }, name),
225 Span::call_site(),
226 );
227
228 let key = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
229 let value = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
230
231 let error = next(&mut input_iter);
232 let error = if error.is_empty() {
233 quote! { GraphError }
234 } else {
235 proc_macro2::TokenStream::from_iter(error.into_iter())
236 };
237
238 let cursor_type = if rev {
239 quote! {
240 Result<crate::pristine::RevCursor<Self, &'txn Self, Self::#cursor_name, #key, #value>, TxnErr<Self::#error>>
241 }
242 } else {
243 quote! {
244 Result<crate::pristine::Cursor<Self, &'txn Self, Self::#cursor_name, #key, #value>, TxnErr<Self::#error>>
245 }
246 };
247 let def = if rev {
248 quote! {}
249 } else {
250 quote! {
251 type #cursor_name;
252 fn #name_next <'txn> (
253 &'txn self,
254 cursor: &mut Self::#cursor_name,
255 ) -> Result<Option<(&'txn #key, &'txn #value)>, TxnErr<Self::#error>>;
256 fn #name_prev <'txn> (
257 &'txn self,
258 cursor: &mut Self::#cursor_name,
259 ) -> Result<Option<(&'txn #key, &'txn #value)>, TxnErr<Self::#error>>;
260 }
261 };
262 let borrow = if borrow {
263 quote! {
264 fn #name_cursor_ref<RT: std::ops::Deref<Target = Self>>(
265 txn: RT,
266 db: &Self::#name_capital,
267 pos: Option<(&#key, Option<&#value>)>,
268 ) -> Result<crate::pristine::Cursor<Self, RT, Self::#cursor_name, #key, #value>, TxnErr<Self::#error>>;
269 }
270 } else {
271 quote! {}
272 };
273 let iter = if !iter {
274 quote! {}
275 } else {
276 quote! {
277 fn #name_iter <'txn> (
278 &'txn self,
279 k: &#key,
280 v: Option<&#value>
281 ) -> #cursor_type;
282 }
283 };
284 assert!(input_iter.next().is_none());
285 proc_macro::TokenStream::from(quote! {
286 #def
287 fn #name_cursor<'txn>(
288 &'txn self,
289 db: &Self::#name_capital,
290 pos: Option<(&#key, Option<&#value>)>,
291 ) -> #cursor_type;
292 #borrow
293 #iter
294 })
295 }
296
297 #[proc_macro]
sanakirja_cursor(input: proc_macro::TokenStream) -> TokenStream298 pub fn sanakirja_cursor(input: proc_macro::TokenStream) -> TokenStream {
299 sanakirja_cursor_(input, false, false, false)
300 }
301
302 #[proc_macro]
sanakirja_cursor_ref(input: proc_macro::TokenStream) -> TokenStream303 pub fn sanakirja_cursor_ref(input: proc_macro::TokenStream) -> TokenStream {
304 sanakirja_cursor_(input, false, false, true)
305 }
306
307 #[proc_macro]
sanakirja_iter(input: proc_macro::TokenStream) -> TokenStream308 pub fn sanakirja_iter(input: proc_macro::TokenStream) -> TokenStream {
309 sanakirja_cursor_(input, false, true, false)
310 }
311
312 #[proc_macro]
sanakirja_rev_cursor(input: proc_macro::TokenStream) -> TokenStream313 pub fn sanakirja_rev_cursor(input: proc_macro::TokenStream) -> TokenStream {
314 sanakirja_cursor_(input, true, false, false)
315 }
316
sanakirja_cursor_( input: proc_macro::TokenStream, rev: bool, iter: bool, borrow: bool, ) -> TokenStream317 fn sanakirja_cursor_(
318 input: proc_macro::TokenStream,
319 rev: bool,
320 iter: bool,
321 borrow: bool,
322 ) -> TokenStream {
323 let input = proc_macro2::TokenStream::from(input);
324 let mut input_iter = input.into_iter();
325 let name = match input_iter.next() {
326 Some(TokenTree::Ident(id)) => id.to_string(),
327 _ => panic!("txn_table: first argument not an identifier"),
328 };
329 let cursor_name = syn::Ident::new(
330 &format!("{}Cursor", name_capital(&name),),
331 Span::call_site(),
332 );
333
334 let name_capital = syn::Ident::new(&name_capital(&name), Span::call_site());
335 let name_next = syn::Ident::new(&format!("cursor_{}_next", name), Span::call_site());
336 let name_prev = syn::Ident::new(&format!("cursor_{}_prev", name), Span::call_site());
337 let name_cursor = syn::Ident::new(
338 &format!("{}cursor_{}", if rev { "rev_" } else { "" }, name),
339 Span::call_site(),
340 );
341 let name_cursor_ref = syn::Ident::new(
342 &format!("{}cursor_{}_ref", if rev { "rev_" } else { "" }, name),
343 Span::call_site(),
344 );
345 let name_iter = syn::Ident::new(
346 &format!("{}iter_{}", if rev { "rev_" } else { "" }, name),
347 Span::call_site(),
348 );
349
350 let name = syn::Ident::new(&name, Span::call_site());
351 let key = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
352 let value = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
353
354 let iter = if iter {
355 quote! {
356 fn #name_iter <'txn> (
357 &'txn self,
358 k: &#key,
359 v: Option<&#value>
360 ) -> Result<Cursor<Self, &'txn Self, Self::#cursor_name, #key, #value>, TxnErr<SanakirjaError>> {
361 self.#name_cursor(&self.#name, Some((k, v)))
362 }
363 }
364 } else {
365 quote! {}
366 };
367
368 let borrow = if borrow {
369 quote! {
370 fn #name_cursor_ref <RT: std::ops::Deref<Target = Self>> (
371 txn: RT,
372 db: &Self::#name_capital,
373 pos: Option<(&#key, Option<&#value>)>,
374 ) -> Result<Cursor<Self, RT, Self::#cursor_name, #key, #value>, TxnErr<SanakirjaError>> {
375 let mut cursor = ::sanakirja::btree::cursor::Cursor::new(&txn.txn, &db)?;
376 if let Some((k, v)) = pos {
377 cursor.set(&txn.txn, k, v)?;
378 }
379 Ok(Cursor {
380 cursor,
381 txn,
382 k: std::marker::PhantomData,
383 v: std::marker::PhantomData,
384 t: std::marker::PhantomData,
385 })
386 }
387 }
388 } else {
389 quote! {}
390 };
391
392 proc_macro::TokenStream::from(if rev {
393 quote! {
394 fn #name_cursor<'txn>(
395 &'txn self,
396 db: &Self::#name_capital,
397 pos: Option<(&#key, Option<&#value>)>,
398 ) -> Result<super::RevCursor<Self, &'txn Self, Self::#cursor_name, #key, #value>, TxnErr<SanakirjaError>> {
399 let mut cursor = ::sanakirja::btree::cursor::Cursor::new(&self.txn, &db)?;
400 if let Some((k, v)) = pos {
401 cursor.set(&self.txn, k, v)?;
402 } else {
403 cursor.set_last(&self.txn)?;
404 }
405 Ok(super::RevCursor {
406 cursor,
407 txn: self,
408 k: std::marker::PhantomData,
409 v: std::marker::PhantomData,
410 t: std::marker::PhantomData,
411 })
412 }
413 }
414 } else {
415 quote! {
416 fn #name_cursor<'txn>(
417 &'txn self,
418 db: &Self::#name_capital,
419 pos: Option<(&#key, Option<&#value>)>,
420 ) -> Result<Cursor<Self, &'txn Self, Self::#cursor_name, #key, #value>, TxnErr<SanakirjaError>> {
421 let mut cursor = ::sanakirja::btree::cursor::Cursor::new(&self.txn, &db)?;
422 if let Some((k, v)) = pos {
423 cursor.set(&self.txn, k, v)?;
424 }
425 Ok(Cursor {
426 cursor,
427 txn: self,
428 k: std::marker::PhantomData,
429 v: std::marker::PhantomData,
430 t: std::marker::PhantomData,
431 })
432 }
433 #borrow
434 fn #name_next <'txn> (
435 &'txn self,
436 cursor: &mut Self::#cursor_name,
437 ) -> Result<Option<(&'txn #key, &'txn #value)>, TxnErr<SanakirjaError>> {
438 let x = if let Ok(x) = cursor.next(&self.txn) {
439 x
440 } else {
441 return Err(TxnErr(SanakirjaError::PristineCorrupt))
442 };
443 Ok(x)
444 }
445 fn #name_prev <'txn> (
446 &'txn self,
447 cursor: &mut Self::#cursor_name,
448 ) -> Result<Option<(&'txn #key, &'txn #value)>, TxnErr<SanakirjaError>> {
449 let x = if let Ok(x) = cursor.next(&self.txn) {
450 x
451 } else {
452 return Err(TxnErr(SanakirjaError::PristineCorrupt))
453 };
454 Ok(x)
455 }
456 #iter
457 }
458 })
459 }
460
461 #[proc_macro]
initialized_cursor(input: proc_macro::TokenStream) -> TokenStream462 pub fn initialized_cursor(input: proc_macro::TokenStream) -> TokenStream {
463 initialized_cursor_(input, false)
464 }
465
466 #[proc_macro]
initialized_rev_cursor(input: proc_macro::TokenStream) -> TokenStream467 pub fn initialized_rev_cursor(input: proc_macro::TokenStream) -> TokenStream {
468 initialized_cursor_(input, true)
469 }
470
initialized_cursor_(input: proc_macro::TokenStream, rev: bool) -> TokenStream471 fn initialized_cursor_(input: proc_macro::TokenStream, rev: bool) -> TokenStream {
472 let input = proc_macro2::TokenStream::from(input);
473 let mut input_iter = input.into_iter();
474 let name = match input_iter.next() {
475 Some(TokenTree::Ident(id)) => id.to_string(),
476 _ => panic!("txn_table: first argument not an identifier"),
477 };
478 let cursor_name = syn::Ident::new(
479 &format!("{}Cursor", name_capital(&name),),
480 Span::call_site(),
481 );
482 let name_next = syn::Ident::new(&format!("cursor_{}_next", name), Span::call_site());
483 let name_prev = syn::Ident::new(&format!("cursor_{}_prev", name), Span::call_site());
484 let key = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
485 let value = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
486
487 let txnt = next(&mut input_iter);
488 let txnt: proc_macro2::TokenStream = if txnt.is_empty() {
489 proc_macro2::TokenStream::from(quote! { TxnT })
490 } else {
491 proc_macro2::TokenStream::from_iter(txnt.into_iter())
492 };
493
494 let error = next(&mut input_iter);
495 let error: proc_macro2::TokenStream = if error.is_empty() {
496 proc_macro2::TokenStream::from(quote! { GraphError })
497 } else {
498 proc_macro2::TokenStream::from_iter(error.into_iter())
499 };
500
501 assert!(input_iter.next().is_none());
502 if rev {
503 proc_macro::TokenStream::from(quote! {
504 impl<'a, T: #txnt> Iterator for crate::pristine::RevCursor<T, &'a T, T::#cursor_name, #key, #value>
505 {
506 type Item = Result<(&'a #key, &'a #value), TxnErr<T::#error>>;
507 fn next(&mut self) -> Option<Self::Item> {
508 match self.txn.#name_prev(&mut self.cursor) {
509 Ok(Some(x)) => Some(Ok(x)),
510 Ok(None) => None,
511 Err(e) => Some(Err(e)),
512 }
513 }
514 }
515 })
516 } else {
517 proc_macro::TokenStream::from(quote! {
518 impl<'a, T: #txnt>
519 crate::pristine::Cursor<T, &'a T, T::#cursor_name, #key, #value>
520 {
521 pub fn prev(&mut self) -> Option<Result<(&'a #key, &'a #value), TxnErr<T::#error>>> {
522 match self.txn.#name_prev(&mut self.cursor) {
523 Ok(Some(x)) => Some(Ok(x)),
524 Ok(None) => None,
525 Err(e) => Some(Err(e)),
526 }
527 }
528 }
529 impl<'a, T: #txnt> Iterator for crate::pristine::Cursor<T, &'a T, T::#cursor_name, #key, #value>
530 {
531 type Item = Result<(&'a #key, &'a #value), TxnErr<T::#error>>;
532 fn next(&mut self) -> Option<Self::Item> {
533 match self.txn.#name_next(&mut self.cursor) {
534 Ok(Some(x)) => Some(Ok(x)),
535 Ok(None) => None,
536 Err(e) => Some(Err(e)),
537 }
538 }
539 }
540 })
541 }
542 }
543
544 #[proc_macro]
put_del(input: proc_macro::TokenStream) -> TokenStream545 pub fn put_del(input: proc_macro::TokenStream) -> TokenStream {
546 let input = proc_macro2::TokenStream::from(input);
547 let mut input_iter = input.into_iter();
548 let name = match input_iter.next() {
549 Some(TokenTree::Ident(id)) => id.to_string(),
550 _ => panic!("txn_table: first argument not an identifier"),
551 };
552 let put = syn::Ident::new(&format!("put_{}", name), Span::call_site());
553 let del = syn::Ident::new(&format!("del_{}", name), Span::call_site());
554
555 let key = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
556 let value = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
557
558 let error = next(&mut input_iter);
559 let error = if error.is_empty() {
560 quote! { Error }
561 } else {
562 proc_macro2::TokenStream::from_iter(error.into_iter())
563 };
564 assert!(input_iter.next().is_none());
565 proc_macro::TokenStream::from(quote! {
566 fn #put(
567 &mut self,
568 k: &#key,
569 e: &#value,
570 ) -> Result<bool, TxnErr<Self::#error>>;
571 fn #del(
572 &mut self,
573 k: &#key,
574 e: Option<&#value>,
575 ) -> Result<bool, TxnErr<Self::#error>>;
576 })
577 }
578
579 #[proc_macro]
sanakirja_put_del(input: proc_macro::TokenStream) -> TokenStream580 pub fn sanakirja_put_del(input: proc_macro::TokenStream) -> TokenStream {
581 let input = proc_macro2::TokenStream::from(input);
582 let mut input_iter = input.into_iter();
583 let name = match input_iter.next() {
584 Some(TokenTree::Ident(id)) => id.to_string(),
585 _ => panic!("txn_table: first argument not an identifier"),
586 };
587 let put = syn::Ident::new(&format!("put_{}", name), Span::call_site());
588 let del = syn::Ident::new(&format!("del_{}", name), Span::call_site());
589 let name = syn::Ident::new(&name, Span::call_site());
590
591 let key = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
592 let value = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());
593
594 let error = next(&mut input_iter);
595 let error = if error.is_empty() {
596 quote! { Error }
597 } else {
598 proc_macro2::TokenStream::from_iter(error.into_iter())
599 };
600 assert!(input_iter.next().is_none());
601 proc_macro::TokenStream::from(quote! {
602 fn #put(
603 &mut self,
604 k: &#key,
605 v: &#value,
606 ) -> Result<bool, TxnErr<Self::#error>> {
607 Ok(::sanakirja::btree::put(&mut self.txn, &mut self.#name, k, v).map_err(TxnErr)?)
608 }
609 fn #del(
610 &mut self,
611 k: &#key,
612 v: Option<&#value>,
613 ) -> Result<bool, TxnErr<Self::#error>> {
614 Ok(::sanakirja::btree::del(&mut self.txn, &mut self.#name, k, v).map_err(TxnErr)?)
615 }
616 })
617 }
618