use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use serde_json::Value;
use crate::tl::function::TonFunction;
use crate::tl::result::TonResult;
use crate::tl::TlError;
pub(crate) fn serialize_function(function: &TonFunction) -> Result<CString, TlError> {
let str = serde_json::to_string(function)?;
let cstr = CString::new(str)?;
Ok(cstr)
}
pub(crate) fn serialize_function_extra(
function: &TonFunction,
extra: &str,
) -> Result<CString, TlError> {
let mut value = serde_json::to_value(function)?;
let obj = value.as_object_mut().unwrap();
obj.insert(String::from("@extra"), serde_json::Value::from(extra));
let str = serde_json::to_string(&value)?;
let cstr = CString::new(str)?;
Ok(cstr)
}
pub(crate) unsafe fn deserialize_result(c_str: *const c_char) -> Result<TonResult, TlError> {
let cstr = CStr::from_ptr(c_str);
let str = cstr.to_str()?;
let r = serde_json::from_str(str).unwrap(); Ok(r)
}
pub(crate) unsafe fn deserialize_result_extra(
c_str: *const c_char,
) -> (Result<TonResult, TlError>, Option<String>) {
let cstr = CStr::from_ptr(c_str);
let str_result = cstr.to_str();
if let Err(err) = str_result {
return (Err(TlError::Utf8Error(err)), None);
}
let str = str_result.unwrap();
let value_result: Result<Value, serde_json::Error> = serde_json::from_str(str);
if let Err(err) = value_result {
return (Err(TlError::SerdeJsonError(err)), None);
}
let value = value_result.unwrap();
let extra: Option<String> = value
.as_object()
.and_then(|m| m.get("@extra"))
.and_then(|v| v.as_str())
.map(|s| s.to_string());
let result: Result<TonResult, TlError> =
serde_json::from_value(value).map_err(TlError::SerdeJsonError);
(result, extra)
}
#[cfg(test)]
mod tests {
use std::ffi::CString;
use crate::tl::function::TonFunction;
use crate::tl::result::TonResult;
use crate::tl::serial::{deserialize_result_extra, serialize_function_extra};
#[test]
fn it_serializes_function_extra() {
let func = TonFunction::SetLogVerbosityLevel {
new_verbosity_level: 100500,
};
let cstr: CString = serialize_function_extra(&func, "some_extra").unwrap();
assert_eq!(
"{\"@extra\":\"some_extra\",\"@type\":\"setLogVerbosityLevel\",\"new_verbosity_level\":100500}",
cstr.to_str().unwrap())
}
#[test]
fn it_deserializes_result_extra() {
let cstr = CString::new("{\"@extra\":\"some_extra\",\"@type\":\"logVerbosityLevel\",\"verbosity_level\":100500}").unwrap();
let (result, extra) = unsafe { deserialize_result_extra(cstr.as_ptr()) };
let expected = Some(String::from("some_extra"));
assert_eq!(extra, expected);
match result.unwrap() {
TonResult::LogVerbosityLevel(verbosity_level) => {
assert_eq!(verbosity_level.verbosity_level, 100500)
}
_ => panic!("Unexpected result"),
}
}
#[test]
fn it_deserializes_options_info() {
let cstr = CString::new(r#"{"@type":"options.info","config_info":
{"@type":"options.configInfo","default_wallet_id":"698983191",
"default_rwallet_init_public_key":"Puasxr0QfFZZnYISRphVse7XHKfW7pZU5SJarVHXvQ+rpzkD"},"@extra":"0"}"#).unwrap();
let (_, extra) = unsafe { deserialize_result_extra(cstr.as_ptr()) };
assert_eq!(extra, Some(String::from("0")));
}
}