blob: 2fac912ae508c4bda515e766b76ce45d61b2dbc8 [file] [log] [blame]
//! 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<CppAconfigd>,
}
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<Vec<u8>, CppAconfigdError> {
let_cxx_string!(messages_string_ = messages_bytes);
let res: Result<UniquePtr<CxxString>, 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<CxxString>,
error_message: String,
status: CppResultStatus,
}
unsafe extern "C++" {
include!("libcxx_aconfigd.hpp");
type CppAconfigd;
fn new_cpp_aconfigd(str1: &CxxString, str2: &CxxString) -> UniquePtr<CppAconfigd>;
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<Result<(), CppAconfigdError>> 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<Result<UniquePtr<CxxString>, CppAconfigdError>> for CppStringResult {
fn into(self) -> Result<UniquePtr<CxxString>, CppAconfigdError> {
match self.status {
CppResultStatus::Ok => Ok(self.data),
CppResultStatus::Err => Err(CppAconfigdError::new(&self.error_message)),
_ => Err(CppAconfigdError::new("unknown status")),
}
}
}