#[cfg(not(windows))]
compile_error!("windy-macros is Windows-host-only.");
use crate::convert::get_system_default_acp;
use std::str::FromStr;
use syn::{
Lit, LitInt, Token,
parse::{Parse, ParseStream},
parse_macro_input,
};
use windy::*;
mod convert;
mod raw;
#[allow(unused)]
pub(crate) const WC_ERR_INVALID_CHARS: u32 = 0x80;
#[allow(unused)]
pub(crate) const WC_NO_BEST_FIT_CHARS: u32 = 0x400;
fn lit_to_string(ast: Lit) -> String {
match ast {
Lit::Str(x) => x.value(),
Lit::Char(x) => x.value().to_string(),
Lit::Int(x) => x.base10_digits().to_string(),
Lit::Float(x) => x.base10_digits().to_string(),
Lit::Bool(x) => x.value.to_string(),
_ => panic!("Unsupported literal"),
}
}
macro_rules! lit_to_bs_lossy {
($x:ident, $ast:expr) => {{
let s = lit_to_string($ast);
let s = $x::from_utf8_lossy(&s);
let bytes = s.as_bytes_with_nul();
format!("{:?}", bytes)
}};
(@a $cp:expr, $ast:expr) => {{
let s = lit_to_string($ast);
let s =
windy::DAString::try_from_utf8_lossy($cp, &s).unwrap_or_else(|x| {
panic!(
"{:?} Couldn't be converted to code page {} : {:X?}",
s, $cp, x
)
});
let bytes = s.as_bytes_with_nul();
format!("{:?}", bytes)
}};
}
macro_rules! lit_to_bs {
($x:ident, $ast:expr) => {{
let s = lit_to_string($ast);
let s = $x::from_utf8(&s).unwrap_or_else(|x| {
panic!(
concat!(
"{:?} Couldn't be converted to ",
stringify!($x),
": {:X?}"
),
s, x
)
});
let bytes = s.as_bytes_with_nul();
format!("{:?}", bytes)
}};
(@a $cp:expr, $ast:expr) => {{
let s = lit_to_string($ast);
let s = windy::DAString::from_utf8($cp, &s).unwrap_or_else(|x| {
panic!(
"{:?} Couldn't be converted to code page {} : {:X?}",
s, $cp, x
)
});
let bytes = s.as_bytes_with_nul();
format!("{:?}", bytes)
}};
}
#[proc_macro]
pub fn wstring(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(ast as Lit);
let bs = lit_to_bs!(WString, ast);
let ts = format!(
"unsafe {{ ::windy::WString::from_vec_with_nul_unchecked({}) }}",
bs
);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn wstring_lossy(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(ast as Lit);
let bs = lit_to_bs_lossy!(WString, ast);
let ts = format!(
"unsafe {{ ::windy::WString::from_vec_with_nul_unchecked({}) }}",
bs
);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
fn code_page_literal_value(code_page: &LitInt) -> u32 {
code_page
.base10_parse::<u32>()
.expect("code page must be a u32 integer literal")
}
struct AStringInput {
code_page: LitInt,
value: Lit,
}
impl Parse for AStringInput {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let code_page = input.parse()?;
input.parse::<Token![,]>()?;
let value = input.parse()?;
if !input.is_empty() {
return Err(input.error(
"expected exactly two arguments: code page integer literal \
and literal",
));
}
Ok(Self { code_page, value })
}
}
#[proc_macro]
pub fn astring(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(ast as AStringInput);
let code_page = code_page_literal_value(&input.code_page);
let code_page_arg = code_page.to_string();
let bs = lit_to_bs!(@a code_page, input.value);
let ts = format!(
"unsafe {{ ::windy::AString::<{{ {} \
}}>::from_vec_with_nul_unchecked({}) }}",
code_page_arg, bs
);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn astring_lossy(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(ast as AStringInput);
let code_page = code_page_literal_value(&input.code_page);
let code_page_arg = code_page.to_string();
let bs = lit_to_bs_lossy!(@a code_page, input.value);
let ts = format!(
"unsafe {{ ::windy::AString::<{{ {} \
}}>::from_vec_with_nul_unchecked({}) }}",
code_page_arg, bs
);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn acpstring(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(ast as Lit);
let default_cp =
get_system_default_acp().expect("Failed to get system default acp");
let bs = lit_to_bs!(@a default_cp, ast);
let ts = format!(
"unsafe {{ ::windy::ACPString::from_vec_with_nul_unchecked({}) }}",
bs
);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn acpstring_lossy(
ast: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let ast = parse_macro_input!(ast as Lit);
let default_cp =
get_system_default_acp().expect("Failed to get system default acp");
let bs = lit_to_bs_lossy!(@a default_cp, ast);
let ts = format!(
"unsafe {{ ::windy::ACPString::from_vec_with_nul_unchecked({}) }}",
bs
);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn wstr(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(ast as Lit);
let bs = lit_to_bs!(WString, ast);
let ts = format!(
"unsafe {{ ::windy::WStr::from_bytes_with_nul_unchecked(&{}) }}",
bs
);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn wstr_lossy(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(ast as Lit);
let bs = lit_to_bs_lossy!(WString, ast);
let ts = format!(
"unsafe {{ ::windy::WStr::from_bytes_with_nul_unchecked(&{}) }}",
bs
);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn astr(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(ast as AStringInput);
let code_page = code_page_literal_value(&input.code_page);
let code_page_arg = code_page.to_string();
let bs = lit_to_bs!(@a code_page, input.value);
let ts = format!(
"unsafe {{ ::windy::AStr::<{{ {} \
}}>::from_bytes_with_nul_unchecked(&{}) }}",
code_page_arg, bs
);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn astr_lossy(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(ast as AStringInput);
let code_page = code_page_literal_value(&input.code_page);
let code_page_arg = code_page.to_string();
let bs = lit_to_bs_lossy!(@a code_page, input.value);
let ts = format!(
"unsafe {{ ::windy::AStr::<{{ {} \
}}>::from_bytes_with_nul_unchecked(&{}) }}",
code_page_arg, bs
);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn acpstr(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(ast as Lit);
let default_cp =
get_system_default_acp().expect("Failed to get system default acp");
let bs = lit_to_bs!(@a default_cp, ast);
let ts = format!(
"unsafe {{ ::windy::AStr::<0>::from_bytes_with_nul_unchecked(&{}) }}",
bs
);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn acpstr_lossy(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(ast as Lit);
let default_cp =
get_system_default_acp().expect("Failed to get system default acp");
let bs = lit_to_bs_lossy!(@a default_cp, ast);
let ts = format!(
"unsafe {{ ::windy::AStr::<0>::from_bytes_with_nul_unchecked(&{}) }}",
bs
);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn warr(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(ast as Lit);
let ts = lit_to_bs!(WString, ast);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn warr_lossy(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(ast as Lit);
let ts = lit_to_bs_lossy!(WString, ast);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn aarr(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(ast as AStringInput);
let code_page = code_page_literal_value(&input.code_page);
let ts = lit_to_bs!(@a code_page, input.value);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn aarr_lossy(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(ast as AStringInput);
let code_page = code_page_literal_value(&input.code_page);
let ts = lit_to_bs_lossy!(@a code_page, input.value);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn acparr(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(ast as Lit);
let default_cp =
get_system_default_acp().expect("Failed to get system default acp");
let ts = lit_to_bs!(@a default_cp, ast);
proc_macro::TokenStream::from_str(&ts).unwrap()
}
#[proc_macro]
pub fn acparr_lossy(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(ast as Lit);
let default_cp =
get_system_default_acp().expect("Failed to get system default acp");
let ts = lit_to_bs_lossy!(@a default_cp, ast);
proc_macro::TokenStream::from_str(&ts).unwrap()
}