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
#![doc = include_str!("../README.md")]
use std::{ffi::CStr, os::raw::c_char};
pub fn initialize() {
unsafe { librclone_sys::RcloneInitialize() };
}
pub fn finalize() {
unsafe { librclone_sys::RcloneFinalize() };
}
pub fn rpc<S1: Into<String>, S2: Into<String>>(method: S1, input: S2) -> Result<String, String> {
let method_bytes: Vec<u8> = method.into().into_bytes();
let mut method_c_chars: Vec<i8> = method_bytes.iter().map(|c| *c as i8).collect::<Vec<i8>>();
method_c_chars.push(0);
let method_mut_ptr: *mut c_char = method_c_chars.as_mut_ptr();
let input_bytes: Vec<u8> = input.into().into_bytes();
let mut input_c_chars: Vec<i8> = input_bytes.iter().map(|c| *c as i8).collect::<Vec<i8>>();
input_c_chars.push(0);
let input_mut_ptr: *mut c_char = input_c_chars.as_mut_ptr();
let result = unsafe { librclone_sys::RcloneRPC(method_mut_ptr, input_mut_ptr) };
let output_c_str: &CStr = unsafe { CStr::from_ptr(result.Output) };
let output_slice: &str = output_c_str.to_str().unwrap();
let output: String = output_slice.to_owned();
unsafe { libc::free(result.Output as *mut libc::c_void) };
match result.Status {
200 => Ok(output),
_ => Err(output),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
initialize();
assert_eq!(rpc("rc/noop", "{}"), Ok("{}\n".to_string()));
assert_eq!(rpc("rc/error", "{}"), Err("{\n\t\"error\": \"arbitrary error on input map[]\",\n\t\"input\": {},\n\t\"path\": \"rc/error\",\n\t\"status\": 500\n}\n".to_string()));
finalize();
}
}