// Copyright (c) the JPEG XL Project Authors. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.
externcrate proc_macro;
use proc_macro::TokenStream; use proc_macro_error2::{abort, proc_macro_error}; use proc_macro2::TokenStream as TokenStream2; use quote::quote; use syn::{DeriveInput, Meta, parse_macro_input};
fn get_bits(expr_call: &syn::ExprCall) -> syn::Expr { iflet syn::Expr::Path(ep) = &*expr_call.func { if !ep.path.is_ident("Bits") {
abort!(
expr_call, "Unexpected function name in coder: {}",
ep.path.get_ident().unwrap()
);
} if expr_call.args.len() != 1 {
abort!(
expr_call, "Unexpected number of arguments for Bits() in coder: {}",
expr_call.args.len()
);
} return expr_call.args[0].clone();
}
abort!(expr_call, "Unexpected function call in coder");
}
fn parse_single_coder(input: &syn::Expr, extra_lit: Option<&syn::ExprLit>) -> TokenStream2 { match &input {
syn::Expr::Lit(lit) => match extra_lit {
None => quote! {U32::Val(#lit)},
Some(elit) => quote! {U32::Val(#lit + #elit)},
},
syn::Expr::Call(expr_call) => { let bits = get_bits(expr_call); match extra_lit {
None => quote! {U32::Bits(#bits)},
Some(elit) => quote! {U32::BitsOffset{n: #bits, off: #elit}},
}
}
syn::Expr::Binary(syn::ExprBinary {
attrs: _,
left,
op: syn::BinOp::Add(_),
right,
}) => { let (left, right) = iflet syn::Expr::Lit(_) = **left {
(right, left)
} else {
(left, right)
}; match (&**left, &**right) {
(syn::Expr::Call(expr_call), syn::Expr::Lit(lit)) => { let bits = get_bits(expr_call); match extra_lit {
None => quote! {U32::BitsOffset{n: #bits, off: #lit}},
Some(elit) => quote! {U32::BitsOffset{n: #bits, off: #lit + #elit}},
}
}
_ => abort!(
input, "Unexpected expression in coder, must be Bits(a) + b, Bits(a), or b"
),
}
}
_ => abort!(
input, "Unexpected expression in coder, must be Bits(a) + b, Bits(a), or b"
),
}
}
fn parse_coder(input: &syn::Expr) -> TokenStream2 { let parse_u2s = |expr_call: &syn::ExprCall, lit: Option<&syn::ExprLit>| { iflet syn::Expr::Path(ep) = &*expr_call.func { if !ep.path.is_ident("u2S") { let coder = parse_single_coder(input, None); return quote! {U32Coder::Direct(#coder)};
} if expr_call.args.len() != 4 {
abort!(
input, "Unexpected number of arguments for U32() in coder: {}",
expr_call.args.len()
);
} let args = vec![
parse_single_coder(&expr_call.args[0], lit),
parse_single_coder(&expr_call.args[1], lit),
parse_single_coder(&expr_call.args[2], lit),
parse_single_coder(&expr_call.args[3], lit),
]; return quote! {U32Coder::Select(#(#args),*)};
}
abort!(input, "Unexpected function call in coder");
};
match &**func {
syn::Expr::Path(expr_path) if expr_path.path.is_ident("implicit") => { let arg = args.first().unwrap().clone();
parse_coder(&arg)
}
syn::Expr::Path(expr_path) if expr_path.path.is_ident("explicit") => {
quote! { U32Coder::Direct(U32::Val(#args)) }
}
_ => abort!(
input, "Unexpected expression in size_coder, must be 'implicit()' or 'explicit()'"
),
}
}
_ => abort!(
input, "Unexpected expression in size_coder, must be 'implicit()' or 'explicit()'"
),
}
}
// Parse attributes. for a in &f.attrs { match a.path().get_ident().map(syn::Ident::to_string).as_deref() {
Some("coder") => { if coder.is_some() {
abort!(f, "Repeated coder");
} let coder_ast = a.parse_args::<syn::Expr>().unwrap();
coder = Some(Coder::U32(U32 {
coder: parse_coder(&coder_ast),
}));
}
Some("default") => { if default.is_some() {
abort!(f, "Repeated default");
} let default_expr = a.parse_args::<syn::Expr>().unwrap();
default = Some(quote! {#default_expr});
}
Some("default_element") => { if default_element.is_some() {
abort!(f, "Repeated default_element")
} let default_element_expr = a.parse_args::<syn::Expr>().unwrap();
default_element = Some(quote! { #default_element_expr })
}
Some("condition") => { if condition.is_some() {
abort!(f, "Repeated condition");
} let condition_ast = a.parse_args::<syn::Expr>().unwrap(); let pretty_cond = prettify_condition(&condition_ast);
condition = Some(Condition {
expr: Some(condition_ast),
has_all_default: all_default_field.is_some(),
pretty: pretty_cond,
});
}
Some("all_default") => { if num != 0 {
abort!(f, "all_default is not the first field");
} if default.is_some() {
abort!(f, "all_default has an implicit default");
}
is_all_default = true;
default = Some(quote! { true });
}
Some("select_coder") => { if select_coder.is_some() {
abort!(f, "Repeated select_coder");
} let condition_ast = a.parse_args::<syn::Expr>().unwrap(); let pretty_cond = prettify_condition(&condition_ast);
select_coder = Some(Condition {
expr: Some(condition_ast),
has_all_default: false,
pretty: pretty_cond,
});
}
Some("coder_false") => { if coder_false.is_some() {
abort!(f, "Repeated coder_false");
} let coder_ast = a.parse_args::<syn::Expr>().unwrap();
coder_false = Some(U32 {
coder: parse_coder(&coder_ast),
});
}
Some("coder_true") => { if coder_true.is_some() {
abort!(f, "Repeated coder_true");
} let coder_ast = a.parse_args::<syn::Expr>().unwrap();
coder_true = Some(U32 {
coder: parse_coder(&coder_ast),
});
}
Some("size_coder") => { if size_coder.is_some() {
abort!(f, "Repeated size_coder");
} let coder_ast = a.parse_args::<syn::Expr>().unwrap();
size_coder = Some(U32 {
coder: parse_size_coder(coder_ast),
});
}
Some("nonserialized") => { let Meta::List(ns) = &a.meta else {
abort!(a, "Invalid attribute");
}; let stream = &ns.tokens;
nonserialized.push(quote! {#stream});
}
_ => {}
}
}
if default.is_some() && default_element.is_some() {
abort!(f, "default is incompatible with default_element");
}
iflet Some(select_coder) = select_coder { if coder_true.is_none() || coder_false.is_none() {
abort!(
f, "Invalid field, select_coder is set but coder_true or coder_false are not"
)
} if coder.is_some() {
abort!(f, "Invalid field, select_coder and coder are both present")
}
coder = Some(Coder::Select(
select_coder,
coder_true.unwrap(),
coder_false.unwrap(),
))
}
quote! { let#ident = { let cond = #cnd; let cfg = #cfg; type NS = <#tyas DefaultedCoder<#cfg_ty>>::Nonserialized; let field_nonserialized = NS { #(#nonserialized_inits),* }; let default = #default;
<#ty>::#read_fn(&cfg, cond, default, br, &field_nonserialized)?
}; #trc
}
}
}
}
// Produces default code. fn default_code(&self) -> TokenStream2 { let ident = &self.name; let ty = &self.ty; let nonserialized_inits = &self.nonserialized_inits; let default = &self.default; match &self.kind {
FieldKind::Defaulted(_, coder) => { let cfg_ty = coder.ty(); let default = &self.default;
#[cfg(feature = "test")] #[proc_macro] pubfn for_each_test_file(input: TokenStream) -> TokenStream { use std::{fs, path::Path}; use syn::Ident;
let fn_name = parse_macro_input!(input as Ident); let root_test_dir = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("jxl")
.join("resources")
.join("test"); let conformance_test_dir = root_test_dir.join("conformance_test_images");
letmut tests = vec![];
for test_dir in [root_test_dir, conformance_test_dir] { for entry in fs::read_dir(&test_dir).unwrap() { let entry = entry.unwrap(); let path = entry.path(); if path.extension().is_some_and(|ext| ext == "jxl") { let pathname = path.to_string_lossy(); let relative_path = path
.strip_prefix(&test_dir)
.unwrap()
.to_string_lossy()
.replace('/', "_slash_"); let test_name = format!( "{}_{}",
fn_name,
relative_path.strip_suffix(".jxl").unwrap()
)
.replace(|c: char| !c.is_alphanumeric() && c != '_', "_"); let test_name = Ident::new(&test_name, fn_name.span());
tests.push(quote! { #[test] fn#test_name() { #fn_name(&Path::new(#pathname)).unwrap()
}
});
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.