blob: debdb515321e5ebcdfe715f3477182fcfdf81a49 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Defines the messages and abstracts out communication for storage.
mod file_storage;
pub use file_storage::FileStorage;
use std::any::{type_name, Any};
use std::borrow::Borrow;
use std::error::Error as StdError;
use std::fmt::{self, Debug};
use std::result::Result as StdResult;
use flexbuffers::FlexbufferSerializer;
use serde::de::{Deserialize, DeserializeOwned, Visitor};
use serde::export::Formatter;
use serde::{Deserializer, Serialize, Serializer};
use thiserror::Error as ThisError;
#[derive(ThisError, Debug)]
pub enum Error {
#[error("id not found {0}")]
IdNotFound(String),
#[error("storage regjected id {0}")]
InvalidIdForStorage(String),
#[error("failed to cast data from '{from}' to '{to}'")]
CastData { from: String, to: String },
#[error("failed to read data")]
ReadData(Option<Box<dyn StdError>>),
#[error("id not written yet")]
EmptyRead,
#[error("failed to write data")]
WriteData(Option<Box<dyn StdError>>),
}
pub fn to_read_data_error<E: StdError + 'static>(err: E) -> Error {
Error::ReadData(Some(Box::new(err)))
}
pub fn to_write_data_error<E: StdError + 'static>(err: E) -> Error {
Error::WriteData(Some(Box::new(err)))
}
/// The result of an operation in this crate.
pub type Result<T> = std::result::Result<T, Error>;
pub trait Storable: Any + Clone + Serialize + DeserializeOwned {}
impl<S: Any + Clone + Serialize + DeserializeOwned> Storable for S {}
pub trait Storage {
fn read_data<S: Storable>(&mut self, id: &str) -> Result<S>;
fn write_data<S: Storable>(&mut self, id: &str, data: &S) -> Result<()>;
}
/// A flexible type that can be used in storable data structures. This should be used sparingly
/// because it results in nested serialization.
pub enum StorableMember {
Deserialized {
value: Box<dyn Any>,
store: fn(&dyn Any) -> Result<Vec<u8>>,
typename: &'static str,
},
// TODO consider zero copy alternatives to Vec.
Serialized(Vec<u8>),
}
const SERIALIZED: &str = "<unknown serialized>";
impl StorableMember {
pub fn new_serialized(data: Vec<u8>) -> Self {
StorableMember::Serialized(data)
}
pub fn new_deserialized<S: Storable>(value: S) -> Self {
StorableMember::Deserialized {
value: Box::new(value),
store: store::<S>,
typename: type_name::<Self>(),
}
}
fn get_typename(&self) -> &'static str {
match self {
StorableMember::Deserialized {
value: _,
store: _,
typename,
} => typename,
StorableMember::Serialized(_) => SERIALIZED,
}
}
pub fn interpret<S: Storable>(&mut self) -> Result<&mut Self> {
if let StorableMember::Serialized(data) = self {
let ser_reader = flexbuffers::Reader::get_root(&data).map_err(to_read_data_error)?;
*self = StorableMember::new_deserialized(
S::deserialize(ser_reader).map_err(to_read_data_error)?,
);
}
Ok(self)
}
pub fn try_borrow_mut<S: Storable>(&mut self) -> Result<&mut S> {
self.interpret::<S>()?;
match self {
StorableMember::Deserialized {
value,
store: _,
typename,
} => match value.downcast_mut::<S>() {
Some(value) => Ok(value),
None => Err(Error::CastData {
from: typename.to_string(),
to: type_name::<S>().to_string(),
}),
},
StorableMember::Serialized(_) => Err(Error::CastData {
from: self.get_typename().to_string(),
to: type_name::<S>().to_string(),
}),
}
}
pub fn try_borrow<S: Storable>(&self) -> Result<&S> {
if let StorableMember::Deserialized {
value,
store: _,
typename: _,
} = self
{
if let Some(value) = value.downcast_ref::<S>() {
return Ok(value);
}
}
Err(Error::CastData {
from: self.get_typename().to_string(),
to: type_name::<S>().to_string(),
})
}
}
fn store<S: Storable>(val: &dyn Any) -> Result<Vec<u8>> {
if let Some(value) = val.downcast_ref::<S>() {
let mut ser = FlexbufferSerializer::new();
value.serialize(&mut ser).map_err(to_write_data_error)?;
Ok(ser.take_buffer())
} else {
Err(Error::CastData {
from: type_name::<dyn Any>().to_string(),
to: type_name::<S>().to_string(),
})
}
}
impl Into<Vec<u8>> for StorableMember {
fn into(self) -> Vec<u8> {
match self {
StorableMember::Deserialized {
value,
store,
typename: _,
} => store(value.borrow()).unwrap(),
StorableMember::Serialized(value) => value,
}
}
}
impl Serialize for StorableMember {
fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
let data;
serializer.serialize_bytes(match &self {
StorableMember::Deserialized {
value,
store,
typename: _,
} => {
data = store(value.borrow()).unwrap();
&data
}
StorableMember::Serialized(value) => value,
})
}
}
struct StorableMemberVisitor;
impl<'de> Visitor<'de> for StorableMemberVisitor {
type Value = StorableMember;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("bytes")
}
fn visit_bytes<E: std::error::Error>(self, v: &[u8]) -> StdResult<Self::Value, E> {
Ok(StorableMember::new_serialized(v.to_vec()))
}
}
impl<'de> Deserialize<'de> for StorableMember {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
deserializer.deserialize_bytes(StorableMemberVisitor)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn storablemember_internal_test() {
let test_value = "Test value".to_string();
let to_write = StorableMember::new_deserialized(test_value.clone());
let serialized: Vec<u8> = to_write.into();
let mut to_read = StorableMember::new_serialized(serialized);
assert_eq!(to_read.try_borrow_mut::<String>().unwrap(), &test_value);
}
#[test]
fn storablemember_external_test() {
let test_value = "Test value".to_string();
let to_write = StorableMember::new_deserialized(test_value.clone());
let mut ser = FlexbufferSerializer::new();
to_write.serialize(&mut ser).unwrap();
let serialized: Vec<u8> = ser.take_buffer();
let ser_reader = flexbuffers::Reader::get_root(&serialized).unwrap();
let mut to_read = StorableMember::deserialize(ser_reader).unwrap();
assert_eq!(to_read.try_borrow_mut::<String>().unwrap(), &test_value);
}
}