#![allow(unsafe_code)]
use bit_vec::BitVec;
use byteorder::{ByteOrder, LittleEndian};
use super::{CheckedOffset, Error, Field, Offset, Result};
use crypto::Hash;
use messages::{MessageBuffer, RawMessage, HEADER_LENGTH};
pub trait SegmentField<'a>: Sized {
fn item_size() -> Offset;
fn count(&self) -> Offset;
unsafe fn from_buffer(buffer: &'a [u8], from: Offset, count: Offset) -> Self;
fn extend_buffer(&self, buffer: &mut Vec<u8>);
#[allow(unused_variables)]
fn check_data(
buffer: &'a [u8],
from: CheckedOffset,
count: CheckedOffset,
latest_segment: CheckedOffset,
) -> Result;
}
impl<'a, T> Field<'a> for T
where
T: SegmentField<'a>,
{
fn field_size() -> Offset {
8
}
unsafe fn read(buffer: &'a [u8], from: Offset, to: Offset) -> Self {
let pos = LittleEndian::read_u32(&buffer[from as usize..from as usize + 4]);
let count = LittleEndian::read_u32(&buffer[from as usize + 4..to as usize]);
Self::from_buffer(buffer, pos, count)
}
fn write(&self, buffer: &mut Vec<u8>, from: Offset, to: Offset) {
let pos = buffer.len() as u32;
LittleEndian::write_u32(&mut buffer[from as usize..from as usize + 4], pos);
LittleEndian::write_u32(
&mut buffer[from as usize + 4..to as usize],
self.count() as u32,
);
self.extend_buffer(buffer);
}
fn check(
buffer: &'a [u8],
pointer_from: CheckedOffset,
pointer_to: CheckedOffset,
latest_segment: CheckedOffset,
) -> Result {
debug_assert_eq!(
(pointer_to - pointer_from)?.unchecked_offset(),
Self::field_size()
);
let pointer_count_start: Offset = (pointer_from + 4)?.unchecked_offset();
let segment_start: CheckedOffset = LittleEndian::read_u32(
&buffer[pointer_from.unchecked_offset() as usize..pointer_count_start as usize],
).into();
let count: CheckedOffset = LittleEndian::read_u32(
&buffer[pointer_count_start as usize..pointer_to.unchecked_offset() as usize],
).into();
if segment_start < latest_segment {
return Err(Error::OverlappingSegment {
last_end: latest_segment.unchecked_offset(),
start: segment_start.unchecked_offset(),
});
} else if segment_start > latest_segment {
return Err(Error::SpaceBetweenSegments {
last_end: latest_segment.unchecked_offset(),
start: segment_start.unchecked_offset(),
});
}
let segment_end = (segment_start + (count * Self::item_size())?)?;
if segment_end.unchecked_offset() > buffer.len() as u32 {
return Err(Error::IncorrectSegmentSize {
position: pointer_count_start,
value: count.unchecked_offset(),
});
}
let latest_segment = segment_end;
Self::check_data(buffer, segment_start, count, latest_segment)
}
}
impl<'a> SegmentField<'a> for &'a str {
fn item_size() -> Offset {
1
}
fn count(&self) -> Offset {
self.as_bytes().len() as Offset
}
unsafe fn from_buffer(buffer: &'a [u8], from: Offset, count: Offset) -> Self {
let to = from + count * Self::item_size();
let slice = &buffer[from as usize..to as usize];
::std::str::from_utf8_unchecked(slice)
}
fn extend_buffer(&self, buffer: &mut Vec<u8>) {
buffer.extend_from_slice(self.as_bytes())
}
fn check_data(
buffer: &'a [u8],
from: CheckedOffset,
count: CheckedOffset,
latest_segment: CheckedOffset,
) -> Result {
let size: CheckedOffset = (count * Self::item_size())?;
let to: CheckedOffset = (from + size)?;
let slice = &buffer[from.unchecked_offset() as usize..to.unchecked_offset() as usize];
if let Err(e) = ::std::str::from_utf8(slice) {
return Err(Error::Utf8 {
position: from.unchecked_offset(),
error: e,
});
}
Ok(latest_segment)
}
}
impl<'a> SegmentField<'a> for RawMessage {
fn item_size() -> Offset {
1
}
fn count(&self) -> Offset {
self.as_ref().len() as Offset
}
unsafe fn from_buffer(buffer: &'a [u8], from: Offset, to: Offset) -> Self {
let to = from + to * Self::item_size();
let slice = &buffer[from as usize..to as usize];
Self::new(MessageBuffer::from_vec(Vec::from(slice)))
}
fn extend_buffer(&self, buffer: &mut Vec<u8>) {
buffer.extend_from_slice(self.as_ref())
}
fn check_data(
buffer: &'a [u8],
from: CheckedOffset,
count: CheckedOffset,
latest_segment: CheckedOffset,
) -> Result {
let size: CheckedOffset = (count * Self::item_size())?;
let to: CheckedOffset = (from + size)?;
let slice = &buffer[from.unchecked_offset() as usize..to.unchecked_offset() as usize];
if slice.len() < HEADER_LENGTH {
return Err(Error::UnexpectedlyShortRawMessage {
position: from.unchecked_offset(),
size: slice.len() as Offset,
});
}
let actual_size = slice.len() as Offset;
let declared_size: Offset = LittleEndian::read_u32(&slice[6..10]);
if actual_size != declared_size {
return Err(Error::IncorrectSizeOfRawMessage {
position: from.unchecked_offset(),
actual_size: slice.len() as Offset,
declared_size,
});
}
Ok(latest_segment)
}
}
impl<'a, T> SegmentField<'a> for Option<T>
where
T: Field<'a>,
{
fn item_size() -> Offset {
T::field_size()
}
fn count(&self) -> Offset {
self.is_some() as usize as Offset
}
unsafe fn from_buffer(buffer: &'a [u8], from: Offset, count: Offset) -> Self {
if count > 0 {
Some(T::read(buffer, from, from + Self::item_size()))
} else {
None
}
}
fn extend_buffer(&self, mut buffer: &mut Vec<u8>) {
let start = buffer.len() as Offset;
if let Some(ref v) = self {
buffer.resize((start + Self::item_size()) as usize, 0);
v.write(&mut buffer, start, start + Self::item_size());
}
}
fn check_data(
buffer: &'a [u8],
from: CheckedOffset,
count: CheckedOffset,
latest_segment: CheckedOffset,
) -> Result {
if count.unchecked_offset() == 1 {
T::check(buffer, from, (from + Self::item_size())?, latest_segment)
} else {
Ok(latest_segment)
}
}
}
impl<'a, T> SegmentField<'a> for Vec<T>
where
T: Field<'a>,
{
fn item_size() -> Offset {
T::field_size()
}
fn count(&self) -> Offset {
self.len() as Offset
}
unsafe fn from_buffer(buffer: &'a [u8], from: Offset, count: Offset) -> Self {
let mut vec = Vec::with_capacity(count as usize);
let mut start = from;
for _ in 0..count {
vec.push(T::read(buffer, start, start + Self::item_size()));
start += Self::item_size();
}
vec
}
fn extend_buffer(&self, mut buffer: &mut Vec<u8>) {
let mut start = buffer.len() as Offset;
buffer.resize((start + self.count() * Self::item_size()) as usize, 0);
for i in self.iter() {
i.write(&mut buffer, start, start + Self::item_size());
start += Self::item_size();
}
}
fn check_data(
buffer: &'a [u8],
from: CheckedOffset,
count: CheckedOffset,
latest_segment: CheckedOffset,
) -> Result {
let mut start = from;
let mut latest_segment = latest_segment;
for _ in 0..count.unchecked_offset() {
latest_segment = T::check(buffer, start, (start + Self::item_size())?, latest_segment)?;
start = (start + Self::item_size())?;
}
Ok(latest_segment)
}
}
impl<'a> SegmentField<'a> for BitVec {
fn item_size() -> Offset {
1
}
fn count(&self) -> Offset {
self.to_bytes().len() as Offset
}
unsafe fn from_buffer(buffer: &'a [u8], from: Offset, count: Offset) -> Self {
let to = from + count * Self::item_size();
let slice = &buffer[from as usize..to as usize];
Self::from_bytes(slice)
}
fn extend_buffer(&self, buffer: &mut Vec<u8>) {
let slice = &self.to_bytes();
buffer.extend_from_slice(slice);
}
fn check_data(
_: &'a [u8],
_: CheckedOffset,
_: CheckedOffset,
latest_segment: CheckedOffset,
) -> Result {
Ok(latest_segment)
}
}
impl<'a> SegmentField<'a> for &'a [u8] {
fn item_size() -> Offset {
1
}
fn count(&self) -> Offset {
self.len() as Offset
}
unsafe fn from_buffer(buffer: &'a [u8], from: Offset, count: Offset) -> Self {
let to = from + count * Self::item_size();
&buffer[from as usize..to as usize]
}
fn extend_buffer(&self, buffer: &mut Vec<u8>) {
buffer.extend_from_slice(self)
}
fn check_data(
_: &'a [u8],
_: CheckedOffset,
_: CheckedOffset,
latest_segment: CheckedOffset,
) -> Result {
Ok(latest_segment)
}
}
#[macro_export]
macro_rules! implement_pod_array_field {
($name:ident) => {
impl<'a> SegmentField<'a> for &'a [$name] {
fn item_size() -> Offset {
::std::mem::size_of::<$name>() as Offset
}
fn count(&self) -> Offset {
self.len() as Offset
}
unsafe fn from_buffer(buffer: &'a [u8], from: Offset, count: Offset) -> Self {
let to = from + count * Self::item_size();
let slice = &buffer[(from as usize)..(to as usize)];
::std::slice::from_raw_parts(
slice.as_ptr() as *const Hash,
slice.len() / Self::item_size() as usize,
)
}
fn extend_buffer(&self, buffer: &mut Vec<u8>) {
let slice = unsafe {
::std::slice::from_raw_parts(
self.as_ptr() as *const u8,
self.len() * Self::item_size() as usize,
)
};
buffer.extend_from_slice(slice)
}
fn check_data(
_: &'a [u8],
_: CheckedOffset,
_: CheckedOffset,
latest_segment: CheckedOffset,
) -> Result {
Ok(latest_segment)
}
}
};
}
implement_pod_array_field!{Hash}