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); 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::(chunk.1)); } Ok(()) } #[inline] pub fn read_n_from(n: usize, src: &mut Read) -> Result { let mut chunks = Vec::with_capacity(n); for _ in 0..n { let hash = try!(Hash::read_from(src)); let len = try!(src.read_u32::()); 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 } } impl Default for ChunkList { #[inline] fn default() -> Self { ChunkList(Vec::new()) } } impl From> for ChunkList { fn from(val: Vec) -> Self { ChunkList(val) } } impl Into> for ChunkList { fn into(self) -> Vec { 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(&self, serializer: S) -> Result 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(deserializer: D) -> Result where D: serde::Deserializer { let data: Vec = 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()) } }