use crate::parse::Language;
use heck::*;
use proc_macro2::{Literal, TokenStream};
use quote::{format_ident, quote};
use std::borrow::Cow;
use syn::LitStr;
pub(crate) fn build(lang: Language, prefix: Option<&LitStr>) -> Option<TokenStream> {
let prefix = prefix
.map(|lit| Cow::Owned(lit.value()))
.unwrap_or_else(|| Cow::Borrowed("cbor_"));
match lang {
Language::C => Some(build_c(&prefix)),
Language::Typescript => Some(build_ts(&prefix)),
_ => None,
}
}
fn build_c(pre: &str) -> TokenStream {
let len_num = format_ident!("{}", &format!("{}_len_num", pre).to_snake_case());
let len_bool = format_ident!("{}", &format!("{}_len_bool", pre).to_snake_case());
let enc_num = format_ident!("{}", &format!("{}_encode_num", pre).to_snake_case());
let enc_bool = format_ident!("{}", &format!("{}_encode_bool", pre).to_snake_case());
let enc_arr = format_ident!("{}", &format!("{}_encode_fixed_array", pre).to_snake_case());
let enc_map = format_ident!("{}", &format!("{}_encode_map", pre).to_snake_case());
let dec_num = format_ident!("{}", &format!("{}_decode_num", pre).to_snake_case());
let dec_bool = format_ident!("{}", &format!("{}_decode_bool", pre).to_snake_case());
let dec_arr = format_ident!("{}", &format!("{}_decode_fixed_array", pre).to_snake_case());
let dec_map = format_ident!("{}", &format!("{}_decode_map", pre).to_snake_case());
let enc_str = format_ident!("{}", &format!("{}_encode_str", pre).to_snake_case());
let enc_str_len = format_ident!("{}", &format!("{}_len_str", pre).to_snake_case());
let enc_bytes = format_ident!("{}", &format!("{}_encode_bytes", pre).to_snake_case());
let enc_bytes_len = format_ident!("{}", &format!("{}_len_bytes", pre).to_snake_case());
let dec_str = format_ident!("{}", &format!("{}_decode_str", pre).to_snake_case());
let dec_bytes = format_ident!("{}", &format!("{}_decode_bytes", pre).to_snake_case());
quote! {
#[no_mangle]
pub extern "C" fn #len_num(val: i64) -> u32 {
minicbor::encode::CborLen::cbor_len(&val, &mut ()) as u32
}
#[no_mangle]
pub extern "C" fn #len_bool(val: bool) -> u32 {
minicbor::encode::CborLen::cbor_len(&val, &mut ()) as u32
}
#[no_mangle]
pub extern "C" fn #enc_num(dst: *mut u8, dstlen: u32, val: i64) -> i32 {
let dstslice = unsafe { core::slice::from_raw_parts_mut(dst, dstlen as usize) };
let mut enc = minicbor::Encoder::new(minicbor::encode::write::Cursor::new(dstslice.as_mut()));
minicbor::Encoder::i64(&mut enc, val.into()).map_or(-1, |enc| enc.writer().position() as i32)
}
#[no_mangle]
pub extern "C" fn #enc_bool(dst: *mut u8, dstlen: u32, val: bool) -> i32 {
let dstslice = unsafe { core::slice::from_raw_parts_mut(dst, dstlen as usize) };
let mut enc = minicbor::Encoder::new(minicbor::encode::write::Cursor::new(dstslice.as_mut()));
minicbor::Encoder::bool(&mut enc, val.into()).map_or(-1, |enc| enc.writer().position() as i32)
}
#[no_mangle]
pub extern "C" fn #enc_arr(dst: *mut u8, dstlen: u32, val: u32) -> i32 {
let dstslice = unsafe { core::slice::from_raw_parts_mut(dst, dstlen as usize) };
let mut enc = minicbor::Encoder::new(minicbor::encode::write::Cursor::new(dstslice.as_mut()));
minicbor::Encoder::array(&mut enc, val.into()).map_or(-1, |enc| enc.writer().position() as i32)
}
#[no_mangle]
pub extern "C" fn #enc_map(dst: *mut u8, dstlen: u32, val: u32) -> i32 {
let dstslice = unsafe { core::slice::from_raw_parts_mut(dst, dstlen as usize) };
let mut enc = minicbor::Encoder::new(minicbor::encode::write::Cursor::new(dstslice.as_mut()));
minicbor::Encoder::map(&mut enc, val.into()).map_or(-1, |enc| enc.writer().position() as i32)
}
#[no_mangle]
pub extern "C" fn #dec_num(dst: *mut i64, src: *mut u8, srclen: u32) -> i32 {
let srcslice = unsafe { core::slice::from_raw_parts_mut(src, srclen as usize) };
let mut dec = minicbor::Decoder::new(srcslice);
if let Ok(b) = minicbor::Decoder::i64(&mut dec) {
unsafe { *dst = b };
dec.position() as i32
} else {
-1
}
}
#[no_mangle]
pub extern "C" fn #dec_bool(dst: *mut bool, src: *mut u8, srclen: u32) -> i32 {
let srcslice = unsafe { core::slice::from_raw_parts_mut(src, srclen as usize) };
let mut dec = minicbor::Decoder::new(srcslice);
if let Ok(b) = minicbor::Decoder::bool(&mut dec) {
unsafe { *dst = b };
dec.position() as i32
} else {
-1
}
}
#[no_mangle]
pub extern "C" fn #dec_arr(src: *mut u8, srclen: u32) -> i32 {
let slice = unsafe { core::slice::from_raw_parts(src as *const u8, srclen as usize) };
let mut decoder = minicbor::Decoder::new(slice);
match minicbor::Decoder::array(&mut decoder) {
Ok(Some(val)) => val as i32,
Ok(None) => 0,
Err(_) => -1,
}
}
#[no_mangle]
pub extern "C" fn #dec_map(src: *mut u8, srclen: u32) -> i32 {
let slice = unsafe { core::slice::from_raw_parts(src as *const u8, srclen as usize) };
let mut decoder = minicbor::Decoder::new(slice);
match minicbor::Decoder::map(&mut decoder) {
Ok(Some(val)) => val as i32,
Ok(None) => 0,
Err(_) => -1,
}
}
#[no_mangle]
pub extern "C" fn #enc_str(dst: *mut u8, dstlen: u32, src: *const i8) -> i32 {
let slice = unsafe { core::slice::from_raw_parts_mut(dst, dstlen as usize) };
let src = unsafe { core::ffi::CStr::from_ptr(src as _) };
if let Ok(src) = src.to_str() {
let mut encoder = minicbor::Encoder::new(minicbor::encode::write::Cursor::new(slice.as_mut()));
encoder
.str(src)
.map_or(-1, |encoder| encoder.writer().position() as i32)
} else {
-1
}
}
#[no_mangle]
pub extern "C" fn #enc_str_len(src: *const i8) -> i32 {
let src = unsafe { core::ffi::CStr::from_ptr(src as _) };
if let Ok(src) = src.to_str() {
minicbor::encode::CborLen::cbor_len(src, &mut ()) as i32
} else {
-1
}
}
#[no_mangle]
pub extern "C" fn #enc_bytes(dst: *mut u8, dstlen: u32, src: *const u8, srclen: u32) -> i32 {
let dstslice = unsafe { core::slice::from_raw_parts_mut(dst, dstlen as usize) };
let srcslice = unsafe { core::slice::from_raw_parts(src, srclen as usize) };
let mut enc = minicbor::Encoder::new(minicbor::encode::write::Cursor::new(dstslice.as_mut()));
enc.bytes(srcslice).map_or(-1, |enc| enc.writer().position() as i32)
}
#[no_mangle]
pub extern "C" fn #enc_bytes_len(src: *const u8, srclen: u32) -> u32 {
let slice = unsafe { core::slice::from_raw_parts(src, srclen as usize) };
minicbor::encode::CborLen::cbor_len(slice, &mut ()) as u32
}
#[no_mangle]
pub extern "C" fn #dec_str(dst: *mut u8, dstlen: u32, src: *const u8, srclen: u32) -> i32 {
let dstslice = unsafe { core::slice::from_raw_parts_mut(dst, dstlen as usize) };
let srcslice = unsafe { core::slice::from_raw_parts(src, srclen as usize) };
let mut decoder = minicbor::Decoder::new(srcslice);
if let Ok(bytes) = decoder.str() {
if bytes.len() <= dstslice.len() {
dstslice[0..bytes.len()].copy_from_slice(bytes.as_bytes());
bytes.len() as i32
} else {
-1
}
} else {
-1
}
}
#[no_mangle]
pub extern "C" fn #dec_bytes(dst: *mut u8, dstlen: u32, src: *const u8, srclen: u32) -> i32 {
let dstslice = unsafe { core::slice::from_raw_parts_mut(dst, dstlen as usize) };
let srcslice = unsafe { core::slice::from_raw_parts(src, srclen as usize) };
let mut decoder = minicbor::Decoder::new(srcslice);
if let Ok(bytes) = decoder.bytes() {
if bytes.len() <= dstslice.len() {
dstslice[0..bytes.len()].copy_from_slice(bytes);
bytes.len() as i32
} else {
-1
}
} else {
-1
}
}
}
}
fn build_ts(prefix: &str) -> TokenStream {
let enc_str_js = Literal::string(&format!("{}_encode_str", prefix).to_lower_camel_case());
let dec_str_js = Literal::string(&format!("{}_decode_str", prefix).to_lower_camel_case());
let enc_num_js = Literal::string(&format!("{}_encode_num", prefix).to_lower_camel_case());
let dec_num_js = Literal::string(&format!("{}_decode_num", prefix).to_lower_camel_case());
let enc_str = format_ident!("{}", enc_str_js.to_string().to_snake_case());
let dec_str = format_ident!("{}", dec_str_js.to_string().to_snake_case());
let enc_num = format_ident!("{}", enc_num_js.to_string().to_snake_case());
let dec_num = format_ident!("{}", dec_num_js.to_string().to_snake_case());
quote! {
#[wasm_bindgen(js_name = #enc_str_js)]
pub fn #enc_str(s: String) -> Vec<u8> {
let len = minicbor::encode::CborLen::cbor_len(s.as_str(), &mut ());
let mut enc = minicbor::Encoder::new(seedle::infallible_encoder::InfallibleEncoder::new(len));
enc.encode(s.as_str()).expect("infallible!");
enc.into_writer().into_inner()
}
#[wasm_bindgen(js_name = #dec_str_js)]
pub fn #dec_str(cbor: &[u8]) -> Result<String, JsValue> {
let mut dec = minicbor::Decoder::new(cbor);
dec.str()
.map(|s| s.to_string())
.map_err(|e| JsValue::from(e.to_string()))
}
#[wasm_bindgen(js_name = #enc_num_js)]
pub fn #enc_num(i: i64) -> Vec<u8> {
let len = minicbor::encode::CborLen::cbor_len(&i, &mut ());
let mut enc = minicbor::Encoder::new(seedle::infallible_encoder::InfallibleEncoder::new(len));
enc.encode(&i).expect("infallible!");
enc.into_writer().into_inner()
}
#[wasm_bindgen(js_name = #dec_num_js)]
pub fn #dec_num(cbor: &[u8]) -> Result<i64, JsValue> {
let mut dec = minicbor::Decoder::new(cbor);
dec.decode().map_err(|e| JsValue::from(e.to_string()))
}
}
}