1#![doc(html_root_url = "https://docs.rs/iter-tuple/0.3.8")]
2use proc_macro::TokenStream;
22use proc_macro2::TokenStream as PM2TS;
23use proc_macro2::{TokenTree, Ident, Literal}; use proc_macro2::{Span}; use quote::{quote, ToTokens}; use syn; use std::ops::Deref;
28
29fn pre_ast_ident(pre: &str, id: &Ident, post: &str, a: bool) -> TokenStream {
32let mut s = id.to_string();
35 if !a { s = s.to_lowercase(); }
36 let str_id = &format!("{}{}{}", pre, s, post);
37 let mut ts: PM2TS = PM2TS::new(); Ident::new(str_id, Span::call_site()).to_tokens(&mut ts);
39 ts.into()
40}
41
42fn pre_ast_string(pre: &str, id: &Ident, post: &str, a: bool) -> TokenStream {
45 let mut s = id.to_string();
46 if !a { s = s.to_lowercase(); }
47 let str_id = &format!("{}{}{}", pre, s, post);
48 let mut ts: PM2TS = PM2TS::new(); Literal::string(str_id).to_tokens(&mut ts);
50 ts.into()
51}
52
53fn pre_ast_usize(n: usize) -> TokenStream {
55 let mut ts: PM2TS = PM2TS::new(); Literal::usize_unsuffixed(n).to_tokens(&mut ts); ts.into()
58}
59
60fn ast_dtype(dt: &Ident) -> PM2TS {
62 match dt.to_string().as_str() {
63 "Int64" => quote! { i64 },
64 "Int32" => quote! { i32 },
65 "Int16" => quote! { i16 },
66 "Int8" => quote! { i8 },
67 "UInt64" => quote! { u64 },
68 "UInt32" => quote! { u32 },
69 "UInt16" => quote! { u16 },
70 "UInt8" => quote! { u8 },
71 "Float64" => quote! { f64 }, "Float32" => quote! { f32 }, "Utf8" => quote! { &'a str }, "String" => quote! { &'a str }, "Boolean" => quote! { bool },
76 "Binary" => quote! { Vec<u8> },
77 "Null" => quote! { i64 }, "Unknown" => quote! { i64 }, _ => quote! { i64 } }
81}
82
83fn ast_dtype_from_anyvalue_col(dt: &Ident, n: &Literal) -> PM2TS {
85quote! { from_any!(v[#n], DataType::#dt) }
117}
118
119fn ast_dtype_to_sqlite3_vec(dt: &Ident, ast_id: &Ident) -> PM2TS {
121 match dt.to_string().as_str() {
122 "Int64" => quote! { self.#ast_id },
123 "Int32" => quote! { (self.#ast_id as i64) },
124 "Int16" => quote! { (self.#ast_id as i64) },
125 "Int8" => quote! { (self.#ast_id as i64) },
126 "UInt64" => quote! { (self.#ast_id as i64) },
127 "UInt32" => quote! { (self.#ast_id as i64) },
128 "UInt16" => quote! { (self.#ast_id as i64) },
129 "UInt8" => quote! { (self.#ast_id as i64) },
130 "Float64" => quote! { self.#ast_id }, "Float32" => quote! { (self.#ast_id as f64) }, "Utf8" => quote! { self.#ast_id }, "String" => quote! { self.#ast_id }, "Boolean" => quote! { (if self.#ast_id {"T"} else {"F"}) },
135 "Binary" => quote! { (&self.#ast_id[..]) },
136 "Null" => quote! { self.#ast_id }, "Unknown" => quote! { self.#ast_id }, _ => quote! { self.#ast_id } }
140}
141
142fn ast_dtype_sqlite3_col(dt: &Ident) -> (PM2TS, PM2TS) {
144 match dt.to_string().as_str() {
145 "Int64" => (quote! { i64 }, quote! {}),
146 "Int32" => (quote! { i64 }, quote! { as i32 }),
147 "Int16" => (quote! { i64 }, quote! { as i16 }),
148 "Int8" => (quote! { i64 }, quote! { as i8 }),
149 "UInt64" => (quote! { i64 }, quote! { as u64 }),
150 "UInt32" => (quote! { i64 }, quote! { as u32 }),
151 "UInt16" => (quote! { i64 }, quote! { as u16 }),
152 "UInt8" => (quote! { i64 }, quote! { as u8 }),
153 "Float64" => (quote! { f64 }, quote! {}), "Float32" => (quote! { f64 }, quote! { as f32 }), "Utf8" => (quote! { &'a str }, quote! {}), "String" => (quote! { &'a str }, quote! {}), "Boolean" => (quote! { &'a str }, quote! { == "T" }), "Binary" => (quote! { &[u8] }, quote! { .to_vec() }), "Null" => (quote! { i64 }, quote! {}), "Unknown" => (quote! { i64 }, quote! {}), _ => (quote! { i64 }, quote! {}) }
163}
164
165fn sqlite3_cols(attr: PM2TS, n: &mut usize) -> TokenStream {
167 let mut cols = quote! {};
168 for tt in attr { match tt {
170 TokenTree::Ident(dt) => { let i = pre_ast_usize(*n); let ast_i = syn::parse_macro_input!(i as Literal);
174 let (t, p) = ast_dtype_sqlite3_col(&dt);
175 cols = quote! {
176 #cols
177 row.read::<#t, _>(#ast_i) #p,
178 };
179 *n += 1;
180 },
181 _ => {} }
183 }
184 quote! { (#cols) }.into()
185}
186
187fn type_cols(attr: PM2TS) -> TokenStream {
189 let mut cols = quote! {};
190 for tt in attr { match tt {
192 TokenTree::Ident(dt) => { cols = quote! {
195 #cols
196 DataType::#dt,
197 };
198 },
199 _ => {} }
201 }
202 quote! { vec![#cols] }.into()
203}
204
205fn vec_cols(attr: PM2TS, n: &mut usize) -> TokenStream {
207 let mut cols = quote! {};
208 for tt in attr { match tt {
210 TokenTree::Ident(dt) => { let i = pre_ast_usize(*n); let ast_i = syn::parse_macro_input!(i as Literal);
214 let v = match dt.to_string().as_str() {
215 "Binary" => quote! { to_any!(t.#ast_i, DataType::BinaryOwned) },
218 _ => quote! { to_any!(t.#ast_i, DataType::#dt) }
220 };
221 cols = quote! {
222 #cols
223 #v,
227 };
228 *n += 1;
229 },
230 _ => {} }
232 }
233 quote! { let v = vec![#cols]; }.into()
234}
235
236fn to_sqlite3_vec(mns: &Vec<Ident>, dts: &Vec<Ident>) -> TokenStream {
238 let mut members = quote! {};
239 for (i, n) in mns.iter().enumerate() {
240 let tag = pre_ast_string(":", n, "", true);
241 let ast_tag = syn::parse_macro_input!(tag as Literal); let id = pre_ast_ident("", n, "", true);
243 let ast_id = syn::parse_macro_input!(id as syn::Ident); let v = ast_dtype_to_sqlite3_vec(&dts[i], &ast_id);
245 members = quote! {
246 #members
247 (#ast_tag, #v.into()),
248 }
249 }
250 quote! { vec![#members] }.into() }
252
253fn from_anyvalue_col(dts: &Vec<Ident>) -> TokenStream {
255 let mut members = quote! {};
256 for (i, dt) in dts.iter().enumerate() {
257 let u = pre_ast_usize(i); let ast_i = syn::parse_macro_input!(u as Literal);
259 let v = ast_dtype_from_anyvalue_col(dt, &ast_i);
260 members = quote! {
261 #members
262 #v,
263 };
264 }
265 quote! { (#members) }.into() }
267
268fn from_tuple_members(mns: &Vec<Ident>) -> TokenStream {
270 let mut members = quote! {};
271 for (i, n) in mns.iter().enumerate() {
272 let id = pre_ast_ident("", n, "", true);
273 let ast_id = syn::parse_macro_input!(id as syn::Ident); let u = pre_ast_usize(i); let ast_i = syn::parse_macro_input!(u as Literal);
276 members = quote! {
277 #members
278 #ast_id: t.#ast_i,
279 };
280 }
281 members.into() }
283
284fn to_tuple_members(mns: &Vec<Ident>, dts: &Vec<Ident>) -> TokenStream {
286 let mut members = quote! {};
287 for (i, n) in mns.iter().enumerate() {
288 let id = pre_ast_ident("", n, "", true);
289 let ast_id = syn::parse_macro_input!(id as syn::Ident); let v = match dts[i].to_string().as_str() {
291 "Binary" => quote! { self.#ast_id.clone() },
293 _ => quote! { self.#ast_id }
294 };
295 members = quote! {
296 #members
297 #v,
298 };
299 }
300 quote! { (#members) }.into() }
302
303fn type_members(dts: &Vec<Ident>) -> TokenStream {
305 let mut members = quote! {};
306 for dt in dts.iter() {
307 members = quote! {
308 #members
309 DataType::#dt,
310 };
311 }
312 quote! { vec![#members] }.into() }
314
315fn str_members(mns: &Vec<Ident>) -> TokenStream {
317 let mut members = quote! {};
318 for n in mns.iter() {
319 let id = pre_ast_ident("", n, "", true);
320 let ast_id = syn::parse_macro_input!(id as syn::Ident); members = quote! {
322 #members
323 stringify!(#ast_id),
324 };
325 }
326 quote! { vec![#members] }.into() }
328
329fn list_members(mns: &Vec<Ident>, dts: &Vec<Ident>) -> TokenStream {
331 let mut members = quote! {};
332 for (i, n) in mns.iter().enumerate() {
333 let id = pre_ast_ident("", n, "", true);
334 let ast_id = syn::parse_macro_input!(id as syn::Ident); let dt = ast_dtype(&dts[i]);
336 members = quote! {
337 #members
338 pub #ast_id: #dt,
340 };
341 }
342 members.into() }
344
345fn parse_attr(attr: PM2TS) -> (Vec<Ident>, Vec<Ident>) {
347 let (mut mns, mut dts) = (Vec::<Ident>::new(), Vec::<Ident>::new());
348 let mut i = 0usize;
349 for tt in attr { match tt {
351 TokenTree::Group(gp) => { for t in gp.stream() {
353 match t {
354 TokenTree::Ident(dt) => { if i == 0 { mns.push(dt); } else { dts.push(dt); }
357 },
358 _ => {} }
360 }
361 i += 1;
362 },
363 _ => {} }
365 }
366 (mns, dts)
367}
368
369fn tuple_check(item: TokenStream, n: usize, f: &str) -> TokenStream {
371 let ast = syn::parse_macro_input!(item as syn::ItemType);
372let ty = &ast.ty; let elem_len = match ty.deref() {
376 syn::Type::Tuple(typetuple) => { typetuple.elems.len()
379 },
380 _ => { panic!("{} requires type alias of tuple", f); }
381 };
382if elem_len != n { panic!("{} attributes not match with tuple", f); }
384 ast.into_token_stream().into()
385}
386
387#[proc_macro_attribute]
390pub fn struct_derive(attr: TokenStream, item: TokenStream) -> TokenStream {
391let (mns, dts) = parse_attr(attr.into());
393 let (m, n) = (mns.len(), dts.len());
394 if m != n { panic!("struct_derive attributes not same length"); }
395 let ast_type_members: PM2TS = type_members(&dts).into();
396let ast_str_members: PM2TS = str_members(&mns).into();
398let ast_list_members: PM2TS = list_members(&mns, &dts).into();
400let ast_to_tuple_members: PM2TS = to_tuple_members(&mns, &dts).into();
402let ast_from_tuple_members: PM2TS = from_tuple_members(&mns).into();
404let ast_to_sqlite3_vec: PM2TS = to_sqlite3_vec(&mns, &dts).into();
406let ast_from_anyvalue_col: PM2TS = from_anyvalue_col(&dts).into();
408let tp = tuple_check(item, n, "struct_derive");
411 let ast = syn::parse_macro_input!(tp as syn::ItemType);
412
413 let tpl_id = &ast.ident;
414let st_id = pre_ast_ident("St", tpl_id, "", true); let ast_st_id = syn::parse_macro_input!(st_id as syn::Ident);
417let fnc_id = pre_ast_ident("to_", tpl_id, "", false); let ast_fnc_id = syn::parse_macro_input!(fnc_id as syn::Ident);
420let rec_id = pre_ast_ident("Rec", tpl_id, "", true); let ast_rec_id = syn::parse_macro_input!(rec_id as syn::Ident);
423quote! {
426#ast
427pub struct #ast_st_id<'a> {
429 #ast_list_members
430}
431impl<'a> #ast_st_id<'a> {
433 pub fn members() -> Vec<&'a str> {
435 #ast_str_members
436 }
437 pub fn types() -> Vec<DataType> {
439 #ast_type_members
440 }
441 pub fn #ast_fnc_id(&self) -> #tpl_id<'_> {
443 #ast_to_tuple_members
444 }
445}
446impl<'a> IntoAnyValueVec<'a> for #ast_st_id<'a> {
448 fn into_vec(self) -> Vec<AnyValue<'a>> {
450#ast_rec_id::from(#ast_to_tuple_members).v
452 }
453}
454impl<'a> ToSqlite3ValueVec for #ast_st_id<'a> {
456 fn to_sqlite3_vec(&self) -> Vec<(&'_ str, sqlite::Value)> {
458 #ast_to_sqlite3_vec
459 }
460}
461impl<'a> From<#tpl_id<'a>> for #ast_st_id<'a> {
463 fn from(t: #tpl_id<'a>) -> #ast_st_id<'_> {
465 #ast_st_id{#ast_from_tuple_members}
466 }
467}
468impl<'a> From<&'a sqlite::Row> for #ast_st_id<'a> {
470 fn from(row: &'a sqlite::Row) -> #ast_st_id<'_> {
472 #ast_st_id::from(#ast_fnc_id(row))
473 }
474}
475impl<'a> From<&'a Vec<AnyValue<'a>>> for #ast_st_id<'a> {
477 fn from(v: &'a Vec<AnyValue<'a>>) -> #ast_st_id<'_> {
479 #ast_st_id::from(#ast_from_anyvalue_col)
480 }
481}
482 }.into()
483}
488
489#[proc_macro_attribute]
492pub fn tuple_sqlite3(attr: TokenStream, item: TokenStream) -> TokenStream {
493let mut n = 0usize;
495 let ts_cols = sqlite3_cols(attr.into(), &mut n); let ast_cols = syn::parse_macro_input!(ts_cols as syn::Expr);
497let tp = tuple_check(item, n, "tuple_sqlite3");
500 let ast = syn::parse_macro_input!(tp as syn::ItemType);
501
502 let tpl_id = &ast.ident;
503let rec_id = pre_ast_ident("Rec", tpl_id, "", true); let ast_rec_id = syn::parse_macro_input!(rec_id as syn::Ident);
506let fnc_id = pre_ast_ident("to_", tpl_id, "", false); let ast_fnc_id = syn::parse_macro_input!(fnc_id as syn::Ident);
509quote! {
512#ast
513pub fn #ast_fnc_id<'a>(row: &'a sqlite::Row) -> #tpl_id<'_> {
515 #ast_cols
516}
517impl<'a> From<&'a sqlite::Row> for #ast_rec_id<'a> {
519 fn from(row: &'a sqlite::Row) -> #ast_rec_id<'_> {
521 #ast_rec_id::from(#ast_fnc_id(row))
522 }
523}
524 }.into()
525}
530
531#[proc_macro_attribute]
535pub fn tuple_derive(attr: TokenStream, item: TokenStream) -> TokenStream {
536let type_cols = type_cols(attr.clone().into()); let ast_type_members = syn::parse_macro_input!(type_cols as syn::Expr);
539let mut n = 0usize;
542 let ts_cols = vec_cols(attr.into(), &mut n); let ast_cols = syn::parse_macro_input!(ts_cols as syn::Stmt);
544let tp = tuple_check(item, n, "tuple_derive");
547 let ast = syn::parse_macro_input!(tp as syn::ItemType);
548
549 let tpl_id = &ast.ident;
550let rec_id = pre_ast_ident("Rec", tpl_id, "", true); let ast_rec_id = syn::parse_macro_input!(rec_id as syn::Ident);
553quote! {
556#ast
557pub struct #ast_rec_id<'a> {
559 pub v: Vec<AnyValue<'a>>
561}
562impl<'a> IntoIterator for #ast_rec_id<'a> {
564 type Item = AnyValue<'a>;
566 type IntoIter = std::vec::IntoIter<Self::Item>;
568 fn into_iter(self) -> Self::IntoIter {
571 self.v.into_iter()
572 }
573}
574impl<'a> From<#tpl_id<'a>> for #ast_rec_id<'a> {
576 fn from(t: #tpl_id<'a>) -> #ast_rec_id<'_> {
578 #ast_cols
579 #ast_rec_id{v}
580 }
581}
582impl<'a> #ast_rec_id<'a> {
584 pub fn types() -> Vec<DataType> {
586 #ast_type_members
587 }
588 pub fn into_iter(t: #tpl_id<'a>) -> std::vec::IntoIter<AnyValue<'_>> {
590 #ast_rec_id::from(t).into_iter()
591 }
592}
593 }.into()
594}
599
600#[cfg(test)]
602mod tests {
603#[test]
608 fn test_iter_tuple() {
609 assert_eq!(true, true);
610 }
611}