<commit_before>use arena::{TypedArena, DroplessArena};
use std::mem;
use std::ptr;
use std::slice;
use std::cell::RefCell;
use std::marker::PhantomData;
use smallvec::SmallVec;

/// This declares a list of types which can be allocated by `Arena`.
///
/// The `few` modifier will cause allocation to use the shared arena and recording the destructor.
/// This is faster and more memory efficient if there's only a few allocations of the type.
/// Leaving `few` out will cause the type to get its own dedicated `TypedArena` which is
/// faster and more memory efficient if there is lots of allocations.
///
/// Specifying the `decode` modifier will add decode impls for &T and &[T] where T is the type
/// listed. These impls will appear in the implement_ty_decoder! macro.
#[macro_export]
macro_rules! arena_types {
    ($macro:path, $args:tt, $tcx:lifetime) => (
        $macro!($args, [
            [] vtable_method: Option<(
                rustc::hir::def_id::DefId,
                rustc::ty::subst::SubstsRef<$tcx>
            )>,
            [few, decode] mir_keys: rustc::util::nodemap::DefIdSet,
            [decode] specialization_graph: rustc::traits::specialization_graph::Graph,
            [] region_scope_tree: rustc::middle::region::ScopeTree,
            [] item_local_set: rustc::util::nodemap::ItemLocalSet,
            [decode] mir_const_qualif: rustc_data_structures::bit_set::BitSet<rustc::mir::Local>,
            [] trait_impls_of: rustc::ty::trait_def::TraitImpls,
            [] dropck_outlives:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx,
                        rustc::traits::query::dropck_outlives::DropckOutlivesResult<'tcx>
                    >
                >,
            [] normalize_projection_ty:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx,
                        rustc::traits::query::normalize::NormalizationResult<'tcx>
                    >
                >,
            [] implied_outlives_bounds:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx,
                        Vec<rustc::traits::query::outlives_bounds::OutlivesBound<'tcx>>
                    >
                >,
            [] type_op_subtype:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx, ()>
                >,
            [] type_op_normalize_poly_fn_sig:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::PolyFnSig<'tcx>>
                >,
            [] type_op_normalize_fn_sig:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::FnSig<'tcx>>
                >,
            [] type_op_normalize_predicate:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::Predicate<'tcx>>
                >,
            [] type_op_normalize_ty:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::Ty<'tcx>>
                >,
            [few] crate_inherent_impls: rustc::ty::CrateInherentImpls,
            [decode] borrowck: rustc::middle::borrowck::BorrowCheckResult,
            [few] upstream_monomorphizations:
                rustc::util::nodemap::DefIdMap<
                    rustc_data_structures::fx::FxHashMap<
                        rustc::ty::subst::SubstsRef<'tcx>,
                        rustc::hir::def_id::CrateNum
                    >
                >,
            [few] resolve_lifetimes: rustc::middle::resolve_lifetime::ResolveLifetimes,
            [decode] generic_predicates: rustc::ty::GenericPredicates<'tcx>,
        ], $tcx);
    )
}

macro_rules! arena_for_type {
    ([][$ty:ty]) => {
        TypedArena<$ty>
    };
    ([few $(, $attrs:ident)*][$ty:ty]) => {
        PhantomData<$ty>
    };
    ([$ignore:ident $(, $attrs:ident)*]$args:tt) => {
        arena_for_type!([$($attrs),*]$args)
    };
}

macro_rules! declare_arena {
    ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
        #[derive(Default)]
        pub struct Arena<$tcx> {
            dropless: DroplessArena,
            drop: DropArena,
            $($name: arena_for_type!($a[$ty]),)*
        }
    }
}

macro_rules! which_arena_for_type {
    ([][$arena:expr]) => {
        Some($arena)
    };
    ([few$(, $attrs:ident)*][$arena:expr]) => {
        None
    };
    ([$ignore:ident$(, $attrs:ident)*]$args:tt) => {
        which_arena_for_type!([$($attrs),*]$args)
    };
}

macro_rules! impl_arena_allocatable {
    ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
        $(
            impl ArenaAllocatable for $ty {}
            unsafe impl<$tcx> ArenaField<$tcx> for $ty {
                #[inline]
                fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a TypedArena<Self>> {
                    which_arena_for_type!($a[&_arena.$name])
                }
            }
        )*
    }
}

arena_types!(declare_arena, [], 'tcx);

arena_types!(impl_arena_allocatable, [], 'tcx);

pub trait ArenaAllocatable {}

impl<T: Copy> ArenaAllocatable for T {}

pub unsafe trait ArenaField<'tcx>: Sized {
    /// Returns a specific arena to allocate from.
    /// If None is returned, the DropArena will be used.
    fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a TypedArena<Self>>;
}

unsafe impl<'tcx, T> ArenaField<'tcx> for T {
    #[inline]
    default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a TypedArena<Self>> {
        panic!()
    }
}

impl<'tcx> Arena<'tcx> {
    #[inline]
    pub fn alloc<T: ArenaAllocatable>(&self, value: T) -> &mut T {
        if !mem::needs_drop::<T>() {
            return self.dropless.alloc(value);
        }
        match <T as ArenaField<'tcx>>::arena(self) {
            Some(arena) => arena.alloc(value),
            None => unsafe { self.drop.alloc(value) },
        }
    }

    #[inline]
    pub fn alloc_slice<T: Copy>(&self, value: &[T]) -> &mut [T] {
        if value.len() == 0 {
            return &mut []
        }
        self.dropless.alloc_slice(value)
    }

    pub fn alloc_from_iter<
        T: ArenaAllocatable,
        I: IntoIterator<Item = T>
    >(
        &'a self,
        iter: I
    ) -> &'a mut [T] {
        if !mem::needs_drop::<T>() {
            return self.dropless.alloc_from_iter(iter);
        }
        match <T as ArenaField<'tcx>>::arena(self) {
            Some(arena) => arena.alloc_from_iter(iter),
            None => unsafe { self.drop.alloc_from_iter(iter) },
        }
    }
}

/// Calls the destructor for an object when dropped.
struct DropType {
    drop_fn: unsafe fn(*mut u8),
    obj: *mut u8,
}

unsafe fn drop_for_type<T>(to_drop: *mut u8) {
    std::ptr::drop_in_place(to_drop as *mut T)
}

impl Drop for DropType {
    fn drop(&mut self) {
        unsafe {
            (self.drop_fn)(self.obj)
        }
    }
}

/// An arena which can be used to allocate any type.
/// Allocating in this arena is unsafe since the type system
/// doesn't know which types it contains. In order to
/// allocate safely, you must store a PhantomData<T>
/// alongside this arena for each type T you allocate.
#[derive(Default)]
struct DropArena {
    /// A list of destructors to run when the arena drops.
    /// Ordered so `destructors` gets dropped before the arena
    /// since its destructor can reference memory in the arena.
    destructors: RefCell<Vec<DropType>>,
    arena: DroplessArena,
}

impl DropArena {
    #[inline]
    unsafe fn alloc<T>(&self, object: T) -> &mut T {
        let mem = self.arena.alloc_raw(
            mem::size_of::<T>(),
            mem::align_of::<T>()
        ) as *mut _ as *mut T;
        // Write into uninitialized memory.
        ptr::write(mem, object);
        let result = &mut *mem;
        // Record the destructor after doing the allocation as that may panic
        // and would cause `object`'s destuctor to run twice if it was recorded before
        self.destructors.borrow_mut().push(DropType {
            drop_fn: drop_for_type::<T>,
            obj: result as *mut T as *mut u8,
        });
        result
    }

    #[inline]
    unsafe fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
        let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
        if vec.is_empty() {
            return &mut [];
        }
        let len = vec.len();

        let start_ptr = self.arena.alloc_raw(
            len.checked_mul(mem::size_of::<T>()).unwrap(),
            mem::align_of::<T>()
        ) as *mut _ as *mut T;

        let mut destructors = self.destructors.borrow_mut();
        // Reserve space for the destructors so we can't panic while adding them
        destructors.reserve(len);

        // Move the content to the arena by copying it and then forgetting
        // the content of the SmallVec
        vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
        mem::forget(vec.drain());

        // Record the destructors after doing the allocation as that may panic
        // and would cause `object`'s destuctor to run twice if it was recorded before
        for i in 0..len {
            destructors.push(DropType {
                drop_fn: drop_for_type::<T>,
                obj: start_ptr.offset(i as isize) as *mut u8,
            });
        }

        slice::from_raw_parts_mut(start_ptr, len)
    }
}
<commit_msg>Make ArenaField private<commit_after>use arena::{TypedArena, DroplessArena};
use std::mem;
use std::ptr;
use std::slice;
use std::cell::RefCell;
use std::marker::PhantomData;
use smallvec::SmallVec;

/// This declares a list of types which can be allocated by `Arena`.
///
/// The `few` modifier will cause allocation to use the shared arena and recording the destructor.
/// This is faster and more memory efficient if there's only a few allocations of the type.
/// Leaving `few` out will cause the type to get its own dedicated `TypedArena` which is
/// faster and more memory efficient if there is lots of allocations.
///
/// Specifying the `decode` modifier will add decode impls for &T and &[T] where T is the type
/// listed. These impls will appear in the implement_ty_decoder! macro.
#[macro_export]
macro_rules! arena_types {
    ($macro:path, $args:tt, $tcx:lifetime) => (
        $macro!($args, [
            [] vtable_method: Option<(
                rustc::hir::def_id::DefId,
                rustc::ty::subst::SubstsRef<$tcx>
            )>,
            [few, decode] mir_keys: rustc::util::nodemap::DefIdSet,
            [decode] specialization_graph: rustc::traits::specialization_graph::Graph,
            [] region_scope_tree: rustc::middle::region::ScopeTree,
            [] item_local_set: rustc::util::nodemap::ItemLocalSet,
            [decode] mir_const_qualif: rustc_data_structures::bit_set::BitSet<rustc::mir::Local>,
            [] trait_impls_of: rustc::ty::trait_def::TraitImpls,
            [] dropck_outlives:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx,
                        rustc::traits::query::dropck_outlives::DropckOutlivesResult<'tcx>
                    >
                >,
            [] normalize_projection_ty:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx,
                        rustc::traits::query::normalize::NormalizationResult<'tcx>
                    >
                >,
            [] implied_outlives_bounds:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx,
                        Vec<rustc::traits::query::outlives_bounds::OutlivesBound<'tcx>>
                    >
                >,
            [] type_op_subtype:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx, ()>
                >,
            [] type_op_normalize_poly_fn_sig:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::PolyFnSig<'tcx>>
                >,
            [] type_op_normalize_fn_sig:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::FnSig<'tcx>>
                >,
            [] type_op_normalize_predicate:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::Predicate<'tcx>>
                >,
            [] type_op_normalize_ty:
                rustc::infer::canonical::Canonical<'tcx,
                    rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::Ty<'tcx>>
                >,
            [few] crate_inherent_impls: rustc::ty::CrateInherentImpls,
            [decode] borrowck: rustc::middle::borrowck::BorrowCheckResult,
            [few] upstream_monomorphizations:
                rustc::util::nodemap::DefIdMap<
                    rustc_data_structures::fx::FxHashMap<
                        rustc::ty::subst::SubstsRef<'tcx>,
                        rustc::hir::def_id::CrateNum
                    >
                >,
            [few] resolve_lifetimes: rustc::middle::resolve_lifetime::ResolveLifetimes,
            [decode] generic_predicates: rustc::ty::GenericPredicates<'tcx>,
        ], $tcx);
    )
}

