mod move_money; pub use self::move_money::*; use std::ffi::c_char; use std::ffi::CStr; use std::ffi::CString; mod overhead_allocation; pub use self::overhead_allocation::*; mod products; pub use self::products::create_products; mod shared_models; pub use self::shared_models::*; pub mod link; pub mod filter; #[no_mangle] pub extern "C" fn move_money_from_text( rules: *const c_char, lines: *const c_char, accounts: *const c_char, cost_centres: *const c_char, use_numeric_accounts: bool, ) -> *mut c_char { let mut output_writer = csv::Writer::from_writer(vec![]); let safe_rules = unwrap_c_char(rules); let safe_lines = unwrap_c_char(lines); let safe_accounts = unwrap_c_char(accounts); let safe_cost_centres = unwrap_c_char(cost_centres); move_money( &mut csv::Reader::from_reader(safe_rules.to_bytes()), &mut csv::Reader::from_reader(safe_lines.to_bytes()), &mut csv::Reader::from_reader(safe_accounts.to_bytes()), &mut csv::Reader::from_reader(safe_cost_centres.to_bytes()), &mut output_writer, use_numeric_accounts, false, ) .expect("Failed to move money"); // TODO: Replace all these unwraps with something more elegant let inner = output_writer.into_inner().unwrap(); CString::new(String::from_utf8(inner).unwrap()) .unwrap() .into_raw() // Also some resources I looked at, in case things aren't going right: // https://notes.huy.rocks/en/string-ffi-rust.html // http://jakegoulding.com/rust-ffi-omnibus/string_return/ // https://rust-unofficial.github.io/patterns/idioms/ffi/passing-strings.html // This looks like exactly what I'm doing too: https://mozilla.github.io/firefox-browser-architecture/experiments/2017-09-06-rust-on-ios.htmlcar } #[no_mangle] pub extern "C" fn move_money_from_text_free(s: *mut c_char) { unsafe { if s.is_null() { return; } CString::from_raw(s) }; } #[no_mangle] pub extern "C" fn allocate_overheads_from_text( lines: *const c_char, accounts: *const c_char, allocation_statistics: *const c_char, areas: *const c_char, cost_centres: *const c_char, account_type: *const c_char, use_numeric_accounts: bool, ) -> *mut c_char { let lines = unwrap_c_char(lines); let accounts = unwrap_c_char(accounts); let allocation_statistics = unwrap_c_char(allocation_statistics); let areas = unwrap_c_char(areas); let cost_centres = unwrap_c_char(cost_centres); let account_type = unwrap_c_char(account_type); let mut output_writer = csv::Writer::from_writer(vec![]); reciprocal_allocation( &mut csv::Reader::from_reader(lines.to_bytes()), &mut csv::Reader::from_reader(accounts.to_bytes()), &mut csv::Reader::from_reader(allocation_statistics.to_bytes()), &mut csv::Reader::from_reader(areas.to_bytes()), &mut csv::Reader::from_reader(cost_centres.to_bytes()), &mut output_writer, use_numeric_accounts, false, true, account_type.to_str().unwrap().to_owned(), // This needs to be false when we return just a string, as the // amount of data produced could easily go out of memory (9000ccs + 1000 // accounts can reach 2gb) false, 0.1, ) .expect("Failed to allocate overheads"); let inner = output_writer.into_inner().unwrap(); CString::new(String::from_utf8(inner).unwrap()) .unwrap() .into_raw() } #[no_mangle] pub extern "C" fn allocate_overheads_from_text_to_file( lines: *const c_char, accounts: *const c_char, allocation_statistics: *const c_char, areas: *const c_char, cost_centres: *const c_char, account_type: *const c_char, output_path: *const c_char, use_numeric_accounts: bool, show_from: bool, ) { let lines = unwrap_c_char(lines); let accounts = unwrap_c_char(accounts); let allocation_statistics = unwrap_c_char(allocation_statistics); let areas = unwrap_c_char(areas); let cost_centres = unwrap_c_char(cost_centres); let account_type = unwrap_c_char(account_type); let output_path = unwrap_c_char(output_path); reciprocal_allocation( &mut csv::Reader::from_reader(lines.to_bytes()), &mut csv::Reader::from_reader(accounts.to_bytes()), &mut csv::Reader::from_reader(allocation_statistics.to_bytes()), &mut csv::Reader::from_reader(areas.to_bytes()), &mut csv::Reader::from_reader(cost_centres.to_bytes()), &mut csv::Writer::from_path(output_path.to_str().unwrap()).unwrap(), use_numeric_accounts, false, true, account_type.to_str().unwrap().to_owned(), show_from, 0.1, ) .expect("Failed to allocate overheads"); } fn unwrap_c_char<'a>(s: *const c_char) -> &'a CStr { unsafe { assert!(!s.is_null()); CStr::from_ptr(s) } } #[no_mangle] pub extern "C" fn allocate_overheads_from_text_free(s: *mut c_char) { unsafe { if s.is_null() { return; } CString::from_raw(s) }; }