starlane_primitive_macros/
lib.rs1#![crate_type = "lib"]
3#![allow(warnings)]
4#[feature("proc_macro_lib2")]
5#[macro_use]
6extern crate quote;
7
8use proc_macro::TokenStream;
9use proc_macro2::Ident;
10use proc_macro_crate::{crate_name, FoundCrate};
11use quote::quote;
12use quote::ToTokens;
13use syn::__private::TokenStream2;
14use syn::token::Mut;
15use syn::{
16 parse_file, parse_macro_input, AttrStyle, Attribute, AttributeArgs, Data, DeriveInput, Expr,
17 ExprTuple, File, FnArg, ImplItem, ItemImpl, LitStr, PatType, PathArguments, Token, Type,
18 Visibility,
19};
20
21#[proc_macro_derive(Autobox)]
57pub fn autobox(item: TokenStream) -> TokenStream {
58 let input = parse_macro_input!(item as DeriveInput);
59 let ident = &input.ident;
60
61 let mut xforms = vec![];
62 if let Data::Enum(data) = &input.data {
63 for variant in data.variants.clone() {
64 if variant.fields.len() > 1 {
65 panic!("derive Transform only works on Enums with single value tuples")
66 }
67
68 let variant_ident = variant.ident.clone();
69
70 if variant.fields.len() == 1 {
71 let mut i = variant.fields.iter();
72 let field = i.next().unwrap().clone();
73 let ty = field.ty.clone();
74 match ty {
75 Type::Path(path) => {
76 let segment = path.path.segments.last().cloned().unwrap();
77 if segment.ident == format_ident!("{}", "Box") {
78 let ty = match segment.arguments {
79 PathArguments::AngleBracketed(ty) => {
80 format_ident!("{}", ty.args.to_token_stream().to_string())
81 }
82 _ => panic!("expecting angle brackets"),
83 };
84
85 let ty_str = ty.to_string();
86
87 xforms.push(quote! {
88 impl TryInto<#ty> for #ident {
89 type Error=ParseErrs;
90
91 fn try_into(self) -> Result<#ty,Self::Error> {
92 match self {
93 Self::#variant_ident(val) => Ok(*val),
94 _ => Err(ParseErrs::new(format!("expected {}",#ty_str)))
95 }
96 }
97 }
98
99
100 impl From<#ty> for #ident {
101 fn from(f: #ty) -> #ident {
102 #ident::#variant_ident(Box::new(f))
103 }
104 }
105 });
106 } else {
107 let ty = segment.ident;
108 let ty_str = ty.to_token_stream().to_string();
109 xforms.push(quote! {
110 impl TryInto<#ty> for #ident {
111 type Error=ParseErrs;
112
113 fn try_into(self) -> Result<#ty,Self::Error> {
114 match self {
115 Self::#variant_ident(val) => Ok(val),
116 _ => Err(ParseErrs::new(format!("expected {}",#ty_str)))
117 }
118 }
119 }
120
121
122 impl From<#ty> for #ident {
123 fn from(f: #ty) -> #ident {
124 #ident::#variant_ident(f)
125 }
126 }
127 });
128 }
129 }
130 _ => {
131 panic!("TransformVariants can only handle Path types")
132 }
133 }
134 }
135 }
136 } else {
137 panic!("derive Transform only works on Enums")
138 }
139
140 let rtn = quote! { #(#xforms)* };
141
142 rtn.into()
143}
144
145#[proc_macro_derive(ToSubstance)]
146pub fn to_substance(item: TokenStream) -> TokenStream {
147 let input = parse_macro_input!(item as DeriveInput);
148 let ident = &input.ident;
149
150 let mut xforms = vec![];
151 if let Data::Enum(data) = &input.data {
152 for variant in data.variants.clone() {
153 if variant.fields.len() > 1 {
154 panic!("derive Transform only works on Enums with single value tuples")
155 }
156
157 let variant_ident = variant.ident.clone();
158
159 if variant.fields.len() == 1 {
160 let mut i = variant.fields.iter();
161 let field = i.next().unwrap().clone();
162 let ty = field.ty.clone();
163 match ty {
164 Type::Path(path) => {
165 let segment = path.path.segments.last().cloned().unwrap();
166 if segment.ident == format_ident!("{}", "Box") {
167 let ty = match segment.arguments {
168 PathArguments::AngleBracketed(ty) => {
169 format_ident!("{}", ty.args.to_token_stream().to_string())
170 }
171 _ => panic!("expecting angle brackets"),
172 };
173
174 let ty_str = ty.to_string();
175
176 xforms.push(quote! {
177 impl ToSubstance<#ty> for #ident {
178 fn to_substance(self) -> Result<#ty,ParseErrs> {
179 match self {
180 Self::#variant_ident(val) => Ok(*val),
181 _ => Err(ParseErrs::new(format!("expected {}",#ty_str)))
182 }
183 }
184
185 fn to_substance_ref(&self) -> Result<&#ty,ParseErrs> {
186 match self {
187 Self::#variant_ident(val) => Ok(val.as_ref()),
188 _ => Err(ParseErrs::new(format!("expected {}",#ty_str)))
189 }
190 }
191 }
192
193 });
194 } else {
195 let ty = segment.ident;
196 let ty_str = ty.to_token_stream().to_string();
197 xforms.push(quote! {
198 impl ToSubstance<#ty> for #ident {
199 fn to_substance(self) -> Result<#ty,ParseErrs> {
200 match self {
201 Self::#variant_ident(val) => Ok(val),
202 _ => Err(ParseErrs::new(format!("expected {}",#ty_str)))
203 }
204 }
205 fn to_substance_ref(&self) -> Result<&#ty,ParseErrs> {
206 match self {
207 Self::#variant_ident(val) => Ok(val),
208 _ => Err(ParseErrs::new(format!("expected {}",#ty_str)))
209 }
210 }
211 }
212
213 });
214 }
215 }
216 _ => {
217 panic!("ToSubstance can only handle Path types")
218 }
219 }
220 } else {
221 xforms.push(quote! {
222 impl ToSubstance<()> for #ident {
223 fn to_substance(self) -> Result<(),ParseErrs> {
224 match self {
225 Self::#variant_ident => Ok(()),
226 _ => Err(ParseErrs::new(format!("expected Empty")))
227 }
228 }
229 fn to_substance_ref(&self) -> Result<&(),ParseErrs> {
230 match self {
231 Self::#variant_ident => Ok(&()),
232 _ => Err(ParseErrs::new(format!("expected Empty")))
233 }
234 }
235 }
236
237 });
238 }
239 }
240 } else {
241 panic!("derive ToSubstance only works on Enums")
242 }
243
244 let rtn = quote! { #(#xforms)* };
245
246 rtn.into()
247}
248
249#[proc_macro_derive(ToBase)]
315pub fn base(item: TokenStream) -> TokenStream {
316 let input = parse_macro_input!(item as DeriveInput);
317 let ident = &input.ident;
318 let base = format_ident!("{}Base", ident);
319 let mut variants: Vec<Ident> = vec![];
320
321 if let Data::Enum(data) = &input.data {
322 for variant in data.variants.clone() {
323 variants.push(variant.ident.clone());
324 }
325 }
326
327 let rtn = quote! {
328 pub enum #base {
329 #(#variants),*
330 }
331
332
333 #[allow(bindings_with_variant_name)]
334 impl ToString for #base {
335 fn to_string(&self) -> String {
336 match self {
337 #( #variants => "#variants".to_string() ),*
338 }
339 }
340 }
341 };
342
343 rtn.into()
344}
345
346#[proc_macro_derive(ToLogMark)]
347pub fn to_log_mark(item: TokenStream) -> TokenStream {
348 let input = parse_macro_input!(item as DeriveInput);
349 let ident = &input.ident;
350 let base = format_ident!("{}Base", ident);
351 let mut variants: Vec<Ident> = vec![];
352
353 if let Data::Enum(data) = &input.data {
354 for variant in data.variants.clone() {
355 variants.push(variant.ident.clone());
356 }
357 }
358
359 let rtn = quote! {
360 pub enum #base {
361 #(#variants),*
362 }
363
364
365 #[allow(bindings_with_variant_name)]
366 impl ToString for #base {
367 fn to_string(&self) -> String {
368 match self {
369 #( #variants => "#variants".to_string() ),*
370 }
371 }
372 }
373 };
374
375 rtn.into()
376}
377
378#[cfg(test)]
379mod tests {
380 #[test]
381 fn it_works() {
382 let result = 2 + 2;
383 assert_eq!(result, 4);
384 }
385}
386
387#[proc_macro_derive(EnumAsStr)]
388pub fn directed_handler(item: TokenStream) -> TokenStream {
389 TokenStream::from(quote! {})
390}
391
392#[proc_macro_attribute]
393pub fn loggerhead(_attr: TokenStream, item: TokenStream) -> TokenStream {
394 let mut out = vec![];
395 let input = parse_macro_input!(item as File);
396 for item in input.items.into_iter() {
397 let item = quote!(#item);
398 println!("running parser over {}", item);
399 out.push(item);
400 }
401
402 let rtn = quote! {
403 #(#out)*
404 };
405
406 rtn.into()
407}
408
409#[proc_macro]
410pub fn push_loc(tokens: TokenStream) -> TokenStream {
411 let crt = crt_name();
412 let tuple = parse_macro_input!(tokens as ExprTuple);
413 let mut iter = tuple.elems.into_iter();
414 let logger = iter.next().unwrap();
415 let loc = iter.next().unwrap();
416
417 let rtn = quote! {
418 {
419 let mut builder = #crt::space::log::LogMarkBuilder::default();
420 builder.package(env!("CARGO_PKG_NAME").to_string());
421 builder.file(file!().to_string());
422 builder.line(line!().to_string());
423 let mark = builder.build().unwrap();
424 #logger.push(#loc)
425 }
426 };
427
428 rtn.into()
429}
430
431#[proc_macro]
432pub fn log_span(tokens: TokenStream) -> TokenStream {
433 let crt = crt_name();
434 let input = parse_macro_input!(tokens as Expr);
435 let rtn = quote! {
436 {
437 let mut builder = #crt::space::log::LogMarkBuilder::default();
438 builder.package(env!("CARGO_PKG_NAME").to_string());
439 builder.file(file!().to_string());
440 builder.line(line!().to_string());
441 let mark = builder.build().unwrap();
442 #input.push_mark(mark)
443 }
444 };
445
446 rtn.into()
447}
448
449#[proc_macro]
450pub fn logger(item: TokenStream) -> TokenStream {
451 let crt = crt_name();
452 let log_pack = quote!(#crt::space::log);
453
454 let loc = if !item.is_empty() {
455 let expr = parse_macro_input!(item as Expr);
456 quote!( #log_pack::logger().push(#expr); )
457 } else {
458 quote!( #log_pack::logger(); )
459 };
460
461 let rtn = quote! {
462 {
463 let logger = #loc;
464 let mut builder = #log_pack::LogMarkBuilder::default();
465 builder.package(env!("CARGO_PKG_NAME").to_string());
466 builder.file(file!().to_string());
467 builder.line(line!().to_string());
468 let mark = builder.build().unwrap();
469 logger.push_mark(mark)
470 }
471 };
472
473 rtn.into()
474}
475
476#[proc_macro]
477pub fn push_mark(_item: TokenStream) -> TokenStream {
478 let crt = crt_name();
479 let logger = parse_macro_input!(_item as Expr);
480 let rtn = quote! {
481 {
482 let mut builder = #crt::space::log::LogMarkBuilder::default();
483 builder.package(env!("CARGO_PKG_NAME").to_string());
484 builder.file(file!().to_string());
485 builder.line(line!().to_string());
486 let mark = builder.build().unwrap();
487 #logger.push_mark(mark)
488 }
489
490 };
491
492 rtn.into()
493
494}
495
496#[proc_macro]
497pub fn create_mark(_item: TokenStream) -> TokenStream {
498 let crt = crt_name();
499 let rtn = quote! {
500 {
501println!("CARGO_PKG_NAME: {}", env!("CARGO_PKG_NAME"));
502 let mut builder = #crt::space::log::LogMarkBuilder::default();
503 builder.package(env!("CARGO_PKG_NAME").to_string());
504 builder.file(file!().to_string());
505 builder.line(line!().to_string());
506 builder.build().unwrap()
507 }
508 };
509
510 rtn.into()
511}
512
513#[proc_macro]
514pub fn warn(_item: TokenStream) -> TokenStream {
515 let crt = crt_name();
516 let input = parse_macro_input!(_item as LitStr);
517 let rtn = quote! {
518
519 {
522 use starlane_primitive_macros::mark;
523 use starlane_primitive_macros::create_mark;
524 use #crt::space::log::Log;
525 use #crt::space::log::LOGGER;
526 use #crt::space::log::root_logger;
527
528 LOGGER.try_with(|logger| {
530 logger.warn(stringify!(#input));
531 } ).map_err(|e| {
532 root_logger().warn(stringify!(#input));
533 })
534 }
535 };
536 rtn.into()
537}
538
539#[proc_macro_attribute]
562pub fn log(attr: TokenStream, item: TokenStream) -> TokenStream {
563 item.into()
564}
565
566#[proc_macro_attribute]
567pub fn logger_att(attr: TokenStream, item: TokenStream) -> TokenStream {
568 let surface = if attr.is_empty() {
569 format_ident!("logger")
570 } else {
571 format_ident!("{}", attr.to_string())
572 };
573
574 let item_cp = item.clone();
575 let mut impl_item = parse_macro_input!(item_cp as syn::ItemImpl);
576 for item_impl in &impl_item.items {
580 if let ImplItem::Method(call) = item_impl {
581 {
582 let (__async, __await) = match call.sig.asyncness {
583 None => (quote! {}, quote! {}),
584 Some(_) => (quote! {async}, quote! {.await}),
585 };
586
587 let mut inner_call = call.clone();
588 inner_call.vis = Visibility::Inherited;
589 inner_call.sig.ident = format_ident!("__{}", call.sig.ident);
590 inner_call.attrs = vec![];
591 todo!();
609
610 let attributes = call.attrs.clone();
611 let vis = call.vis.clone();
612 let sig = call.sig.clone();
613 let block = call.block.clone();
614
615 call.clone();
616 let blah = quote! {
617 #(#attributes)*
618 #vis
619 #__async
620 #sig
621 {
622 #inner_call
623 }
624 };
625 panic!("{}", blah);
626 }
627 }
628 }
629
630 todo!()
632}
633
634fn find_impl_type(item_impl: &ItemImpl) -> Ident {
635 if let Type::Path(path) = &*item_impl.self_ty {
636 path.path.segments.last().as_ref().unwrap().ident.clone()
637 } else {
638 panic!("could not get impl name")
639 }
640}
641
642fn find_log_attr(attrs: &Vec<Attribute>) -> TokenStream {
643 for attr in attrs {
644 if attr
645 .path
646 .segments
647 .last()
648 .expect("segment")
649 .to_token_stream()
650 .to_string()
651 .as_str()
652 == "logger"
653 {
654 let rtn = quote!(#attr);
655 return rtn.into();
656 }
657 }
658 let rtn = quote!(logger);
659 rtn.into()
660}
661
662
663
664
665fn crt_name () -> TokenStream2{
666 let found_crate = crate_name("starlane").expect("my-crate is present in `Cargo.toml`");
667
668 let crt = match found_crate {
669 FoundCrate::Itself => quote!( crate ),
670 FoundCrate::Name(name) => {
671 quote!( starlane )
672 }
673 };
674 crt
675}
676