macro_rules! arena_for_type {
    ([][$ty:ty]) => {
        TypedArena<$ty>
    };
    ([few $(, $attrs:ident)*][$ty:ty]) => {
        PhantomData<$ty>
    };
    ([$ignore:ident $(, $attrs:ident)*]$args:tt) => {
        arena_for_type!([$($attrs),*]$args)
    };
}

macro_rules! declare_arena {
    ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
        #[derive(Default)]
        pub struct Arena<$tcx> {
            dropless: DroplessArena,
            drop: DropArena,
            $($name: arena_for_type!($a[$ty]),)*
        }
    }
}

macro_rules! which_arena_for_type {
    ([][$arena:expr]) => {
        Some($arena)
    };
    ([few$(, $attrs:ident)*][$arena:expr]) => {
        None
    };
    ([$ignore:ident$(, $attrs:ident)*]$args:tt) => {
        which_arena_for_type!([$($attrs),*]$args)
    };
}

macro_rules! impl_arena_allocatable {
    ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
        $(
            impl ArenaAllocatable for $ty {}
            unsafe impl<$tcx> ArenaField<$tcx> for $ty {
                #[inline]
                fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a TypedArena<Self>> {
                    which_arena_for_type!($a[&_arena.$name])
                }
            }
        )*
    }
}

arena_types!(declare_arena, [], 'tcx);

arena_types!(impl_arena_allocatable, [], 'tcx);

pub trait ArenaAllocatable {}

impl<T: Copy> ArenaAllocatable for T {}

unsafe trait ArenaField<'tcx>: Sized {
    /// Returns a specific arena to allocate from.
    /// If None is returned, the DropArena will be used.
    fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a TypedArena<Self>>;
}

unsafe impl<'tcx, T> ArenaField<'tcx> for T {
    #[inline]
    default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a TypedArena<Self>> {
        panic!()
    }
}

impl<'tcx> Arena<'tcx> {
    #[inline]
    pub fn alloc<T: ArenaAllocatable>(&self, value: T) -> &mut T {
        if !mem::needs_drop::<T>() {
            return self.dropless.alloc(value);
        }
        match <T as ArenaField<'tcx>>::arena(self) {
            Some(arena) => arena.alloc(value),
            None => unsafe { self.drop.alloc(value) },
        }
    }

    #[inline]
    pub fn alloc_slice<T: Copy>(&self, value: &[T]) -> &mut [T] {
        if value.len() == 0 {
            return &mut []
        }
        self.dropless.alloc_slice(value)
    }

    pub fn alloc_from_iter<
        T: ArenaAllocatable,
        I: IntoIterator<Item = T>
    >(
        &'a self,
        iter: I
    ) -> &'a mut [T] {
        if !mem::needs_drop::<T>() {
            return self.dropless.alloc_from_iter(iter);
        }
        match <T as ArenaField<'tcx>>::arena(self) {
            Some(arena) => arena.alloc_from_iter(iter),
            None => unsafe { self.drop.alloc_from_iter(iter) },
        }
    }
}

/// Calls the destructor for an object when dropped.
struct DropType {
    drop_fn: unsafe fn(*mut u8),
    obj: *mut u8,
}

unsafe fn drop_for_type<T>(to_drop: *mut u8) {
    std::ptr::drop_in_place(to_drop as *mut T)
}

impl Drop for DropType {
    fn drop(&mut self) {
        unsafe {
            (self.drop_fn)(self.obj)
        }
    }
}

/// An arena which can be used to allocate any type.
/// Allocating in this arena is unsafe since the type system
/// doesn't know which types it contains. In order to
/// allocate safely, you must store a PhantomData<T>
/// alongside this arena for each type T you allocate.
#[derive(Default)]
struct DropArena {
    /// A list of destructors to run when the arena drops.
    /// Ordered so `destructors` gets dropped before the arena
    /// since its destructor can reference memory in the arena.
    destructors: RefCell<Vec<DropType>>,
    arena: DroplessArena,
}

impl DropArena {
    #[inline]
    unsafe fn alloc<T>(&self, object: T) -> &mut T {
        let mem = self.arena.alloc_raw(
            mem::size_of::<T>(),
            mem::align_of::<T>()
        ) as *mut _ as *mut T;
        // Write into uninitialized memory.
        ptr::write(mem, object);
        let result = &mut *mem;
        // Record the destructor after doing the allocation as that may panic
        // and would cause `object`'s destuctor to run twice if it was recorded before
        self.destructors.borrow_mut().push(DropType {
            drop_fn: drop_for_type::<T>,
            obj: result as *mut T as *mut u8,
        });
        result
    }

    #[inline]
    unsafe fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
        let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
        if vec.is_empty() {
            return &mut [];
        }
        let len = vec.len();

        let start_ptr = self.arena.alloc_raw(
            len.checked_mul(mem::size_of::<T>()).unwrap(),
            mem::align_of::<T>()
        ) as *mut _ as *mut T;

        let mut destructors = self.destructors.borrow_mut();
        // Reserve space for the destructors so we can't panic while adding them
        destructors.reserve(len);

        // Move the content to the arena by copying it and then forgetting
        // the content of the SmallVec
        vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
        mem::forget(vec.drain());

        // Record the destructors after doing the allocation as that may panic
        // and would cause `object`'s destuctor to run twice if it was recorded before
        for i in 0..len {
            destructors.push(DropType {
                drop_fn: drop_for_type::<T>,
                obj: start_ptr.offset(i as isize) as *mut u8,
            });
        }

        slice::from_raw_parts_mut(start_ptr, len)
    }
}
<|endoftext|>


<commit_before>use bson::{Bson, Document};
use mongodb::{Client, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use mongodb::cursor::Cursor;
use mongodb::wire_protocol::flags::OpQueryFlags;

#[test]
fn cursor_features() {
    let client = Client::with_uri("mongodb://localhost:27017").unwrap();
    let db = client.db("test");
    let coll = db.collection("cursor_test");

    coll.drop().ok().expect("Failed to drop database.");

    let docs = (0..10).map(|i| {
        doc! { "foo" => (i as i64) }
    }).collect();

    assert!(coll.insert_many(docs, false, None).is_ok());

    let doc = Document::new();
    let flags = OpQueryFlags::no_flags();

    let result = Cursor::query_with_batch_size(client.clone(), "test.cursor_test".to_owned(),
                                               3, flags,
                                               0, 0, doc, None, false);

    let mut cursor = match result {
        Ok(c) => c,
        Err(s) => panic!("{}", s)
    };

    let batch = cursor.next_batch().ok().expect("Failed to get next batch from cursor.");

    assert_eq!(batch.len(), 3 as usize);

    for i in 0..batch.len() {
        match batch[i].get("foo") {
            Some(&Bson::I64(j)) => assert_eq!(i as i64, j),
            _ => panic!("Wrong value returned from Cursor#next_batch")
        };
    }

    let bson = match cursor.next() {
        Some(Ok(b)) => b,
        Some(Err(_)) => panic!("Received error on 'cursor.next()'"),
        None => panic!("Nothing returned from Cursor#next")
    };

    match bson.get("foo") {
        Some(&Bson::I64(3)) => (),
        _ => panic!("Wrong value returned from Cursor#next")
    };

    assert!(cursor.has_next().ok().expect("Failed to execute 'has_next()'."));
    let vec = cursor.next_n(20).ok().expect("Failed to get next 20 results.");;

    assert_eq!(vec.len(), 6 as usize);
    assert!(!cursor.has_next().ok().expect("Failed to execute 'has_next()'."));

    for i in 0..vec.len() {
        match vec[i].get("foo") {
            Some(&Bson::I64(j)) => assert_eq!(4 + i as i64 , j),
            _ => panic!("Wrong value returned from Cursor#next_batch")
        };
    }
}
<commit_msg>changed test to fit new API<commit_after>use bson::{Bson, Document};
use mongodb::{Client, ThreadedClient};
use mongodb::command_type::CommandType;
use mongodb::db::ThreadedDatabase;
use mongodb::cursor::Cursor;
use mongodb::wire_protocol::flags::OpQueryFlags;

#[test]
fn cursor_features() {
    let client = Client::with_uri("mongodb://localhost:27017").unwrap();
    let db = client.db("test");
    let coll = db.collection("cursor_test");

    coll.drop().ok().expect("Failed to drop database.");

    let docs = (0..10).map(|i| {
        doc! { "foo" => (i as i64) }
    }).collect();

    assert!(coll.insert_many(docs, false, None).is_ok());

    let doc = Document::new();
    let flags = OpQueryFlags::no_flags();

    let result = Cursor::query_with_batch_size(client.clone(), "test.cursor_test".to_owned(),
                                               3, flags, 0, 0, doc, None, CommandType::Find,
                                               false);

    let mut cursor = match result {
        Ok(c) => c,
        Err(s) => panic!("{}", s)
    };

    let batch = cursor.next_batch().ok().expect("Failed to get next batch from cursor.");

    assert_eq!(batch.len(), 3 as usize);

    for i in 0..batch.len() {
        match batch[i].get("foo") {
            Some(&Bson::I64(j)) => assert_eq!(i as i64, j),
            _ => panic!("Wrong value returned from Cursor#next_batch")
        };
    }

    let bson = match cursor.next() {
        Some(Ok(b)) => b,
        Some(Err(_)) => panic!("Received error on 'cursor.next()'"),
        None => panic!("Nothing returned from Cursor#next")
    };

    match bson.get("foo") {
        Some(&Bson::I64(3)) => (),
        _ => panic!("Wrong value returned from Cursor#next")
    };

    assert!(cursor.has_next().ok().expect("Failed to execute 'has_next()'."));
    let vec = cursor.next_n(20).ok().expect("Failed to get next 20 results.");;

    assert_eq!(vec.len(), 6 as usize);
    assert!(!cursor.has_next().ok().expect("Failed to execute 'has_next()'."));

    for i in 0..vec.len() {
        match vec[i].get("foo") {
            Some(&Bson::I64(j)) => assert_eq!(4 + i as i64 , j),
            _ => panic!("Wrong value returned from Cursor#next_batch")
        };
    }
}
<|endoftext|>


<commit_before>#![feature(asm)]
#![feature(no_std)]
#![feature(const_fn)]
#![feature(core_str_ext)]
#![no_std]

mod intrinsics;
mod hypercall;

pub mod defs;

pub mod memory;
pub mod event;
pub mod sched;

pub mod console;

pub mod arch;

extern "C" {
    // This symbol must be present in code using libxen
    pub static mut shared_info: self::defs::SharedInfo;
}

pub fn enable_upcalls() -> u8 {
    unsafe {
        let ret = shared_info.vcpu_info[0].evtchn_upcall_mask;

        self::intrinsics::wmb();
        shared_info.vcpu_info[0].evtchn_upcall_mask = 0;
        self::intrinsics::wmb();

        ret
    }
}

pub fn disable_upcalls() -> u8 {
    unsafe {
        let ret = shared_info.vcpu_info[0].evtchn_upcall_mask;

        shared_info.vcpu_info[0].evtchn_upcall_mask = 1;
        self::intrinsics::wmb();

        ret
    }
}
<commit_msg>libxen: Add set_upcalls_state<commit_after>#![feature(asm)]
#![feature(no_std)]
#![feature(const_fn)]
#![feature(core_str_ext)]
#![no_std]

mod intrinsics;
mod hypercall;

pub mod defs;

pub mod memory;
pub mod event;
pub mod sched;

pub mod console;

pub mod arch;

extern "C" {
    // This symbol must be present in code using libxen
    pub static mut shared_info: self::defs::SharedInfo;
}

pub fn enable_upcalls() -> u8 {
    unsafe {
        let ret = shared_info.vcpu_info[0].evtchn_upcall_mask;

        self::intrinsics::wmb();
        shared_info.vcpu_info[0].evtchn_upcall_mask = 0;
        self::intrinsics::wmb();

        ret
    }
}

pub fn disable_upcalls() -> u8 {
    unsafe {
        let ret = shared_info.vcpu_info[0].evtchn_upcall_mask;

        shared_info.vcpu_info[0].evtchn_upcall_mask = 1;
        self::intrinsics::wmb();

        ret
    }
}

pub fn set_upcalls_state(state: u8) {
    unsafe {
        self::intrinsics::wmb();
        shared_info.vcpu_info[0].evtchn_upcall_mask = state;
        self::intrinsics::wmb();
    }
}
<|endoftext|>


<commit_before>use num::Num;
use num::Zero;
use num::One;

/// Vector whose dimension is known at runtime
///
/// Assumes the `Vector` is represented as a
/// tuple of numbers representing its projection
/// along orthogonal base vectors
pub trait Vector: Clone {
    /// Underlying scalar type of `Vector` type
    type Scalar: Num + Zero + One + Copy;
    /// Maximum allowed index for `at` and `mut_at`
    fn dimension(&self) -> usize;
    /// Length of projection along `i`-th base
    fn at(&self, i: usize) -> Self::Scalar;
    /// Mutable access to length of projection along `i`-th base
    fn mut_at<'a>(&'a mut self, i: usize) -> &'a mut Self::Scalar;
    /// Scalar product
    ///
    /// Default implementation using `at` and `dimension` is provided
    fn dot(&self, other: &Self) -> Self::Scalar {
        let mut result = Self::Scalar::zero();
        for i in 0..self.dimension() {
            result = result + self.at(i) * other.at(i)
        }
        result
    }
}

