//! Library for interacting with aconfigd. use crate::ffi::{CppAconfigd, CppResultStatus, CppStringResult, CppVoidResult}; use cxx::{let_cxx_string, CxxString, UniquePtr}; use std::error::Error; use std::fmt; /// Wrapper for interacting with aconfigd. pub struct Aconfigd { cpp_aconfigd: UniquePtr, } impl Aconfigd { /// Create a new Aconfigd. pub fn new(root_dir: &str, persist_storage_records: &str) -> Self { let_cxx_string!(root_dir_ = root_dir); let_cxx_string!(persist_storage_records_ = persist_storage_records); Self { cpp_aconfigd: ffi::new_cpp_aconfigd(&root_dir_, &persist_storage_records_) } } /// Create persistent storage files for platform partition. pub fn initialize_platform_storage(&self) -> Result<(), CppAconfigdError> { self.cpp_aconfigd.initialize_platform_storage().into() } /// Create persistent storage files for mainline modules. pub fn initialize_mainline_storage(&self) -> Result<(), CppAconfigdError> { self.cpp_aconfigd.initialize_mainline_storage().into() } /// Read storage records into memory. pub fn initialize_in_memory_storage_records(&self) -> Result<(), CppAconfigdError> { self.cpp_aconfigd.initialize_in_memory_storage_records().into() } /// Process a `StorageRequestMessages`, and return the bytes of a `StorageReturnMessages`. /// /// `messages_bytes` should contain the serialized bytes of a `StorageRequestMessages`. pub fn handle_socket_request( &self, messages_bytes: &[u8], ) -> Result, CppAconfigdError> { let_cxx_string!(messages_string_ = messages_bytes); let res: Result, CppAconfigdError> = self.cpp_aconfigd.handle_socket_request(&messages_string_).into(); res.map(|s| s.as_bytes().to_vec()) } } /// Represents an error in the C++ aconfigd. /// /// The C++ aconfigd uses the C++ Result type. Result errors are mapped /// to this type. #[derive(Debug)] pub struct CppAconfigdError { msg: String, } impl CppAconfigdError { pub fn new(msg: &str) -> Self { Self { msg: msg.to_string() } } } impl fmt::Display for CppAconfigdError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "CppAconfigd error: {}", self.msg) } } impl Error for CppAconfigdError {} #[cxx::bridge(namespace = "aconfigdwrapper")] mod ffi { enum CppResultStatus { Ok, Err, } struct CppVoidResult { error_message: String, status: CppResultStatus, } struct CppStringResult { data: UniquePtr, error_message: String, status: CppResultStatus, } unsafe extern "C++" { include!("libcxx_aconfigd.hpp"); type CppAconfigd; fn new_cpp_aconfigd(str1: &CxxString, str2: &CxxString) -> UniquePtr; fn initialize_platform_storage(&self) -> CppVoidResult; fn initialize_mainline_storage(&self) -> CppVoidResult; fn initialize_in_memory_storage_records(&self) -> CppVoidResult; fn handle_socket_request(&self, message_string: &CxxString) -> CppStringResult; } } impl Into> for CppVoidResult { fn into(self) -> Result<(), CppAconfigdError> { match self.status { CppResultStatus::Ok => Ok(()), CppResultStatus::Err => Err(CppAconfigdError::new(&self.error_message)), _ => Err(CppAconfigdError::new("unknown status")), } } } impl Into, CppAconfigdError>> for CppStringResult { fn into(self) -> Result, CppAconfigdError> { match self.status { CppResultStatus::Ok => Ok(self.data), CppResultStatus::Err => Err(CppAconfigdError::new(&self.error_message)), _ => Err(CppAconfigdError::new("unknown status")), } } }