mod move_money; use std::ffi::c_char; use std::ffi::CStr; use std::ffi::CString; pub use self::move_money::*; mod overhead_allocation; pub use self::overhead_allocation::*; mod create_products; pub use self::create_products::*; mod shared_models; pub use self::shared_models::*; #[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 = unsafe { assert!(!rules.is_null()); CStr::from_ptr(rules) }; let safe_lines = unsafe { assert!(!lines.is_null()); CStr::from_ptr(lines) }; let safe_accounts = unsafe { assert!(!accounts.is_null()); CStr::from_ptr(accounts) }; let safe_cost_centres = unsafe { assert!(!cost_centres.is_null()); CStr::from_ptr(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, true, ) .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 = unsafe { assert!(!lines.is_null()); CStr::from_ptr(lines) }; let accounts = unsafe { assert!(!accounts.is_null()); CStr::from_ptr(accounts) }; let allocation_statistics = unsafe { assert!(!allocation_statistics.is_null()); CStr::from_ptr(allocation_statistics) }; let areas = unsafe { assert!(!areas.is_null()); CStr::from_ptr(areas) }; let cost_centres = unsafe { assert!(!cost_centres.is_null()); CStr::from_ptr(cost_centres) }; let account_type = unsafe { assert!(!account_type.is_null()); CStr::from_ptr(account_type) }; let mut output_writer = csv::Writer::from_writer(vec![]); reciprocal_allocation( csv::Reader::from_reader(lines.to_bytes()), csv::Reader::from_reader(accounts.to_bytes()), csv::Reader::from_reader(allocation_statistics.to_bytes()), csv::Reader::from_reader(areas.to_bytes()), csv::Reader::from_reader(cost_centres.to_bytes()), &mut output_writer, use_numeric_accounts, false, true, account_type.to_str().unwrap().to_owned(), ) .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_free(s: *mut c_char) { unsafe { if s.is_null() { return; } CString::from_raw(s) }; }