rsbind 0.6.0

Provide tools to bind rust trait with other language and export library artifact directly. Invoke rust functions just like you write it in native language.
Documentation
use proc_macro2::TokenStream;
use rstgen::swift::Swift;
use rstgen::{swift, Tokens};

use crate::ast::types::{AstBaseType, AstType};
use crate::base::lang::{Convertible, Direction};
use crate::ident;
use crate::swift::ty::basic::quote_free_swift_ptr;

pub(crate) struct VecBase {
    pub(crate) ty: AstType,
}

impl<'a> Convertible<Swift<'a>> for VecBase {
    fn native_to_transferable(
        &self,
        origin: String,
        direction: Direction,
    ) -> Tokens<'static, Swift<'a>> {
        let mut body = Tokens::new();
        let transfer_ty = self.native_transferable_type(direction);
        let base_ty = self.native_base_type_str();
        body.append(toks!("{ () -> ", transfer_ty.clone(), " in"));
        nested_f!(
            body,
            "let tmp_ptr = UnsafeMutablePointer<{}>.allocate(capacity: {}.count)",
            base_ty,
            origin
        );
        nested_f!(body, "{}.withUnsafeBufferPointer {{ buffer in", origin);
        nested_f!(body, |t| {
            nested_f!(
                t,
                "tmp_ptr.initialize(from: buffer.baseAddress!, count: buffer.count)"
            )
        });
        nested_f!(body, "}");
        nested_f!(body, quote_free_swift_ptr(&base_ty));
        nested!(
            body,
            "return ",
            transfer_ty.clone(),
            "(ptr: tmp_ptr, len: Int32(",
            origin,
            ".count), cap: Int32(",
            origin,
            ".capacity), free_ptr: free_ptr)",
        );
        push_f!(body, "}()");
        body
    }

    fn transferable_to_native(
        &self,
        origin: String,
        _direction: Direction,
    ) -> Tokens<'static, Swift<'a>> {
        let mut body = Tokens::new();
        let ty = format!("[{}]", self.native_base_type_str());
        body.append(toks_f!("{{ () -> {} in", ty));
        nested_f!(body, |t| {
            nested_f!(
                t,
                "let array = {}(UnsafeBufferPointer(start: {}.ptr, count: Int({}.len)))",
                ty,
                origin,
                origin
            );
            nested_f!(
                t,
                "({}.free_ptr)(UnsafeMutablePointer(mutating: {}.ptr), {}.len, {}.cap)",
                origin,
                origin,
                origin,
                origin
            );
            nested_f!(t, "return array");
        });
        nested_f!(body, "}()");
        body
    }

    fn rust_to_transferable(&self, origin: TokenStream, _direction: Direction) -> TokenStream {
        let base_ty = self.rust_base_transfer_type();
        let c_array_ty = self.rust_transferable_type(Direction::Down);
        let free_ptr = match self.ty.clone() {
            AstType::Vec(AstBaseType::Byte(ref _base)) => {
                ident!("free_i8_array")
            }
            AstType::Vec(AstBaseType::Short(ref _base)) => {
                ident!("free_i16_array")
            }
            AstType::Vec(AstBaseType::Int(ref _base)) => {
                ident!("free_i32_array")
            }
            AstType::Vec(AstBaseType::Long(ref _base)) => {
                ident!("free_i64_array")
            }
            AstType::Vec(AstBaseType::Float(_)) => {
                ident!("free_f32_array")
            }
            AstType::Vec(AstBaseType::Double(_)) => {
                ident!("free_f64_array")
            }
            _ => {
                ident!("free_i8_array")
            }
        };

        quote! {{
            let mut copy = #origin.clone();
            let ptr_name = copy.as_ptr();
            let len_name = copy.len();
            let cap_name = copy.capacity();
            let array = #c_array_ty {
                ptr: ptr_name as (*const #base_ty),
                len: len_name as i32,
                cap: cap_name as i32,
                free_ptr: #free_ptr
            };
            std::mem::forget(copy);
            array
        }}
    }

