use crate::general::Result; use core::str::FromStr; use std::convert::TryFrom; use std::{slice, str}; use waku_sys::WakuCallBack; use waku_sys::{RET_ERR, RET_MISSING_CALLBACK, RET_OK}; #[derive(Debug, Default, PartialEq)] pub enum LibwakuResponse { Success(Option), Failure(String), MissingCallback, #[default] Undefined, } impl TryFrom<(u32, &str)> for LibwakuResponse { type Error = String; fn try_from((ret_code, response): (u32, &str)) -> std::result::Result { let opt_value = Some(response.to_string()).filter(|s| !s.is_empty()); match ret_code { RET_OK => Ok(LibwakuResponse::Success(opt_value)), RET_ERR => Ok(LibwakuResponse::Failure(format!( "waku error: {}", response ))), RET_MISSING_CALLBACK => Ok(LibwakuResponse::MissingCallback), _ => Err(format!("undefined return code {}", ret_code)), } } } // Define the WakuDecode trait pub trait WakuDecode: Sized { fn decode(input: &str) -> Result; } pub fn decode(input: String) -> Result { T::decode(input.as_str()) } unsafe extern "C" fn trampoline( ret_code: ::std::os::raw::c_int, data: *const ::std::os::raw::c_char, data_len: usize, user_data: *mut ::std::os::raw::c_void, ) where F: FnMut(LibwakuResponse), { let closure = &mut *(user_data as *mut F); let response = if data.is_null() { "" } else { str::from_utf8(slice::from_raw_parts(data as *mut u8, data_len)) .expect("could not retrieve response") }; let result = LibwakuResponse::try_from((ret_code as u32, response)) .expect("invalid response obtained from libwaku"); closure(result); } pub fn get_trampoline(_closure: &F) -> WakuCallBack where F: FnMut(LibwakuResponse), { Some(trampoline::) } pub fn handle_no_response(code: i32, result: LibwakuResponse) -> Result<()> { if result == LibwakuResponse::Undefined && code as u32 == RET_OK { // Some functions will only execute the callback on error return Ok(()); } match result { LibwakuResponse::Success(_) => Ok(()), LibwakuResponse::Failure(v) => Err(v), LibwakuResponse::MissingCallback => panic!("callback is required"), LibwakuResponse::Undefined => panic!( "undefined ffi state: code({}) was returned but callback was not executed", code ), } } pub fn handle_json_response(code: i32, result: LibwakuResponse) -> Result { match result { LibwakuResponse::Success(v) => decode(v.unwrap_or_default()), LibwakuResponse::Failure(v) => Err(v), LibwakuResponse::MissingCallback => panic!("callback is required"), LibwakuResponse::Undefined => panic!( "undefined ffi state: code({}) was returned but callback was not executed", code ), } } pub fn handle_response(code: i32, result: LibwakuResponse) -> Result where ::Err: std::fmt::Debug, { match result { LibwakuResponse::Success(v) => v .unwrap_or_default() .parse() .map_err(|e| format!("could not parse value: {:?}", e)), LibwakuResponse::Failure(v) => Err(v), LibwakuResponse::MissingCallback => panic!("callback is required"), LibwakuResponse::Undefined => panic!( "undefined ffi state: code({}) was returned but callback was not executed", code ), } }