<commit_before>use alloc::boxed::Box;
use collections::string::String;
use collections::string::ToString;
use collections::vec::Vec;

use core::fmt::{Debug, Formatter, Error};

use super::termlist::parse_term_list;
use super::namedobj::{ RegionSpace, FieldFlags };
use super::parser::{AmlExecutionContext, ExecutionState};
use super::AmlError;

#[derive(Clone)]
pub enum FieldSelector {
    Region(String),
    Bank {
        region: String,
        bank_selector: Box<AmlValue>
    },
    Index {
        index_selector: String,
        data_selector: String
    }
}

#[derive(Clone)]
pub enum ObjectReference {
    ArgObj(u8),
    LocalObj(u8),
    NamedObj(String),
    Object(Box<AmlValue>),
    Index(Box<AmlValue>, Box<AmlValue>)
}

#[derive(Clone)]
pub struct Method {
    pub arg_count: u8,
    pub serialized: bool,
    pub sync_level: u8,
    pub term_list: Vec<u8>
}

#[derive(Clone)]
pub struct BufferField {
    pub source_buf: Box<AmlValue>,
    pub index: Box<AmlValue>,
    pub length: Box<AmlValue>
}

#[derive(Clone)]
pub struct FieldUnit {
    pub selector: FieldSelector,
    pub connection: Box<AmlValue>,
    pub flags: FieldFlags,
    pub offset: usize,
    pub length: usize
}

#[derive(Clone)]
pub struct Processor {
    pub proc_id: u8,
    pub p_blk: Option<u32>,
    pub obj_list: Vec<String>
}

#[derive(Clone)]
pub struct OperationRegion {
    pub region: RegionSpace,
    pub offset: Box<AmlValue>,
    pub len: Box<AmlValue>,
    pub accessor: Accessor,
    pub accessed_by: Option<u64>
}

#[derive(Clone)]
pub struct PowerResource {
    pub system_level: u8,
    pub resource_order: u16,
    pub obj_list: Vec<String>
}

pub struct Accessor {
    pub read: fn(usize) -> u64,
    pub write: fn(usize, u64)
}

impl Clone for Accessor {
    fn clone(&self) -> Accessor {
        Accessor {
            read: (*self).read,
            write: (*self).write
        }
    }
}

#[derive(Clone)]
pub enum AmlValue {
    None,
    Uninitialized,
    Buffer(Vec<u8>),
    BufferField(BufferField),
    DDBHandle(Vec<String>),
    DebugObject,
    Device(Vec<String>),
    Event(u64),
    FieldUnit(FieldUnit),
    Integer(u64),
    IntegerConstant(u64),
    Method(Method),
    Mutex((u8, Option<u64>)),
    ObjectReference(ObjectReference),
    OperationRegion(OperationRegion),
    Package(Vec<AmlValue>),
    String(String),
    PowerResource(PowerResource),
    Processor(Processor),
    RawDataBuffer(Vec<u8>),
    ThermalZone(Vec<String>)
}

impl Debug for AmlValue {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { Ok(()) }
}

