1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4
5use proc_macro_hack::proc_macro_hack;
6use quote::quote;
7use syn::{parse_macro_input, LitStr};
8
9use unic_langid_impl::{subtags, LanguageIdentifier};
10
11#[proc_macro_hack]
12pub 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]
29pub 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]
41pub 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]
53pub 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]
65pub 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