impl Vector for f64 {
    type Scalar = f64;

    fn dimension(&self) -> usize {
        1
    }

    fn at(&self, _: usize) -> f64 {
        *self
    }

    fn mut_at(&mut self, _: usize) -> &mut f64 {
        self
    }

    fn dot(&self, other: &f64) -> f64 {
        self * other
    }
}

impl Vector for [f64; 2] {
    type Scalar = f64;

    fn dimension(&self) -> usize {
        2
    }

    fn at(&self, index: usize) -> f64 {
        self[index]
    }

    fn mut_at(&mut self, index: usize) -> &mut f64 {
        &mut self[index]
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn dot() {

        use linear_algebra::Vector;

        let a = [1.0, 2.0];
        let b = [3.0, 4.0];

        assert_eq!(11.0, a.dot(&b))
    }
}
<commit_msg>removed explicit lifetime<commit_after>use num::Num;
use num::Zero;
use num::One;

/// Vector whose dimension is known at runtime
///
/// Assumes the `Vector` is represented as a
/// tuple of numbers representing its projection
/// along orthogonal base vectors
pub trait Vector: Clone {
    /// Underlying scalar type of `Vector` type
    type Scalar: Num + Zero + One + Copy;
    /// Maximum allowed index for `at` and `mut_at`
    fn dimension(&self) -> usize;
    /// Length of projection along `i`-th base
    fn at(&self, i: usize) -> Self::Scalar;
    /// Mutable access to length of projection along `i`-th base
    fn mut_at(& mut self, i: usize) -> & mut Self::Scalar;
    /// Scalar product
    ///
    /// Default implementation using `at` and `dimension` is provided
    fn dot(&self, other: &Self) -> Self::Scalar {
        let mut result = Self::Scalar::zero();
        for i in 0..self.dimension() {
            result = result + self.at(i) * other.at(i)
        }
        result
    }
}

impl Vector for f64 {
    type Scalar = f64;

    fn dimension(&self) -> usize {
        1
    }

    fn at(&self, _: usize) -> f64 {
        *self
    }

    fn mut_at(&mut self, _: usize) -> &mut f64 {
        self
    }

    fn dot(&self, other: &f64) -> f64 {
        self * other
    }
}

impl Vector for [f64; 2] {
    type Scalar = f64;

    fn dimension(&self) -> usize {
        2
    }

    fn at(&self, index: usize) -> f64 {
        self[index]
    }

    fn mut_at(&mut self, index: usize) -> &mut f64 {
        &mut self[index]
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn dot() {

        use linear_algebra::Vector;

        let a = [1.0, 2.0];
        let b = [3.0, 4.0];

        assert_eq!(11.0, a.dot(&b))
    }
}
<|endoftext|>


<commit_before>use alloc::boxed;
use alloc::boxed::Box;

use core::option::Option::{self, Some, None};

use super::concurrency::Atomic32;
use super::data_structures::Queue;

mod init;
mod current;
mod ready_queue;

// constants
const STACK_SIZE: usize = 2048;

// next pid
static NEXT_ID: Atomic32 = Atomic32 {i: 0};

// Process state
enum State {
    INIT,
    READY,
    RUNNING,
    BLOCKED,
    TERMINATED,
}

// A wrapper around stack pointers for use in initializing the stack
#[derive(Copy,Clone)]
struct StackPtr {
    ptr: *mut usize,
}

impl StackPtr {
    fn get_stack() -> StackPtr {
        // TODO: fudge
        // Allocate a stack
        let stack = Box::new([0; STACK_SIZE]);

        // set the pointer
        StackPtr {ptr: unsafe {boxed::into_raw(stack) as *mut usize} }
    }

    fn smash(&self) {
        // Get entry point of process
        let entry = start_proc as usize;

        // Smash the stack
        unsafe {
            for idx in (STACK_SIZE - 6)..STACK_SIZE {
                *self.ptr.offset(idx as isize) = 0;
            }
            *self.ptr.offset(-2) = entry;
        }
    }

    fn get_kesp(&self) -> StackPtr {
        // Create a new struct that contains the starting
        // kesp value for this stack
        StackPtr {ptr : (self.ptr as usize - 6) as *mut usize}
    }
}

// Process struct
pub struct Process {
    name: &'static str,
    pid: usize,
    run: fn(&Process) -> usize,
    state: State,
    stack: StackPtr,
    kesp: StackPtr,
}

impl Process {
    pub fn new(name: &'static str, run: fn(&Process) -> usize) -> Process {
        let stack = StackPtr::get_stack();
        stack.smash();

        Process {
            name: name,
            pid: NEXT_ID.get_then_add(),
            run: run,
            state: State::INIT,
            stack: stack,
            kesp: stack.get_kesp(),
        }
    }

    pub fn dispatch(prev: Option<Box<Process>>) {
        //TODO
    }
}

pub fn init() {

    // Create the init process
    let mut init = Box::new(Process::new("init", self::init::run));

    // Create the ready q
    ready_queue::init();

    // Add the init process to the ready q
    ready_queue::make_ready(init);

}

// The entry point of all processes
fn start_proc() {
    // get current process
    let c_op = current::current();
    match c_op {
        Some(c_box) => {
            ((*c_box).run)(&*c_box);
        }
        None => {
            panic!("Start proc without current process");
        }
    }
}

pub fn proc_yield(q: Option<Box<Queue<Box<Process>>>>) {

}
<commit_msg>Attempting proc_yield<commit_after>use alloc::boxed;
use alloc::boxed::Box;

use core::option::Option::{self, Some, None};

use super::concurrency::Atomic32;
use super::data_structures::Queue;

mod init;
mod current;
mod ready_queue;

// constants
const STACK_SIZE: usize = 2048;

// next pid
static NEXT_ID: Atomic32 = Atomic32 {i: 0};

// Process state
enum State {
    INIT,
    READY,
    RUNNING,
    BLOCKED,
    TERMINATED,
}

// A wrapper around stack pointers for use in initializing the stack
#[derive(Copy,Clone)]
struct StackPtr {
    ptr: *mut usize,
}

impl StackPtr {
    fn get_stack() -> StackPtr {
        // TODO: fudge
        // Allocate a stack
        let stack = Box::new([0; STACK_SIZE]);

        // set the pointer
        StackPtr {ptr: unsafe {boxed::into_raw(stack) as *mut usize} }
    }

    fn smash(&self) {
        // Get entry point of process
        let entry = start_proc as usize;

        // Smash the stack
        unsafe {
            for idx in (STACK_SIZE - 6)..STACK_SIZE {
                *self.ptr.offset(idx as isize) = 0;
            }
            *self.ptr.offset(-2) = entry;
        }
    }

    fn get_kesp(&self) -> StackPtr {
        // Create a new struct that contains the starting
        // kesp value for this stack
        StackPtr {ptr : (self.ptr as usize - 6) as *mut usize}
    }
}

// Process struct
pub struct Process {
    name: &'static str,
    pid: usize,
    run: fn(&Process) -> usize,
    state: State,
    stack: StackPtr,
    kesp: StackPtr,
}

impl Process {
    pub fn new(name: &'static str, run: fn(&Process) -> usize) -> Process {
        let stack = StackPtr::get_stack();
        stack.smash();

        Process {
            name: name,
            pid: NEXT_ID.get_then_add(),
            run: run,
            state: State::INIT,
            stack: stack,
            kesp: stack.get_kesp(),
        }
    }