impl AmlValue {
    pub fn get_as_buffer(&self) -> Result<Vec<u8>, AmlError> {
        match *self {
            AmlValue::Buffer(ref b) => Ok(b.clone()),
            AmlValue::Integer(ref i) => {
                let mut v: Vec<u8> = vec!();
                let mut i = i.clone();

                while i != 0 {
                    v.push((i & 0xFF) as u8);
                    i >>= 8;
                }

                while v.len() < 8 {
                    v.push(0);
                }

                Ok(v)
            },
            AmlValue::String(ref s) => {
                Ok(s.clone().into_bytes())
            },
            AmlValue::BufferField(ref b) => {
                let buf = b.source_buf.get_as_buffer()?;
                let idx = b.index.get_as_integer()? as usize;
                let len = b.length.get_as_integer()? as usize;

                if idx + len > buf.len() {
                    return Err(AmlError::AmlValueError);
                }

                Ok(buf[idx .. idx + len].to_vec())
            },
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_buffer_field(&self) -> Result<BufferField, AmlError> {
        match *self {
            AmlValue::BufferField(ref b) => Ok(b.clone()),
            _ => {
                let raw_buf = self.get_as_buffer()?;
                let buf = Box::new(AmlValue::Buffer(raw_buf.clone()));
                let idx = Box::new(AmlValue::IntegerConstant(0));
                let len = Box::new(AmlValue::Integer(raw_buf.len() as u64));

                Ok(BufferField {
                    source_buf: buf,
                    index: idx,
                    length: len
                })
            }
        }
    }

    pub fn get_as_ddb_handle(&self) -> Result<Vec<String>, AmlError> {
        // TODO: Integer conversion
        match *self {
            AmlValue::DDBHandle(ref v) => Ok(v.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_device(&self) -> Result<Vec<String>, AmlError> {
        match *self {
            AmlValue::Device(ref s) => Ok(s.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_event(&self) -> Result<u64, AmlError> {
        match *self {
            AmlValue::Event(ref e) => Ok(e.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_field_unit(&self) -> Result<FieldUnit, AmlError> {
        match *self {
            AmlValue::FieldUnit(ref e) => Ok(e.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_integer(&self) -> Result<u64, AmlError> {
        match *self {
            AmlValue::IntegerConstant(ref i) => Ok(i.clone()),
            AmlValue::Integer(ref i) => Ok(i.clone()),
            AmlValue::Buffer(ref b) => {
                let mut b = b.clone();
                if b.len() > 8 {
                    return Err(AmlError::AmlValueError);
                }

                let mut i: u64 = 0;

                while b.len() > 0 {
                    i <<= 8;
                    i += b.pop().expect("Won't happen") as u64;
                }

                Ok(i)
            },
            AmlValue::BufferField(_) => {
                let mut b = self.get_as_buffer()?;
                if b.len() > 8 {
                    return Err(AmlError::AmlValueError);
                }

                let mut i: u64 = 0;

                while b.len() > 0 {
                    i <<= 8;
                    i += b.pop().expect("Won't happen") as u64;
                }

                Ok(i)
            },
            AmlValue::String(ref s) => {
                let mut s = s.clone()[0..8].to_string().to_uppercase();
                let mut i: u64 = 0;

                for c in s.chars() {
                    if !c.is_digit(16) {
                        break;
                    }

                    i <<= 8;
                    i += c.to_digit(16).unwrap() as u64;
                }

                Ok(i)
            },
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_integer_constant(&self) -> Result<u64, AmlError> {
        match *self {
            AmlValue::IntegerConstant(ref i) => Ok(i.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_method(&self) -> Result<Method, AmlError> {
        match *self {
            AmlValue::Method(ref m) => Ok(m.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_mutex(&self) -> Result<(u8, Option<u64>), AmlError> {
        match *self {
            AmlValue::Mutex(ref m) => Ok(m.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_object_reference(&self) -> Result<ObjectReference, AmlError> {
        match *self {
            AmlValue::ObjectReference(ref m) => Ok(m.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_operation_region(&self) -> Result<OperationRegion, AmlError> {
        match *self {
            AmlValue::OperationRegion(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_package(&self) -> Result<Vec<AmlValue>, AmlError> {
        match *self {
            AmlValue::Package(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_string(&self) -> Result<String, AmlError> {
        match *self {
            AmlValue::String(ref s) => Ok(s.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_power_resource(&self) -> Result<PowerResource, AmlError> {
        match *self {
            AmlValue::PowerResource(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_processor(&self) -> Result<Processor, AmlError> {
        match *self {
            AmlValue::Processor(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_raw_data_buffer(&self) -> Result<Vec<u8>, AmlError> {
        match *self {
            AmlValue::RawDataBuffer(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_thermal_zone(&self) -> Result<Vec<String>, AmlError> {
        match *self {
            AmlValue::ThermalZone(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }
}

impl Method {
    pub fn execute(&self, scope: String, parameters: Vec<AmlValue>) -> AmlValue {
        let mut ctx = AmlExecutionContext::new(scope);
        ctx.init_arg_vars(parameters);

        parse_term_list(&self.term_list[..], &mut ctx);
        ctx.clean_namespace();

        match ctx.state {
            ExecutionState::RETURN(v) => v,
            _ => AmlValue::IntegerConstant(0)
        }
    }
}

pub fn get_namespace_string(current: String, modifier_v: AmlValue) -> Result<String, AmlError> {
    let mut modifier = modifier_v.get_as_string()?;

    if current.len() == 0 {
        return Ok(modifier);
    }

    if modifier.len() == 0 {
        return Ok(current);
    }

    if modifier.starts_with("\\") {
        return Ok(modifier);
    }

    let mut namespace = current.clone();

    if modifier.starts_with("^") {
        while modifier.starts_with("^") {
            modifier = modifier[1..].to_string();

            if namespace.ends_with("\\") {
                return Err(AmlError::AmlValueError);
            }

            loop {
                if namespace.ends_with(".") {
                    namespace.pop();
                    break;
                }

                if namespace.pop() == None {
                    return Err(AmlError::AmlValueError);
                }
            }
        }
    }

    if !namespace.ends_with("\\") {
        namespace.push('.');
    }

    Ok(namespace + &modifier)
}
<commit_msg>Converted all types to string<commit_after>use alloc::boxed::Box;
use collections::string::String;
use collections::string::ToString;
use collections::vec::Vec;

use core::fmt::{Debug, Formatter, Error};

use super::termlist::parse_term_list;
use super::namedobj::{ RegionSpace, FieldFlags };
use super::parser::{AmlExecutionContext, ExecutionState};
use super::AmlError;

#[derive(Clone)]
pub enum FieldSelector {
    Region(String),
    Bank {
        region: String,
        bank_selector: Box<AmlValue>
    },
    Index {
        index_selector: String,
        data_selector: String
    }
}

#[derive(Clone)]
pub enum ObjectReference {
    ArgObj(u8),
    LocalObj(u8),
    NamedObj(String),
    Object(Box<AmlValue>),
    Index(Box<AmlValue>, Box<AmlValue>)
}

#[derive(Clone)]
pub struct Method {
    pub arg_count: u8,
    pub serialized: bool,
    pub sync_level: u8,
    pub term_list: Vec<u8>
}

#[derive(Clone)]
pub struct BufferField {
    pub source_buf: Box<AmlValue>,
    pub index: Box<AmlValue>,
    pub length: Box<AmlValue>
}

#[derive(Clone)]
pub struct FieldUnit {
    pub selector: FieldSelector,
    pub connection: Box<AmlValue>,
    pub flags: FieldFlags,
    pub offset: usize,
    pub length: usize
}

#[derive(Clone)]
pub struct Processor {
    pub proc_id: u8,
    pub p_blk: Option<u32>,
    pub obj_list: Vec<String>
}

#[derive(Clone)]
pub struct OperationRegion {
    pub region: RegionSpace,
    pub offset: Box<AmlValue>,
    pub len: Box<AmlValue>,
    pub accessor: Accessor,
    pub accessed_by: Option<u64>
}

#[derive(Clone)]
pub struct PowerResource {
    pub system_level: u8,
    pub resource_order: u16,
    pub obj_list: Vec<String>
}

pub struct Accessor {
    pub read: fn(usize) -> u64,
    pub write: fn(usize, u64)
}

impl Clone for Accessor {
    fn clone(&self) -> Accessor {
        Accessor {
            read: (*self).read,
            write: (*self).write
        }
    }
}

#[derive(Clone)]
pub enum AmlValue {
    None,
    Uninitialized,
    Buffer(Vec<u8>),
    BufferField(BufferField),
    DDBHandle(Vec<String>),
    DebugObject,
    Device(Vec<String>),
    Event(u64),
    FieldUnit(FieldUnit),
    Integer(u64),
    IntegerConstant(u64),
    Method(Method),
    Mutex((u8, Option<u64>)),
    ObjectReference(ObjectReference),
    OperationRegion(OperationRegion),
    Package(Vec<AmlValue>),
    String(String),
    PowerResource(PowerResource),
    Processor(Processor),
    RawDataBuffer(Vec<u8>),
    ThermalZone(Vec<String>)
}

impl Debug for AmlValue {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { Ok(()) }
}

impl AmlValue {
    pub fn get_as_buffer(&self) -> Result<Vec<u8>, AmlError> {
        match *self {
            AmlValue::Buffer(ref b) => Ok(b.clone()),
            AmlValue::Integer(ref i) => {
                let mut v: Vec<u8> = vec!();
                let mut i = i.clone();

                while i != 0 {
                    v.push((i & 0xFF) as u8);
                    i >>= 8;
                }

                while v.len() < 8 {
                    v.push(0);
                }

                Ok(v)
            },
            AmlValue::String(ref s) => {
                Ok(s.clone().into_bytes())
            },
            AmlValue::BufferField(ref b) => {
                let buf = b.source_buf.get_as_buffer()?;
                let idx = b.index.get_as_integer()? as usize;
                let len = b.length.get_as_integer()? as usize;

                if idx + len > buf.len() {
                    return Err(AmlError::AmlValueError);
                }

                Ok(buf[idx .. idx + len].to_vec())
            },
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_buffer_field(&self) -> Result<BufferField, AmlError> {
        match *self {
            AmlValue::BufferField(ref b) => Ok(b.clone()),
            _ => {
                let raw_buf = self.get_as_buffer()?;
                let buf = Box::new(AmlValue::Buffer(raw_buf.clone()));
                let idx = Box::new(AmlValue::IntegerConstant(0));
                let len = Box::new(AmlValue::Integer(raw_buf.len() as u64));

                Ok(BufferField {
                    source_buf: buf,
                    index: idx,
                    length: len
                })
            }
        }
    }

    pub fn get_as_ddb_handle(&self) -> Result<Vec<String>, AmlError> {
        // TODO: Integer conversion
        match *self {
            AmlValue::DDBHandle(ref v) => Ok(v.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_device(&self) -> Result<Vec<String>, AmlError> {
        match *self {
            AmlValue::Device(ref s) => Ok(s.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_event(&self) -> Result<u64, AmlError> {
        match *self {
            AmlValue::Event(ref e) => Ok(e.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_field_unit(&self) -> Result<FieldUnit, AmlError> {
        match *self {
            AmlValue::FieldUnit(ref e) => Ok(e.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_integer(&self) -> Result<u64, AmlError> {
        match *self {
            AmlValue::IntegerConstant(ref i) => Ok(i.clone()),
            AmlValue::Integer(ref i) => Ok(i.clone()),
            AmlValue::Buffer(ref b) => {
                let mut b = b.clone();
                if b.len() > 8 {
                    return Err(AmlError::AmlValueError);
                }

                let mut i: u64 = 0;

                while b.len() > 0 {
                    i <<= 8;
                    i += b.pop().expect("Won't happen") as u64;
                }

                Ok(i)
            },
            AmlValue::BufferField(_) => {
                let mut b = self.get_as_buffer()?;
                if b.len() > 8 {
                    return Err(AmlError::AmlValueError);
                }

                let mut i: u64 = 0;

                while b.len() > 0 {
                    i <<= 8;
                    i += b.pop().expect("Won't happen") as u64;
                }

                Ok(i)
            },
            AmlValue::String(ref s) => {
                let mut s = s.clone()[0..8].to_string().to_uppercase();
                let mut i: u64 = 0;

                for c in s.chars() {
                    if !c.is_digit(16) {
                        break;
                    }

                    i <<= 8;
                    i += c.to_digit(16).unwrap() as u64;
                }

                Ok(i)
            },
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_integer_constant(&self) -> Result<u64, AmlError> {
        match *self {
            AmlValue::IntegerConstant(ref i) => Ok(i.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_method(&self) -> Result<Method, AmlError> {
        match *self {
            AmlValue::Method(ref m) => Ok(m.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_mutex(&self) -> Result<(u8, Option<u64>), AmlError> {
        match *self {
            AmlValue::Mutex(ref m) => Ok(m.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_object_reference(&self) -> Result<ObjectReference, AmlError> {
        match *self {
            AmlValue::ObjectReference(ref m) => Ok(m.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_operation_region(&self) -> Result<OperationRegion, AmlError> {
        match *self {
            AmlValue::OperationRegion(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_package(&self) -> Result<Vec<AmlValue>, AmlError> {
        match *self {
            AmlValue::Package(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_string(&self) -> Result<String, AmlError> {
        match *self {
            AmlValue::String(ref s) => Ok(s.clone()),
            AmlValue::Integer(ref i) => Ok(format!("{:X}", i)),
            AmlValue::IntegerConstant(ref i) => Ok(format!("{:X}", i)),
            AmlValue::Buffer(ref b) => Ok(String::from_utf8(b.clone()).expect("Invalid UTF-8")),
            AmlValue::BufferField(_) => {
                let b = self.get_as_buffer()?;
                Ok(String::from_utf8(b).expect("Invalid UTF-8"))
            },
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_power_resource(&self) -> Result<PowerResource, AmlError> {
        match *self {
            AmlValue::PowerResource(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_processor(&self) -> Result<Processor, AmlError> {
        match *self {
            AmlValue::Processor(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_raw_data_buffer(&self) -> Result<Vec<u8>, AmlError> {
        match *self {
            AmlValue::RawDataBuffer(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get_as_thermal_zone(&self) -> Result<Vec<String>, AmlError> {
        match *self {
            AmlValue::ThermalZone(ref p) => Ok(p.clone()),
            _ => Err(AmlError::AmlValueError)
        }
    }
}

impl Method {
    pub fn execute(&self, scope: String, parameters: Vec<AmlValue>) -> AmlValue {
        let mut ctx = AmlExecutionContext::new(scope);
        ctx.init_arg_vars(parameters);

        parse_term_list(&self.term_list[..], &mut ctx);
        ctx.clean_namespace();

        match ctx.state {
            ExecutionState::RETURN(v) => v,
            _ => AmlValue::IntegerConstant(0)
        }
    }
}

pub fn get_namespace_string(current: String, modifier_v: AmlValue) -> Result<String, AmlError> {
    let mut modifier = modifier_v.get_as_string()?;

    if current.len() == 0 {
        return Ok(modifier);
    }

    if modifier.len() == 0 {
        return Ok(current);
    }

    if modifier.starts_with("\\") {
        return Ok(modifier);
    }

    let mut namespace = current.clone();

    if modifier.starts_with("^") {
        while modifier.starts_with("^") {
            modifier = modifier[1..].to_string();

            if namespace.ends_with("\\") {
                return Err(AmlError::AmlValueError);
            }

            loop {
                if namespace.ends_with(".") {
                    namespace.pop();
                    break;
                }

                if namespace.pop() == None {
                    return Err(AmlError::AmlValueError);
                }
            }
        }
    }

    if !namespace.ends_with("\\") {
        namespace.push('.');
    }

    Ok(namespace + &modifier)
}
<|endoftext|>


<commit_before>use std::num::{One, Zero};
use std::rand::{Rand, Rng, RngUtil};
use std::cmp::ApproxEq;
use traits::dim::Dim;
use traits::inv::Inv;
use traits::rotation::{Rotation, Rotate};
use traits::translation::{Translation, Translate};
use Ts = traits::transformation::Transform;
use traits::transformation::{Transformation};
use traits::rlmul::{RMul, LMul};
use traits::homogeneous::{ToHomogeneous, FromHomogeneous};
use traits::column::Column;
use adaptors::rotmat::Rotmat;
use vec::Vec3;
use mat::Mat3;

/// Matrix-Vector wrapper used to represent a matrix multiplication followed by a translation.
/// Usually, a matrix in homogeneous coordinate is used to be able to apply an affine transform with
/// a translation to a vector. This is weird because it makes a `n`-dimentional transformation be
/// an `n + 1`-matrix. Using the `Transform` wrapper avoid homogeneous coordinates by having the
/// translation separate from the other transformations. This is particularity useful when the
/// underlying transform is a rotation (see `Rotmat`): this makes inversion much faster than
/// inverting the homogeneous matrix itself.
#[deriving(Eq, ToStr, Clone)]
pub struct Transform<M, V> {
    priv submat   : M,
    priv subtrans : V
}

impl<M, V> Transform<M, V> {
    /// Builds a new transform from a matrix and a vector.
    #[inline]
    pub fn new(mat: M, trans: V) -> Transform<M, V> {
        Transform {
            submat:   mat,
            subtrans: trans
        }
    }
}

impl<M: Clone, V: Clone> Transform<M, V> {
    /// Gets a copy of the internal matrix.
    #[inline]
    pub fn submat(&self) -> M {
        self.submat.clone()
    }

    /// Gets a copy of the internal translation.
    #[inline]
    pub fn subtrans(&self) -> V {
        self.subtrans.clone()
    }
}

impl<N: Clone + Num + Algebraic> Transform<Rotmat<Mat3<N>>, Vec3<N>> {
    /// Reorient and translate this transformation such that its local `x` axis points to a given
    /// direction.  Note that the usually known `look_at` function does the same thing but with the
    /// `z` axis. See `look_at_z` for that.
    ///
    /// # Arguments
    ///   * eye - The new translation of the transformation.
    ///   * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
    ///   aligned with
    ///   * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at(&mut self, eye: &Vec3<N>, at: &Vec3<N>, up: &Vec3<N>) {
        self.submat.look_at(&(*at - *eye), up);
        self.subtrans = eye.clone();
    }

    /// Reorient and translate this transformation such that its local `z` axis points to a given
    /// direction.
    ///
    /// # Arguments
    ///   * eye - The new translation of the transformation.
    ///   * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
    ///   aligned with
    ///   * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at_z(&mut self, eye: &Vec3<N>, at: &Vec3<N>, up: &Vec3<N>) {
        self.submat.look_at_z(&(*at - *eye), up);
        self.subtrans = eye.clone();
    }
}

impl<M: Dim, V> Dim for Transform<M, V> {
    #[inline]
    fn dim() -> uint {
        Dim::dim::<M>()
    }
}

impl<M: One, V: Zero> One for Transform<M, V> {
    #[inline]
    fn one() -> Transform<M, V> {
        Transform {
            submat: One::one(), subtrans: Zero::zero()
        }
    }
}

impl<M: Zero, V: Zero> Zero for Transform<M, V> {
    #[inline]
    fn zero() -> Transform<M, V> {
        Transform {
            submat: Zero::zero(), subtrans: Zero::zero()
        }
    }

    #[inline]
    fn is_zero(&self) -> bool {
        self.submat.is_zero() && self.subtrans.is_zero()
    }
}

impl<M: RMul<V> + Mul<M, M>, V: Add<V, V>>
Mul<Transform<M, V>, Transform<M, V>> for Transform<M, V> {
    #[inline]
    fn mul(&self, other: &Transform<M, V>) -> Transform<M, V> {
        Transform {
            submat:   self.submat * other.submat,
            subtrans: self.subtrans + self.submat.rmul(&other.subtrans)
        }
    }
}

impl<M: RMul<V>, V: Add<V, V>> RMul<V> for Transform<M, V> {
    #[inline]
    fn rmul(&self, other: &V) -> V {
        self.submat.rmul(other) + self.subtrans
    }
}

impl<M: LMul<V>, V: Add<V, V>> LMul<V> for Transform<M, V> {
    #[inline]
    fn lmul(&self, other: &V) -> V {
        self.submat.lmul(other) + self.subtrans
    }
}

impl<M: Clone, V: Translation<V>> Translation<V> for Transform<M, V> {
    #[inline]
    fn translation(&self) -> V {
        self.subtrans.translation()
    }

    #[inline]
    fn inv_translation(&self) -> V {
        self.subtrans.inv_translation()
    }

    #[inline]
    fn translate_by(&mut self, t: &V) {
        self.subtrans.translate_by(t)
    }

    #[inline]
    fn translated(&self, t: &V) -> Transform<M, V> {
        Transform::new(self.submat.clone(), self.subtrans.translated(t))
    }
}

impl<M: Translate<V>, V, _0> Translate<V> for Transform<M, _0> {
    #[inline]
    fn translate(&self, v: &V) -> V {
        self.submat.translate(v)
    }

    #[inline]
    fn inv_translate(&self, v: &V) -> V {
        self.submat.inv_translate(v)
    }
}

impl<M: Rotation<AV> + RMul<V> + One, V, AV>
Rotation<AV> for Transform<M, V> {
    #[inline]
    fn rotation(&self) -> AV {
        self.submat.rotation()
    }

    #[inline]
    fn inv_rotation(&self) -> AV {
        self.submat.inv_rotation()
    }

    #[inline]
    fn rotate_by(&mut self, rot: &AV) {
        // FIXME: this does not seem opitmal
        let mut delta = One::one::<M>();
        delta.rotate_by(rot);
        self.submat.rotate_by(rot);
        self.subtrans = delta.rmul(&self.subtrans);
    }

    #[inline]
    fn rotated(&self, rot: &AV) -> Transform<M, V> {
        // FIXME: this does not seem opitmal
        let delta = One::one::<M>().rotated(rot);

        Transform::new(self.submat.rotated(rot), delta.rmul(&self.subtrans))
    }
}

impl<M: Rotate<V>, V, _0> Rotate<V> for Transform<M, _0> {
    #[inline]
    fn rotate(&self, v: &V) -> V {
        self.submat.rotate(v)
    }

    #[inline]
    fn inv_rotate(&self, v: &V) -> V {
        self.submat.inv_rotate(v)
    }
}

impl<M: Inv + RMul<V> + Mul<M, M> + Clone, V: Add<V, V> + Neg<V> + Clone>
Transformation<Transform<M, V>> for Transform<M, V> {
    fn transformation(&self) -> Transform<M, V> {
        self.clone()
    }

    fn inv_transformation(&self) -> Transform<M, V> {
        // FIXME: fail or return a Some<Transform<M, V>> ?
        match self.inverse() {
            Some(t) => t,
            None    => fail!("This transformation was not inversible.")
        }
    }

    fn transform_by(&mut self, other: &Transform<M, V>) {
        *self = other * *self
    }

    fn transformed(&self, t: &Transform<M, V>) -> Transform<M, V> {
        t * *self
    }
}

impl<M: Ts<V>, V: Add<V, V> + Sub<V, V>>
Ts<V> for Transform<M, V> {
    #[inline]
    fn transform(&self, v: &V) -> V {
        self.submat.transform(v) + self.subtrans
    }

    #[inline]
    fn inv_transform(&self, v: &V) -> V {
        self.submat.inv_transform(&(v - self.subtrans))
    }
}

impl<M: Inv + RMul<V> + Clone, V: Neg<V> + Clone>
Inv for Transform<M, V> {
    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        if !self.submat.inplace_inverse() {
            false
        }
        else {
            self.subtrans = self.submat.rmul(&-self.subtrans);
            true
        }
    }

    #[inline]
    fn inverse(&self) -> Option<Transform<M, V>> {
        let mut res = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }
}

impl<M: ToHomogeneous<M2>, M2: Dim + Column<V>, V: Clone>
ToHomogeneous<M2> for Transform<M, V> {
    fn to_homogeneous(&self) -> M2 {
        let mut res = self.submat.to_homogeneous();

        // copy the translation
        let dim = Dim::dim::<M2>();

        res.set_column(dim - 1, self.subtrans.clone());

        res
    }
}

impl<M: Column<V> + Dim, M2: FromHomogeneous<M>, V>
FromHomogeneous<M> for Transform<M2, V> {
    fn from(m: &M) -> Transform<M2, V> {
        Transform::new(FromHomogeneous::from(m), m.column(Dim::dim::<M>() - 1))
    }
}

impl<N: ApproxEq<N>, M:ApproxEq<N>, V:ApproxEq<N>>
ApproxEq<N> for Transform<M, V> {
    #[inline]
    fn approx_epsilon() -> N {
        ApproxEq::approx_epsilon::<N, N>()
    }

    #[inline]
    fn approx_eq(&self, other: &Transform<M, V>) -> bool {
        self.submat.approx_eq(&other.submat) &&
            self.subtrans.approx_eq(&other.subtrans)
    }

    #[inline]
    fn approx_eq_eps(&self, other: &Transform<M, V>, epsilon: &N) -> bool {
        self.submat.approx_eq_eps(&other.submat, epsilon) &&
            self.subtrans.approx_eq_eps(&other.subtrans, epsilon)
    }
}

impl<M: Rand, V: Rand> Rand for Transform<M, V> {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> Transform<M, V> {
        Transform::new(rng.gen(), rng.gen())
    }
}
<commit_msg>Fix Transform adaptor ToHomogeneous implementation.<commit_after>use std::num::{One, Zero};
use std::rand::{Rand, Rng, RngUtil};
use std::cmp::ApproxEq;
use traits::dim::Dim;
use traits::inv::Inv;
use traits::rotation::{Rotation, Rotate};
use traits::translation::{Translation, Translate};
use Ts = traits::transformation::Transform;
use traits::transformation::{Transformation};
use traits::rlmul::{RMul, LMul};
use traits::homogeneous::{ToHomogeneous, FromHomogeneous};
use traits::column::Column;
use adaptors::rotmat::Rotmat;
use vec::Vec3;
use mat::Mat3;

/// Matrix-Vector wrapper used to represent a matrix multiplication followed by a translation.
/// Usually, a matrix in homogeneous coordinate is used to be able to apply an affine transform with
/// a translation to a vector. This is weird because it makes a `n`-dimentional transformation be
/// an `n + 1`-matrix. Using the `Transform` wrapper avoid homogeneous coordinates by having the
/// translation separate from the other transformations. This is particularity useful when the
/// underlying transform is a rotation (see `Rotmat`): this makes inversion much faster than
/// inverting the homogeneous matrix itself.
#[deriving(Eq, ToStr, Clone)]
pub struct Transform<M, V> {
    priv submat   : M,
    priv subtrans : V
}

impl<M, V> Transform<M, V> {
    /// Builds a new transform from a matrix and a vector.
    #[inline]
    pub fn new(mat: M, trans: V) -> Transform<M, V> {
        Transform {
            submat:   mat,
            subtrans: trans
        }
    }
}

impl<M: Clone, V: Clone> Transform<M, V> {
    /// Gets a copy of the internal matrix.
    #[inline]
    pub fn submat(&self) -> M {
        self.submat.clone()
    }

    /// Gets a copy of the internal translation.
    #[inline]
    pub fn subtrans(&self) -> V {
        self.subtrans.clone()
    }
}

impl<N: Clone + Num + Algebraic> Transform<Rotmat<Mat3<N>>, Vec3<N>> {
    /// Reorient and translate this transformation such that its local `x` axis points to a given
    /// direction.  Note that the usually known `look_at` function does the same thing but with the
    /// `z` axis. See `look_at_z` for that.
    ///
    /// # Arguments
    ///   * eye - The new translation of the transformation.
    ///   * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
    ///   aligned with
    ///   * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at(&mut self, eye: &Vec3<N>, at: &Vec3<N>, up: &Vec3<N>) {
        self.submat.look_at(&(*at - *eye), up);
        self.subtrans = eye.clone();
    }

    /// Reorient and translate this transformation such that its local `z` axis points to a given
    /// direction.
    ///
    /// # Arguments
    ///   * eye - The new translation of the transformation.
    ///   * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
    ///   aligned with
    ///   * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at_z(&mut self, eye: &Vec3<N>, at: &Vec3<N>, up: &Vec3<N>) {
        self.submat.look_at_z(&(*at - *eye), up);
        self.subtrans = eye.clone();
    }
}

impl<M: Dim, V> Dim for Transform<M, V> {
    #[inline]
    fn dim() -> uint {
        Dim::dim::<M>()
    }
}

impl<M: One, V: Zero> One for Transform<M, V> {
    #[inline]
    fn one() -> Transform<M, V> {
        Transform {
            submat: One::one(), subtrans: Zero::zero()
        }
    }
}

impl<M: Zero, V: Zero> Zero for Transform<M, V> {
    #[inline]
    fn zero() -> Transform<M, V> {
        Transform {
            submat: Zero::zero(), subtrans: Zero::zero()
        }
    }

    #[inline]
    fn is_zero(&self) -> bool {
        self.submat.is_zero() && self.subtrans.is_zero()
    }
}

impl<M: RMul<V> + Mul<M, M>, V: Add<V, V>>
Mul<Transform<M, V>, Transform<M, V>> for Transform<M, V> {
    #[inline]
    fn mul(&self, other: &Transform<M, V>) -> Transform<M, V> {
        Transform {
            submat:   self.submat * other.submat,
            subtrans: self.subtrans + self.submat.rmul(&other.subtrans)
        }
    }
}

impl<M: RMul<V>, V: Add<V, V>> RMul<V> for Transform<M, V> {
    #[inline]
    fn rmul(&self, other: &V) -> V {
        self.submat.rmul(other) + self.subtrans
    }
}

impl<M: LMul<V>, V: Add<V, V>> LMul<V> for Transform<M, V> {
    #[inline]
    fn lmul(&self, other: &V) -> V {
        self.submat.lmul(other) + self.subtrans
    }
}

impl<M: Clone, V: Translation<V>> Translation<V> for Transform<M, V> {
    #[inline]
    fn translation(&self) -> V {
        self.subtrans.translation()
    }

    #[inline]
    fn inv_translation(&self) -> V {
        self.subtrans.inv_translation()
    }

    #[inline]
    fn translate_by(&mut self, t: &V) {
        self.subtrans.translate_by(t)
    }

    #[inline]
    fn translated(&self, t: &V) -> Transform<M, V> {
        Transform::new(self.submat.clone(), self.subtrans.translated(t))
    }
}

impl<M: Translate<V>, V, _0> Translate<V> for Transform<M, _0> {
    #[inline]
    fn translate(&self, v: &V) -> V {
        self.submat.translate(v)
    }

    #[inline]
    fn inv_translate(&self, v: &V) -> V {
        self.submat.inv_translate(v)
    }
}

impl<M: Rotation<AV> + RMul<V> + One, V, AV>
Rotation<AV> for Transform<M, V> {
    #[inline]
    fn rotation(&self) -> AV {
        self.submat.rotation()
    }

    #[inline]
    fn inv_rotation(&self) -> AV {
        self.submat.inv_rotation()
    }

    #[inline]
    fn rotate_by(&mut self, rot: &AV) {
        // FIXME: this does not seem opitmal
        let mut delta = One::one::<M>();
        delta.rotate_by(rot);
        self.submat.rotate_by(rot);
        self.subtrans = delta.rmul(&self.subtrans);
    }

    #[inline]
    fn rotated(&self, rot: &AV) -> Transform<M, V> {
        // FIXME: this does not seem opitmal
        let delta = One::one::<M>().rotated(rot);

        Transform::new(self.submat.rotated(rot), delta.rmul(&self.subtrans))
    }
}

impl<M: Rotate<V>, V, _0> Rotate<V> for Transform<M, _0> {
    #[inline]
    fn rotate(&self, v: &V) -> V {
        self.submat.rotate(v)
    }

    #[inline]
    fn inv_rotate(&self, v: &V) -> V {
        self.submat.inv_rotate(v)
    }
}

impl<M: Inv + RMul<V> + Mul<M, M> + Clone, V: Add<V, V> + Neg<V> + Clone>
Transformation<Transform<M, V>> for Transform<M, V> {
    fn transformation(&self) -> Transform<M, V> {
        self.clone()
    }

    fn inv_transformation(&self) -> Transform<M, V> {
        // FIXME: fail or return a Some<Transform<M, V>> ?
        match self.inverse() {
            Some(t) => t,
            None    => fail!("This transformation was not inversible.")
        }
    }

    fn transform_by(&mut self, other: &Transform<M, V>) {
        *self = other * *self
    }

    fn transformed(&self, t: &Transform<M, V>) -> Transform<M, V> {
        t * *self
    }
}

impl<M: Ts<V>, V: Add<V, V> + Sub<V, V>>
Ts<V> for Transform<M, V> {
    #[inline]
    fn transform(&self, v: &V) -> V {
        self.submat.transform(v) + self.subtrans
    }

    #[inline]
    fn inv_transform(&self, v: &V) -> V {
        self.submat.inv_transform(&(v - self.subtrans))
    }
}

impl<M: Inv + RMul<V> + Clone, V: Neg<V> + Clone>
Inv for Transform<M, V> {
    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        if !self.submat.inplace_inverse() {
            false
        }
        else {
            self.subtrans = self.submat.rmul(&-self.subtrans);
            true
        }
    }

    #[inline]
    fn inverse(&self) -> Option<Transform<M, V>> {
        let mut res = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }
}

impl<M: ToHomogeneous<M2>, M2: Dim + Column<V2>, V: ToHomogeneous<V2> + Clone, V2>
ToHomogeneous<M2> for Transform<M, V> {
    fn to_homogeneous(&self) -> M2 {
        let mut res = self.submat.to_homogeneous();

        // copy the translation
        let dim = Dim::dim::<M2>();

        res.set_column(dim - 1, self.subtrans.to_homogeneous());

        res
    }
}

impl<M: Column<V> + Dim, M2: FromHomogeneous<M>, V>
FromHomogeneous<M> for Transform<M2, V> {
    fn from(m: &M) -> Transform<M2, V> {
        Transform::new(FromHomogeneous::from(m), m.column(Dim::dim::<M>() - 1))
    }
}

impl<N: ApproxEq<N>, M:ApproxEq<N>, V:ApproxEq<N>>
ApproxEq<N> for Transform<M, V> {
    #[inline]
    fn approx_epsilon() -> N {
        ApproxEq::approx_epsilon::<N, N>()
    }

    #[inline]
    fn approx_eq(&self, other: &Transform<M, V>) -> bool {
        self.submat.approx_eq(&other.submat) &&
            self.subtrans.approx_eq(&other.subtrans)
    }

    #[inline]
    fn approx_eq_eps(&self, other: &Transform<M, V>, epsilon: &N) -> bool {
        self.submat.approx_eq_eps(&other.submat, epsilon) &&
            self.subtrans.approx_eq_eps(&other.subtrans, epsilon)
    }
}

impl<M: Rand, V: Rand> Rand for Transform<M, V> {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> Transform<M, V> {
        Transform::new(rng.gen(), rng.gen())
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

#[macro_use]
extern crate lazy_static;

use background_hang_monitor::HangMonitorRegister;
use ipc_channel::ipc;
use msg::constellation_msg::ScriptHangAnnotation;
use msg::constellation_msg::TEST_PIPELINE_ID;
use msg::constellation_msg::{HangAlert, HangAnnotation, HangMonitorAlert};
use msg::constellation_msg::{MonitoredComponentId, MonitoredComponentType};
use std::sync::Mutex;
use std::thread;
use std::time::Duration;

lazy_static! {
    static ref SERIAL: Mutex<()> = Mutex::new(());
}

#[test]
#[cfg(any(target_os = "macos", target_os = "linux"))]
fn test_sampler() {
    let _lock = SERIAL.lock().unwrap();

    use msg::constellation_msg::SamplerControlMsg;
    use serde_json::Value;

    let (background_hang_monitor_ipc_sender, background_hang_monitor_receiver) =
        ipc::channel().expect("ipc channel failure");
    let (sampler_sender, sampler_receiver) = ipc::channel().expect("ipc channel failure");

    let background_hang_monitor_register =
        HangMonitorRegister::init(background_hang_monitor_ipc_sender.clone(), sampler_receiver);
    let _background_hang_monitor = background_hang_monitor_register.register_component(
        MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script),
        Duration::from_millis(10),
        Duration::from_millis(1000),
    );

    const RATE: u64 = 10;
    const MAX_DURATION: u64 = 10;
    sampler_sender
        .send(SamplerControlMsg::Enable(
            Duration::from_millis(RATE),
            Duration::from_secs(MAX_DURATION),
        ))
        .unwrap();

    thread::sleep(Duration::from_millis(100));

    sampler_sender.send(SamplerControlMsg::Disable).unwrap();

    loop {
        match background_hang_monitor_receiver.recv().unwrap() {
            HangMonitorAlert::Hang(_) => continue,
            HangMonitorAlert::Profile(ref bytes) => {
                let json: Value = serde_json::from_slice(bytes).unwrap();
                let rate = json["rate"].as_u64().unwrap();
                assert_eq!(rate, RATE);
                let data = json["data"].as_array().unwrap();
                assert!(data.len() > 1);
                assert_eq!(data[0]["name"].as_str().unwrap(), "test_sampler");
                assert!(data[0]["frames"].as_array().unwrap().len() > 0);
                break;
            },
        }
    }
}

#[test]
fn test_hang_monitoring() {
    let _lock = SERIAL.lock().unwrap();

    let (background_hang_monitor_ipc_sender, background_hang_monitor_receiver) =
        ipc::channel().expect("ipc channel failure");
    let (_sampler_sender, sampler_receiver) = ipc::channel().expect("ipc channel failure");

    let background_hang_monitor_register =
        HangMonitorRegister::init(background_hang_monitor_ipc_sender.clone(), sampler_receiver);
    let background_hang_monitor = background_hang_monitor_register.register_component(
        MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script),
        Duration::from_millis(10),
        Duration::from_millis(1000),
    );

    // Start an activity.
    let hang_annotation = HangAnnotation::Script(ScriptHangAnnotation::AttachLayout);
    background_hang_monitor.notify_activity(hang_annotation);

    // Sleep until the "transient" timeout has been reached.
    thread::sleep(Duration::from_millis(10));

    // Check for a transient hang alert.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangMonitorAlert::Hang(HangAlert::Transient(component_id, _annotation)) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        _ => unreachable!(),
    }

    // Sleep until the "permanent" timeout has been reached.
    thread::sleep(Duration::from_millis(1000));

    // Check for a permanent hang alert.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangMonitorAlert::Hang(HangAlert::Permanent(component_id, _annotation, _profile)) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        _ => unreachable!(),
    }

    // Now the component is not hanging anymore.
    background_hang_monitor.notify_activity(hang_annotation);
    assert!(background_hang_monitor_receiver.try_recv().is_err());

    // Sleep for a while.
    thread::sleep(Duration::from_millis(10));

    // Check for a transient hang alert.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangMonitorAlert::Hang(HangAlert::Transient(component_id, _annotation)) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        _ => unreachable!(),
    }

    // Now the component is waiting for a new task.
    background_hang_monitor.notify_wait();

    // Sleep for a while.
    thread::sleep(Duration::from_millis(100));

    // The component is still waiting, but not hanging.
    assert!(background_hang_monitor_receiver.try_recv().is_err());

    // New task handling starts.
    background_hang_monitor.notify_activity(hang_annotation);

    // Sleep for a while.
    thread::sleep(Duration::from_millis(10));

    // We're getting new hang alerts for the latest task.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangMonitorAlert::Hang(HangAlert::Transient(component_id, _annotation)) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        _ => unreachable!(),
    }

    // No new alert yet
    assert!(background_hang_monitor_receiver.try_recv().is_err());

    // Shut-down the hang monitor
    drop(background_hang_monitor_register);
    drop(background_hang_monitor);

    // Sleep until the "max-timeout" has been reached.
    thread::sleep(Duration::from_millis(1000));

    // Still no new alerts because the hang monitor has shut-down already.
    assert!(background_hang_monitor_receiver.try_recv().is_err());
}

#[test]
fn test_hang_monitoring_unregister() {
    let _lock = SERIAL.lock().unwrap();

    let (background_hang_monitor_ipc_sender, background_hang_monitor_receiver) =
        ipc::channel().expect("ipc channel failure");
    let (_sampler_sender, sampler_receiver) = ipc::channel().expect("ipc channel failure");

    let background_hang_monitor_register =
        HangMonitorRegister::init(background_hang_monitor_ipc_sender.clone(), sampler_receiver);
    let background_hang_monitor = background_hang_monitor_register.register_component(
        MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script),
        Duration::from_millis(10),
        Duration::from_millis(1000),
    );

    // Start an activity.
    let hang_annotation = HangAnnotation::Script(ScriptHangAnnotation::AttachLayout);
    background_hang_monitor.notify_activity(hang_annotation);

    // Unregister the component.
    background_hang_monitor.unregister();

    // Sleep until the "transient" timeout has been reached.
    thread::sleep(Duration::from_millis(10));

    // No new alert yet
    assert!(background_hang_monitor_receiver.try_recv().is_err());
}
<commit_msg>Remove sampling profiler unit test.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

#[macro_use]
extern crate lazy_static;

use background_hang_monitor::HangMonitorRegister;
use ipc_channel::ipc;
use msg::constellation_msg::ScriptHangAnnotation;
use msg::constellation_msg::TEST_PIPELINE_ID;
use msg::constellation_msg::{HangAlert, HangAnnotation, HangMonitorAlert};
use msg::constellation_msg::{MonitoredComponentId, MonitoredComponentType};
use std::sync::Mutex;
use std::thread;
use std::time::Duration;

lazy_static! {
    static ref SERIAL: Mutex<()> = Mutex::new(());
}

#[test]
fn test_hang_monitoring() {
    let _lock = SERIAL.lock().unwrap();

    let (background_hang_monitor_ipc_sender, background_hang_monitor_receiver) =
        ipc::channel().expect("ipc channel failure");
    let (_sampler_sender, sampler_receiver) = ipc::channel().expect("ipc channel failure");

    let background_hang_monitor_register =
        HangMonitorRegister::init(background_hang_monitor_ipc_sender.clone(), sampler_receiver);
    let background_hang_monitor = background_hang_monitor_register.register_component(
        MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script),
        Duration::from_millis(10),
        Duration::from_millis(1000),
    );

    // Start an activity.
    let hang_annotation = HangAnnotation::Script(ScriptHangAnnotation::AttachLayout);
    background_hang_monitor.notify_activity(hang_annotation);

    // Sleep until the "transient" timeout has been reached.
    thread::sleep(Duration::from_millis(10));

    // Check for a transient hang alert.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangMonitorAlert::Hang(HangAlert::Transient(component_id, _annotation)) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        _ => unreachable!(),
    }

    // Sleep until the "permanent" timeout has been reached.
    thread::sleep(Duration::from_millis(1000));

    // Check for a permanent hang alert.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangMonitorAlert::Hang(HangAlert::Permanent(component_id, _annotation, _profile)) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        _ => unreachable!(),
    }

    // Now the component is not hanging anymore.
    background_hang_monitor.notify_activity(hang_annotation);
    assert!(background_hang_monitor_receiver.try_recv().is_err());

    // Sleep for a while.
    thread::sleep(Duration::from_millis(10));

    // Check for a transient hang alert.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangMonitorAlert::Hang(HangAlert::Transient(component_id, _annotation)) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        _ => unreachable!(),
    }

    // Now the component is waiting for a new task.
    background_hang_monitor.notify_wait();

    // Sleep for a while.
    thread::sleep(Duration::from_millis(100));

    // The component is still waiting, but not hanging.
    assert!(background_hang_monitor_receiver.try_recv().is_err());

    // New task handling starts.
    background_hang_monitor.notify_activity(hang_annotation);

    // Sleep for a while.
    thread::sleep(Duration::from_millis(10));

    // We're getting new hang alerts for the latest task.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangMonitorAlert::Hang(HangAlert::Transient(component_id, _annotation)) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        _ => unreachable!(),
    }

    // No new alert yet
    assert!(background_hang_monitor_receiver.try_recv().is_err());

    // Shut-down the hang monitor
    drop(background_hang_monitor_register);
    drop(background_hang_monitor);

    // Sleep until the "max-timeout" has been reached.
    thread::sleep(Duration::from_millis(1000));

    // Still no new alerts because the hang monitor has shut-down already.
    assert!(background_hang_monitor_receiver.try_recv().is_err());
}

#[test]
fn test_hang_monitoring_unregister() {
    let _lock = SERIAL.lock().unwrap();

    let (background_hang_monitor_ipc_sender, background_hang_monitor_receiver) =
        ipc::channel().expect("ipc channel failure");
    let (_sampler_sender, sampler_receiver) = ipc::channel().expect("ipc channel failure");

    let background_hang_monitor_register =
        HangMonitorRegister::init(background_hang_monitor_ipc_sender.clone(), sampler_receiver);
    let background_hang_monitor = background_hang_monitor_register.register_component(
        MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script),
        Duration::from_millis(10),
        Duration::from_millis(1000),
    );

    // Start an activity.
    let hang_annotation = HangAnnotation::Script(ScriptHangAnnotation::AttachLayout);
    background_hang_monitor.notify_activity(hang_annotation);

    // Unregister the component.
    background_hang_monitor.unregister();

    // Sleep until the "transient" timeout has been reached.
    thread::sleep(Duration::from_millis(10));

    // No new alert yet
    assert!(background_hang_monitor_receiver.try_recv().is_err());
}
<|endoftext|>


<commit_before>#![feature(no_core, lang_items, intrinsics, unboxed_closures)]
#![no_core]
#![allow(dead_code)]

#[lang = "sized"]
pub trait Sized {}

#[lang = "unsize"]
pub trait Unsize<T: ?Sized> {}

#[lang = "coerce_unsized"]
pub trait CoerceUnsized<T> {}

impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}

#[lang = "copy"]
pub unsafe trait Copy {}

unsafe impl Copy for bool {}
unsafe impl Copy for u8 {}
unsafe impl Copy for u16 {}
unsafe impl Copy for u32 {}
unsafe impl Copy for u64 {}
unsafe impl Copy for usize {}
unsafe impl Copy for i8 {}
unsafe impl Copy for i16 {}
unsafe impl Copy for i32 {}
unsafe impl Copy for isize {}
unsafe impl Copy for char {}
unsafe impl<'a, T: ?Sized> Copy for &'a T {}
unsafe impl<T: ?Sized> Copy for *const T {}

#[lang = "sync"]
pub unsafe trait Sync {}

unsafe impl Sync for bool {}
unsafe impl Sync for u8 {}
unsafe impl Sync for u16 {}
unsafe impl Sync for u32 {}
unsafe impl Sync for u64 {}
unsafe impl Sync for usize {}
unsafe impl Sync for i8 {}
unsafe impl Sync for i16 {}
unsafe impl Sync for i32 {}
unsafe impl Sync for isize {}
unsafe impl Sync for char {}
unsafe impl<'a, T: ?Sized> Sync for &'a T {}

#[lang = "freeze"]
trait Freeze {}

#[lang = "mul"]
pub trait Mul<RHS = Self> {
    type Output;

    #[must_use]
    fn mul(self, rhs: RHS) -> Self::Output;
}

impl Mul for u8 {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self::Output {
        self * rhs
    }
}

#[lang = "add"]
pub trait Add<RHS = Self> {
    type Output;

    fn add(self, rhs: RHS) -> Self::Output;
}

impl Add for u8 {
    type Output = Self;

    fn add(self, rhs: Self) -> Self {
        self + rhs
    }
}

#[lang = "sub"]
pub trait Sub<RHS = Self> {
    type Output;

    fn sub(self, rhs: RHS) -> Self::Output;
}

impl Sub for usize {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self {
        self - rhs
    }
}

#[lang = "bitor"]
pub trait BitOr<RHS = Self> {
    type Output;

    #[must_use]
    fn bitor(self, rhs: RHS) -> Self::Output;
}

impl BitOr for bool {
    type Output = bool;

    fn bitor(self, rhs: bool) -> bool {
        self | rhs
    }
}

impl<'a> BitOr<bool> for &'a bool {
    type Output = bool;

    fn bitor(self, rhs: bool) -> bool {
        *self | rhs
    }
}

#[lang = "eq"]
pub trait PartialEq<Rhs: ?Sized = Self> {
    fn eq(&self, other: &Rhs) -> bool;
    fn ne(&self, other: &Rhs) -> bool;
}

impl PartialEq for u8 {
    fn eq(&self, other: &u8) -> bool {
        (*self) == (*other)
    }
    fn ne(&self, other: &u8) -> bool {
        (*self) != (*other)
    }
}

impl PartialEq for char {
    fn eq(&self, other: &char) -> bool {
        (*self) == (*other)
    }
    fn ne(&self, other: &char) -> bool {
        (*self) != (*other)
    }
}

impl<T: ?Sized> PartialEq for *const T {
    fn eq(&self, other: &*const T) -> bool {
        *self == *other
    }
    fn ne(&self, other: &*const T) -> bool {
        *self != *other
    }
}

#[lang = "fn_once"]
#[rustc_paren_sugar]
pub trait FnOnce<Args> {
    type Output;

    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}

#[lang = "fn_mut"]
#[rustc_paren_sugar]
pub trait FnMut<Args>: FnOnce<Args> {
    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}

#[lang = "panic"]
pub fn panic(_expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! {
    loop {}
}

#[lang = "eh_personality"]
fn eh_personality() -> ! {
    loop {}
}

#[lang = "drop_in_place"]
#[allow(unconditional_recursion)]
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
    // Code here does not matter - this is replaced by the
    // real drop glue by the compiler.
    drop_in_place(to_drop);
}

pub mod intrinsics {
    extern "rust-intrinsic" {
        pub fn size_of<T>() -> usize;
        pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
        pub fn transmute<T, U>(e: T) -> U;
        pub fn uninit<T>() -> T;
        pub fn ctlz_nonzero<T>(x: T) -> T;
    }
}

#[lang = "index"]
pub trait Index<Idx: ?Sized> {
    type Output: ?Sized;
    fn index(&self, index: Idx) -> &Self::Output;
}

impl<T> Index<usize> for [T; 3] {
    type Output = T;

    fn index(&self, index: usize) -> &Self::Output {
        &self[index]
    }
}

impl<T> Index<usize> for [T] {
    type Output = T;

    fn index(&self, index: usize) -> &Self::Output {
        &self[index]
    }
}
<commit_msg>Replace infinite loop in mini_core::panic with intrinsic::abort<commit_after>#![feature(no_core, lang_items, intrinsics, unboxed_closures)]
#![no_core]
#![allow(dead_code)]

#[lang = "sized"]
pub trait Sized {}

#[lang = "unsize"]
pub trait Unsize<T: ?Sized> {}

#[lang = "coerce_unsized"]
pub trait CoerceUnsized<T> {}

impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}

#[lang = "copy"]
pub unsafe trait Copy {}

unsafe impl Copy for bool {}
unsafe impl Copy for u8 {}
unsafe impl Copy for u16 {}
unsafe impl Copy for u32 {}
unsafe impl Copy for u64 {}
unsafe impl Copy for usize {}
unsafe impl Copy for i8 {}
unsafe impl Copy for i16 {}
unsafe impl Copy for i32 {}
unsafe impl Copy for isize {}
unsafe impl Copy for char {}
unsafe impl<'a, T: ?Sized> Copy for &'a T {}
unsafe impl<T: ?Sized> Copy for *const T {}

#[lang = "sync"]
pub unsafe trait Sync {}

unsafe impl Sync for bool {}
unsafe impl Sync for u8 {}
unsafe impl Sync for u16 {}
unsafe impl Sync for u32 {}
unsafe impl Sync for u64 {}
unsafe impl Sync for usize {}
unsafe impl Sync for i8 {}
unsafe impl Sync for i16 {}
unsafe impl Sync for i32 {}
unsafe impl Sync for isize {}
unsafe impl Sync for char {}
unsafe impl<'a, T: ?Sized> Sync for &'a T {}

#[lang = "freeze"]
trait Freeze {}

#[lang = "mul"]
pub trait Mul<RHS = Self> {
    type Output;

    #[must_use]
    fn mul(self, rhs: RHS) -> Self::Output;
}

impl Mul for u8 {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self::Output {
        self * rhs
    }
}

#[lang = "add"]
pub trait Add<RHS = Self> {
    type Output;

    fn add(self, rhs: RHS) -> Self::Output;
}

impl Add for u8 {
    type Output = Self;

    fn add(self, rhs: Self) -> Self {
        self + rhs
    }
}

#[lang = "sub"]
pub trait Sub<RHS = Self> {
    type Output;

    fn sub(self, rhs: RHS) -> Self::Output;
}

impl Sub for usize {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self {
        self - rhs
    }
}

#[lang = "bitor"]
pub trait BitOr<RHS = Self> {
    type Output;

    #[must_use]
    fn bitor(self, rhs: RHS) -> Self::Output;
}

impl BitOr for bool {
    type Output = bool;

    fn bitor(self, rhs: bool) -> bool {
        self | rhs
    }
}

impl<'a> BitOr<bool> for &'a bool {
    type Output = bool;

    fn bitor(self, rhs: bool) -> bool {
        *self | rhs
    }
}

#[lang = "eq"]
pub trait PartialEq<Rhs: ?Sized = Self> {
    fn eq(&self, other: &Rhs) -> bool;
    fn ne(&self, other: &Rhs) -> bool;
}

impl PartialEq for u8 {
    fn eq(&self, other: &u8) -> bool {
        (*self) == (*other)
    }
    fn ne(&self, other: &u8) -> bool {
        (*self) != (*other)
    }
}

impl PartialEq for char {
    fn eq(&self, other: &char) -> bool {
        (*self) == (*other)
    }
    fn ne(&self, other: &char) -> bool {
        (*self) != (*other)
    }
}

impl<T: ?Sized> PartialEq for *const T {
    fn eq(&self, other: &*const T) -> bool {
        *self == *other
    }
    fn ne(&self, other: &*const T) -> bool {
        *self != *other
    }
}

#[lang = "fn_once"]
#[rustc_paren_sugar]
pub trait FnOnce<Args> {
    type Output;

    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}

#[lang = "fn_mut"]
#[rustc_paren_sugar]
pub trait FnMut<Args>: FnOnce<Args> {
    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}

#[lang = "panic"]
pub fn panic(_expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! {
    unsafe {
        intrinsics::abort();
    }
}

#[lang = "eh_personality"]
fn eh_personality() -> ! {
    loop {}
}

#[lang = "drop_in_place"]
#[allow(unconditional_recursion)]
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
    // Code here does not matter - this is replaced by the
    // real drop glue by the compiler.
    drop_in_place(to_drop);
}

pub mod intrinsics {
    extern "rust-intrinsic" {
        pub fn abort() -> !;
        pub fn size_of<T>() -> usize;
        pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
        pub fn transmute<T, U>(e: T) -> U;
        pub fn uninit<T>() -> T;
        pub fn ctlz_nonzero<T>(x: T) -> T;
    }
}

#[lang = "index"]
pub trait Index<Idx: ?Sized> {
    type Output: ?Sized;
    fn index(&self, index: Idx) -> &Self::Output;
}

impl<T> Index<usize> for [T; 3] {
    type Output = T;

    fn index(&self, index: usize) -> &Self::Output {
        &self[index]
    }
}

impl<T> Index<usize> for [T] {
    type Output = T;

    fn index(&self, index: usize) -> &Self::Output {
        &self[index]
    }
}
<|endoftext|>


<commit_before>use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::{au, px_to_au};
use libc::{c_void};
use font_library::FontLibrary;
use font::Font;
use glyph::Glyph;
use shaper::shape_text;

#[doc="A single, unbroken line of text."]
struct TextRun {
    priv glyphs: ~[Glyph],
    priv size_: Size2D<au>,
    priv min_break_width_: au,
}

impl TextRun {
    /// The size of the entire TextRun
    fn size() -> Size2D<au> { self.size_ }
    fn min_break_width() -> au { self.min_break_width_ }
}

fn TextRun(font: &Font, text: ~str) -> TextRun {
    let glyphs = shape_text(font, text);
    let size = glyph_run_size(glyphs);
    let min_break_width = calc_min_break_width(font, text);

    TextRun {
        glyphs: shape_text(font, text),
        size_: size,
        min_break_width_: min_break_width
    }
}

fn glyph_run_size(glyphs: &[Glyph]) -> Size2D<au> {
    let height = px_to_au(20);
    let pen_start_x = px_to_au(0);
    let pen_start_y = height;
    let pen_start = Point2D(pen_start_x, pen_start_y);
    let pen_end = glyphs.foldl(pen_start, |cur, glyph| {
        Point2D(cur.x.add(glyph.pos.offset.x).add(glyph.pos.advance.x),
                cur.y.add(glyph.pos.offset.y).add(glyph.pos.advance.y))
    });
    return Size2D(pen_end.x, pen_end.y);
}

/// Discovers the width of the largest indivisible substring
fn calc_min_break_width(font: &Font, text: &str) -> au {
    let mut max_piece_width = au(0);
    do iter_indivisible_slices(font, text) |slice| {
        let glyphs = shape_text(font, slice);
        let size = glyph_run_size(glyphs);
        if size.width > max_piece_width {
            max_piece_width = size.width
        }
    }
    return max_piece_width;
}

/// Iterates over all the indivisible substrings
fn iter_indivisible_slices(font: &Font, text: &r/str,
                           f: fn((&r/str))) {

    let mut curr = text;
    loop {
        match str::find(curr, |c| !char::is_whitespace(c) ) {
          Some(idx) => {
            curr = str::view(curr, idx, curr.len());
          }
          None => {
            // Everything else is whitespace
            break
          }
        }

        match str::find(curr, |c| char::is_whitespace(c) ) {
          Some(idx) => {
            let piece = str::view(curr, 0, idx);
            f(piece);
            curr = str::view(curr, idx, curr.len());
          }
          None => {
            assert curr.is_not_empty();
            f(curr);
            // This is the end of the string
            break;
          }
        }
    }
}

#[test]
fn test_calc_min_break_width1() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"firecracker");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_calc_min_break_width2() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"firecracker yumyum");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_calc_min_break_width3() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"yumyum firecracker");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_calc_min_break_width4() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"yumyum firecracker yumyum");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_iter_indivisible_slices() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "firecracker yumyum woopwoop") |slice| {
        slices += [slice];
    }
    assert slices == ~["firecracker", "yumyum", "woopwoop"];
}

#[test]
fn test_iter_indivisible_slices_trailing_whitespace() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "firecracker  ") |slice| {
        slices += [slice];
    }
    assert slices == ~["firecracker"];
}

#[test]
fn test_iter_indivisible_slices_leading_whitespace() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "  firecracker") |slice| {
        slices += [slice];
    }
    assert slices == ~["firecracker"];
}

#[test]
fn test_iter_indivisible_slices_empty() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "") |slice| {
        slices += [slice];
    }
    assert slices == ~[];
}

fn should_calculate_the_total_size() {
    #[test];
    #[ignore(cfg(target_os = "macos"))];

    let flib = FontLibrary();
    let font = flib.get_test_font();
    let run = TextRun(font, ~"firecracker");
    let expected = Size2D(px_to_au(84), px_to_au(20));
    assert run.size() == expected;
}

<commit_msg>Remove doc attrs from text_run<commit_after>use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::{au, px_to_au};
use libc::{c_void};
use font_library::FontLibrary;
use font::Font;
use glyph::Glyph;
use shaper::shape_text;

/// A single, unbroken line of text
struct TextRun {
    priv glyphs: ~[Glyph],
    priv size_: Size2D<au>,
    priv min_break_width_: au,
}

impl TextRun {
    /// The size of the entire TextRun
    fn size() -> Size2D<au> { self.size_ }
    fn min_break_width() -> au { self.min_break_width_ }
}

fn TextRun(font: &Font, text: ~str) -> TextRun {
    let glyphs = shape_text(font, text);
    let size = glyph_run_size(glyphs);
    let min_break_width = calc_min_break_width(font, text);

    TextRun {
        glyphs: shape_text(font, text),
        size_: size,
        min_break_width_: min_break_width
    }
}

fn glyph_run_size(glyphs: &[Glyph]) -> Size2D<au> {
    let height = px_to_au(20);
    let pen_start_x = px_to_au(0);
    let pen_start_y = height;
    let pen_start = Point2D(pen_start_x, pen_start_y);
    let pen_end = glyphs.foldl(pen_start, |cur, glyph| {
        Point2D(cur.x.add(glyph.pos.offset.x).add(glyph.pos.advance.x),
                cur.y.add(glyph.pos.offset.y).add(glyph.pos.advance.y))
    });
    return Size2D(pen_end.x, pen_end.y);
}

/// Discovers the width of the largest indivisible substring
fn calc_min_break_width(font: &Font, text: &str) -> au {
    let mut max_piece_width = au(0);
    do iter_indivisible_slices(font, text) |slice| {
        let glyphs = shape_text(font, slice);
        let size = glyph_run_size(glyphs);
        if size.width > max_piece_width {
            max_piece_width = size.width
        }
    }
    return max_piece_width;
}

/// Iterates over all the indivisible substrings
fn iter_indivisible_slices(font: &Font, text: &r/str,
                           f: fn((&r/str))) {

    let mut curr = text;
    loop {
        match str::find(curr, |c| !char::is_whitespace(c) ) {
          Some(idx) => {
            curr = str::view(curr, idx, curr.len());
          }
          None => {
            // Everything else is whitespace
            break
          }
        }

        match str::find(curr, |c| char::is_whitespace(c) ) {
          Some(idx) => {
            let piece = str::view(curr, 0, idx);
            f(piece);
            curr = str::view(curr, idx, curr.len());
          }
          None => {
            assert curr.is_not_empty();
            f(curr);
            // This is the end of the string
            break;
          }
        }
    }
}

#[test]
fn test_calc_min_break_width1() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"firecracker");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_calc_min_break_width2() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"firecracker yumyum");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_calc_min_break_width3() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"yumyum firecracker");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_calc_min_break_width4() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"yumyum firecracker yumyum");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_iter_indivisible_slices() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "firecracker yumyum woopwoop") |slice| {
        slices += [slice];
    }
    assert slices == ~["firecracker", "yumyum", "woopwoop"];
}

#[test]
fn test_iter_indivisible_slices_trailing_whitespace() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "firecracker  ") |slice| {
        slices += [slice];
    }
    assert slices == ~["firecracker"];
}

#[test]
fn test_iter_indivisible_slices_leading_whitespace() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "  firecracker") |slice| {
        slices += [slice];
    }
    assert slices == ~["firecracker"];
}

#[test]
fn test_iter_indivisible_slices_empty() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "") |slice| {
        slices += [slice];
    }
    assert slices == ~[];
}

fn should_calculate_the_total_size() {
    #[test];
    #[ignore(cfg(target_os = "macos"))];

    let flib = FontLibrary();
    let font = flib.get_test_font();
    let run = TextRun(font, ~"firecracker");
    let expected = Size2D(px_to_au(84), px_to_au(20));
    assert run.size() == expected;
}

<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Timers for non-linux/non-windows OSes
//!
//! This module implements timers with a worker thread, select(), and a lot of
//! witchcraft that turns out to be horribly inaccurate timers. The unfortunate
//! part is that I'm at a loss of what else to do one these OSes. This is also
//! why linux has a specialized timerfd implementation and windows has its own
//! implementation (they're more accurate than this one).
//!
//! The basic idea is that there is a worker thread that's communicated to via a
//! channel and a pipe, the pipe is used by the worker thread in a select()
//! syscall with a timeout. The timeout is the "next timer timeout" while the
//! channel is used to send data over to the worker thread.
//!
//! Whenever the call to select() times out, then a channel receives a message.
//! Whenever the call returns that the file descriptor has information, then the
//! channel from timers is drained, enqueueing all incoming requests.
//!
//! The actual implementation of the helper thread is a sorted array of
//! timers in terms of target firing date. The target is the absolute time at
//! which the timer should fire. Timers are then re-enqueued after a firing if
//! the repeat boolean is set.
//!
//! Naturally, all this logic of adding times and keeping track of
//! relative/absolute time is a little lossy and not quite exact. I've done the
//! best I could to reduce the amount of calls to 'now()', but there's likely
//! still inaccuracies trickling in here and there.
//!
//! One of the tricky parts of this implementation is that whenever a timer is
//! acted upon, it must cancel whatever the previous action was (if one is
//! active) in order to act like the other implementations of this timer. In
//! order to do this, the timer's inner pointer is transferred to the worker
//! thread. Whenever the timer is modified, it first takes ownership back from
//! the worker thread in order to modify the same data structure. This has the
//! side effect of "cancelling" the previous requests while allowing a
//! re-enqueueing later on.
//!
//! Note that all time units in this file are in *milliseconds*.

use libc;
use std::mem;
use std::os;
use std::ptr;
use std::rt::rtio;
use std::sync::atomics;

use io::file::FileDesc;
use io::IoResult;
use io::timer_helper;

pub struct Timer {
    id: uint,
    inner: Option<~Inner>,
}

struct Inner {
    tx: Option<Sender<()>>,
    interval: u64,
    repeat: bool,
    target: u64,
    id: uint,
}

#[allow(visible_private_types)]
pub enum Req {
    // Add a new timer to the helper thread.
    NewTimer(~Inner),

    // Remove a timer based on its id and then send it back on the channel
    // provided
    RemoveTimer(uint, Sender<~Inner>),

    // Shut down the loop and then ACK this channel once it's shut down
    Shutdown,
}

// returns the current time (in milliseconds)
fn now() -> u64 {
    unsafe {
        let mut now: libc::timeval = mem::init();
        assert_eq!(imp::gettimeofday(&mut now, ptr::null()), 0);
        return (now.tv_sec as u64) * 1000 + (now.tv_usec as u64) / 1000;
    }
}

fn helper(input: libc::c_int, messages: Receiver<Req>) {
    let mut set: imp::fd_set = unsafe { mem::init() };

    let mut fd = FileDesc::new(input, true);
    let mut timeout: libc::timeval = unsafe { mem::init() };

    // active timers are those which are able to be selected upon (and it's a
    // sorted list, and dead timers are those which have expired, but ownership
    // hasn't yet been transferred back to the timer itself.
    let mut active: Vec<~Inner> = vec![];
    let mut dead = vec![];

    // inserts a timer into an array of timers (sorted by firing time)
    fn insert(t: ~Inner, active: &mut Vec<~Inner>) {
        match active.iter().position(|tm| tm.target > t.target) {
            Some(pos) => { active.insert(pos, t); }
            None => { active.push(t); }
        }
    }

    // signals the first requests in the queue, possible re-enqueueing it.
    fn signal(active: &mut Vec<~Inner>, dead: &mut Vec<(uint, ~Inner)>) {
        let mut timer = match active.shift() {
            Some(timer) => timer, None => return
        };
        let tx = timer.tx.take_unwrap();
        if tx.send_opt(()).is_ok() && timer.repeat {
            timer.tx = Some(tx);
            timer.target += timer.interval;
            insert(timer, active);
        } else {
            drop(tx);
            dead.push((timer.id, timer));
        }
    }

    'outer: loop {
        let timeout = if active.len() == 0 {
            // Empty array? no timeout (wait forever for the next request)
            ptr::null()
        } else {
            let now = now();
            // If this request has already expired, then signal it and go
            // through another iteration
            if active.get(0).target <= now {
                signal(&mut active, &mut dead);
                continue;
            }

            // The actual timeout listed in the requests array is an
            // absolute date, so here we translate the absolute time to a
            // relative time.
            let tm = active.get(0).target - now;
            timeout.tv_sec = (tm / 1000) as libc::time_t;
            timeout.tv_usec = ((tm % 1000) * 1000) as libc::suseconds_t;
            &timeout as *libc::timeval
        };

        imp::fd_set(&mut set, input);
        match unsafe {
            imp::select(input + 1, &set, ptr::null(), ptr::null(), timeout)
        } {
            // timed out
            0 => signal(&mut active, &mut dead),

            // file descriptor write woke us up, we've got some new requests
            1 => {
                loop {
                    match messages.try_recv() {
                        Ok(Shutdown) => {
                            assert!(active.len() == 0);
                            break 'outer;
                        }

                        Ok(NewTimer(timer)) => insert(timer, &mut active),

                        Ok(RemoveTimer(id, ack)) => {
                            match dead.iter().position(|&(i, _)| id == i) {
                                Some(i) => {
                                    let (_, i) = dead.remove(i).unwrap();
                                    ack.send(i);
                                    continue
                                }
                                None => {}
                            }
                            let i = active.iter().position(|i| i.id == id);
                            let i = i.expect("no timer found");
                            let t = active.remove(i).unwrap();
                            ack.send(t);
                        }
                        _ => break
                    }
                }

                // drain the file descriptor
                let mut buf = [0];
                assert_eq!(fd.inner_read(buf).unwrap(), 1);
            }

            -1 if os::errno() == libc::EINTR as int => {}
            n => fail!("helper thread failed in select() with error: {} ({})",
                       n, os::last_os_error())
        }
    }
}

impl Timer {
    pub fn new() -> IoResult<Timer> {
        timer_helper::boot(helper);

        static mut ID: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
        let id = unsafe { ID.fetch_add(1, atomics::Relaxed) };
        Ok(Timer {
            id: id,
            inner: Some(~Inner {
                tx: None,
                interval: 0,
                target: 0,
                repeat: false,
                id: id,
            })
        })
    }

    pub fn sleep(ms: u64) {
        let mut to_sleep = libc::timespec {
            tv_sec: (ms / 1000) as libc::time_t,
            tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
        };
        while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
            if os::errno() as int != libc::EINTR as int {
                fail!("failed to sleep, but not because of EINTR?");
            }
        }
    }

    fn inner(&mut self) -> ~Inner {
        match self.inner.take() {
            Some(i) => i,
            None => {
                let (tx, rx) = channel();
                timer_helper::send(RemoveTimer(self.id, tx));
                rx.recv()
            }
        }
    }
}

impl rtio::RtioTimer for Timer {
    fn sleep(&mut self, msecs: u64) {
        let mut inner = self.inner();
        inner.tx = None; // cancel any previous request
        self.inner = Some(inner);

        Timer::sleep(msecs);
    }

    fn oneshot(&mut self, msecs: u64) -> Receiver<()> {
        let now = now();
        let mut inner = self.inner();

        let (tx, rx) = channel();
        inner.repeat = false;
        inner.tx = Some(tx);
        inner.interval = msecs;
        inner.target = now + msecs;

        timer_helper::send(NewTimer(inner));
        return rx;
    }

    fn period(&mut self, msecs: u64) -> Receiver<()> {
        let now = now();
        let mut inner = self.inner();

        let (tx, rx) = channel();
        inner.repeat = true;
        inner.tx = Some(tx);
        inner.interval = msecs;
        inner.target = now + msecs;

        timer_helper::send(NewTimer(inner));
        return rx;
    }
}

impl Drop for Timer {
    fn drop(&mut self) {
        self.inner = Some(self.inner());
    }
}

#[cfg(target_os = "macos")]
mod imp {
    use libc;

    pub static FD_SETSIZE: uint = 1024;

    pub struct fd_set {
        fds_bits: [i32, ..(FD_SETSIZE / 32)]
    }

    pub fn fd_set(set: &mut fd_set, fd: i32) {
        set.fds_bits[(fd / 32) as uint] |= 1 << (fd % 32);
    }

    extern {
        pub fn select(nfds: libc::c_int,
                      readfds: *fd_set,
                      writefds: *fd_set,
                      errorfds: *fd_set,
                      timeout: *libc::timeval) -> libc::c_int;

        pub fn gettimeofday(timeval: *mut libc::timeval,
                            tzp: *libc::c_void) -> libc::c_int;
    }
}

#[cfg(target_os = "android")]
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "linux")]
mod imp {
    use libc;
    use std::uint;

    pub static FD_SETSIZE: uint = 1024;

    pub struct fd_set {
        fds_bits: [uint, ..(FD_SETSIZE / uint::BITS)]
    }

    pub fn fd_set(set: &mut fd_set, fd: i32) {
        let fd = fd as uint;
        set.fds_bits[fd / uint::BITS] |= 1 << (fd % uint::BITS);
    }

    extern {
        pub fn select(nfds: libc::c_int,
                      readfds: *fd_set,
                      writefds: *fd_set,
                      errorfds: *fd_set,
                      timeout: *libc::timeval) -> libc::c_int;

        pub fn gettimeofday(timeval: *mut libc::timeval,
                            tzp: *libc::c_void) -> libc::c_int;
    }
}
<commit_msg>native: Be more stringent about pattern matching<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Timers for non-linux/non-windows OSes
//!
//! This module implements timers with a worker thread, select(), and a lot of
//! witchcraft that turns out to be horribly inaccurate timers. The unfortunate
//! part is that I'm at a loss of what else to do one these OSes. This is also
//! why linux has a specialized timerfd implementation and windows has its own
//! implementation (they're more accurate than this one).
//!
//! The basic idea is that there is a worker thread that's communicated to via a
//! channel and a pipe, the pipe is used by the worker thread in a select()
//! syscall with a timeout. The timeout is the "next timer timeout" while the
//! channel is used to send data over to the worker thread.
//!
//! Whenever the call to select() times out, then a channel receives a message.
//! Whenever the call returns that the file descriptor has information, then the
//! channel from timers is drained, enqueueing all incoming requests.
//!
//! The actual implementation of the helper thread is a sorted array of
//! timers in terms of target firing date. The target is the absolute time at
//! which the timer should fire. Timers are then re-enqueued after a firing if
//! the repeat boolean is set.
//!
//! Naturally, all this logic of adding times and keeping track of
//! relative/absolute time is a little lossy and not quite exact. I've done the
//! best I could to reduce the amount of calls to 'now()', but there's likely
//! still inaccuracies trickling in here and there.
//!
//! One of the tricky parts of this implementation is that whenever a timer is
//! acted upon, it must cancel whatever the previous action was (if one is
//! active) in order to act like the other implementations of this timer. In
//! order to do this, the timer's inner pointer is transferred to the worker
//! thread. Whenever the timer is modified, it first takes ownership back from
//! the worker thread in order to modify the same data structure. This has the
//! side effect of "cancelling" the previous requests while allowing a
//! re-enqueueing later on.
//!
//! Note that all time units in this file are in *milliseconds*.

use libc;
use std::mem;
use std::os;
use std::ptr;
use std::rt::rtio;
use std::sync::atomics;

use io::file::FileDesc;
use io::IoResult;
use io::timer_helper;

pub struct Timer {
    id: uint,
    inner: Option<~Inner>,
}

struct Inner {
    tx: Option<Sender<()>>,
    interval: u64,
    repeat: bool,
    target: u64,
    id: uint,
}

#[allow(visible_private_types)]
pub enum Req {
    // Add a new timer to the helper thread.
    NewTimer(~Inner),

    // Remove a timer based on its id and then send it back on the channel
    // provided
    RemoveTimer(uint, Sender<~Inner>),

    // Shut down the loop and then ACK this channel once it's shut down
    Shutdown,
}

// returns the current time (in milliseconds)
fn now() -> u64 {
    unsafe {
        let mut now: libc::timeval = mem::init();
        assert_eq!(imp::gettimeofday(&mut now, ptr::null()), 0);
        return (now.tv_sec as u64) * 1000 + (now.tv_usec as u64) / 1000;
    }
}

fn helper(input: libc::c_int, messages: Receiver<Req>) {
    let mut set: imp::fd_set = unsafe { mem::init() };

    let mut fd = FileDesc::new(input, true);
    let mut timeout: libc::timeval = unsafe { mem::init() };

    // active timers are those which are able to be selected upon (and it's a
    // sorted list, and dead timers are those which have expired, but ownership
    // hasn't yet been transferred back to the timer itself.
    let mut active: Vec<~Inner> = vec![];
    let mut dead = vec![];

    // inserts a timer into an array of timers (sorted by firing time)
    fn insert(t: ~Inner, active: &mut Vec<~Inner>) {
        match active.iter().position(|tm| tm.target > t.target) {
            Some(pos) => { active.insert(pos, t); }
            None => { active.push(t); }
        }
    }

    // signals the first requests in the queue, possible re-enqueueing it.
    fn signal(active: &mut Vec<~Inner>, dead: &mut Vec<(uint, ~Inner)>) {
        let mut timer = match active.shift() {
            Some(timer) => timer, None => return
        };
        let tx = timer.tx.take_unwrap();
        if tx.send_opt(()).is_ok() && timer.repeat {
            timer.tx = Some(tx);
            timer.target += timer.interval;
            insert(timer, active);
        } else {
            drop(tx);
            dead.push((timer.id, timer));
        }
    }

    'outer: loop {
        let timeout = if active.len() == 0 {
            // Empty array? no timeout (wait forever for the next request)
            ptr::null()
        } else {
            let now = now();
            // If this request has already expired, then signal it and go
            // through another iteration
            if active.get(0).target <= now {
                signal(&mut active, &mut dead);
                continue;
            }

            // The actual timeout listed in the requests array is an
            // absolute date, so here we translate the absolute time to a
            // relative time.
            let tm = active.get(0).target - now;
            timeout.tv_sec = (tm / 1000) as libc::time_t;
            timeout.tv_usec = ((tm % 1000) * 1000) as libc::suseconds_t;
            &timeout as *libc::timeval
        };

        imp::fd_set(&mut set, input);
        match unsafe {
            imp::select(input + 1, &set, ptr::null(), ptr::null(), timeout)
        } {
            // timed out
            0 => signal(&mut active, &mut dead),

            // file descriptor write woke us up, we've got some new requests
            1 => {
                loop {
                    match messages.try_recv() {
                        Ok(Shutdown) => {
                            assert!(active.len() == 0);
                            break 'outer;
                        }

                        Ok(NewTimer(timer)) => insert(timer, &mut active),

                        Ok(RemoveTimer(id, ack)) => {
                            match dead.iter().position(|&(i, _)| id == i) {
                                Some(i) => {
                                    let (_, i) = dead.remove(i).unwrap();
                                    ack.send(i);
                                    continue
                                }
                                None => {}
                            }
                            let i = active.iter().position(|i| i.id == id);
                            let i = i.expect("no timer found");
                            let t = active.remove(i).unwrap();
                            ack.send(t);
                        }
                        Err(..) => break
                    }
                }

                // drain the file descriptor
                let mut buf = [0];
                assert_eq!(fd.inner_read(buf).unwrap(), 1);
            }

            -1 if os::errno() == libc::EINTR as int => {}
            n => fail!("helper thread failed in select() with error: {} ({})",
                       n, os::last_os_error())
        }
    }
}

impl Timer {
    pub fn new() -> IoResult<Timer> {
        timer_helper::boot(helper);

        static mut ID: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
        let id = unsafe { ID.fetch_add(1, atomics::Relaxed) };
        Ok(Timer {
            id: id,
            inner: Some(~Inner {
                tx: None,
                interval: 0,
                target: 0,
                repeat: false,
                id: id,
            })
        })
    }

    pub fn sleep(ms: u64) {
        let mut to_sleep = libc::timespec {
            tv_sec: (ms / 1000) as libc::time_t,
            tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
        };
        while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
            if os::errno() as int != libc::EINTR as int {
                fail!("failed to sleep, but not because of EINTR?");
            }
        }
    }

    fn inner(&mut self) -> ~Inner {
        match self.inner.take() {
            Some(i) => i,
            None => {
                let (tx, rx) = channel();
                timer_helper::send(RemoveTimer(self.id, tx));
                rx.recv()
            }
        }
    }
}

impl rtio::RtioTimer for Timer {
    fn sleep(&mut self, msecs: u64) {
        let mut inner = self.inner();
        inner.tx = None; // cancel any previous request
        self.inner = Some(inner);

        Timer::sleep(msecs);
    }

    fn oneshot(&mut self, msecs: u64) -> Receiver<()> {
        let now = now();
        let mut inner = self.inner();

        let (tx, rx) = channel();
        inner.repeat = false;
        inner.tx = Some(tx);
        inner.interval = msecs;
        inner.target = now + msecs;

        timer_helper::send(NewTimer(inner));
        return rx;
    }

    fn period(&mut self, msecs: u64) -> Receiver<()> {
        let now = now();
        let mut inner = self.inner();

        let (tx, rx) = channel();
        inner.repeat = true;
        inner.tx = Some(tx);
        inner.interval = msecs;
        inner.target = now + msecs;

        timer_helper::send(NewTimer(inner));
        return rx;
    }
}

impl Drop for Timer {
    fn drop(&mut self) {
        self.inner = Some(self.inner());
    }
}

#[cfg(target_os = "macos")]
mod imp {
    use libc;

    pub static FD_SETSIZE: uint = 1024;

    pub struct fd_set {
        fds_bits: [i32, ..(FD_SETSIZE / 32)]
    }

    pub fn fd_set(set: &mut fd_set, fd: i32) {
        set.fds_bits[(fd / 32) as uint] |= 1 << (fd % 32);
    }

    extern {
        pub fn select(nfds: libc::c_int,
                      readfds: *fd_set,
                      writefds: *fd_set,
                      errorfds: *fd_set,
                      timeout: *libc::timeval) -> libc::c_int;

        pub fn gettimeofday(timeval: *mut libc::timeval,
                            tzp: *libc::c_void) -> libc::c_int;
    }
}

#[cfg(target_os = "android")]
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "linux")]
mod imp {
    use libc;
    use std::uint;

    pub static FD_SETSIZE: uint = 1024;

    pub struct fd_set {
        fds_bits: [uint, ..(FD_SETSIZE / uint::BITS)]
    }

    pub fn fd_set(set: &mut fd_set, fd: i32) {
        let fd = fd as uint;
        set.fds_bits[fd / uint::BITS] |= 1 << (fd % uint::BITS);
    }

    extern {
        pub fn select(nfds: libc::c_int,
                      readfds: *fd_set,
                      writefds: *fd_set,
                      errorfds: *fd_set,
                      timeout: *libc::timeval) -> libc::c_int;

        pub fn gettimeofday(timeval: *mut libc::timeval,
                            tzp: *libc::c_void) -> libc::c_int;
    }
}
<|endoftext|>