use any_pointer;
use private::units::*;
use private::arena::{BuilderArena, ReaderArena, SegmentBuilder, SegmentReader};
use private::layout;
use traits::{FromPointerReader, FromPointerBuilder, SetPointerBuilder};
use {OutputSegments, Result, Word};
#[derive(Clone, Copy)]
pub struct ReaderOptions {
pub traversal_limit_in_words : u64,
pub nesting_limit : i32,
}
pub const DEFAULT_READER_OPTIONS : ReaderOptions =
ReaderOptions { traversal_limit_in_words : 8 * 1024 * 1024, nesting_limit : 64 };
impl Default for ReaderOptions {
fn default() -> ReaderOptions {
ReaderOptions { traversal_limit_in_words : 8 * 1024 * 1024, nesting_limit : 64 }
}
}
impl ReaderOptions {
pub fn new() -> ReaderOptions { DEFAULT_READER_OPTIONS }
pub fn nesting_limit<'a>(&'a mut self, value : i32) -> &'a mut ReaderOptions {
self.nesting_limit = value;
return self;
}
pub fn traversal_limit_in_words<'a>(&'a mut self, value : u64) -> &'a mut ReaderOptions {
self.traversal_limit_in_words = value;
return self;
}
}
type SegmentId = u32;
pub trait ReaderSegments {
fn get_segment<'a>(&'a self, id: u32) -> Option<&'a [Word]>;
}
pub struct SegmentArray<'a> {
segments: &'a [&'a [Word]],
}
impl <'a> SegmentArray<'a> {
pub fn new(segments: &'a [&'a [Word]]) -> SegmentArray<'a> {
SegmentArray { segments: segments }
}
}
impl <'b> ReaderSegments for SegmentArray<'b> {
fn get_segment<'a>(&'a self, id: u32) -> Option<&'a [Word]> {
self.segments.get(id as usize).map(|slice| *slice)
}
}
pub struct Reader<S> where S: ReaderSegments {
arena: Box<ReaderArena>,
segments: Box<S>,
options: ReaderOptions,
}
unsafe impl <S> Send for Reader<S> where S: Send + ReaderSegments {}
impl <S> Reader<S> where S: ReaderSegments {
pub fn new(segments: S, options: ReaderOptions) -> Reader<S> {
let boxed_segments = Box::new(segments);
let boxed_segments_ref = {
let r :&S = &*boxed_segments;
unsafe { ::std::mem::transmute(r as &ReaderSegments) }
};
let arena = ReaderArena::new(boxed_segments_ref, options);
Reader { arena: arena, segments: boxed_segments, options: options }
}
fn get_root_internal(&self) -> Result<any_pointer::Reader> {
unsafe {
let segment : *const SegmentReader = &self.arena.segment0;
let pointer_reader = try!(layout::PointerReader::get_root(
segment, (*segment).get_start_ptr(), self.options.nesting_limit));
Ok(any_pointer::Reader::new(pointer_reader))
}
}
pub fn get_root<'a, T : FromPointerReader<'a>>(&'a self) -> Result<T> {
try!(self.get_root_internal()).get_as()
}
pub fn into_segments(self) -> S {
*self.segments
}
}
pub unsafe trait Allocator {
fn allocate_segment(&mut self, minimum_size: u32) -> (*mut Word, u32);
fn pre_drop(&mut self, _segment0_currently_allocated: u32) {}
}
pub struct Builder<A> where A: Allocator {
arena: Box<BuilderArena>,
allocator: Box<A>,
cap_table: Vec<Option<Box<::private::capability::ClientHook>>>,
}
unsafe impl <A> Send for Builder<A> where A: Send + Allocator {}
impl <A> Builder<A> where A: Allocator {
pub fn new(allocator: A) -> Builder<A> {
let mut boxed_allocator = Box::new(allocator);
let boxed_allocator_ref = {
let r: &mut A = &mut *boxed_allocator;
unsafe { ::std::mem::transmute(r as &mut Allocator) }
};
let arena = BuilderArena::new(boxed_allocator_ref);
Builder {
arena: arena,
allocator: boxed_allocator,
cap_table: Vec::new(),
}
}
fn get_root_internal<'a>(&mut self) -> any_pointer::Builder<'a> {
let root_segment: *mut SegmentBuilder = &mut self.arena.segment0;
if self.arena.segment0.current_size() == 0 {
match self.arena.segment0.allocate(WORDS_PER_POINTER as u32) {
None => {panic!("could not allocate root pointer") }
Some(location) => {
assert!(location == self.arena.segment0.get_ptr_unchecked(0),
"First allocated word of new segment was not at offset 0");
any_pointer::Builder::new(layout::PointerBuilder::get_root(root_segment, location))
}
}
} else {
any_pointer::Builder::new(
layout::PointerBuilder::get_root(root_segment,
self.arena.segment0.get_ptr_unchecked(0)))
}
}
pub fn init_root<'a, T: FromPointerBuilder<'a>>(&'a mut self) -> T {
use ::traits::ImbueMut;
let mut root = self.get_root_internal();
root.imbue_mut(&mut self.cap_table);
root.init_as()
}
pub fn get_root<'a, T: FromPointerBuilder<'a>>(&'a mut self) -> Result<T> {
use ::traits::ImbueMut;
let mut root = self.get_root_internal();
root.imbue_mut(&mut self.cap_table);
root.get_as()
}
pub fn get_root_as_reader<'a, T: FromPointerReader<'a>>(&'a self) -> Result<T> {
let root_segment: *const SegmentReader = &self.arena.segment0.reader;
if self.arena.segment0.current_size() == 0 {
Err(::Error::failed("Segment zero is empty.".to_string()))
} else {
use ::traits::Imbue;
let mut root = any_pointer::Reader::new(
try!(layout::PointerReader::get_root(root_segment,
self.arena.segment0.get_ptr_unchecked(0),
0x7fffffff)));
root.imbue(&self.cap_table);
root.get_as()
}
}
pub fn set_root<To, From: SetPointerBuilder<To>>(&mut self, value : From) -> Result<()> {
use ::traits::ImbueMut;
let mut root = self.get_root_internal();
root.imbue_mut(&mut self.cap_table);
root.set_as(value)
}
pub fn get_segments_for_output<'a>(&'a self) -> OutputSegments<'a> {
self.arena.get_segments_for_output()
}
}
impl <A> Drop for Builder<A> where A: Allocator {
fn drop(&mut self) {
self.allocator.pre_drop(self.arena.segment0.current_size());
}
}
pub struct HeapAllocator {
owned_memory : Vec<Vec<Word>>,
next_size: u32,
allocation_strategy: AllocationStrategy,
}
#[derive(Clone, Copy)]
pub enum AllocationStrategy {
FixedSize,
GrowHeuristically
}
pub const SUGGESTED_FIRST_SEGMENT_WORDS : u32 = 1024;
pub const SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy = AllocationStrategy::GrowHeuristically;
impl HeapAllocator {
pub fn new() -> HeapAllocator {
HeapAllocator { owned_memory: Vec::new(),
next_size: SUGGESTED_FIRST_SEGMENT_WORDS,
allocation_strategy: SUGGESTED_ALLOCATION_STRATEGY }
}
pub fn first_segment_words(mut self, value: u32) -> HeapAllocator {
self.next_size = value;
self
}
pub fn allocation_strategy(mut self, value : AllocationStrategy) -> HeapAllocator {
self.allocation_strategy = value;
self
}
}
unsafe impl Allocator for HeapAllocator {
fn allocate_segment(&mut self, minimum_size: u32) -> (*mut Word, u32) {
let size = ::std::cmp::max(minimum_size, self.next_size);
let mut new_words = Word::allocate_zeroed_vec(size as usize);
let ptr = new_words.as_mut_ptr();
self.owned_memory.push(new_words);
match self.allocation_strategy {
AllocationStrategy::GrowHeuristically => { self.next_size += size; }
_ => { }
}
(ptr, size as u32)
}
}
impl Builder<HeapAllocator> {
pub fn new_default() -> Builder<HeapAllocator> {
Builder::new(HeapAllocator::new())
}
}
pub struct ScratchSpace<'a> {
slice: &'a mut [Word],
in_use: bool,
}
impl <'a> ScratchSpace<'a> {
pub fn new(slice: &'a mut [Word]) -> ScratchSpace<'a> {
ScratchSpace { slice: slice, in_use: false }
}
}
pub struct ScratchSpaceHeapAllocator<'a, 'b: 'a> {
scratch_space: &'a mut ScratchSpace<'b>,
allocator: HeapAllocator,
}
impl <'a, 'b: 'a> ScratchSpaceHeapAllocator<'a, 'b> {
pub fn new(scratch_space: &'a mut ScratchSpace<'b>) -> ScratchSpaceHeapAllocator<'a, 'b> {
ScratchSpaceHeapAllocator { scratch_space: scratch_space,
allocator: HeapAllocator::new()}
}
pub fn second_segment_words(mut self, value: u32) -> ScratchSpaceHeapAllocator<'a, 'b> {
ScratchSpaceHeapAllocator { scratch_space: self.scratch_space,
allocator: self.allocator.first_segment_words(value) }
}
pub fn allocation_strategy(mut self, value: AllocationStrategy) -> ScratchSpaceHeapAllocator<'a, 'b> {
ScratchSpaceHeapAllocator { scratch_space: self.scratch_space,
allocator: self.allocator.allocation_strategy(value) }
}
}
unsafe impl <'a, 'b: 'a> Allocator for ScratchSpaceHeapAllocator<'a, 'b> {
fn allocate_segment(&mut self, minimum_size: u32) -> (*mut Word, u32) {
if !self.scratch_space.in_use {
self.scratch_space.in_use = true;
(self.scratch_space.slice.as_mut_ptr(), self.scratch_space.slice.len() as u32)
} else {
self.allocator.allocate_segment(minimum_size)
}
}
fn pre_drop(&mut self, segment0_currently_allocated: u32) {
let ptr = self.scratch_space.slice.as_mut_ptr();
unsafe {
::std::ptr::write_bytes(ptr, 0u8, segment0_currently_allocated as usize);
}
self.scratch_space.in_use = false;
}
}