2017-03-18 15:41:59 +01:00
|
|
|
use std::io::{self, Write, Read, Cursor};
|
|
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
|
|
|
|
use serde::{self, Serialize, Deserialize};
|
|
|
|
use serde::bytes::{Bytes, ByteBuf};
|
|
|
|
use serde::de::Error;
|
|
|
|
|
|
|
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
|
|
|
|
|
|
|
use super::Hash;
|
|
|
|
|
|
|
|
pub type Chunk = (Hash, u32);
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
|
|
|
pub struct ChunkList(Vec<Chunk>);
|
|
|
|
|
|
|
|
impl ChunkList {
|
|
|
|
#[inline]
|
|
|
|
pub fn new() -> Self {
|
|
|
|
ChunkList(Vec::new())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn with_capacity(num: usize) -> Self {
|
|
|
|
ChunkList(Vec::with_capacity(num))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.0.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.0.is_empty()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn push(&mut self, chunk: Chunk) {
|
|
|
|
self.0.push(chunk)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn write_to(&self, dst: &mut Write) -> Result<(), io::Error> {
|
|
|
|
for chunk in &self.0 {
|
|
|
|
try!(chunk.0.write_to(dst));
|
|
|
|
try!(dst.write_u32::<LittleEndian>(chunk.1));
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn read_n_from(n: usize, src: &mut Read) -> Result<Self, io::Error> {
|
|
|
|
let mut chunks = Vec::with_capacity(n);
|
|
|
|
for _ in 0..n {
|
|
|
|
let hash = try!(Hash::read_from(src));
|
|
|
|
let len = try!(src.read_u32::<LittleEndian>());
|
|
|
|
chunks.push((hash, len));
|
|
|
|
}
|
|
|
|
Ok(ChunkList(chunks))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn read_from(src: &[u8]) -> Self {
|
|
|
|
if src.len() % 20 != 0 {
|
|
|
|
warn!("Reading truncated chunk list");
|
|
|
|
}
|
|
|
|
ChunkList::read_n_from(src.len()/20, &mut Cursor::new(src)).unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn encoded_size(&self) -> usize {
|
|
|
|
self.0.len() * 20
|
|
|
|
}
|
2017-03-22 12:27:17 +01:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn into_inner(self) -> Vec<Chunk> {
|
|
|
|
self.0
|
|
|
|
}
|
2017-03-18 15:41:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for ChunkList {
|
|
|
|
#[inline]
|
|
|
|
fn default() -> Self {
|
|
|
|
ChunkList(Vec::new())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Vec<Chunk>> for ChunkList {
|
|
|
|
fn from(val: Vec<Chunk>) -> Self {
|
|
|
|
ChunkList(val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Into<Vec<Chunk>> for ChunkList {
|
|
|
|
fn into(self) -> Vec<Chunk> {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Deref for ChunkList {
|
|
|
|
type Target = [Chunk];
|
|
|
|
fn deref(&self) -> &[Chunk] {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DerefMut for ChunkList {
|
|
|
|
fn deref_mut(&mut self) -> &mut [Chunk] {
|
|
|
|
&mut self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serialize for ChunkList {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
|
|
|
let mut buf = Vec::with_capacity(self.encoded_size());
|
|
|
|
self.write_to(&mut buf).unwrap();
|
|
|
|
Bytes::from(&buf as &[u8]).serialize(serializer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Deserialize for ChunkList {
|
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer {
|
|
|
|
let data: Vec<u8> = try!(ByteBuf::deserialize(deserializer)).into();
|
|
|
|
if data.len() % 20 != 0 {
|
|
|
|
return Err(D::Error::custom("Invalid chunk list length"));
|
|
|
|
}
|
|
|
|
Ok(ChunkList::read_n_from(data.len()/20, &mut Cursor::new(data)).unwrap())
|
|
|
|
}
|
|
|
|
}
|