pijul_macros/
lib.rs

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