    pub fn dispatch(&mut self, prev: Option<Box<Process>>) {
        //TODO
    }
}

pub fn init() {

    // Create the init process
    let mut init = Box::new(Process::new("init", self::init::run));

    // Create the ready q
    ready_queue::init();

    // Add the init process to the ready q
    ready_queue::make_ready(init);

}

// The entry point of all processes
#[allow(private_no_mangle_fns)]
#[no_mangle]
fn start_proc() {
    // get current process
    match current::current() {
        Some(c_box) => { ((*c_box).run)(&*c_box); }
        None => { panic!("No current process to start"); }
    }
}

// Yield to the next process waiting
//
// The current process yields onto the q
// If q is null, yield to ready q
// If current proc is null, then it is not added to the q
// The process state is set accordingly
//
// The next process from the ready q is dispatched
// If the q is empty, then the current process continues running
pub fn proc_yield(q: Option<Box<Queue<Box<Process>>>>) {

    // TODO: lock here

    let me = current::current();
    match me {
        Some(me_ptr) => {
            match q {
                Some(q_ptr) => {
                    /* a queue is specified, I'm blocking on that queue */
                    //if (me_ptr->iDepth != 0) {
                    //    Debug::printf("process %s#%d %X ", me_ptr->name, me_ptr->id, me_ptr);
                    //    Debug::panic("blocking while iDepth = %d",me_ptr->iDepth);
                    //}
                    (*me_ptr).state = State::BLOCKED;
                    (*q_ptr).push(*me_ptr);

                    // Debug::printf("blocking process %s#%d %X\n", me->name, me->id, me);
                }
                None => {
                    /* no queue is specified, put me on the ready queue */
                    ready_queue::make_ready(*me_ptr);
                }
            }
        }
        _ => {}
    }

    let next: Box<Process>;
    let rq = ready_queue::ready_q();

    if ((*rq).is_empty()) {
        panic!("Nothing to do!");
        //if (!idleProcess) {
        //    idleProcess = new IdleProcess();
        //    idleProcess->start();
        //}
        //next = idleProcess;
    } else {
        match rq.pop() {
            Some(n) => { next = n; }
            None    => { panic!("ready q is pseudo-empty"); }
        }
    }

    (*next).dispatch(me);

    //TODO: unlock here
}
<|endoftext|>


<commit_before>#[derive(Clone, Debug)]
pub struct URIBase {
    base_uri: String,
    port: u16,
}

impl Default for URIBase {
    fn default() -> URIBase {
        URIBase {
            base_uri: "localhost".to_string(),
            port: 10041,
        }
    }
}

impl URIBase {
    ///
    /// Create URIBase struct.
    ///
    /// Default values are:
    ///
    ///   base_uri: "localhost"
    ///
    ///   port: 10041
    ///
    pub fn new() -> URIBase {
        let default: URIBase = Default::default();
        default
    }

    /// Set base to replace default value with specified value.
    pub fn base_uri(mut self, base_uri: String) -> URIBase {
        self.base_uri = base_uri;
        self
    }

    /// Set port number to replace default value with specified value.
    pub fn port(mut self, port: u16) -> URIBase {
        self.port = port;
        self
    }

    /// Build and get base uri.
    pub fn build(self) -> String {
        format!("http://{}:{}", self.base_uri, self.port)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn construct_uri_default() {
        let uri_base = URIBase::new().build();
        assert_eq!("http://localhost:10041", uri_base)
    }

    #[test]
    fn buikld_only_uri_base() {
        let uri_base = URIBase::new()
                           .base_uri("127.0.0.1".to_string())
                           .build();
        assert_eq!("http://127.0.0.1:10041", uri_base);
    }

    #[test]
    fn build_only_port() {
        let uri_base = URIBase::new().port(10042).build();
        assert_eq!("http://localhost:10042", uri_base);
    }

    #[test]
    fn uri_with_builder() {
        let uri_base = URIBase::new()
                           .base_uri("127.0.1.1".to_string())
                           .port(10043)
                           .build();
        assert_eq!("http://127.0.1.1:10043", uri_base)
    }

}
<commit_msg>Fix a typo<commit_after>#[derive(Clone, Debug)]
pub struct URIBase {
    base_uri: String,
    port: u16,
}

impl Default for URIBase {
    fn default() -> URIBase {
        URIBase {
            base_uri: "localhost".to_string(),
            port: 10041,
        }
    }
}

impl URIBase {
    ///
    /// Create URIBase struct.
    ///
    /// Default values are:
    ///
    ///   base_uri: "localhost"
    ///
    ///   port: 10041
    ///
    pub fn new() -> URIBase {
        let default: URIBase = Default::default();
        default
    }

    /// Set base to replace default value with specified value.
    pub fn base_uri(mut self, base_uri: String) -> URIBase {
        self.base_uri = base_uri;
        self
    }

    /// Set port number to replace default value with specified value.
    pub fn port(mut self, port: u16) -> URIBase {
        self.port = port;
        self
    }

