1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright (C) 2018, Hao Hou
#![feature(box_leak)]
#![feature(associated_type_defaults)]

//! The Plumber-Rust servlet library. This is the basic library that can be used to create Plumber
//! servlets/guest code with Rust. For more details about how to create the Plumber servlet with
//! Rust, please read the [README.md](https://github.com/38/plumber-rs/blob/master/README.md) under the repository. 
//!
//! To learn more about the Plumber dataflow programming middleware, please visit
//! [https://plumberserver.com](https://plumberserver.com)
//! 
//! Sample servlet in Rust:
//! ```
//! 
//! #[macro_use]
//! extern crate plumber_rs;
//! use plumber_rs::servlet::{Bootstrap, BootstrapResult, Unimplemented, SyncServlet, ServletFuncResult, success};
//! struct Bootstrapper;
//! struct Servlet;
//! 
//! impl SyncServlet for Servlet {
//!     no_protocol!();
//!     fn init(&mut self, args : &[&str], _protocol: &mut Self::ProtocolType) -> ServletFuncResult
//!     {
//!         plumber_log!(W "Hello World! args = {:?}", args);
//!         return success();
//!     }
//!     fn exec(&mut self, _data : Self::DataModelType) -> ServletFuncResult  { success() }
//!     fn cleanup(&mut self) -> ServletFuncResult { success() }
//! }
//! 
//! impl Bootstrap for Bootstrapper {
//!     type SyncServletType = Servlet;
//!     type AsyncServletType = Unimplemented;
//!     fn get(_args : &[&str]) -> BootstrapResult<Self>
//!     {
//!         return Self::sync(Servlet{});
//!     }
//! }
//! export_bootstrap!(Bootstrapper);
//! ```


#[macro_use]
mod plumber_api_call;
mod plumber_api;
mod pstd;
mod va_list_helper;

pub mod servlet;
pub mod rust_servlet;
pub mod pipe;
pub mod log;
pub mod protocol;

/**
 * The type for the Plumber API address table
 **/
pub type ApiAddressTable        = ::plumber_api::runtime_api_address_table_t;

/**
 * The function pointer for the variadic helper function
 **/
pub type VariadicWrapperFunc    = ::va_list_helper::rust_va_list_wrapper_func_t;


#[allow(dead_code)]
#[no_mangle]
#[export_name="__plumber_address_table"]
#[allow(dead_code)]
/**
 * The Plumber API address table. 
 *
 * Do not try to change it in the application code
 **/
pub static mut API_ADDRESS_TABLE: Option<&'static ApiAddressTable> = None;

#[allow(dead_code)]
static mut VA_LIST_HELPER: VariadicWrapperFunc = None;

/**
 * Assign the basic address tables used by Rust servlet
 *
 * This function is desgined to be called from the `export_bootstrap` marco only, do not use it
 * directly
 *
 * * `api_table` The Plumber framework API table
 * * `va_helper` The variadic helper function
 **/
pub fn assign_address_table(api_table : *const ApiAddressTable, va_helpr: VariadicWrapperFunc) 
{
    unsafe {
        API_ADDRESS_TABLE = api_table.as_ref();
        VA_LIST_HELPER    = va_helpr;
    }
}

/**
 * The macro that is used to export the servlet to the shared object that can be loaded by
 * Plumber-Rust binary loader. This macro will emit all the function that is required by the
 * Plumber-Rust binary loader. 
 *
 * It calls the helper function, which translates the Plumber servlet calls into a Rust fashion.
 * All the functions under `plumber_rs::rust_servlet` serves this purpose. So if you need to call
 * any function under `plumber_rs::rust_servlet`, something is probably wrong. 
 *
 * This macro is the only correct way to use the `plumber_rs::rust_servlet` module
 *
 * To invoke this macro, you need a bootstrap class which carries all the information about the
 * Rust servlet. The bootstrap servlet must implemement trait `plumber_rs::servlet::Bootstrap`
 **/
#[macro_export]
macro_rules! export_bootstrap {
    ($bs:ty) => {

        #[allow(dead_code)]
        #[no_mangle]
        pub extern "C" fn _rs_invoke_bootstrap(argc: u32, 
                                               argv: *const *const ::std::os::raw::c_char,
                                               tm_ptr: *mut ::std::os::raw::c_void,
                                               address_table : *const ::plumber_rs::ApiAddressTable, 
                                               va_helper : ::plumber_rs::VariadicWrapperFunc) -> *mut ::std::os::raw::c_void 
        {
            ::plumber_rs::assign_address_table(address_table, va_helper);
            return unsafe{ ::plumber_rs::rust_servlet::call_bootstrap_obj::<$bs>(argc, argv, tm_ptr) };
        }

        #[allow(dead_code)]
        #[no_mangle]
        pub extern "C" fn _rs_invoke_init(obj_ptr    : *mut ::std::os::raw::c_void, 
                                          argc       : u32, 
                                          argv       : *const *const ::std::os::raw::c_char) -> i32 
        {
            ::plumber_rs::rust_servlet::invoke_servlet_init::<$bs>(obj_ptr, argc, argv)
        }

        #[allow(dead_code)]
        #[no_mangle]
        pub extern "C" fn _rs_invoke_exec(obj_ptr   : *mut ::std::os::raw::c_void, 
                                          type_inst : *mut ::std::os::raw::c_void) -> i32 
        {
            ::plumber_rs::rust_servlet::invoke_servlet_sync_exec::<$bs>(obj_ptr, type_inst)
        }

        #[allow(dead_code)]
        #[no_mangle]
        pub extern "C" fn _rs_invoke_cleanup(obj_ptr : *mut ::std::os::raw::c_void) -> i32 
        {
            ::plumber_rs::rust_servlet::invoke_servlet_cleanup::<$bs>(obj_ptr)
        }

        #[allow(dead_code)]
        #[no_mangle]
        pub extern "C" fn _rs_invoke_async_init(obj_ptr  : *mut ::std::os::raw::c_void, 
                                                handle   : *mut ::std::os::raw::c_void,
                                                type_inst: *mut ::std::os::raw::c_void) -> *mut ::std::os::raw::c_void
        {
            ::plumber_rs::rust_servlet::invoke_servlet_async_init::<$bs>(obj_ptr, handle, type_inst)
        }

        #[allow(dead_code)]
        #[no_mangle]
        pub extern "C" fn _rs_invoke_async_exec(handle : *mut ::std::os::raw::c_void, 
                                                task : *mut ::std::os::raw::c_void) -> i32
        {
            ::plumber_rs::rust_servlet::invoke_servlet_async_exec::<$bs>(handle, task)
        }

        #[allow(dead_code)]
        #[no_mangle]
        pub extern "C" fn _rs_invoke_async_cleanup(obj_ptr   : *mut ::std::os::raw::c_void, 
                                                   handle    : *mut ::std::os::raw::c_void, 
                                                   task      : *mut ::std::os::raw::c_void,
                                                   type_inst : *mut ::std::os::raw::c_void) -> i32
        {
            ::plumber_rs::rust_servlet::invoke_servlet_async_cleanup::<$bs>(obj_ptr, handle, task, type_inst)
        }
    }
}