seedle-macros 1.8.2

cbor codegeneration
Documentation
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()))
        }
    }
}