    /// Build and get base uri.
    pub fn build(self) -> String {
        format!("http://{}:{}", self.base_uri, self.port)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn construct_uri_default() {
        let uri_base = URIBase::new().build();
        assert_eq!("http://localhost:10041", uri_base)
    }

    #[test]
    fn build_only_uri_base() {
        let uri_base = URIBase::new()
                           .base_uri("127.0.0.1".to_string())
                           .build();
        assert_eq!("http://127.0.0.1:10041", uri_base);
    }

    #[test]
    fn build_only_port() {
        let uri_base = URIBase::new().port(10042).build();
        assert_eq!("http://localhost:10042", uri_base);
    }

    #[test]
    fn uri_with_builder() {
        let uri_base = URIBase::new()
                           .base_uri("127.0.1.1".to_string())
                           .port(10043)
                           .build();
        assert_eq!("http://127.0.1.1:10043", uri_base)
    }

}
<|endoftext|>


<commit_before>/*! Example IRC bot

    This sample bot uses the library to connect to Freenode, under the nickname "rustirclib###"
    (where ### is a random number). It then joins the channel ##rustirclib, says hello, and prints
    to standard output any messages sent to the channel.

    Any incoming message of the form "rustirclib###: some message" will elicit a generic response.

    Any incoming message of the form "!rustirclib### quit" will cause the bot to shut down.
 */

#[crate_id = "github.com/kballard/rust-irclib#ircbot:0.1"];
#[crate_type = "bin"];

extern mod irc;

use irc::conn::{Conn, Line, Event, IRCCmd, IRCCode, IRCAction};

use std::{rand, str};
use std::rand::Rng;

fn main() {
    let mut opts = irc::conn::Options::new("chat.freenode.net", irc::conn::DefaultPort);

    let nick = format!("rustirclib{}", rand::task_rng().gen_range(100u, 1000u));
    opts.nick = nick.as_slice();
    match irc::conn::connect(opts, handler) {
        Ok(()) => println!("Exiting..."),
        Err(err) => println!("Connection error: {}", err)
    }
}

fn handler(conn: &mut Conn, event: Event) {
    match event {
        irc::conn::Connected => println!("Connected"),
        irc::conn::Disconnected => println!("Disconnected"),
        irc::conn::LineReceived(line) => {
            match line {
                Line{command: IRCCode(1), ..} => {
                    println!("Logged in");
                    // we've logged in
                    conn.join(bytes!("##rustirclib"), [])
                }
                Line{command: IRCCmd(~"JOIN"), args, prefix: Some(prefix) } => {
                    if prefix.nick() != conn.me().nick() {
                        return;
                    }
                    if args.is_empty() {
                        let line = Line{command: IRCCmd(~"JOIN"), args: args, prefix: Some(prefix)};
                        println!("ERROR: Invalid JOIN message received: {}", line_desc(&line));
                        return;
                    }
                    let chan = args[0];
                    conn.privmsg(chan, bytes!("Hello"));
                    let chan = str::from_utf8(chan).unwrap_or("(invalid utf8)");
                    println!("JOINED: {}", chan);
                }
                Line{command: IRCCmd(cmd@~"PRIVMSG"), args, prefix } |
                Line{command: IRCCmd(cmd@~"NOTICE"), args, prefix } => {
                    let (src, dst, msg) = match (args, prefix.is_some()) {
                        ([dst, msg], true) => {
                            (prefix.as_ref().unwrap().nick(), dst, msg)
                        }
                        (args, _) => {
                            print!("ERROR: Unexpected {} line: ", cmd);
                            let line = Line{command: IRCCmd(cmd), args: args, prefix: prefix};
                            println!("{}", line_desc(&line));
                            return;
                        }
                    };
                    let dsts = str::from_utf8(dst).unwrap_or("(invalid utf8)");
                    let srcs = str::from_utf8(src).unwrap_or("(invalid utf8)");
                    let msgs = str::from_utf8(msg).unwrap_or("(invalid utf8)");
                    println!("<-- {}({}) {}: {}", cmd, dsts, srcs, msgs);
                    handle_privmsg(conn, msg, src, dst)
                }
                Line{command: IRCAction(dst), args, prefix } => {
                    let (src, msg) = match (args, prefix.is_some()) {
                        ([msg], true) => {
                            (prefix.as_ref().unwrap().nick(), msg)
                        }
                        (args, _) => {
                            let line = Line{command: IRCAction(dst), args: args, prefix: prefix};
                            println!("ERROR: Unexpected ACTION line: {}", line_desc(&line));
                            return;
                        }
                    };
                    let dst = str::from_utf8(dst).unwrap_or("(invalid utf8)");
                    let src = str::from_utf8(src).unwrap_or("(invalid utf8)");
                    let msg = str::from_utf8(msg).unwrap_or("(invalid utf8)");
                    println!("<-- PRIVMSG({}) {} {}", dst, src, msg);
                }
                _ => ()
            }
        }
    }
}

fn handle_privmsg(conn: &mut Conn, msg: &[u8], src: &[u8], dst: &[u8]) {
    enum MsgType<'a> {
        DirectedMessage,
        CommandMessage(&'a [u8]),
        NormalMessage
    }
    let msgtype = {
        let nick = conn.me().nick();
        if msg.starts_with(nick) && msg.slice_from(nick.len()).starts_with(bytes!(": ")) &&
        msg.len() > nick.len() + 2 {
            DirectedMessage
        } else if msg.starts_with(bytes!("!")) && msg.slice_from(1).starts_with(nick) &&
                msg.slice_from(nick.len()+1).starts_with(bytes!(" ")) {
            let args = msg.slice_from(conn.me().nick().len()+2);
            let mut argit = args.split(|&b| b == ' ' as u8).skip_while(|v| v.is_empty());
            match argit.next() {
                Some(arg) => CommandMessage(arg),
                None => CommandMessage(bytes!(""))
            }
        } else {
            NormalMessage
        }
    };
    match msgtype {
        DirectedMessage => {
            let reply = if dst == conn.me().nick() { src } else { dst };
            let msg = src + bytes!(": Hello");
            conn.privmsg(reply, msg);
            let src = str::from_utf8(conn.me().nick()).unwrap_or("(invalid utf8)");
            let reply = str::from_utf8(reply).unwrap_or("(invalid utf8)");
            let msg = str::from_utf8(msg).unwrap_or("(invalid utf8)");
            println!("--> PRIVMSG({}) {}: {}", reply, src, msg);
        }
        CommandMessage(cmd) if cmd == bytes!("quit") => {
            println!("Quitting...");
            conn.quit([]);
        }
        _ => ()
    }
}

fn line_desc(line: &Line) -> ~str {
    let raw = line.to_raw();
    let raws = str::from_utf8(raw);
    raws.map(|s| s.to_owned()).unwrap_or_else(|| format!("{:?}", raw))
}
<commit_msg>s/extern mod/extern crate/<commit_after>/*! Example IRC bot

    This sample bot uses the library to connect to Freenode, under the nickname "rustirclib###"
    (where ### is a random number). It then joins the channel ##rustirclib, says hello, and prints
    to standard output any messages sent to the channel.

    Any incoming message of the form "rustirclib###: some message" will elicit a generic response.

    Any incoming message of the form "!rustirclib### quit" will cause the bot to shut down.
 */

#[crate_id = "github.com/kballard/rust-irclib#ircbot:0.1"];
#[crate_type = "bin"];

extern crate irc;

use irc::conn::{Conn, Line, Event, IRCCmd, IRCCode, IRCAction};

use std::{rand, str};
use std::rand::Rng;

fn main() {
    let mut opts = irc::conn::Options::new("chat.freenode.net", irc::conn::DefaultPort);

    let nick = format!("rustirclib{}", rand::task_rng().gen_range(100u, 1000u));
    opts.nick = nick.as_slice();
    match irc::conn::connect(opts, handler) {
        Ok(()) => println!("Exiting..."),
        Err(err) => println!("Connection error: {}", err)
    }
}

fn handler(conn: &mut Conn, event: Event) {
    match event {
        irc::conn::Connected => println!("Connected"),
        irc::conn::Disconnected => println!("Disconnected"),
        irc::conn::LineReceived(line) => {
            match line {
                Line{command: IRCCode(1), ..} => {
                    println!("Logged in");
                    // we've logged in
                    conn.join(bytes!("##rustirclib"), [])
                }
                Line{command: IRCCmd(~"JOIN"), args, prefix: Some(prefix) } => {
                    if prefix.nick() != conn.me().nick() {
                        return;
                    }
                    if args.is_empty() {
                        let line = Line{command: IRCCmd(~"JOIN"), args: args, prefix: Some(prefix)};
                        println!("ERROR: Invalid JOIN message received: {}", line_desc(&line));
                        return;
                    }
                    let chan = args[0];
                    conn.privmsg(chan, bytes!("Hello"));
                    let chan = str::from_utf8(chan).unwrap_or("(invalid utf8)");
                    println!("JOINED: {}", chan);
                }
                Line{command: IRCCmd(cmd@~"PRIVMSG"), args, prefix } |
                Line{command: IRCCmd(cmd@~"NOTICE"), args, prefix } => {
                    let (src, dst, msg) = match (args, prefix.is_some()) {
                        ([dst, msg], true) => {
                            (prefix.as_ref().unwrap().nick(), dst, msg)
                        }
                        (args, _) => {
                            print!("ERROR: Unexpected {} line: ", cmd);
                            let line = Line{command: IRCCmd(cmd), args: args, prefix: prefix};
                            println!("{}", line_desc(&line));
                            return;
                        }
                    };
                    let dsts = str::from_utf8(dst).unwrap_or("(invalid utf8)");
                    let srcs = str::from_utf8(src).unwrap_or("(invalid utf8)");
                    let msgs = str::from_utf8(msg).unwrap_or("(invalid utf8)");
                    println!("<-- {}({}) {}: {}", cmd, dsts, srcs, msgs);
                    handle_privmsg(conn, msg, src, dst)
                }
                Line{command: IRCAction(dst), args, prefix } => {
                    let (src, msg) = match (args, prefix.is_some()) {
                        ([msg], true) => {
                            (prefix.as_ref().unwrap().nick(), msg)
                        }
                        (args, _) => {
                            let line = Line{command: IRCAction(dst), args: args, prefix: prefix};
                            println!("ERROR: Unexpected ACTION line: {}", line_desc(&line));
                            return;
                        }
                    };
                    let dst = str::from_utf8(dst).unwrap_or("(invalid utf8)");
                    let src = str::from_utf8(src).unwrap_or("(invalid utf8)");
                    let msg = str::from_utf8(msg).unwrap_or("(invalid utf8)");
                    println!("<-- PRIVMSG({}) {} {}", dst, src, msg);
                }
                _ => ()
            }
        }
    }
}

fn handle_privmsg(conn: &mut Conn, msg: &[u8], src: &[u8], dst: &[u8]) {
    enum MsgType<'a> {
        DirectedMessage,
        CommandMessage(&'a [u8]),
        NormalMessage
    }
    let msgtype = {
        let nick = conn.me().nick();
        if msg.starts_with(nick) && msg.slice_from(nick.len()).starts_with(bytes!(": ")) &&
        msg.len() > nick.len() + 2 {
            DirectedMessage
        } else if msg.starts_with(bytes!("!")) && msg.slice_from(1).starts_with(nick) &&
                msg.slice_from(nick.len()+1).starts_with(bytes!(" ")) {
            let args = msg.slice_from(conn.me().nick().len()+2);
            let mut argit = args.split(|&b| b == ' ' as u8).skip_while(|v| v.is_empty());
            match argit.next() {
                Some(arg) => CommandMessage(arg),
                None => CommandMessage(bytes!(""))
            }
        } else {
            NormalMessage
        }
    };
    match msgtype {
        DirectedMessage => {
            let reply = if dst == conn.me().nick() { src } else { dst };
            let msg = src + bytes!(": Hello");
            conn.privmsg(reply, msg);
            let src = str::from_utf8(conn.me().nick()).unwrap_or("(invalid utf8)");
            let reply = str::from_utf8(reply).unwrap_or("(invalid utf8)");
            let msg = str::from_utf8(msg).unwrap_or("(invalid utf8)");
            println!("--> PRIVMSG({}) {}: {}", reply, src, msg);
        }
        CommandMessage(cmd) if cmd == bytes!("quit") => {
            println!("Quitting...");
            conn.quit([]);
        }
        _ => ()
    }
}

fn line_desc(line: &Line) -> ~str {
    let raw = line.to_raw();
    let raws = str::from_utf8(raw);
    raws.map(|s| s.to_owned()).unwrap_or_else(|| format!("{:?}", raw))
}
<|endoftext|>


<commit_before>use state::{Selectable, Editable, Named};
use std::cmp;
use std::io::{stdout, Stdout, Write, Result};
use std::iter;
use termion::terminal_size;
use termion::input::MouseTerminal;
use termion::raw::{IntoRawMode, RawTerminal};
use termion::{clear, style, cursor, color};

pub struct View {
    stdout: MouseTerminal<RawTerminal<Stdout>>,
    message: Option<String>,
    is_prompt: bool,
    line_offset: u16,
}

const TAB_LENGTH: usize = 4;

impl View {
    pub fn new() -> Result<View> {
        let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap());
        try!(write!(stdout, "{}{}", clear::All, cursor::Show));
        Ok(View {
            stdout: stdout,
            message: None,
            is_prompt: false,
            line_offset: 0,
        })
    }

    pub fn message(&mut self, message: &str) {
        self.is_prompt = false;
        self.message = Some(String::from(message));
    }

    pub fn prompt(&mut self, prompt: &str, message: &str) {
        self.is_prompt = true;
        let msg = String::from(prompt) + message;
        self.message = Some(msg);
    }

    pub fn quiet(&mut self) {
        self.is_prompt = false;
        self.message = None;
    }

    pub fn center_view(&mut self, line: usize) {
        self.line_offset = match line.checked_sub(self.lines_height() as usize / 2) {
            None => 0,
            Some(val) => val as u16,
        }
    }

    pub fn adjust_view(&mut self, line: usize) {
        let line = line as u16;
        if line < self.line_offset {
            self.line_offset = line;
        } else if line + 1 >= self.line_offset + self.lines_height() {
            self.line_offset = 1 + line - self.lines_height();
        }
    }

    pub fn scroll_view<T: Editable>(&mut self, offset: isize, content: &T) {
        self.line_offset =
            cmp::min(cmp::max((self.line_offset as isize) + offset, 0),
                     (content.line_count() as isize) - 1) as u16;

    }

    pub fn render<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Named + Selectable
    {
        try!(write!(self.stdout, "{}", clear::All));
        try!(self.paint_lines(content));
        try!(self.paint_status(content));
        try!(self.paint_message());
        try!(self.paint_cursor(content));
        try!(self.stdout.flush());
        Ok(())
    }

    pub fn translate_coordinates<T>(&self, content: &T, x: u16, y: u16) -> (usize, usize)
        where T: Editable
    {
        let line = y as isize + self.line_offset as isize - 1;
        let col = cmp::max(0,
                           x as isize - self.line_number_width(content.line_count()) as isize - 2);
        (line as usize, col as usize)
    }

    fn paint_message(&mut self) -> Result<()> {
        if let Some(ref message) = self.message {
            let y = self.lines_height() + 1;
            try!(write!(self.stdout, "{}{}", cursor::Goto(1, 1 + y as u16), message));
            try!(self.stdout.flush());
        }
        Ok(())
    }

    fn paint_cursor<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Selectable
    {
        if (content.line() as u16) < self.line_offset ||
           content.line() as u16 >= self.line_offset + self.lines_height() ||
           content.sel().is_some() {
            try!(write!(self.stdout, "{}", cursor::Hide));
            return Ok(());
        }

        // in the case of a prompt, the cursor should be drawn in the message line
        let (x, y) = if self.is_prompt {
            (self.message.clone().unwrap().len() as u16, self.lines_height() + 1)
        } else {
            let (a, b) = self.cursor_pos(content);
            (a as u16, b as u16)
        };
        try!(write!(self.stdout,
                    "{}{}",
                    cursor::Show,
                    cursor::Goto(1 + x, 1 + y)));
        Ok(())
    }

    fn paint_status<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Named
    {
        let line = content.line();
        let column = content.col();
        let line_count = content.line_count();
        let advance = ((line + 1) as f64 / line_count as f64 * 100.0).floor();

        let (screen_width, _) = terminal_size().unwrap();
        let empty_line = (0..screen_width).map(|_| ' ').collect::<String>();
        let y = self.lines_height() as u16;

        try!(write!(self.stdout,
                    "{}{}{}{}{}{}",
                    color::Fg(color::White),
                    style::Invert,
                    cursor::Goto(1, 1 + y),
                    empty_line,
                    cursor::Goto(1, 1 + y),
                    content.name()));

        let position_info = format!("{}% {}/{}: {}", advance, line + 1, line_count, column);
        let x = screen_width - position_info.len() as u16;
        try!(write!(self.stdout,
                    "{}{}{}",
                    cursor::Goto(1 + x, 1 + y),
                    position_info,
                    style::Reset));
        Ok(())
    }

