1 | extern crate proc_macro; |
2 | |
3 | use proc_macro::TokenStream; |
4 | |
5 | use proc_macro_hack::proc_macro_hack; |
6 | use quote::quote; |
7 | use syn::{parse_macro_input, LitStr}; |
8 | |
9 | use unic_langid_impl::{subtags, LanguageIdentifier}; |
10 | |
11 | #[proc_macro_hack ] |
12 | pub fn lang(input: TokenStream) -> TokenStream { |
13 | let id: LitStr = parse_macro_input!(input as LitStr); |
14 | let parsed: subtags::Language = id.value().parse().expect(msg:"Malformed Language Subtag" ); |
15 | |
16 | let lang: Option<u64> = parsed.into(); |
17 | let lang: TokenStream = if let Some(lang: u64) = lang { |
18 | quote!(unsafe { $crate::subtags::Language::from_raw_unchecked(#lang) }) |
19 | } else { |
20 | quote!(None) |
21 | }; |
22 | |
23 | TokenStream::from(quote! { |
24 | #lang |
25 | }) |
26 | } |
27 | |
28 | #[proc_macro_hack ] |
29 | pub fn script(input: TokenStream) -> TokenStream { |
30 | let id: LitStr = parse_macro_input!(input as LitStr); |
31 | let parsed: subtags::Script = id.value().parse().expect(msg:"Malformed Script Subtag" ); |
32 | |
33 | let script: u32 = parsed.into(); |
34 | |
35 | TokenStream::from(quote! { |
36 | unsafe { $crate::subtags::Script::from_raw_unchecked(#script) } |
37 | }) |
38 | } |
39 | |
40 | #[proc_macro_hack ] |
41 | pub fn region(input: TokenStream) -> TokenStream { |
42 | let id: LitStr = parse_macro_input!(input as LitStr); |
43 | let parsed: subtags::Region = id.value().parse().expect(msg:"Malformed Region Subtag" ); |
44 | |
45 | let region: u32 = parsed.into(); |
46 | |
47 | TokenStream::from(quote! { |
48 | unsafe { $crate::subtags::Region::from_raw_unchecked(#region) } |
49 | }) |
50 | } |
51 | |
52 | #[proc_macro_hack ] |
53 | pub fn variant_fn(input: TokenStream) -> TokenStream { |
54 | let id: LitStr = parse_macro_input!(input as LitStr); |
55 | let parsed: subtags::Variant = id.value().parse().expect(msg:"Malformed Variant Subtag" ); |
56 | |
57 | let variant: u64 = parsed.into(); |
58 | |
59 | TokenStream::from(quote! { |
60 | unsafe { $crate::subtags::Variant::from_raw_unchecked(#variant) } |
61 | }) |
62 | } |
63 | |
64 | #[proc_macro_hack ] |
65 | pub fn langid(input: TokenStream) -> TokenStream { |
66 | let id = parse_macro_input!(input as LitStr); |
67 | let parsed: LanguageIdentifier = id.value().parse().expect("Malformed Language Identifier" ); |
68 | |
69 | let (lang, script, region, variants) = parsed.into_parts(); |
70 | |
71 | let lang: Option<u64> = lang.into(); |
72 | let lang = if let Some(lang) = lang { |
73 | quote!(unsafe { $crate::subtags::Language::from_raw_unchecked(#lang) }) |
74 | } else { |
75 | quote!($crate::subtags::Language::default()) |
76 | }; |
77 | |
78 | let script = if let Some(script) = script { |
79 | let script: u32 = script.into(); |
80 | quote!(Some(unsafe { $crate::subtags::Script::from_raw_unchecked(#script) })) |
81 | } else { |
82 | quote!(None) |
83 | }; |
84 | |
85 | let region = if let Some(region) = region { |
86 | let region: u32 = region.into(); |
87 | quote!(Some(unsafe { $crate::subtags::Region::from_raw_unchecked(#region) })) |
88 | } else { |
89 | quote!(None) |
90 | }; |
91 | |
92 | let variants = if !variants.is_empty() { |
93 | let v: Vec<_> = variants |
94 | .iter() |
95 | .map(|v| { |
96 | let variant: u64 = v.into(); |
97 | quote!(unsafe { $crate::subtags::Variant::from_raw_unchecked(#variant) }) |
98 | }) |
99 | .collect(); |
100 | quote!(Some(Box::new([#(#v,)*]))) |
101 | } else { |
102 | quote!(None) |
103 | }; |
104 | |
105 | TokenStream::from(quote! { |
106 | unsafe { $crate::LanguageIdentifier::from_raw_parts_unchecked(#lang, #script, #region, #variants) } |
107 | }) |
108 | } |
109 | |