use kotlin_codegen::KtType;
use super::*;
pub(crate) struct PrimArray {
pub wire: syn::Type,
pub elem_wire: syn::Type,
pub kotlin: KtType,
pub new_fn: syn::Ident,
pub set_region: syn::Ident,
pub get_region: syn::Ident,
pub is_bool: bool,
pub is_u8: bool,
}
pub(crate) fn prim_array_of(ty: &prebindgen_registry::flat::TypeRef) -> Option<PrimArray> {
use prebindgen_registry::flat::{ScalarKind, TypeKind};
let TypeKind::Array { elem, .. } = ty.kind() else {
return None;
};
let &TypeKind::Scalar(elem) = elem.kind() else {
return None;
};
let (letter, jni_elem) = match elem.as_str() {
"u8" | "i8" => ("byte", "jbyte"),
"u16" | "i16" => ("short", "jshort"),
"u32" | "i32" => ("int", "jint"),
"u64" | "i64" => ("long", "jlong"),
"f32" => ("float", "jfloat"),
"f64" => ("double", "jdouble"),
"bool" => ("boolean", "jboolean"),
_ => return None,
};
let cap = format!("{}{}", letter[..1].to_uppercase(), &letter[1..]);
let wire_ident = format_ident!("J{}Array", cap);
let elem_wire_ident = format_ident!("{}", jni_elem);
Some(PrimArray {
wire: syn::parse_quote!(jni::objects::#wire_ident),
elem_wire: syn::parse_quote!(jni::sys::#elem_wire_ident),
kotlin: KtType::cls(format!("{cap}Array")),
new_fn: format_ident!("new_{}_array", letter),
set_region: format_ident!("set_{}_array_region", letter),
get_region: format_ident!("get_{}_array_region", letter),
is_bool: elem == ScalarKind::Bool,
is_u8: elem == ScalarKind::U8,
})
}
pub(crate) fn output_body(spec: &PrimArray) -> syn::Expr {
if spec.is_u8 {
return syn::parse_quote!({
env.byte_array_from_slice(&v).map_err(|e| {
<__JniErr as ::core::convert::From<String>>::from(format!(
"fixed-size array encode: {}",
e
))
})?
});
}
let elem_wire = &spec.elem_wire;
let new_fn = &spec.new_fn;
let set_region = &spec.set_region;
let to_wire: syn::Expr = syn::parse_quote!(*__x as #elem_wire);
syn::parse_quote!({
let __buf: ::std::vec::Vec<#elem_wire> = v.iter().map(|__x| #to_wire).collect();
let __arr = env.#new_fn(__buf.len() as jni::sys::jsize).map_err(|e| {
<__JniErr as ::core::convert::From<String>>::from(format!(
"fixed-size array encode: {}",
e
))
})?;
env.#set_region(&__arr, 0, &__buf).map_err(|e| {
<__JniErr as ::core::convert::From<String>>::from(format!(
"fixed-size array encode: {}",
e
))
})?;
__arr
})
}
pub(crate) fn input_body(
ty: &prebindgen_registry::flat::TypeRef,
spec: &PrimArray,
emit: &prebindgen_registry::Emit,
) -> syn::Expr {
let key = ty.key();
let elem_ty = match ty.kind() {
prebindgen_registry::flat::TypeKind::Array { elem, .. } => emit.spell(elem),
_ => unreachable!("prim_array_of matched a non-array"),
};
let ty = emit.spell(ty);
let len_err = format!("fixed-size array decode: `{key}` expects a different length");
if spec.is_u8 {
return syn::parse_quote!({
let __buf = env.convert_byte_array(v).map_err(|e| {
<__JniErr as ::core::convert::From<String>>::from(format!(
"fixed-size array decode: {}",
e
))
})?;
let __arr: #ty = __buf.as_slice().try_into().map_err(|_| {
<__JniErr as ::core::convert::From<String>>::from(#len_err.to_string())
})?;
__arr
});
}
let elem_wire = &spec.elem_wire;
let get_region = &spec.get_region;
let from_wire: syn::Expr = if spec.is_bool {
syn::parse_quote!(*__x != 0)
} else {
syn::parse_quote!(*__x as #elem_ty)
};
syn::parse_quote!({
let __len = env.get_array_length(v).map_err(|e| {
<__JniErr as ::core::convert::From<String>>::from(format!(
"fixed-size array decode: {}",
e
))
})? as usize;
let mut __buf: ::std::vec::Vec<#elem_wire> = ::std::vec![0 as #elem_wire; __len];
env.#get_region(v, 0, &mut __buf).map_err(|e| {
<__JniErr as ::core::convert::From<String>>::from(format!(
"fixed-size array decode: {}",
e
))
})?;
let __vals: ::std::vec::Vec<#elem_ty> = __buf.iter().map(|__x| #from_wire).collect();
let __arr: #ty = __vals.as_slice().try_into().map_err(|_| {
<__JniErr as ::core::convert::From<String>>::from(#len_err.to_string())
})?;
__arr
})
}