use nuts_backend::{Backend, Binary, Create, IdSize, Open, ReceiveHeader, HEADER_MAX_SIZE};
use nuts_bytes::{FromBytes, ToBytes};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::Cow;
use std::collections::HashMap;
use std::convert::TryInto;
use std::num::ParseIntError;
use std::str::FromStr;
use std::{cmp, fmt, mem};
use thiserror::Error;
pub fn deserialize_header<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<[u8; HEADER_MAX_SIZE]>, D::Error> {
let value: Option<Vec<u8>> = Deserialize::deserialize(deserializer)?;
match value {
Some(vec) => match vec.try_into() {
Ok(buf) => Ok(Some(buf)),
Err(_) => Err(serde::de::Error::custom("header has an invalid size")),
},
None => Ok(None),
}
}
pub fn serialize_header<S: Serializer>(
value: &Option<[u8; HEADER_MAX_SIZE]>,
serializer: S,
) -> Result<S::Ok, S::Error> {
Serialize::serialize(&value.map(|buf| buf.to_vec()), serializer)
}
#[derive(Debug, Error)]
pub enum Error {
#[error("no such id: {0}")]
NoSuchId(Id),
#[error("already aquired: {0}")]
AlreadAquired(Id),
#[error("no header data available")]
NoHeader,
#[error(transparent)]
Bytes(#[from] nuts_bytes::Error),
}
#[derive(Clone, Copy, Debug, FromBytes, PartialEq, ToBytes)]
pub struct Id(u32);
impl Binary for Id {
fn from_bytes(bytes: &[u8]) -> Option<Self> {
match bytes.try_into() {
Ok(buf) => Some(Id(u32::from_be_bytes(buf))),
Err(_) => None,
}
}
fn as_bytes(&self) -> Vec<u8> {
self.0.to_be_bytes().to_vec()
}
}
impl IdSize for Id {
fn size() -> usize {
mem::size_of::<u32>()
}
}
impl fmt::Display for Id {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, fmt)
}
}
impl FromStr for Id {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, ParseIntError> {
FromStr::from_str(s).map(Id)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Settings;
impl Binary for Settings {
fn from_bytes(bytes: &[u8]) -> Option<Settings> {
if bytes.is_empty() {
Some(Settings)
} else {
None
}
}
fn as_bytes(&self) -> Vec<u8> {
vec![]
}
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct MemoryBackend {
bsize: u32,
blocks: HashMap<u32, Vec<u8>>,
#[serde(
deserialize_with = "deserialize_header",
serialize_with = "serialize_header"
)]
header: Option<[u8; HEADER_MAX_SIZE]>,
}
impl MemoryBackend {
pub fn new() -> MemoryBackend {
Self::new_with_bsize(512)
}
pub fn new_with_bsize(bsize: u32) -> MemoryBackend {
MemoryBackend {
bsize,
blocks: HashMap::new(),
header: None,
}
}
pub fn block_size(&self) -> u32 {
self.bsize
}
pub fn get(&self, id: &Id) -> Option<&[u8]> {
self.blocks.get(&id.0).map(|buf| buf.as_slice())
}
pub fn insert(&mut self) -> Result<Id, Error> {
self.insert_data(&[])
}
pub fn insert_data(&mut self, data: &[u8]) -> Result<Id, Error> {
let id = Id(self.max_id() + 1);
let mut block = vec![0; self.bsize as usize];
let n = cmp::min(block.len(), data.len());
block[..n].copy_from_slice(&data[..n]);
match self.blocks.insert(id.0, block) {
Some(_) => Err(Error::AlreadAquired(id)),
None => Ok(id),
}
}
fn max_id(&self) -> u32 {
*self.blocks.keys().max().unwrap_or(&0)
}
}
impl Default for MemoryBackend {
fn default() -> Self {
Self::new()
}
}
impl ReceiveHeader<Self> for MemoryBackend {
fn get_header_bytes(&mut self, bytes: &mut [u8; HEADER_MAX_SIZE]) -> Result<(), Error> {
match self.header.as_ref() {
Some(source) => {
bytes.copy_from_slice(source);
Ok(())
}
None => Err(Error::NoHeader),
}
}
}
impl Create<Self> for MemoryBackend {
fn settings(&self) -> Settings {
Settings
}
fn build(
mut self,
header: [u8; HEADER_MAX_SIZE],
_overwrite: bool,
) -> Result<MemoryBackend, Error> {
<Self as Backend>::write_header(&mut self, &header)?;
Ok(self)
}
}
impl Open<Self> for MemoryBackend {
fn build(self, _settings: Settings) -> Result<MemoryBackend, Error> {
Ok(self)
}
}
impl Backend for MemoryBackend {
type Settings = Settings;
type Err = Error;
type Id = Id;
type Info = ();
fn info(&self) -> Result<(), Error> {
Ok(())
}
fn block_size(&self) -> u32 {
self.bsize
}
fn aquire(&mut self, buf: &[u8]) -> Result<Id, Error> {
self.insert_data(buf)
}
fn release(&mut self, id: Id) -> Result<(), Error> {
self.blocks.remove(&id.0);
Ok(())
}
fn read(&mut self, id: &Id, buf: &mut [u8]) -> Result<usize, Error> {
match self.blocks.get(&id.0) {
Some(src) => {
let len = cmp::min(src.len(), buf.len());
let source = &src[..len];
let target = &mut buf[..len];
target.copy_from_slice(source);
Ok(len)
}
None => Err(Error::NoSuchId(*id)),
}
}
fn write(&mut self, id: &Id, buf: &[u8]) -> Result<usize, Error> {
match self.blocks.get_mut(&id.0) {
Some(target) => {
let mut source = Cow::from(buf);
let mut len = source.len();
if len != self.bsize as usize {
len = cmp::min(source.len(), self.bsize as usize);
source.to_mut().resize(self.bsize as usize, 0);
}
target.copy_from_slice(&source);
Ok(len)
}
None => Err(Error::NoSuchId(*id)),
}
}
fn write_header(&mut self, buf: &[u8; HEADER_MAX_SIZE]) -> Result<(), Error> {
self.header = Some(*buf);
Ok(())
}
fn delete(self) {
}
}