    fn paint_lines<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Selectable
    {
        let line_offset = self.line_offset;
        let line_height = self.lines_height();
        let line_count = content.line_count();

        let window_it = content.iter()
                .take(content.len() - 1) // the last endline should be invisible to the user
                .scan(('\n', 0, 1), |state, k| {
                    {
                        let (ref mut c, ref mut chars, ref mut lines) = *state;
                        if *c == '\n' {
                            *lines += 1;
                        }
                        *chars += 1;
                        *c = k;
                    }
                    Some(*state)
                })
                .skip_while(|&(_, _, lines)| lines <= 1 + line_offset)
                .take_while(|&(_, _, lines)| lines <= 1 + line_offset + line_height);

        {
            let line_start = self.line_number_width(line_count) as u16 + 1;
            try!(write!(self.stdout,
                        "{}{}{}{}{}",
                        color::Fg(color::White),
                        cursor::Goto(1, 1),
                        line_offset + 1,
                        style::Reset,
                        cursor::Goto(1 + line_start, 1)));
        }
        let mut y = 1;
        let mut line_len = 0;
        for (c, chars, lines) in window_it {
            if c == '\n' {
                if line_len == 0 && content.in_sel(chars) {
                    try!(write!(self.stdout, "{} {}", style::Invert, style::Reset));
                }
                line_len = 0;
                let line_start = self.line_number_width(line_count) as u16 + 1;
                try!(write!(self.stdout,
                            "{}{}{}{}{}",
                            color::Fg(color::White),
                            cursor::Goto(1, 1 + y),
                            lines,
                            style::Reset,
                            cursor::Goto(1 + line_start, 1 + y)));
                y += 1;
            } else {
                if content.in_sel(chars) {
                    try!(write!(self.stdout, "{}", style::Invert));
                }
                if c == '\t' {
                    // FIXME: we should probably use gotos instead of relying on character length
                    try!(write!(self.stdout,
                                "{}",
                                iter::repeat(" ").take(TAB_LENGTH).collect::<String>()));
                } else {
                    try!(write!(self.stdout, "{}", c));
                }
                try!(write!(self.stdout, "{}", style::Reset));
                line_len += 1;
            }
        }
        Ok(())
    }

    fn cursor_pos<T: Editable>(&self, content: &T) -> (usize, usize) {
        // TODO: column offsetting for long lines
        let line = content.line();
        let first_line = self.line_offset;
        let y = line - first_line as usize;
        // we can't trust the actual column because tabs have variable length
        let column = content.visual_col(TAB_LENGTH);
        ((self.line_number_width(content.line_count()) as usize + 1 + column), y)
    }

    fn line_number_width(&self, line_count: usize) -> u16 {
        let max_in_window = self.line_offset + self.lines_height() + 2;
        let max = cmp::min(max_in_window, line_count as u16);
        max.to_string().len() as u16
    }

    fn status_height(&self) -> u16 {
        2
    }

    pub fn lines_height(&self) -> u16 {
        let (_, screen_height) = terminal_size().unwrap();
        cmp::max(screen_height, self.status_height()) - self.status_height()
    }
}
<commit_msg>fixed printing of long lines<commit_after>use state::{Selectable, Editable, Named};
use std::cmp;
use std::io::{stdout, Stdout, Write, Result};
use std::iter;
use termion::terminal_size;
use termion::input::MouseTerminal;
use termion::raw::{IntoRawMode, RawTerminal};
use termion::{clear, style, cursor, color};

pub struct View {
    stdout: MouseTerminal<RawTerminal<Stdout>>,
    message: Option<String>,
    is_prompt: bool,
    line_offset: u16,
}

const TAB_LENGTH: usize = 4;

impl View {
    pub fn new() -> Result<View> {
        let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap());
        try!(write!(stdout, "{}{}", clear::All, cursor::Show));
        Ok(View {
            stdout: stdout,
            message: None,
            is_prompt: false,
            line_offset: 0,
        })
    }

    pub fn message(&mut self, message: &str) {
        self.is_prompt = false;
        self.message = Some(String::from(message));
    }

    pub fn prompt(&mut self, prompt: &str, message: &str) {
        self.is_prompt = true;
        let msg = String::from(prompt) + message;
        self.message = Some(msg);
    }

    pub fn quiet(&mut self) {
        self.is_prompt = false;
        self.message = None;
    }

    pub fn center_view(&mut self, line: usize) {
        self.line_offset = match line.checked_sub(self.lines_height() as usize / 2) {
            None => 0,
            Some(val) => val as u16,
        }
    }

    pub fn adjust_view(&mut self, line: usize) {
        let line = line as u16;
        if line < self.line_offset {
            self.line_offset = line;
        } else if line + 1 >= self.line_offset + self.lines_height() {
            self.line_offset = 1 + line - self.lines_height();
        }
    }

    pub fn scroll_view<T: Editable>(&mut self, offset: isize, content: &T) {
        self.line_offset =
            cmp::min(cmp::max((self.line_offset as isize) + offset, 0),
                     (content.line_count() as isize) - 1) as u16;

    }

    pub fn render<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Named + Selectable
    {
        try!(write!(self.stdout, "{}", clear::All));
        try!(self.paint_lines(content));
        try!(self.paint_status(content));
        try!(self.paint_message());
        try!(self.paint_cursor(content));
        try!(self.stdout.flush());
        Ok(())
    }

    pub fn translate_coordinates<T>(&self, content: &T, x: u16, y: u16) -> (usize, usize)
        where T: Editable
    {
        let line = y as isize + self.line_offset as isize - 1;
        let col = cmp::max(0,
                           x as isize - self.line_number_width(content.line_count()) as isize - 2);
        (line as usize, col as usize)
    }

    fn paint_message(&mut self) -> Result<()> {
        if let Some(ref message) = self.message {
            let y = self.lines_height() + 1;
            try!(write!(self.stdout, "{}{}", cursor::Goto(1, 1 + y as u16), message));
            try!(self.stdout.flush());
        }
        Ok(())
    }

    fn paint_cursor<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Selectable
    {
        // FIXME: don't print the cursor if off screen, though we should in the future for long
        // lines
        if (content.line() as u16) < self.line_offset ||
           content.line() as u16 >= self.line_offset + self.lines_height() ||
           content.col() as u16 >= self.lines_width(content.line_count()) ||
           content.sel().is_some() {
            try!(write!(self.stdout, "{}", cursor::Hide));
            return Ok(());
        }

        // in the case of a prompt, the cursor should be drawn in the message line
        let (x, y) = if self.is_prompt {
            (self.message.clone().unwrap().len() as u16, self.lines_height() + 1)
        } else {
            let (a, b) = self.cursor_pos(content);
            (a as u16, b as u16)
        };
        try!(write!(self.stdout,
                    "{}{}",
                    cursor::Show,
                    cursor::Goto(1 + x, 1 + y)));
        Ok(())
    }

    fn paint_status<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Named
    {
        let line = content.line();
        let column = content.col();
        let line_count = content.line_count();
        let advance = ((line + 1) as f64 / line_count as f64 * 100.0).floor();

        let (screen_width, _) = terminal_size().unwrap();
        let empty_line = (0..screen_width).map(|_| ' ').collect::<String>();
        let y = self.lines_height() as u16;

        try!(write!(self.stdout,
                    "{}{}{}{}{}{}",
                    color::Fg(color::White),
                    style::Invert,
                    cursor::Goto(1, 1 + y),
                    empty_line,
                    cursor::Goto(1, 1 + y),
                    content.name()));

        let position_info = format!("{}% {}/{}: {}", advance, line + 1, line_count, column);
        let x = screen_width - position_info.len() as u16;
        try!(write!(self.stdout,
                    "{}{}{}",
                    cursor::Goto(1 + x, 1 + y),
                    position_info,
                    style::Reset));
        Ok(())
    }

    fn paint_lines<T>(&mut self, content: &T) -> Result<()>
        where T: Editable + Selectable
    {
        let line_offset = self.line_offset;
        let lines_height = self.lines_height();
        let lines_width = self.lines_width(content.line_count());
        let line_count = content.line_count();

        let window_it = content.iter()
                .take(content.len() - 1) // the last endline should be invisible to the user
                .scan(('\n', 0, 1), |state, k| {
                    {
                        let (ref mut c, ref mut chars, ref mut lines) = *state;
                        if *c == '\n' {
                            *lines += 1;
                        }
                        *chars += 1;
                        *c = k;
                    }
                    Some(*state)
                })
                .skip_while(|&(_, _, lines)| lines <= 1 + line_offset)
                .take_while(|&(_, _, lines)| lines <= 1 + line_offset + lines_height);

        {
            let line_start = self.line_number_width(line_count) as u16 + 1;
            try!(write!(self.stdout,
                        "{}{}{}{}{}",
                        color::Fg(color::White),
                        cursor::Goto(1, 1),
                        line_offset + 1,
                        style::Reset,
                        cursor::Goto(1 + line_start, 1)));
        }
        let mut y = 1;
        let mut line_len = 0;
        for (c, chars, lines) in window_it {
            if c == '\n' {
                if line_len == 0 && content.in_sel(chars) {
                    try!(write!(self.stdout, "{} {}", style::Invert, style::Reset));
                }
                line_len = 0;
                let line_start = self.line_number_width(line_count) as u16 + 1;
                try!(write!(self.stdout,
                            "{}{}{}{}{}",
                            color::Fg(color::White),
                            cursor::Goto(1, 1 + y),
                            lines,
                            style::Reset,
                            cursor::Goto(1 + line_start, 1 + y)));
                y += 1;
            } else if line_len > lines_width - 1 {
                // don't print the character
                line_len += 1;
            } else {
                if content.in_sel(chars) {
                    try!(write!(self.stdout, "{}", style::Invert));
                }
                if c == '\t' {
                    // FIXME: we should probably use gotos instead of relying on character length
                    try!(write!(self.stdout,
                                "{}",
                                iter::repeat(" ").take(TAB_LENGTH).collect::<String>()));
                } else {
                    try!(write!(self.stdout, "{}", c));
                }
                try!(write!(self.stdout, "{}", style::Reset));
                line_len += 1;
            }
        }
        Ok(())
    }

    fn cursor_pos<T: Editable>(&self, content: &T) -> (usize, usize) {
        // TODO: column offsetting for long lines
        let line = content.line();
        let first_line = self.line_offset;
        let y = line - first_line as usize;
        // we can't trust the actual column because tabs have variable length
        let column = content.visual_col(TAB_LENGTH);
        ((self.line_number_width(content.line_count()) as usize + 1 + column), y)
    }

    fn line_number_width(&self, line_count: usize) -> u16 {
        let max_in_window = self.line_offset + self.lines_height() + 2;
        let max = cmp::min(max_in_window, line_count as u16);
        max.to_string().len() as u16
    }

    fn status_height(&self) -> u16 {
        2
    }

    pub fn lines_height(&self) -> u16 {
        let (_, screen_height) = terminal_size().unwrap();
        let incompressible = self.status_height();
        cmp::max(screen_height, incompressible) - incompressible
    }

