use std::cmp;
use std::fmt;
use std::str::FromStr;
use std::u128;
use trackable::error::ErrorKindExt;
use block::BlockSize;
use storage::DataRegionLumpData;
use {Error, ErrorKind, Result};
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct LumpId(u128);
impl LumpId {
pub const SIZE: usize = 16;
pub fn new(id: u128) -> Self {
LumpId(id)
}
pub fn as_u128(&self) -> u128 {
self.0
}
}
impl FromStr for LumpId {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
let id = track!(u128::from_str_radix(s, 16).map_err(|e| ErrorKind::InvalidInput.cause(e)))?;
Ok(LumpId::new(id))
}
}
impl fmt::Debug for LumpId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, r#"LumpId("{}")"#, self)
}
}
impl fmt::Display for LumpId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in (0..Self::SIZE).rev() {
let b = (self.0 >> (8 * i)) as u8;
write!(f, "{:02x}", b)?;
}
Ok(())
}
}
#[derive(Clone)]
pub struct LumpData(LumpDataInner);
impl LumpData {
pub const MAX_SIZE: usize = 0xFFFF * (BlockSize::MIN as usize) - 2;
pub const MAX_EMBEDDED_SIZE: usize = 0xFFFF;
#[allow(clippy::new_ret_no_self)]
pub fn new(data: Vec<u8>) -> Result<Self> {
track_assert!(
data.len() <= LumpData::MAX_SIZE,
ErrorKind::InvalidInput,
"Too large lump data: {} bytes",
data.len()
);
Ok(LumpData(LumpDataInner::DataRegionUnaligned(data)))
}
pub fn new_embedded(data: Vec<u8>) -> Result<Self> {
track_assert!(
data.len() <= LumpData::MAX_EMBEDDED_SIZE,
ErrorKind::InvalidInput,
"Too large embedded lump data: {} bytes",
data.len()
);
Ok(LumpData(LumpDataInner::JournalRegion(data)))
}
pub fn as_bytes(&self) -> &[u8] {
self.as_ref()
}
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
self.as_mut()
}
pub fn into_bytes(self) -> Vec<u8> {
match self.0 {
LumpDataInner::JournalRegion(d) => d,
LumpDataInner::DataRegion(d) => Vec::from(d.as_bytes()),
LumpDataInner::DataRegionUnaligned(d) => d,
}
}
pub(crate) fn aligned_allocate(data_len: usize, block_size: BlockSize) -> Result<Self> {
track_assert!(
data_len <= LumpData::MAX_SIZE,
ErrorKind::InvalidInput,
"Too large lump data: {} bytes",
data_len
);
Ok(LumpData::from(DataRegionLumpData::new(
data_len, block_size,
)))
}
pub(crate) fn as_inner(&self) -> &LumpDataInner {
&self.0
}
}
impl AsRef<[u8]> for LumpData {
fn as_ref(&self) -> &[u8] {
match self.0 {
LumpDataInner::JournalRegion(ref d) => d,
LumpDataInner::DataRegion(ref d) => d.as_bytes(),
LumpDataInner::DataRegionUnaligned(ref d) => d,
}
}
}
impl AsMut<[u8]> for LumpData {
fn as_mut(&mut self) -> &mut [u8] {
match self.0 {
LumpDataInner::JournalRegion(ref mut d) => d,
LumpDataInner::DataRegion(ref mut d) => d.as_bytes_mut(),
LumpDataInner::DataRegionUnaligned(ref mut d) => d,
}
}
}
impl fmt::Debug for LumpData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let block_size = if let LumpDataInner::DataRegion(ref x) = self.0 {
Some(x.block_size())
} else {
None
};
let len = cmp::min(128, self.as_bytes().len());
let bytes = &self.as_bytes()[0..len];
let omitted = if len < self.as_ref().len() {
format!("({} bytes omitted)", self.as_ref().len() - len)
} else {
"".to_owned()
};
write!(
f,
"LumpData {{ block_size: {:?}, bytes: {:?}{} }}",
block_size, bytes, omitted
)
}
}
impl PartialEq for LumpData {
fn eq(&self, other: &Self) -> bool {
self.as_ref() == other.as_ref()
}
}
impl Eq for LumpData {}
impl From<DataRegionLumpData> for LumpData {
fn from(f: DataRegionLumpData) -> Self {
LumpData(LumpDataInner::DataRegion(f))
}
}
#[derive(Clone)]
pub(crate) enum LumpDataInner {
JournalRegion(Vec<u8>),
DataRegion(DataRegionLumpData),
DataRegionUnaligned(Vec<u8>),
}
#[derive(Debug, Clone)]
pub struct LumpHeader {
pub approximate_data_size: u32,
}