freenet-macros 0.2.0

Procedural macros for Freenet
Documentation
use proc_macro2::TokenStream;
use quote::quote;
use syn::{ItemImpl, Type, TypePath};

pub fn ffi_impl_wrap(item: &ItemImpl) -> TokenStream {
    let type_name = match &*item.self_ty {
        Type::Path(p) => p.clone(),
        _ => panic!(),
    };
    let s = ImplStruct { type_name };
    let process_fn = s.gen_process_fn();
    quote!(#process_fn)
}

struct ImplStruct {
    type_name: TypePath,
}

impl ImplStruct {
    fn ffi_ret_type(&self) -> TokenStream {
        quote!(i64)
    }

    fn gen_process_fn(&self) -> TokenStream {
        let type_name = &self.type_name;
        let ret = self.ffi_ret_type();
        let set_logger = crate::common::set_logger();
        quote! {
            #[no_mangle]
            #[cfg(feature = "freenet-main-delegate")]
            pub extern "C" fn process(parameters: i64, origin: i64, inbound: i64) -> #ret {
                #set_logger
                let parameters = unsafe {
                    let param_buf = &*(parameters as *const ::freenet_stdlib::memory::buf::BufferBuilder);
                    let bytes = &*std::ptr::slice_from_raw_parts(
                        param_buf.start(),
                        param_buf.bytes_written(),
                    );
                    Parameters::from(bytes)
                };
                let origin: Option<::freenet_stdlib::prelude::MessageOrigin> = unsafe {
                    let origin_buf = &*(origin as *const ::freenet_stdlib::memory::buf::BufferBuilder);
                    let bytes = &*std::ptr::slice_from_raw_parts(
                        origin_buf.start(),
                        origin_buf.bytes_written(),
                    );
                    if bytes.is_empty() {
                        None
                    } else {
                        match ::freenet_stdlib::prelude::bincode::deserialize(bytes) {
                            Ok(v) => Some(v),
                            Err(_) => None,
                        }
                    }
                };
                let inbound = unsafe {
                    let inbound_buf = &mut *(inbound as *mut ::freenet_stdlib::memory::buf::BufferBuilder);
                    let bytes =
                        &*std::ptr::slice_from_raw_parts(inbound_buf.start(), inbound_buf.bytes_written());
                    match ::freenet_stdlib::prelude::bincode::deserialize(bytes) {
                        Ok(v) => v,
                        Err(err) => return ::freenet_stdlib::prelude::DelegateInterfaceResult::from(
                            Err::<::std::vec::Vec<::freenet_stdlib::prelude::OutboundDelegateMsg>, _>(::freenet_stdlib::prelude::DelegateError::Deser(format!("{}", err)))
                        ).into_raw(),
                    }
                };

                // Create opaque handle for context access (includes secrets).
                // SAFETY: The runtime has set up the delegate execution environment
                // before calling this function, so the host functions are available.
                let mut ctx = unsafe { ::freenet_stdlib::prelude::DelegateCtx::__new() };

                let result = <#type_name as ::freenet_stdlib::prelude::DelegateInterface>::process(
                    &mut ctx,
                    parameters,
                    origin,
                    inbound
                );
                ::freenet_stdlib::prelude::DelegateInterfaceResult::from(result).into_raw()
            }
        }
    }
}