    pub fn lines_width(&self, line_count: usize) -> u16 {
        let (screen_width, _) = terminal_size().unwrap();
        let incompressible = self.line_number_width(line_count) + 1;
        cmp::max(screen_width, incompressible) - incompressible
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::ptr;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::swiper::{CARD_SIZE, Region};
use gc::swiper::card::CardTable;
use gc::swiper::crossing::{CrossingEntry, CrossingMap};
use gc::swiper::old::OldGen;
use mem;
use os::{self, ProtType};
use object::Obj;
use timer::{in_ms, Timer};

pub struct YoungGen {
    // bounds of from- & to-space
    total: Region,

    // size of both from- or to-space.
    // Not combined, use total.size() for that.
    size: usize,

    // address that separates from & to-space
    separator: Address,

    // address of next free memory
    free: AtomicUsize,

    // end of free memory (either separator or total.end)
    end: AtomicUsize,

    // separates survived from newly allocated objects
    // needed to decide whether to promote object into old space
    age_marker: AtomicUsize,
}

impl YoungGen {
    pub fn new(young_start: Address, young_end: Address) -> YoungGen {
        let half_size = young_end.offset_from(young_start) / 2;
        let half_address = young_start.offset(half_size);

        YoungGen {
            total: Region::new(young_start, young_end),
            size: half_size,
            separator: half_address,
            age_marker: AtomicUsize::new(young_start.to_usize()),
            free: AtomicUsize::new(young_start.to_usize()),
            end: AtomicUsize::new(half_address.to_usize()),
        }
    }

    pub fn contains(&self, addr: Address) -> bool {
        self.total.contains(addr)
    }

    pub fn should_be_promoted(&self, addr: Address) -> bool {
        debug_assert!(self.contains(addr));

        addr.to_usize() < self.age_marker.load(Ordering::Relaxed)
    }

    pub fn alloc(&self, size: usize) -> *const u8 {
        let mut old = self.free.load(Ordering::Relaxed);
        let mut new;

        loop {
            new = old + size;

            if new >= self.end.load(Ordering::Relaxed) {
                return ptr::null();
            }

            let res = self.free.compare_exchange_weak(
                old,
                new,
                Ordering::SeqCst,
                Ordering::Relaxed,
            );

            match res {
                Ok(_) => break,
                Err(x) => old = x,
            }
        }

        old as *const u8
    }

    pub fn collect(
        &self,
        ctxt: &SemContext,
        rootset: Vec<IndirectObj>,
        card_table: &CardTable,
        crossing_map: &CrossingMap,
        old: &OldGen,
    ) {
        let mut timer = Timer::new(ctxt.args.flag_gc_events);

        let mut scan;
        let mut free;

        let new_end;

        if self.end.load(Ordering::Relaxed) == self.separator.to_usize() {
            scan = self.total.start;
            free = self.separator;
            new_end = self.total.end;

        } else {
            scan = self.separator;
            free = self.total.start;
            new_end = self.separator;
        }

        if cfg!(debug_assertions) {
            // make memory readable & writable again, so that we
            // can copy objects to the to-space.
            // Since this has some overhead, do it only in debug builds.
            os::mprotect(free.to_ptr::<u8>(), self.size, ProtType::Writable);
        }

        // detect all references from roots into young generation
        for &root in &rootset {
            let root_ptr = root.get();

            if self.total.contains(Address::from_ptr(root_ptr)) {
                root.set(copy(root_ptr, &mut free, self, old));
            }
        }

        // detect references from old generation (dirty cards) into young generation
        copy_dirty_cards(card_table, crossing_map, &mut free, self, old);

        // visit all fields in copied objects
        while scan < free {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|child| {
                let child_ptr = child.get();

                if self.total.contains(Address::from_ptr(child_ptr)) {
                    child.set(copy(child_ptr, &mut free, self, old));
                }
            });

            scan = scan.offset(object.size());
        }

        // swap spaces
        self.end.store(new_end.to_usize(), Ordering::Relaxed);

        // update start of free memory
        self.age_marker.store(free.to_usize(), Ordering::Relaxed);
        self.free.store(free.to_usize(), Ordering::SeqCst);

        // Make from-space unaccessible both from read/write.
        // Since this has some overhead, do it only in debug builds.
        if cfg!(debug_assertions) {
            let start = if new_end == self.separator {
                self.total.start
            } else {
                self.separator
            };

            os::mprotect(start.to_ptr::<u8>(), self.size, ProtType::None);
        }

        timer.stop_with(|dur| if ctxt.args.flag_gc_events {
            println!("GC minor: collect garbage ({} ms)", in_ms(dur));
        });
    }
}

// copy all references from old- into young-generation.
fn copy_dirty_cards(
    card_table: &CardTable,
    crossing_map: &CrossingMap,
    mut free: &mut Address,
    young: &YoungGen,
    old: &OldGen,
) {
    card_table.visit_dirty(|card| {
        let crossing_entry = crossing_map.get(card);
        let card_start = crossing_map.address_of_card(card);
        let card_end = card_start.offset(CARD_SIZE);

        match crossing_entry {
            CrossingEntry::NoRefs => panic!("card dirty without any refs"),
            CrossingEntry::LeadingRefs(refs) => {
                let mut ptr = card_start;

                for _ in 0..refs {
                    let ind_ptr = IndirectObj::from_address(ptr);
                    let dir_ptr = ind_ptr.get();

                    if young.contains(Address::from_ptr(dir_ptr)) {
                        ind_ptr.set(copy(dir_ptr, &mut free, young, old));
                    }

                    ptr = ptr.offset(ptr_width());
                }

                // copy all objects from this card
                copy_card(ptr, card_end, free, young, old);
            }

            CrossingEntry::FirstObjectOffset(offset) => {
                let ptr = card_start.offset(offset as usize * ptr_width());

                // copy all objects from this card
                copy_card(ptr, card_end, free, young, old);
            }
        }
    });
}

fn copy_card(mut ptr: Address, end: Address, mut free: &mut Address, young: &YoungGen, old: &OldGen) {
    let old_end: Address = old.free.load(Ordering::Relaxed).into();
    let end = cmp::min(end, old_end);

    while ptr < end {
        let object = unsafe { &mut *ptr.to_mut_ptr::<Obj>() };

        object.visit_reference_fields(|child| {
            let child_ptr = child.get();

            if young.contains(Address::from_ptr(child_ptr)) {
                child.set(copy(child_ptr, &mut free, young, old));
            }
        });

        ptr = ptr.offset(object.size());
    }
}

pub fn copy(obj: *mut Obj, free: &mut Address, young: &YoungGen, old: &OldGen) -> *mut Obj {
    let obj = unsafe { &mut *obj };
    let fwaddr = get_forwarding_address(obj);

    if is_forwarding_address(fwaddr) {
        unmark_forwarding_address(fwaddr).to_mut_ptr::<Obj>()

    } else {
        let obj_size = obj.size();

        let addr: Address;

        // if object is old enough we copy it into the old generation
        if young.should_be_promoted(fwaddr) {
            addr = Address::from_ptr(old.alloc(obj_size));
            copy_object(obj, addr, obj_size);

        // otherwise the object remains in the young generation for now
        } else {
            addr = *free;
            copy_object(obj, addr, obj_size);
            *free = addr.offset(obj_size);
        }

        set_forwarding_address(obj, addr);

        addr.to_mut_ptr::<Obj>()
    }
}

fn copy_object(obj: &Obj, addr: Address, size: usize) {
    unsafe {
        ptr::copy_nonoverlapping(
            obj as *const Obj as *const u8,
            addr.to_mut_ptr::<u8>(),
            size,
        );
    }
}

pub fn is_forwarding_address(obj: Address) -> bool {
    (obj.to_usize() & 1) == 1
}

pub fn mark_forwarding_address(obj: Address) -> Address {
    (obj.to_usize() | 1).into()
}

pub fn unmark_forwarding_address(obj: Address) -> Address {
    (obj.to_usize() & !1).into()
}

pub fn get_forwarding_address(obj: &Obj) -> Address {
    unsafe { *(obj as *const Obj as *const Address) }
}

pub fn set_forwarding_address(obj: &mut Obj, addr: Address) {
    unsafe {
        *(obj as *mut Obj as *mut Address) = mark_forwarding_address(addr);
    }
}

#[inline(always)]
fn ptr_width() -> usize {
    mem::ptr_width() as usize
}
<commit_msg>swiper: fix copying of objects<commit_after>use std::cmp;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::ptr;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::swiper::{CARD_SIZE, Region};
use gc::swiper::card::CardTable;
use gc::swiper::crossing::{CrossingEntry, CrossingMap};
use gc::swiper::old::OldGen;
use mem;
use os::{self, ProtType};
use object::Obj;
use timer::{in_ms, Timer};

pub struct YoungGen {
    // bounds of from- & to-space
    total: Region,

    // size of both from- or to-space.
    // Not combined, use total.size() for that.
    size: usize,

    // address that separates from & to-space
    separator: Address,

    // address of next free memory
    free: AtomicUsize,

    // end of free memory (either separator or total.end)
    end: AtomicUsize,

    // separates survived from newly allocated objects
    // needed to decide whether to promote object into old space
    age_marker: AtomicUsize,
}

impl YoungGen {
    pub fn new(young_start: Address, young_end: Address) -> YoungGen {
        let half_size = young_end.offset_from(young_start) / 2;
        let half_address = young_start.offset(half_size);

        YoungGen {
            total: Region::new(young_start, young_end),
            size: half_size,
            separator: half_address,
            age_marker: AtomicUsize::new(young_start.to_usize()),
            free: AtomicUsize::new(young_start.to_usize()),
            end: AtomicUsize::new(half_address.to_usize()),
        }
    }

    pub fn contains(&self, addr: Address) -> bool {
        self.total.contains(addr)
    }

    pub fn should_be_promoted(&self, addr: Address) -> bool {
        debug_assert!(self.contains(addr));

        addr.to_usize() < self.age_marker.load(Ordering::Relaxed)
    }

    pub fn alloc(&self, size: usize) -> *const u8 {
        let mut old = self.free.load(Ordering::Relaxed);
        let mut new;

        loop {
            new = old + size;

            if new >= self.end.load(Ordering::Relaxed) {
                return ptr::null();
            }

            let res = self.free.compare_exchange_weak(
                old,
                new,
                Ordering::SeqCst,
                Ordering::Relaxed,
            );

            match res {
                Ok(_) => break,
                Err(x) => old = x,
            }
        }

        old as *const u8
    }

    pub fn collect(
        &self,
        ctxt: &SemContext,
        rootset: Vec<IndirectObj>,
        card_table: &CardTable,
        crossing_map: &CrossingMap,
        old: &OldGen,
    ) {
        let mut timer = Timer::new(ctxt.args.flag_gc_events);

        let mut scan: Address;
        let new_end: Address;

        if self.end.load(Ordering::Relaxed) == self.separator.to_usize() {
            scan = self.separator;
            new_end = self.total.end;

        } else {
            // self.end == self.total.end
            scan = self.total.start;
            new_end = self.separator;
        }

        let mut free = scan;

        if cfg!(debug_assertions) {
            // make memory readable & writable again, so that we
            // can copy objects to the to-space.
            // Since this has some overhead, do it only in debug builds.
            os::mprotect(free.to_ptr::<u8>(), self.size, ProtType::Writable);
        }

        // detect all references from roots into young generation
        for &root in &rootset {
            let root_ptr = root.get();

            if self.contains(Address::from_ptr(root_ptr)) {
                root.set(copy(root_ptr, &mut free, self, old));
            }
        }

        // detect references from old generation (dirty cards) into young generation
        copy_dirty_cards(card_table, crossing_map, &mut free, self, old);

        // visit all fields in copied objects
        while scan < free {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|child| {
                let child_ptr = child.get();

                if self.contains(Address::from_ptr(child_ptr)) {
                    child.set(copy(child_ptr, &mut free, self, old));
                }
            });

            scan = scan.offset(object.size());
        }

