const_source_position/
lib.rs

1#![allow(incomplete_features)]
2#![feature(adt_const_params)]
3#![feature(proc_macro_span)]
4extern crate proc_macro;
5
6use proc_macro::{TokenStream, Span};
7use quote::quote;
8use syn::spanned::Spanned;
9use syn::{parse_macro_input, Path};
10
11/**
12Takes a type path as an argument and provides the source code path as a type parameter to the last element of the path.
13This has a very specific use case involving serde and large numbers of structs.
14Example:
15```ignore
16    #![forbid(unsafe_code)]
17    #![feature(adt_const_params)]
18    #![allow(dead_code)]
19    use std::fmt::{Display, Formatter};
20    use std::fmt;
21
22    extern crate const_source_position;
23
24    // Phantom type
25    enum Unconstructable<const SOURCE_LOCATION: &'static str> {}
26
27    impl<const SOURCE_LOCATION: &'static str> Display for Unconstructable<SOURCE_LOCATION>  {
28        fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
29        {
30            write!(f, "{}", SOURCE_LOCATION)
31        }
32    }
33
34    /*
35        complicated type stuff, generics, macros, etc
36    */
37
38    fn generates_unconstructable_somehow() -> Box<dyn Display> {
39        unimplemented!();
40    }
41```
42*/
43#[proc_macro]
44pub fn source_line (item: TokenStream) -> TokenStream {
45    let path = parse_macro_input!(item as Path);
46
47    let span = Span::call_site();
48    let mut file_source =
49    (*span
50        .source_file()
51        .path()
52        .to_string_lossy()
53    )
54            .to_string();
55
56    let line_column = span.source().start();
57
58    file_source.push_str(&format!(":{}:{}", line_column.line, line_column.column));
59    let lit = syn::LitStr::new(&file_source, span.into());
60
61    let gen_arg = syn::GenericArgument::Const(syn::Expr::Lit(syn::ExprLit { attrs: vec![], lit: syn::Lit::Str(lit) }));
62
63    let mut segments = path.segments.clone();
64
65    let mut gen_args = syn::punctuated::Punctuated::<syn::GenericArgument, syn::token::Comma>::new();
66
67    gen_args.push(gen_arg);
68
69    segments.last_mut().unwrap().arguments = syn::PathArguments::AngleBracketed(
70        syn::AngleBracketedGenericArguments {
71            colon2_token: Some(
72                syn::token::Colon2(path.span())
73            ),
74            lt_token: syn::token::Lt(path.span()),
75            args: gen_args,
76            gt_token: syn::token::Gt(path.span())
77        }
78    );
79
80    let c = syn::Type::Path(syn::TypePath { qself: None, path: Path {
81        leading_colon: path.leading_colon,
82        segments,
83    }});
84
85    quote!(#c).into()
86}