use super::Result;
use serde::{Deserialize, Serialize};
use std::fmt::{Debug, Formatter, Write};
use xor_name::XorName;
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct DataMap(Vec<ChunkInfo>);
#[allow(clippy::len_without_is_empty)]
impl DataMap {
pub fn new(mut keys: Vec<ChunkInfo>) -> Self {
keys.sort_by(|a, b| a.index.cmp(&b.index));
Self(keys)
}
pub fn file_size(&self) -> usize {
DataMap::total_size(&self.0)
}
pub fn infos(&self) -> Vec<ChunkInfo> {
self.0.to_vec()
}
fn total_size(keys: &[ChunkInfo]) -> usize {
keys.iter().fold(0, |acc, chunk| acc + chunk.src_size)
}
}
impl Debug for DataMap {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), std::fmt::Error> {
writeln!(formatter, "DataMap:")?;
let len = self.0.len();
for (index, chunk) in self.0.iter().enumerate() {
if index + 1 == len {
write!(formatter, " {:?}", chunk)?
} else {
writeln!(formatter, " {:?}", chunk)?
}
}
Ok(())
}
}
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Default)]
pub struct ChunkInfo {
pub index: usize,
pub dst_hash: XorName,
pub src_hash: XorName,
pub src_size: usize,
}
fn debug_bytes<V: AsRef<[u8]>>(input: V) -> String {
let input_ref = input.as_ref();
if input_ref.is_empty() {
return "<empty>".to_owned();
}
if input_ref.len() <= 6 {
let mut ret = String::new();
for byte in input_ref.iter() {
write!(ret, "{:02x}", byte).unwrap_or(());
}
return ret;
}
format!(
"{:02x}{:02x}{:02x}..{:02x}{:02x}{:02x}",
input_ref[0],
input_ref[1],
input_ref[2],
input_ref[input_ref.len() - 3],
input_ref[input_ref.len() - 2],
input_ref[input_ref.len() - 1]
)
}
impl Debug for ChunkInfo {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), std::fmt::Error> {
write!(
formatter,
"ChunkInfo {{ index: {}, dst_hash: {}, src_hash: {}, src_size: {} }}",
self.index,
debug_bytes(&self.dst_hash),
debug_bytes(&self.src_hash),
self.src_size
)
}
}