        // swap spaces
        self.end.store(new_end.to_usize(), Ordering::Relaxed);

        // update start of free memory
        self.age_marker.store(free.to_usize(), Ordering::Relaxed);
        self.free.store(free.to_usize(), Ordering::SeqCst);

        // Make from-space unaccessible both from read/write.
        // Since this has some overhead, do it only in debug builds.
        if cfg!(debug_assertions) {
            let start = if new_end == self.separator {
                self.total.start
            } else {
                self.separator
            };

            os::mprotect(start.to_ptr::<u8>(), self.size, ProtType::None);
        }

        timer.stop_with(|dur| if ctxt.args.flag_gc_events {
            println!("GC minor: collect garbage ({} ms)", in_ms(dur));
        });
    }
}

// copy all references from old- into young-generation.
fn copy_dirty_cards(
    card_table: &CardTable,
    crossing_map: &CrossingMap,
    mut free: &mut Address,
    young: &YoungGen,
    old: &OldGen,
) {
    card_table.visit_dirty(|card| {
        let crossing_entry = crossing_map.get(card);
        let card_start = crossing_map.address_of_card(card);
        let card_end = card_start.offset(CARD_SIZE);

        match crossing_entry {
            CrossingEntry::NoRefs => panic!("card dirty without any refs"),
            CrossingEntry::LeadingRefs(refs) => {
                let mut ptr = card_start;

                for _ in 0..refs {
                    let ind_ptr = IndirectObj::from_address(ptr);
                    let dir_ptr = ind_ptr.get();

                    if young.contains(Address::from_ptr(dir_ptr)) {
                        ind_ptr.set(copy(dir_ptr, &mut free, young, old));
                    }

                    ptr = ptr.offset(ptr_width());
                }

                // copy all objects from this card
                copy_card(ptr, card_end, free, young, old);
            }

            CrossingEntry::FirstObjectOffset(offset) => {
                let ptr = card_start.offset(offset as usize * ptr_width());

                // copy all objects from this card
                copy_card(ptr, card_end, free, young, old);
            }
        }
    });
}

fn copy_card(mut ptr: Address, end: Address, mut free: &mut Address, young: &YoungGen, old: &OldGen) {
    let old_end: Address = old.free.load(Ordering::Relaxed).into();
    let end = cmp::min(end, old_end);

    while ptr < end {
        let object = unsafe { &mut *ptr.to_mut_ptr::<Obj>() };

        object.visit_reference_fields(|child| {
            let child_ptr = child.get();

            if young.contains(Address::from_ptr(child_ptr)) {
                child.set(copy(child_ptr, &mut free, young, old));
            }
        });

        ptr = ptr.offset(object.size());
    }
}

pub fn copy(obj: *mut Obj, free: &mut Address, young: &YoungGen, old: &OldGen) -> *mut Obj {
    let obj_addr = Address::from_ptr(obj);
    let obj = unsafe { &mut *obj };
    let fwaddr = get_forwarding_address(obj);

    if is_forwarding_address(fwaddr) {
        unmark_forwarding_address(fwaddr).to_mut_ptr::<Obj>()

    } else {
        let obj_size = obj.size();

        let copy_addr: Address;

        // if object is old enough we copy it into the old generation
        if young.should_be_promoted(obj_addr) {
            copy_addr = Address::from_ptr(old.alloc(obj_size));

        // otherwise the object remains in the young generation for now
        } else {
            copy_addr = *free;
            *free = copy_addr.offset(obj_size);
        }

        copy_object(obj, copy_addr, obj_size);
        set_forwarding_address(obj, copy_addr);

        copy_addr.to_mut_ptr::<Obj>()
    }
}

fn copy_object(obj: &Obj, addr: Address, size: usize) {
    unsafe {
        ptr::copy_nonoverlapping(
            obj as *const Obj as *const u8,
            addr.to_mut_ptr::<u8>(),
            size,
        );
    }
}

pub fn is_forwarding_address(obj: Address) -> bool {
    (obj.to_usize() & 1) == 1
}

pub fn mark_forwarding_address(obj: Address) -> Address {
    (obj.to_usize() | 1).into()
}

pub fn unmark_forwarding_address(obj: Address) -> Address {
    (obj.to_usize() & !1).into()
}

pub fn get_forwarding_address(obj: &Obj) -> Address {
    unsafe { *(obj as *const Obj as *const Address) }
}

pub fn set_forwarding_address(obj: &mut Obj, addr: Address) {
    unsafe {
        *(obj as *mut Obj as *mut Address) = mark_forwarding_address(addr);
    }
}

#[inline(always)]
fn ptr_width() -> usize {
    mem::ptr_width() as usize
}
<|endoftext|>


<commit_before>// Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
// The poles (phi) are at the positive and negative y axis.
// The equator starts at positive z.

#[derive(Debug,PartialEq)]
pub struct Spherical {
    pub radius: f32,
    pub phi: f32,
    pub theta: f32,
}

impl Spherical {
    pub const DEFAULT: Spherical = Spherical {
        radius: 1.0,
        phi: 0.0, // up / down towards top and bottom pole
        theta: 0.0, // around the equator of the sphere
    };

    pub fn new(radius: f32, phi: f32, theta: f32) -> Spherical {
        Spherical {
            radius: radius,
            phi: phi,
            theta: theta,
        }
    }
}<commit_msg>add rest of spherical methods<commit_after>use std::f32::consts::PI;
use std::f32::EPSILON;
use math::Vector3;

// Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
// The poles (phi) are at the positive and negative y axis.
// The equator starts at positive z.

#[derive(Debug,PartialEq)]
pub struct Spherical {
    pub radius: f32,
    pub phi: f32,
    pub theta: f32,
}

impl Spherical {
    pub const DEFAULT: Spherical = Spherical {
        radius: 1.0,
        phi: 0.0, // up / down towards top and bottom pole
        theta: 0.0, // around the equator of the sphere
    };

    pub fn new(radius: f32, phi: f32, theta: f32) -> Spherical {
        Spherical {
            radius: radius,
            phi: phi,
            theta: theta,
        }
    }

    // restrict phi to be betwee EPS and PI-EPS
    pub fn make_safe(&self) -> Spherical {
        Spherical { phi: self.phi.min(PI - EPSILON).max(EPSILON), ..*self }
    }

    pub fn from_vector3(vec3: &Vector3) -> Spherical {
        let radius = vec3.length();

        if radius == 0.0 {
            Spherical::new(radius, 0.0, 0.0)
        } else {
            let phi = (vec3.y / radius).max(-1.0).min(1.0).acos(); // polar angle
            let theta = vec3.x.atan2(vec3.z);// equator angle around y-up axis
            Spherical::new(radius, phi, theta)
        }
    }
}<|endoftext|>


<commit_before>// compile-flags: -Zmiri-disable-isolation

use std::time::{SystemTime, Instant, Duration};

fn duration_sanity(diff: Duration) {
    // On my laptop, I observed times around 15-40ms. Add 10x lee-way both ways.
    assert!(diff.as_millis() > 1);
    assert!(diff.as_millis() < 500);
}

// Thus far, only `libc::nanosleep`, is implemented, not `c::Sleep`.
#[cfg(unix)]
fn test_sleep() {
    let before = Instant::now();
    std::thread::sleep(Duration::from_millis(100));
    let after = Instant::now();
    assert!((after - before).as_millis() >= 100);
}

fn main() {
    // Check `SystemTime`.
    let now1 = SystemTime::now();
    let seconds_since_epoch = now1.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
    let years_since_epoch = seconds_since_epoch / 3600 / 24 / 365;
    let year = 1970 + years_since_epoch;
    assert!(2020 <= year && year < 2100);
    // Do some work to make time pass.
    for _ in 0..10 { drop(vec![42]); }
    let now2 = SystemTime::now();
    assert!(now2 > now1);
    // Sanity-check the difference we got.
    let diff = now2.duration_since(now1).unwrap();
    assert_eq!(now1 + diff, now2);
    assert_eq!(now2 - diff, now1);
    duration_sanity(diff);

    // Check `Instant`.
    let now1 = Instant::now();
    // Do some work to make time pass.
    for _ in 0..10 { drop(vec![42]); }
    let now2 = Instant::now();
    assert!(now2 > now1);
    // Sanity-check the difference we got.
    let diff = now2.duration_since(now1);
    assert_eq!(now1 + diff, now2);
    assert_eq!(now2 - diff, now1);
    duration_sanity(diff);

    #[cfg(unix)]
    test_sleep();
}
<commit_msg>Update comment<commit_after>// compile-flags: -Zmiri-disable-isolation

use std::time::{SystemTime, Instant, Duration};

fn duration_sanity(diff: Duration) {
    // On my laptop, I observed times around 15-40ms. Add 10x lee-way both ways.
    assert!(diff.as_millis() > 1);
    assert!(diff.as_millis() < 500);
}

// Sleeping on Windows is not supported yet.
#[cfg(unix)]
fn test_sleep() {
    let before = Instant::now();
    std::thread::sleep(Duration::from_millis(100));
    let after = Instant::now();
    assert!((after - before).as_millis() >= 100);
}

fn main() {
    // Check `SystemTime`.
    let now1 = SystemTime::now();
    let seconds_since_epoch = now1.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
    let years_since_epoch = seconds_since_epoch / 3600 / 24 / 365;
    let year = 1970 + years_since_epoch;
    assert!(2020 <= year && year < 2100);
    // Do some work to make time pass.
    for _ in 0..10 { drop(vec![42]); }
    let now2 = SystemTime::now();
    assert!(now2 > now1);
    // Sanity-check the difference we got.
    let diff = now2.duration_since(now1).unwrap();
    assert_eq!(now1 + diff, now2);
    assert_eq!(now2 - diff, now1);
    duration_sanity(diff);

    // Check `Instant`.
    let now1 = Instant::now();
    // Do some work to make time pass.
    for _ in 0..10 { drop(vec![42]); }
    let now2 = Instant::now();
    assert!(now2 > now1);
    // Sanity-check the difference we got.
    let diff = now2.duration_since(now1);
    assert_eq!(now1 + diff, now2);
    assert_eq!(now2 - diff, now1);
    duration_sanity(diff);

    #[cfg(unix)]
    test_sleep();
}
<|endoftext|>