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}