    fn transferable_to_rust(&self, origin: TokenStream, _direction: Direction) -> TokenStream {
        let transfer_ty = self.rust_base_transfer_type();
        match self.ty.clone() {
            AstType::Vec(AstBaseType::Byte(ref base))
            | AstType::Vec(AstBaseType::Short(ref base))
            | AstType::Vec(AstBaseType::Int(ref base))
            | AstType::Vec(AstBaseType::Long(ref base))
            | AstType::Vec(AstBaseType::Float(ref base))
            | AstType::Vec(AstBaseType::Double(ref base)) => {
                let origin_ident = ident!(base);
                quote! {{
                    let vec = unsafe { std::slice::from_raw_parts(#origin.ptr as (* mut #origin_ident), #origin.len as usize).to_vec() };
                    (#origin.free_ptr)(#origin.ptr as (*mut #transfer_ty), #origin.len, #origin.cap);
                    vec
                }}
            }
            _ => quote! {},
        }
    }

    fn native_type(&self) -> Swift<'a> {
        swift::local(format!("[{}]", self.native_base_type_str()))
    }

    fn native_transferable_type(&self, _direction: Direction) -> Swift<'a> {
        match self.ty.clone() {
            AstType::Vec(AstBaseType::Byte(_)) => swift::local("CInt8Array"),
            AstType::Vec(AstBaseType::Short(_)) => swift::local("CInt16Array"),
            AstType::Vec(AstBaseType::Int(_)) => swift::local("CInt32Array"),
            AstType::Vec(AstBaseType::Long(_)) => swift::local("CInt64Array"),
            AstType::Vec(AstBaseType::Float(_)) => swift::local("CFloat32Array"),
            AstType::Vec(AstBaseType::Double(_)) => swift::local("CFloat64Array"),
            _ => swift::local(""),
        }
    }

    fn rust_transferable_type(&self, _direction: Direction) -> TokenStream {
        match self.ty.clone() {
            AstType::Vec(AstBaseType::Byte(_)) => quote!(CInt8Array),
            AstType::Vec(AstBaseType::Short(_)) => quote!(CInt16Array),
            AstType::Vec(AstBaseType::Int(_)) => quote!(CInt32Array),
            AstType::Vec(AstBaseType::Long(_)) => quote!(CInt64Array),
            AstType::Vec(AstBaseType::Float(_)) => quote!(CFloat32Array),
            AstType::Vec(AstBaseType::Double(_)) => quote!(CFloat64Array),
            _ => quote! {},
        }
    }

    fn quote_common_in_bridge(&self) -> TokenStream {
        quote! {}
    }

    fn quote_common_in_native(&self) -> Tokens<'static, Swift<'a>> {
        Tokens::new()
    }

    fn quote_in_common_rs(&self) -> TokenStream {
        quote! {}
    }
}

impl VecBase {
    fn native_base_type_str(&self) -> String {
        match self.ty.clone() {
            AstType::Vec(AstBaseType::Byte(_)) => "Int8",
            AstType::Vec(AstBaseType::Short(_)) => "Int16",
            AstType::Vec(AstBaseType::Int(_)) => "Int32",
            AstType::Vec(AstBaseType::Long(_)) => "Int64",
            AstType::Vec(AstBaseType::Float(_)) => "Float32",
            AstType::Vec(AstBaseType::Double(_)) => "Float64",
            _ => panic!("Error type found."),
        }
        .to_string()
    }

    fn rust_base_transfer_type(&self) -> TokenStream {
        match self.ty.clone() {
            AstType::Vec(AstBaseType::Byte(_)) => quote!(i8),
            AstType::Vec(AstBaseType::Short(_)) => quote!(i16),
            AstType::Vec(AstBaseType::Int(_)) => quote!(i32),
            AstType::Vec(AstBaseType::Long(_)) => quote!(i64),
            AstType::Vec(AstBaseType::Float(_)) => quote!(f32),
            AstType::Vec(AstBaseType::Double(_)) => quote!(f64),
            _ => panic!("Error type found."),
        }
    }
}