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