use std::marker::PhantomData;
use std::mem;
use data_map::DataMap;
use super::{MIN_CHUNK_SIZE, SelfEncryptionError, Storage, StorageError};
pub const MAX: u64 = (3 * MIN_CHUNK_SIZE as u64) - 1;
pub struct SmallEncryptor<'a, E: StorageError, S: 'a + Storage<E>> {
pub storage: &'a mut S,
pub buffer: Vec<u8>,
phantom: PhantomData<E>,
}
impl<'a, E: StorageError, S: Storage<E>> SmallEncryptor<'a, E, S> {
pub fn new(storage: &'a mut S, data: Vec<u8>) -> SmallEncryptor<'a, E, S> {
debug_assert!(data.len() as u64 <= MAX);
SmallEncryptor {
storage: storage,
buffer: data,
phantom: PhantomData,
}
}
pub fn write(&mut self, data: &[u8]) -> Result<(), SelfEncryptionError<E>> {
debug_assert!(data.len() as u64 + self.len() <= MAX);
Ok(self.buffer.extend_from_slice(data))
}
pub fn close(&mut self) -> Result<DataMap, SelfEncryptionError<E>> {
let mut swapped_buffer = vec![];
mem::swap(&mut swapped_buffer, &mut self.buffer);
Ok(DataMap::Content(swapped_buffer))
}
pub fn len(&self) -> u64 {
self.buffer.len() as u64
}
pub fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
use data_map::DataMap;
use itertools::Itertools;
use maidsafe_utilities::SeededRng;
use rand::Rng;
use self_encryptor::SelfEncryptor;
use super::super::utils;
use test_helpers::SimpleStorage;
fn basic_write_and_close(data: &[u8]) {
let mut storage = SimpleStorage::new();
let data_map;
{
let mut encryptor = SmallEncryptor::new(&mut storage, vec![]);
assert_eq!(encryptor.len(), 0);
assert!(encryptor.is_empty());
unwrap!(encryptor.write(data));
assert_eq!(encryptor.len(), data.len() as u64);
assert!(!encryptor.is_empty() || data.is_empty());
data_map = unwrap!(encryptor.close());
}
match data_map {
DataMap::Content(ref content) => assert!(&content[..] == data),
_ => panic!("Wrong DataMap type returned."),
}
let mut self_encryptor = unwrap!(SelfEncryptor::new(&mut storage, data_map));
let fetched = unwrap!(self_encryptor.read(0, data.len() as u64));
assert!(fetched == data);
}
fn multiple_writes_then_close<T: Rng>(rng: &mut T, data: &[u8]) {
let mut storage = SimpleStorage::new();
let mut existing_data = vec![];
let data_pieces = utils::make_random_pieces(rng, data, 1);
for data in data_pieces {
let data_map;
{
let mut encryptor = SmallEncryptor::new(&mut storage, existing_data.clone());
unwrap!(encryptor.write(data));
existing_data.extend_from_slice(data);
assert_eq!(encryptor.len(), existing_data.len() as u64);
data_map = unwrap!(encryptor.close());
}
match data_map {
DataMap::Content(ref content) => assert!(*content == existing_data),
_ => panic!("Wrong DataMap type returned."),
}
let mut self_encryptor = unwrap!(SelfEncryptor::new(&mut storage, data_map));
assert_eq!(self_encryptor.len(), existing_data.len() as u64);
let fetched = unwrap!(self_encryptor.read(0, existing_data.len() as u64));
assert!(fetched == existing_data);
}
assert!(&existing_data[..] == data);
}
#[test]
fn all_unit() {
let mut rng = SeededRng::new();
let data = rng.gen_iter().take(MAX as usize).collect_vec();
basic_write_and_close(&[]);
basic_write_and_close(&data[..1]);
basic_write_and_close(&data);
multiple_writes_then_close(&mut rng, &data[..100]);
multiple_writes_then_close(&mut rng, &data[..1000]);
multiple_writes_then_close(&mut rng, &data);
}
}