<commit_before>use cairo;
use cairo::{MatrixTrait, PatternTrait, Rectangle};
use std::cell::{Cell, RefCell};

use allowed_url::Href;
use aspect_ratio::AspectRatio;
use attributes::Attribute;
use bbox::BoundingBox;
use drawing_ctx::DrawingCtx;
use error::{NodeError, RenderingError};
use float_eq_cairo::ApproxEqCairo;
use length::{LengthHorizontal, LengthVertical};
use node::*;
use parsers::{ParseError, ParseValue};
use property_bag::PropertyBag;
use rect::RectangleExt;
use viewbox::ViewBox;

pub struct NodeImage {
    aspect: Cell<AspectRatio>,
    x: Cell<LengthHorizontal>,
    y: Cell<LengthVertical>,
    w: Cell<LengthHorizontal>,
    h: Cell<LengthVertical>,
    href: RefCell<Option<Href>>,
}

impl NodeImage {
    pub fn new() -> NodeImage {
        NodeImage {
            aspect: Cell::new(AspectRatio::default()),
            x: Cell::new(Default::default()),
            y: Cell::new(Default::default()),
            w: Cell::new(Default::default()),
            h: Cell::new(Default::default()),
            href: RefCell::new(None),
        }
    }
}

impl NodeTrait for NodeImage {
    fn set_atts(&self, node: &RsvgNode, pbag: &PropertyBag<'_>) -> NodeResult {
        // SVG element has overflow:hidden
        // https://www.w3.org/TR/SVG/styling.html#UAStyleSheet
        node.set_overflow_hidden();

        for (attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(attr.parse(value)?),
                Attribute::Y => self.y.set(attr.parse(value)?),
                Attribute::Width => self
                    .w
                    .set(attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?),
                Attribute::Height => self
                    .h
                    .set(attr.parse_and_validate(value, LengthVertical::check_nonnegative)?),

                Attribute::PreserveAspectRatio => self.aspect.set(attr.parse(value)?),

                // "path" is used by some older Adobe Illustrator versions
                Attribute::XlinkHref | Attribute::Path => {
                    let href = Href::parse(value).map_err(|_| {
                        NodeError::parse_error(attr, ParseError::new("could not parse href"))
                    })?;

                    *self.href.borrow_mut() = Some(href);
                }

                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<(), RenderingError> {
        let values = cascaded.get();
        let params = draw_ctx.get_view_params();

        let x = self.x.get().normalize(values, &params);
        let y = self.y.get().normalize(values, &params);
        let w = self.w.get().normalize(values, &params);
        let h = self.h.get().normalize(values, &params);

        if w.approx_eq_cairo(&0.0) || h.approx_eq_cairo(&0.0) {
            return Ok(());
        }

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            let surface = if let Some(Href::PlainUrl(ref url)) = *self.href.borrow() {
                dc.lookup_image(&url)?
            } else {
                return Ok(());
            };

            let aspect = self.aspect.get();

            if !values.is_overflow() && aspect.is_slice() {
                dc.clip(x, y, w, h);
            }

            let width = surface.width();
            let height = surface.height();
            if clipping || width == 0 || height == 0 {
                return Ok(());
            }

            // The bounding box for <image> is decided by the values of x, y, w, h and not by
            // the final computed image bounds.
            let bbox = BoundingBox::new(&dc.get_cairo_context().get_matrix()).with_rect(Some(
                cairo::Rectangle {
                    x,
                    y,
                    width: w,
                    height: h,
                },
            ));

            let width = f64::from(width);
            let height = f64::from(height);

            let (x, y, w, h) = aspect.compute(
                &ViewBox::new(0.0, 0.0, width, height),
                &Rectangle::new(x, y, w, h),
            );

            let cr = dc.get_cairo_context();

            cr.save();

            dc.set_affine_on_cr(&cr);
            cr.scale(w / width, h / height);
            let x = x * width / w;
            let y = y * height / h;

            // We need to set extend appropriately, so can't use cr.set_source_surface().
            //
            // If extend is left at its default value (None), then bilinear scaling uses
            // transparency outside of the image producing incorrect results.
            // For example, in svg1.1/filters-blend-01-b.svgthere's a completely
            // opaque 100×1 image of a gradient scaled to 100×98 which ends up
            // transparent almost everywhere without this fix (which it shouldn't).
            let ptn = surface.to_cairo_pattern();
            let mut matrix = cairo::Matrix::identity();
            matrix.translate(-x, -y);
            ptn.set_matrix(matrix);
            ptn.set_extend(cairo::Extend::Pad);
            cr.set_source(&ptn);

            // Clip is needed due to extend being set to pad.
            cr.rectangle(x, y, width, height);
            cr.clip();

            cr.paint();

            cr.restore();

            dc.insert_bbox(&bbox);
            Ok(())
        })
    }
}
<commit_msg>image.rs: Use DrawingCtx.push_new_viewport() instead of doing things by hand<commit_after>use cairo;
use cairo::{PatternTrait, Rectangle};
use std::cell::{Cell, RefCell};

use allowed_url::Href;
use aspect_ratio::AspectRatio;
use attributes::Attribute;
use bbox::BoundingBox;
use drawing_ctx::DrawingCtx;
use error::{NodeError, RenderingError};
use float_eq_cairo::ApproxEqCairo;
use length::{LengthHorizontal, LengthVertical};
use node::*;
use parsers::{ParseError, ParseValue};
use property_bag::PropertyBag;
use rect::RectangleExt;
use viewbox::ViewBox;
use viewport::ClipMode;

pub struct NodeImage {
    aspect: Cell<AspectRatio>,
    x: Cell<LengthHorizontal>,
    y: Cell<LengthVertical>,
    w: Cell<LengthHorizontal>,
    h: Cell<LengthVertical>,
    href: RefCell<Option<Href>>,
}

impl NodeImage {
    pub fn new() -> NodeImage {
        NodeImage {
            aspect: Cell::new(AspectRatio::default()),
            x: Cell::new(Default::default()),
            y: Cell::new(Default::default()),
            w: Cell::new(Default::default()),
            h: Cell::new(Default::default()),
            href: RefCell::new(None),
        }
    }
}

impl NodeTrait for NodeImage {
    fn set_atts(&self, node: &RsvgNode, pbag: &PropertyBag<'_>) -> NodeResult {
        // SVG element has overflow:hidden
        // https://www.w3.org/TR/SVG/styling.html#UAStyleSheet
        node.set_overflow_hidden();

        for (attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(attr.parse(value)?),
                Attribute::Y => self.y.set(attr.parse(value)?),
                Attribute::Width => self
                    .w
                    .set(attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?),
                Attribute::Height => self
                    .h
                    .set(attr.parse_and_validate(value, LengthVertical::check_nonnegative)?),

                Attribute::PreserveAspectRatio => self.aspect.set(attr.parse(value)?),

                // "path" is used by some older Adobe Illustrator versions
                Attribute::XlinkHref | Attribute::Path => {
                    let href = Href::parse(value).map_err(|_| {
                        NodeError::parse_error(attr, ParseError::new("could not parse href"))
                    })?;

                    *self.href.borrow_mut() = Some(href);
                }

                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<(), RenderingError> {
        let values = cascaded.get();
        let params = draw_ctx.get_view_params();

        let x = self.x.get().normalize(values, &params);
        let y = self.y.get().normalize(values, &params);
        let w = self.w.get().normalize(values, &params);
        let h = self.h.get().normalize(values, &params);

        if w.approx_eq_cairo(&0.0) || h.approx_eq_cairo(&0.0) {
            return Ok(());
        }

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            let surface = if let Some(Href::PlainUrl(ref url)) = *self.href.borrow() {
                dc.lookup_image(&url)?
            } else {
                return Ok(());
            };

            let aspect = self.aspect.get();

            let clip_mode = if !values.is_overflow() && aspect.is_slice() {
                Some(ClipMode::ClipToViewport)
            } else {
                None
            };

            let image_width = surface.width();
            let image_height = surface.height();
            if clipping || image_width == 0 || image_height == 0 {
                return Ok(());
            }

            // The bounding box for <image> is decided by the values of x, y, w, h and not by
            // the final computed image bounds.
            let bbox = BoundingBox::new(&dc.get_cairo_context().get_matrix()).with_rect(Some(
                cairo::Rectangle {
                    x,
                    y,
                    width: w,
                    height: h,
                },
            ));

            let cr = dc.get_cairo_context();
            cr.save();

            let image_width = f64::from(image_width);
            let image_height = f64::from(image_height);

            if let Some(_params) = dc.push_new_viewport(
                Some(ViewBox::new(0.0, 0.0, image_width, image_height)),
                &Rectangle::new(x, y, w, h),
                aspect,
                clip_mode,
            ) {
                dc.set_affine_on_cr(&cr);

                // We need to set extend appropriately, so can't use cr.set_source_surface().
                //
                // If extend is left at its default value (None), then bilinear scaling uses
                // transparency outside of the image producing incorrect results.
                // For example, in svg1.1/filters-blend-01-b.svgthere's a completely
                // opaque 100×1 image of a gradient scaled to 100×98 which ends up
                // transparent almost everywhere without this fix (which it shouldn't).
                let ptn = surface.to_cairo_pattern();
                ptn.set_extend(cairo::Extend::Pad);
                cr.set_source(&ptn);

                // Clip is needed due to extend being set to pad.
                cr.rectangle(0.0, 0.0, image_width, image_height);
                cr.clip();

                cr.paint();
            }

            cr.restore();
            dc.insert_bbox(&bbox);
            Ok(())
        })
    }
}
<|endoftext|>


<commit_before>use std::sync::{Arc, RwLock};
use subject::{self, Source, Mapper, WrapListener, Subject, Receiver};

pub trait Event<A> {
    fn map<B, F>(&self, f: F) -> Map<A, B, F>
        where F: Fn(A) -> B;
    fn filter<F>(&self, f: F) -> Filter<A, F>
        where F: Fn(&A) -> bool + Send + Sync;
    fn iter(&self) -> Iter<A>;
}

pub struct Sink<A> {
    source: RwLock<Source<A>>,
}

impl<A: Send> Sink<A> {
    pub fn new() -> Sink<A> {
        Sink { source: RwLock::new(Source::new()) }
    }
}

impl<A: Send + Sync + Clone> Sink<A> {
    pub fn send(&self, a: A) {
        self.source.write().unwrap().send(a);
    }
}

impl<A: Send + Sync + Clone> Event<A> for Sink<A> {
    fn map<B, F>(&self, f: F) -> Map<A, B, F>
        where B: Send + Sync + Clone,
              F: Fn(A) -> B + Send + Sync,
    {
        Map::new(&mut *self.source.write().unwrap(), f)
    }

    fn filter<F>(&self, f: F) -> Filter<A, F>
        where F: Fn(&A) -> bool + Send + Sync,
    {
        Filter::new(&mut *self.source.write().unwrap(), f)
    }

    fn iter(&self) -> Iter<A> {
        Iter::new(&mut *self.source.write().unwrap())
    }
}

pub struct Map<A, B, F> {
    mapper: Arc<RwLock<Mapper<A, B, F>>>,
}

impl<A, B, F> Map<A, B, F>
    where A: Send + Sync + Clone,
          B: Send + Sync + Clone,
          F: Fn(A) -> B + Send + Sync,
{
    fn new<S: Subject<A>>(sub: &mut S, f: F) -> Map<A, B, F> {
        let map = Map { mapper: Arc::new(RwLock::new(Mapper::new(f))) };
        sub.listen(map.mapper.wrap());
        map
    }
}

impl<A, B, F> Event<B> for Map<A, B, F>
    where A: Send + Sync + Clone,
          B: Send + Sync + Clone,
          F: Fn(A) -> B + Send + Sync,
{
    fn map<C, G>(&self, g: G) -> Map<B, C, G>
        where C: Send + Sync + Clone,
              G: Fn(B) -> C + Send + Sync,
    {
        Map::new(&mut *self.mapper.write().unwrap(), g)
    }

    fn filter<G>(&self, g: G) -> Filter<B, G>
        where G: Fn(&B) -> bool + Send + Sync,
    {
        Filter::new(&mut *self.mapper.write().unwrap(), g)
    }

    fn iter(&self) -> Iter<B> {
        Iter::new(&mut *self.mapper.write().unwrap())
    }
}

pub struct Filter<A, F> {
    filter: Arc<RwLock<subject::Filter<A, F>>>,
}

impl<A, F> Filter<A, F>
    where A: Send + Sync + Clone,
          F: Fn(&A) -> bool + Send + Sync,
{
    fn new<S: Subject<A>>(sub: &mut S, f: F) -> Filter<A, F> {
        let filter = Filter {
            filter: Arc::new(RwLock::new(subject::Filter::new(f)))
        };
        sub.listen(filter.filter.wrap());
        filter
    }
}

impl<A, F> Event<A> for Filter<A, F>
    where A: Send + Sync + Clone,
          F: Fn(&A) -> bool + Send + Sync,
{
    fn map<B, G>(&self, g: G) -> Map<A, B, G>
        where B: Send + Sync + Clone,
              G: Fn(A) -> B + Send + Sync,
    {
        Map::new(&mut *self.filter.write().unwrap(), g)
    }

    fn filter<G>(&self, g: G) -> Filter<A, G>
        where G: Fn(&A) -> bool + Send + Sync,
    {
        Filter::new(&mut *self.filter.write().unwrap(), g)
    }

    fn iter(&self) -> Iter<A> {
        Iter::new(&mut *self.filter.write().unwrap())
    }
}

pub struct Iter<A> {
    recv: Arc<RwLock<Receiver<A>>>,
}

impl<A: Send + Sync + Clone> Iter<A> {
    fn new<S: Subject<A>>(sub: &mut S) -> Iter<A> {
        let iter = Iter { recv: Arc::new(RwLock::new(Receiver::new())) };
        sub.listen(iter.recv.wrap());
        iter
    }
}

impl<A: Send + Sync> Iterator for Iter<A> {
    type Item = A;
    fn next(&mut self) -> Option<A> {
        self.recv.write().unwrap().next()
    }
}

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

    #[test]
    fn sink() {
        let sink = Sink::new();
        let mut iter = sink.iter();
        sink.send(1);
        sink.send(2);
        assert_eq!(iter.next(), Some(1));
        assert_eq!(iter.next(), Some(2));
    }

    #[test]
    fn map() {
        let sink = Sink::new();
        let triple = sink.map(|x| 3 * x);
        let mut iter = triple.iter();
        sink.send(1);
        assert_eq!(iter.next(), Some(3));
    }

    #[test]
    fn filter() {
        let sink = Sink::new();
        let small = sink.filter(|&x: &i32| x < 11);
        let mut iter = small.iter();
        sink.send(12);
        sink.send(9);
        assert_eq!(iter.next(), Some(9));
    }
}
<commit_msg>Move event method impls into the trait<commit_after>use std::sync::{Arc, RwLock};
use subject::{self, Subject, Source, Mapper, Receiver, WrapListener};

pub trait Event<A: Send + Sync + Clone> {
    type Source: Subject<A>;

    fn source(&self) -> &Arc<RwLock<Self::Source<A>>>;

    fn map<B, F>(&self, f: F) -> Map<A, B, F>
        where B: Send + Sync + Clone,
              F: Fn(A) -> B + Send + Sync,
    {
        Map::new(&mut *self.source().write().unwrap(), f)
    }

    fn filter<F>(&self, f: F) -> Filter<A, F>
        where F: Fn(&A) -> bool + Send + Sync,
    {
        Filter::new(&mut *self.source().write().unwrap(), f)
    }

    fn iter(&self) -> Iter<A> {
        Iter::new(&mut *self.source().write().unwrap())
    }
}

pub struct Sink<A> {
    source: Arc<RwLock<Source<A>>>,
}

impl<A: Send> Sink<A> {
    pub fn new() -> Sink<A> {
        Sink { source: Arc::new(RwLock::new(Source::new())) }
    }
}

impl<A: Send + Sync + Clone> Sink<A> {
    pub fn send(&self, a: A) {
        self.source.write().unwrap().send(a);
    }
}

impl<A: Send + Sync + Clone> Event<A> for Sink<A> {
    type Source = subject::Source<A>;

    fn source(&self) -> &Arc<RwLock<subject::Source<A>>> {
        &self.source
    }
}

pub struct Map<A, B, F> {
    mapper: Arc<RwLock<Mapper<A, B, F>>>,
}

impl<A, B, F> Map<A, B, F>
    where A: Send + Sync + Clone,
          B: Send + Sync + Clone,
          F: Fn(A) -> B + Send + Sync,
{
    fn new<S: Subject<A>>(sub: &mut S, f: F) -> Map<A, B, F> {
        let map = Map { mapper: Arc::new(RwLock::new(Mapper::new(f))) };
        sub.listen(map.mapper.wrap());
        map
    }
}

impl<A, B, F> Event<B> for Map<A, B, F>
    where A: Send + Sync + Clone,
          B: Send + Sync + Clone,
          F: Fn(A) -> B + Send + Sync,
{
    type Source = Mapper<A, B, F>;

    fn source(&self) -> &Arc<RwLock<Mapper<A, B, F>>> {
        &self.mapper
    }
}

pub struct Filter<A, F> {
    filter: Arc<RwLock<subject::Filter<A, F>>>,
}

impl<A, F> Filter<A, F>
    where A: Send + Sync + Clone,
          F: Fn(&A) -> bool + Send + Sync,
{
    fn new<S: Subject<A>>(sub: &mut S, f: F) -> Filter<A, F> {
        let filter = Filter {
            filter: Arc::new(RwLock::new(subject::Filter::new(f)))
        };
        sub.listen(filter.filter.wrap());
        filter
    }
}

impl<A, F> Event<A> for Filter<A, F>
    where A: Send + Sync + Clone,
          F: Fn(&A) -> bool + Send + Sync,
{
    type Source = subject::Filter<A, F>;

    fn source(&self) -> &Arc<RwLock<subject::Filter<A, F>>> {
        &self.filter
    }
}

pub struct Iter<A> {
    recv: Arc<RwLock<Receiver<A>>>,
}

impl<A: Send + Sync + Clone> Iter<A> {
    fn new<S: Subject<A>>(sub: &mut S) -> Iter<A> {
        let iter = Iter { recv: Arc::new(RwLock::new(Receiver::new())) };
        sub.listen(iter.recv.wrap());
        iter
    }
}

impl<A: Send + Sync> Iterator for Iter<A> {
    type Item = A;
    fn next(&mut self) -> Option<A> {
        self.recv.write().unwrap().next()
    }
}

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

    #[test]
    fn sink() {
        let sink = Sink::new();
        let mut iter = sink.iter();
        sink.send(1);
        sink.send(2);
        assert_eq!(iter.next(), Some(1));
        assert_eq!(iter.next(), Some(2));
    }

    #[test]
    fn map() {
        let sink = Sink::new();
        let triple = sink.map(|x| 3 * x);
        let mut iter = triple.iter();
        sink.send(1);
        assert_eq!(iter.next(), Some(3));
    }

    #[test]
    fn filter() {
        let sink = Sink::new();
        let small = sink.filter(|&x: &i32| x < 11);
        let mut iter = small.iter();
        sink.send(12);
        sink.send(9);
        assert_eq!(iter.next(), Some(9));
    }
}
<|endoftext|>


<commit_before>use core::num::{Zero, One};
use numeric::*;

use std::cmp::FuzzyEq;

use mat::{Mat4, BaseMat4};

/**
 * Create a perspective projection matrix
 *
 * Note: the fovy parameter should be specified in degrees.
 *
 * This is the equivalent of the gluPerspective function, the algorithm of which
 * can be found [here](http://www.opengl.org/wiki/GluPerspective_code).
 */
#[inline(always)]
pub fn perspective<T:Copy + Float + Zero + One + FuzzyEq<T> + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>(fovy: T, aspectRatio: T, near: T, far: T) -> Mat4<T> {
    let _2: T = num::cast(2);

    let ymax = near * tan(radians(fovy / _2));
    let xmax = ymax * aspectRatio;

    frustum(-xmax, xmax, -ymax, ymax, near, far)
}

/**
 * Define a view frustrum
 *
 * This is the equivalent of the now deprecated [glFrustrum]
 * (http://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml) function.
 */
#[inline(always)]
pub fn frustum<T:Copy + Float + Zero + One + FuzzyEq<T> + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Mat4<T> {
    let _0: T = num::cast(0);
    let _1: T = num::cast(1);
    let _2: T = num::cast(2);

    let c0r0 = (_2 * near) / (right - left);
    let c0r1 = _0;
    let c0r2 = _0;
    let c0r3 = _0;

    let c1r0 = _0;
    let c1r1 = (_2 * near) / (top - bottom);
    let c1r2 = _0;
    let c1r3 = _0;

    let c2r0 = (right + left) / (right - left);
    let c2r1 = (top + bottom) / (top - bottom);
    let c2r2 = -(far + near) / (far - near);
    let c2r3 = -_1;

    let c3r0 = _0;
    let c3r1 = _0;
    let c3r2 = -(_2 * far * near) / (far - near);
    let c3r3 = _0;

    BaseMat4::new(c0r0, c0r1, c0r2, c0r3,
                  c1r0, c1r1, c1r2, c1r3,
                  c2r0, c2r1, c2r2, c2r3,
                  c3r0, c3r1, c3r2, c3r3)
}

/**
 * Create an orthographic projection matrix
 *
 * This is the equivalent of the now deprecated [glOrtho]
 * (http://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml) function.
 */
#[inline(always)]
pub fn ortho<T:Copy + Float + Zero + One + FuzzyEq<T> + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Mat4<T> {
    let _0: T = num::cast(0);
    let _1: T = num::cast(1);
    let _2: T = num::cast(2);

    let c0r0 = _2 / (right - left);
    let c0r1 = _0;
    let c0r2 = _0;
    let c0r3 = -(right + left) / (right - left);

    let c1r0 = _0;
    let c1r1 = _2 / (top - bottom);
    let c1r2 = _0;
    let c1r3 = -(top + bottom) / (top - bottom);

    let c2r0 = _0;
    let c2r1 = _0;
    let c2r2 = -_2 / (far - near);
    let c2r3 = -(far + near) / (far - near);

    let c3r0 = _0;
    let c3r1 = _0;
    let c3r2 = _0;
    let c3r3 = _1;

    BaseMat4::new(c0r0, c0r1, c0r2, c0r3,
                  c1r0, c1r1, c1r2, c1r3,
                  c2r0, c2r1, c2r2, c2r3,
                  c3r0, c3r1, c3r2, c3r3)
}
<commit_msg>Fix ortho<commit_after>use core::num::{Zero, One};
use numeric::*;

use std::cmp::FuzzyEq;

use mat::{Mat4, BaseMat4};

/**
 * Create a perspective projection matrix
 *
 * Note: the fovy parameter should be specified in degrees.
 *
 * This is the equivalent of the gluPerspective function, the algorithm of which
 * can be found [here](http://www.opengl.org/wiki/GluPerspective_code).
 */
#[inline(always)]
pub fn perspective<T:Copy + Float + Zero + One + FuzzyEq<T> + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>(fovy: T, aspectRatio: T, near: T, far: T) -> Mat4<T> {
    let _2: T = num::cast(2);

    let ymax = near * tan(radians(fovy / _2));
    let xmax = ymax * aspectRatio;

    frustum(-xmax, xmax, -ymax, ymax, near, far)
}

/**
 * Define a view frustrum
 *
 * This is the equivalent of the now deprecated [glFrustrum]
 * (http://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml) function.
 */
#[inline(always)]
pub fn frustum<T:Copy + Float + Zero + One + FuzzyEq<T> + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Mat4<T> {
    let _0: T = num::cast(0);
    let _1: T = num::cast(1);
    let _2: T = num::cast(2);

    let c0r0 = (_2 * near) / (right - left);
    let c0r1 = _0;
    let c0r2 = _0;
    let c0r3 = _0;

    let c1r0 = _0;
    let c1r1 = (_2 * near) / (top - bottom);
    let c1r2 = _0;
    let c1r3 = _0;

    let c2r0 = (right + left) / (right - left);
    let c2r1 = (top + bottom) / (top - bottom);
    let c2r2 = -(far + near) / (far - near);
    let c2r3 = -_1;

    let c3r0 = _0;
    let c3r1 = _0;
    let c3r2 = -(_2 * far * near) / (far - near);
    let c3r3 = _0;

    BaseMat4::new(c0r0, c0r1, c0r2, c0r3,
                  c1r0, c1r1, c1r2, c1r3,
                  c2r0, c2r1, c2r2, c2r3,
                  c3r0, c3r1, c3r2, c3r3)
}

/**
 * Create an orthographic projection matrix
 *
 * This is the equivalent of the now deprecated [glOrtho]
 * (http://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml) function.
 */
#[inline(always)]
pub fn ortho<T:Copy + Float + Zero + One + FuzzyEq<T> + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Mat4<T> {
    let _0: T = num::cast(0);
    let _1: T = num::cast(1);
    let _2: T = num::cast(2);

    let c0r0 = _2 / (right - left);
    let c0r1 = _0;
    let c0r2 = _0;
    let c0r3 = _0;

    let c1r0 = _0;
    let c1r1 = _2 / (top - bottom);
    let c1r2 = _0;
    let c1r3 = _0;

    let c2r0 = _0;
    let c2r1 = _0;
    let c2r2 = -_2 / (far - near);
    let c2r3 = _0;

    let c3r0 = -(right + left) / (right - left);
    let c3r1 = -(top + bottom) / (top - bottom);
    let c3r2 = -(far + near) / (far - near);
    let c3r3 = _1;

    BaseMat4::new(c0r0, c0r1, c0r2, c0r3,
                  c1r0, c1r1, c1r2, c1r3,
                  c2r0, c2r1, c2r2, c2r3,
                  c3r0, c3r1, c3r2, c3r3)
}
<|endoftext|>


<commit_before>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use super::*;
use bit_helper::BitHelper;
use cpu_leaf::*;

// The APIC ID shift in leaf 0xBh specifies the number of bits to shit the x2APIC ID to get a
// unique topology of the next level. This allows 64 logical processors/package.
const LEAFBH_INDEX1_APICID: u32 = 6;

fn update_deterministic_cache_entry(
    entry: &mut kvm_cpuid_entry2,
    vm_spec: &VmSpec,
) -> Result<(), Error> {
    use cpu_leaf::leaf_0x4::*;

    common::update_cache_parameters_entry(entry, vm_spec)?;

    // Put all the cores in the same socket
    entry.eax.write_bits_in_range(
        &eax::MAX_CORES_PER_PACKAGE_BITRANGE,
        u32::from(vm_spec.cpu_count - 1),
    );

    Ok(())
}

fn update_power_management_entry(
    entry: &mut kvm_cpuid_entry2,
    _vm_spec: &VmSpec,
) -> Result<(), Error> {
    use cpu_leaf::leaf_0x6::*;

    entry.eax.write_bit(eax::TURBO_BOOST_BITINDEX, false);
    // Clear X86 EPB feature. No frequency selection in the hypervisor.
    entry.ecx.write_bit(ecx::EPB_BITINDEX, false);

    Ok(())
}

fn update_perf_mon_entry(entry: &mut kvm_cpuid_entry2, _vm_spec: &VmSpec) -> Result<(), Error> {
    // Architectural Performance Monitor Leaf
    // Disable PMU
    entry.eax = 0;
    entry.ebx = 0;
    entry.ecx = 0;
    entry.edx = 0;

    Ok(())
}

fn update_extended_topology_entry(
    entry: &mut kvm_cpuid_entry2,
    vm_spec: &VmSpec,
) -> Result<(), Error> {
    use cpu_leaf::leaf_0xb::*;

    //reset eax, ebx, ecx
    entry.eax = 0 as u32;
    entry.ebx = 0 as u32;
    entry.ecx = 0 as u32;
    // EDX bits 31..0 contain x2APIC ID of current logical processor
    // x2APIC increases the size of the APIC ID from 8 bits to 32 bits
    entry.edx = u32::from(vm_spec.cpu_index);

    // "If SMT is not present in a processor implementation but CPUID leaf 0BH is supported,
    // CPUID.EAX=0BH, ECX=0 will return EAX = 0, EBX = 1 and level type = 1.
    // Number of logical processors at the core level is reported at level type = 2."
    // (Intel® 64 Architecture x2APIC Specification, Ch. 2.8)
    match entry.index {
        // Thread Level Topology; index = 0
        0 => {
            // To get the next level APIC ID, shift right with at most 1 because we have
            // maximum 2 hyperthreads per core that can be represented by 1 bit.
            entry
                .eax
                .write_bits_in_range(&eax::APICID_BITRANGE, u32::from(vm_spec.cpu_bits));
            // When cpu_count == 1 or HT is disabled, there is 1 logical core at this level
            // Otherwise there are 2
            entry.ebx.write_bits_in_range(
                &ebx::NUM_LOGICAL_PROCESSORS_BITRANGE,
                u32::from(vm_spec.cpus_per_core()),
            );

            entry
                .ecx
                .write_bits_in_range(&ecx::LEVEL_TYPE_BITRANGE, LEVEL_TYPE_THREAD);
        }
        // Core Level Processor Topology; index = 1
        1 => {
            entry
                .eax
                .write_bits_in_range(&eax::APICID_BITRANGE, LEAFBH_INDEX1_APICID);
            entry.ebx.write_bits_in_range(
                &ebx::NUM_LOGICAL_PROCESSORS_BITRANGE,
                u32::from(vm_spec.cpu_count),
            );
            entry
                .ecx
                .write_bits_in_range(&ecx::LEVEL_NUMBER_BITRANGE, entry.index as u32);
            entry
                .ecx
                .write_bits_in_range(&ecx::LEVEL_TYPE_BITRANGE, LEVEL_TYPE_CORE);
        }
        // Core Level Processor Topology; index >=2
        // No other levels available; This should already be set correctly,
        // and it is added here as a "re-enforcement" in case we run on
        // different hardware
        level => {
            entry.ecx = level;
        }
    }

    Ok(())
}

pub struct IntelCpuidTransformer {}

impl CpuidTransformer for IntelCpuidTransformer {
    fn entry_transformer_fn(&self, entry: &mut kvm_cpuid_entry2) -> Option<EntryTransformerFn> {
        match entry.function {
            leaf_0x1::LEAF_NUM => Some(common::update_feature_info_entry),
            leaf_0x4::LEAF_NUM => Some(intel::update_deterministic_cache_entry),
            leaf_0x6::LEAF_NUM => Some(intel::update_power_management_entry),
            leaf_0xa::LEAF_NUM => Some(intel::update_perf_mon_entry),
            leaf_0xb::LEAF_NUM => Some(intel::update_extended_topology_entry),
            0x8000_0002..=0x8000_0004 => Some(common::update_brand_string_entry),
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use cpu_leaf::leaf_0xb::LEVEL_TYPE_CORE;
    use cpu_leaf::leaf_0xb::LEVEL_TYPE_THREAD;
    use kvm_bindings::kvm_cpuid_entry2;
    use transformer::VmSpec;

    #[test]
    fn test_update_perf_mon_entry() {
        let vm_spec = VmSpec::new(0, 1, false).expect("Error creating vm_spec");
        let mut entry = &mut kvm_cpuid_entry2 {
            function: leaf_0xa::LEAF_NUM,
            index: 0,
            flags: 0,
            eax: 1,
            ebx: 1,
            ecx: 1,
            edx: 1,
            padding: [0, 0, 0],
        };

        assert!(update_perf_mon_entry(&mut entry, &vm_spec).is_ok());

        assert_eq!(entry.eax, 0);
        assert_eq!(entry.ebx, 0);
        assert_eq!(entry.ecx, 0);
        assert_eq!(entry.edx, 0);
    }

    fn check_update_deterministic_cache_entry(
        cpu_count: u8,
        ht_enabled: bool,
        cache_level: u32,
        expected_max_cores_per_package: u32,
    ) {
        use cpu_leaf::leaf_0x4::*;

        let vm_spec = VmSpec::new(0, cpu_count, ht_enabled).expect("Error creating vm_spec");
        let mut entry = &mut kvm_cpuid_entry2 {
            function: 0x0,
            index: 0,
            flags: 0,
            eax: *(0 as u32).write_bits_in_range(&eax::CACHE_LEVEL_BITRANGE, cache_level),
            ebx: 0,
            ecx: 0,
            edx: 0,
            padding: [0, 0, 0],
        };

        assert!(update_deterministic_cache_entry(&mut entry, &vm_spec).is_ok());

        assert!(
            entry
                .eax
                .read_bits_in_range(&eax::MAX_CORES_PER_PACKAGE_BITRANGE)
                == expected_max_cores_per_package
        );
    }

    fn check_update_extended_topology_entry(
        cpu_count: u8,
        ht_enabled: bool,
        index: u32,
        expected_apicid: u32,
        expected_num_logical_processors: u32,
        expected_level_type: u32,
    ) {
        use cpu_leaf::leaf_0xb::*;

        let vm_spec = VmSpec::new(0, cpu_count, ht_enabled).expect("Error creating vm_spec");
        let mut entry = &mut kvm_cpuid_entry2 {
            function: 0x0,
            index,
            flags: 0,
            eax: 0,
            ebx: 0,
            ecx: 0,
            edx: 0,
            padding: [0, 0, 0],
        };

        assert!(update_extended_topology_entry(&mut entry, &vm_spec).is_ok());

        assert!(entry.eax.read_bits_in_range(&eax::APICID_BITRANGE) == expected_apicid);
        assert!(
            entry
                .ebx
                .read_bits_in_range(&ebx::NUM_LOGICAL_PROCESSORS_BITRANGE)
                == expected_num_logical_processors
        );
        assert!(entry.ecx.read_bits_in_range(&ecx::LEVEL_TYPE_BITRANGE) == expected_level_type);
        assert!(entry.ecx.read_bits_in_range(&ecx::LEVEL_NUMBER_BITRANGE) == index);
    }

    #[test]
    fn test_1vcpu_ht_off() {
        // test update_deterministic_cache_entry
        // test L1
        check_update_deterministic_cache_entry(1, false, 1, 0);
        // test L2
        check_update_deterministic_cache_entry(1, false, 2, 0);
        // test L3
        check_update_deterministic_cache_entry(1, false, 3, 0);

        // test update_extended_topology_entry
        // index 0
        check_update_extended_topology_entry(1, false, 0, 0, 1, LEVEL_TYPE_THREAD);
        // index 1
        check_update_extended_topology_entry(1, false, 1, LEAFBH_INDEX1_APICID, 1, LEVEL_TYPE_CORE);
    }

    #[test]
    fn test_1vcpu_ht_on() {
        // test update_deterministic_cache_entry
        // test L1
        check_update_deterministic_cache_entry(1, true, 1, 0);
        // test L2
        check_update_deterministic_cache_entry(1, true, 2, 0);
        // test L3
        check_update_deterministic_cache_entry(1, true, 3, 0);

        // test update_extended_topology_entry
        // index 0
        check_update_extended_topology_entry(1, true, 0, 0, 1, LEVEL_TYPE_THREAD);
        // index 1
        check_update_extended_topology_entry(1, true, 1, LEAFBH_INDEX1_APICID, 1, LEVEL_TYPE_CORE);
    }

    #[test]
    fn test_2vcpu_ht_off() {
        // test update_deterministic_cache_entry
        // test L1
        check_update_deterministic_cache_entry(2, false, 1, 1);
        // test L2
        check_update_deterministic_cache_entry(2, false, 2, 1);
        // test L3
        check_update_deterministic_cache_entry(2, false, 3, 1);

        // test update_extended_topology_entry
        // index 0
        check_update_extended_topology_entry(2, false, 0, 0, 1, LEVEL_TYPE_THREAD);
        // index 1
        check_update_extended_topology_entry(2, false, 1, LEAFBH_INDEX1_APICID, 2, LEVEL_TYPE_CORE);
    }

    #[test]
    fn test_2vcpu_ht_on() {
        // test update_deterministic_cache_entry
        // test L1
        check_update_deterministic_cache_entry(2, true, 1, 1);
        // test L2
        check_update_deterministic_cache_entry(2, true, 2, 1);
        // test L3
        check_update_deterministic_cache_entry(2, true, 3, 1);

        // test update_extended_topology_entry
        // index 0
        check_update_extended_topology_entry(2, true, 0, 1, 2, LEVEL_TYPE_THREAD);
        // index 1
        check_update_extended_topology_entry(2, true, 1, LEAFBH_INDEX1_APICID, 2, LEVEL_TYPE_CORE);
    }
}
<commit_msg>[cpuid][intel] deterministic cache entry fix<commit_after>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use super::*;
use bit_helper::BitHelper;
use cpu_leaf::*;

// The APIC ID shift in leaf 0xBh specifies the number of bits to shit the x2APIC ID to get a
// unique topology of the next level. This allows 64 logical processors/package.
const LEAFBH_INDEX1_APICID: u32 = 6;

fn update_deterministic_cache_entry(
    entry: &mut kvm_cpuid_entry2,
    vm_spec: &VmSpec,
) -> Result<(), Error> {
    use cpu_leaf::leaf_0x4::*;

    common::update_cache_parameters_entry(entry, vm_spec)?;

    // Put all the cores in the same socket
    entry.eax.write_bits_in_range(
        &eax::MAX_CORES_PER_PACKAGE_BITRANGE,
        u32::from(vm_spec.cpu_count / vm_spec.cpus_per_core()) - 1,
    );

    Ok(())
}

fn update_power_management_entry(
    entry: &mut kvm_cpuid_entry2,
    _vm_spec: &VmSpec,
) -> Result<(), Error> {
    use cpu_leaf::leaf_0x6::*;

    entry.eax.write_bit(eax::TURBO_BOOST_BITINDEX, false);
    // Clear X86 EPB feature. No frequency selection in the hypervisor.
    entry.ecx.write_bit(ecx::EPB_BITINDEX, false);

    Ok(())
}

fn update_perf_mon_entry(entry: &mut kvm_cpuid_entry2, _vm_spec: &VmSpec) -> Result<(), Error> {
    // Architectural Performance Monitor Leaf
    // Disable PMU
    entry.eax = 0;
    entry.ebx = 0;
    entry.ecx = 0;
    entry.edx = 0;

    Ok(())
}

fn update_extended_topology_entry(
    entry: &mut kvm_cpuid_entry2,
    vm_spec: &VmSpec,
) -> Result<(), Error> {
    use cpu_leaf::leaf_0xb::*;

    //reset eax, ebx, ecx
    entry.eax = 0 as u32;
    entry.ebx = 0 as u32;
    entry.ecx = 0 as u32;
    // EDX bits 31..0 contain x2APIC ID of current logical processor
    // x2APIC increases the size of the APIC ID from 8 bits to 32 bits
    entry.edx = u32::from(vm_spec.cpu_index);

    // "If SMT is not present in a processor implementation but CPUID leaf 0BH is supported,
    // CPUID.EAX=0BH, ECX=0 will return EAX = 0, EBX = 1 and level type = 1.
    // Number of logical processors at the core level is reported at level type = 2."
    // (Intel® 64 Architecture x2APIC Specification, Ch. 2.8)
    match entry.index {
        // Thread Level Topology; index = 0
        0 => {
            // To get the next level APIC ID, shift right with at most 1 because we have
            // maximum 2 hyperthreads per core that can be represented by 1 bit.
            entry
                .eax
                .write_bits_in_range(&eax::APICID_BITRANGE, u32::from(vm_spec.cpu_bits));
            // When cpu_count == 1 or HT is disabled, there is 1 logical core at this level
            // Otherwise there are 2
            entry.ebx.write_bits_in_range(
                &ebx::NUM_LOGICAL_PROCESSORS_BITRANGE,
                u32::from(vm_spec.cpus_per_core()),
            );

            entry
                .ecx
                .write_bits_in_range(&ecx::LEVEL_TYPE_BITRANGE, LEVEL_TYPE_THREAD);
        }
        // Core Level Processor Topology; index = 1
        1 => {
            entry
                .eax
                .write_bits_in_range(&eax::APICID_BITRANGE, LEAFBH_INDEX1_APICID);
            entry.ebx.write_bits_in_range(
                &ebx::NUM_LOGICAL_PROCESSORS_BITRANGE,
                u32::from(vm_spec.cpu_count),
            );
            entry
                .ecx
                .write_bits_in_range(&ecx::LEVEL_NUMBER_BITRANGE, entry.index as u32);
            entry
                .ecx
                .write_bits_in_range(&ecx::LEVEL_TYPE_BITRANGE, LEVEL_TYPE_CORE);
        }
        // Core Level Processor Topology; index >=2
        // No other levels available; This should already be set correctly,
        // and it is added here as a "re-enforcement" in case we run on
        // different hardware
        level => {
            entry.ecx = level;
        }
    }

    Ok(())
}

pub struct IntelCpuidTransformer {}

impl CpuidTransformer for IntelCpuidTransformer {
    fn entry_transformer_fn(&self, entry: &mut kvm_cpuid_entry2) -> Option<EntryTransformerFn> {
        match entry.function {
            leaf_0x1::LEAF_NUM => Some(common::update_feature_info_entry),
            leaf_0x4::LEAF_NUM => Some(intel::update_deterministic_cache_entry),
            leaf_0x6::LEAF_NUM => Some(intel::update_power_management_entry),
            leaf_0xa::LEAF_NUM => Some(intel::update_perf_mon_entry),
            leaf_0xb::LEAF_NUM => Some(intel::update_extended_topology_entry),
            0x8000_0002..=0x8000_0004 => Some(common::update_brand_string_entry),
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use cpu_leaf::leaf_0xb::LEVEL_TYPE_CORE;
    use cpu_leaf::leaf_0xb::LEVEL_TYPE_THREAD;
    use kvm_bindings::kvm_cpuid_entry2;
    use transformer::VmSpec;

    #[test]
    fn test_update_perf_mon_entry() {
        let vm_spec = VmSpec::new(0, 1, false).expect("Error creating vm_spec");
        let mut entry = &mut kvm_cpuid_entry2 {
            function: leaf_0xa::LEAF_NUM,
            index: 0,
            flags: 0,
            eax: 1,
            ebx: 1,
            ecx: 1,
            edx: 1,
            padding: [0, 0, 0],
        };

        assert!(update_perf_mon_entry(&mut entry, &vm_spec).is_ok());

        assert_eq!(entry.eax, 0);
        assert_eq!(entry.ebx, 0);
        assert_eq!(entry.ecx, 0);
        assert_eq!(entry.edx, 0);
    }

    fn check_update_deterministic_cache_entry(
        cpu_count: u8,
        ht_enabled: bool,
        cache_level: u32,
        expected_max_cores_per_package: u32,
    ) {
        use cpu_leaf::leaf_0x4::*;

        let vm_spec = VmSpec::new(0, cpu_count, ht_enabled).expect("Error creating vm_spec");
        let mut entry = &mut kvm_cpuid_entry2 {
            function: 0x0,
            index: 0,
            flags: 0,
            eax: *(0 as u32).write_bits_in_range(&eax::CACHE_LEVEL_BITRANGE, cache_level),
            ebx: 0,
            ecx: 0,
            edx: 0,
            padding: [0, 0, 0],
        };

        assert!(update_deterministic_cache_entry(&mut entry, &vm_spec).is_ok());

        assert!(
            entry
                .eax
                .read_bits_in_range(&eax::MAX_CORES_PER_PACKAGE_BITRANGE)
                == expected_max_cores_per_package
        );
    }

    fn check_update_extended_topology_entry(
        cpu_count: u8,
        ht_enabled: bool,
        index: u32,
        expected_apicid: u32,
        expected_num_logical_processors: u32,
        expected_level_type: u32,
    ) {
        use cpu_leaf::leaf_0xb::*;

        let vm_spec = VmSpec::new(0, cpu_count, ht_enabled).expect("Error creating vm_spec");
        let mut entry = &mut kvm_cpuid_entry2 {
            function: 0x0,
            index,
            flags: 0,
            eax: 0,
            ebx: 0,
            ecx: 0,
            edx: 0,
            padding: [0, 0, 0],
        };

        assert!(update_extended_topology_entry(&mut entry, &vm_spec).is_ok());

        assert!(entry.eax.read_bits_in_range(&eax::APICID_BITRANGE) == expected_apicid);
        assert!(
            entry
                .ebx
                .read_bits_in_range(&ebx::NUM_LOGICAL_PROCESSORS_BITRANGE)
                == expected_num_logical_processors
        );
        assert!(entry.ecx.read_bits_in_range(&ecx::LEVEL_TYPE_BITRANGE) == expected_level_type);
        assert!(entry.ecx.read_bits_in_range(&ecx::LEVEL_NUMBER_BITRANGE) == index);
    }

    #[test]
    fn test_1vcpu_ht_off() {
        // test update_deterministic_cache_entry
        // test L1
        check_update_deterministic_cache_entry(1, false, 1, 0);
        // test L2
        check_update_deterministic_cache_entry(1, false, 2, 0);
        // test L3
        check_update_deterministic_cache_entry(1, false, 3, 0);

        // test update_extended_topology_entry
        // index 0
        check_update_extended_topology_entry(1, false, 0, 0, 1, LEVEL_TYPE_THREAD);
        // index 1
        check_update_extended_topology_entry(1, false, 1, LEAFBH_INDEX1_APICID, 1, LEVEL_TYPE_CORE);
    }

    #[test]
    fn test_1vcpu_ht_on() {
        // test update_deterministic_cache_entry
        // test L1
        check_update_deterministic_cache_entry(1, true, 1, 0);
        // test L2
        check_update_deterministic_cache_entry(1, true, 2, 0);
        // test L3
        check_update_deterministic_cache_entry(1, true, 3, 0);

        // test update_extended_topology_entry
        // index 0
        check_update_extended_topology_entry(1, true, 0, 0, 1, LEVEL_TYPE_THREAD);
        // index 1
        check_update_extended_topology_entry(1, true, 1, LEAFBH_INDEX1_APICID, 1, LEVEL_TYPE_CORE);
    }

    #[test]
    fn test_2vcpu_ht_off() {
        // test update_deterministic_cache_entry
        // test L1
        check_update_deterministic_cache_entry(2, false, 1, 1);
        // test L2
        check_update_deterministic_cache_entry(2, false, 2, 1);
        // test L3
        check_update_deterministic_cache_entry(2, false, 3, 1);

        // test update_extended_topology_entry
        // index 0
        check_update_extended_topology_entry(2, false, 0, 0, 1, LEVEL_TYPE_THREAD);
        // index 1
        check_update_extended_topology_entry(2, false, 1, LEAFBH_INDEX1_APICID, 2, LEVEL_TYPE_CORE);
    }

    #[test]
    fn test_2vcpu_ht_on() {
        // test update_deterministic_cache_entry
        // test L1
        check_update_deterministic_cache_entry(2, true, 1, 0);
        // test L2
        check_update_deterministic_cache_entry(2, true, 2, 0);
        // test L3
        check_update_deterministic_cache_entry(2, true, 3, 0);

        // test update_extended_topology_entry
        // index 0
        check_update_extended_topology_entry(2, true, 0, 1, 2, LEVEL_TYPE_THREAD);
        // index 1
        check_update_extended_topology_entry(2, true, 1, LEAFBH_INDEX1_APICID, 2, LEVEL_TYPE_CORE);
    }
}
<|endoftext|>


<commit_before>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::{BTreeMap, Vec, VecDeque};
use spin::Mutex;

use arch;
use context::file::File;
use context::memory::{Grant, Memory, SharedMemory, Tls};
use scheme::{SchemeNamespace, FileHandle};
use syscall::data::Event;
use sync::{WaitMap, WaitQueue};

/// Unique identifier for a context (i.e. `pid`).
use ::core::sync::atomic::AtomicUsize;
int_like!(ContextId, AtomicContextId, usize, AtomicUsize);

/// The status of a context - used for scheduling
/// See syscall::process::waitpid and the sync module for examples of usage
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Runnable,
    Blocked,
    Exited(usize)
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: ContextId,
    /// The ID of the parent context
    pub ppid: ContextId,
    /// The real user id
    pub ruid: u32,
    /// The real group id
    pub rgid: u32,
    /// The real namespace id
    pub rns: SchemeNamespace,
    /// The effective user id
    pub euid: u32,
    /// The effective group id
    pub egid: u32,
    /// The effective namespace id
    pub ens: SchemeNamespace,
    /// Status of context
    pub status: Status,
    /// Context running or not
    pub running: bool,
    /// CPU ID, if locked
    pub cpu_id: Option<usize>,
    /// Context is halting parent
    pub vfork: bool,
    /// Context is being waited on
    pub waitpid: Arc<WaitMap<ContextId, usize>>,
    /// Context should handle pending signals
    pub pending: VecDeque<u8>,
    /// Context should wake up at specified time
    pub wake: Option<(u64, u64)>,
    /// The architecture specific context
    pub arch: arch::context::Context,
    /// Kernel FX - used to store SIMD and FPU registers on context switch
    pub kfx: Option<Box<[u8]>>,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// Executable image
    pub image: Vec<SharedMemory>,
    /// User heap
    pub heap: Option<SharedMemory>,
    /// User stack
    pub stack: Option<Memory>,
    /// User Thread local storage
    pub tls: Option<Tls>,
    /// User grants
    pub grants: Arc<Mutex<Vec<Grant>>>,
    /// The name of the context
    pub name: Arc<Mutex<Vec<u8>>>,
    /// The current working directory
    pub cwd: Arc<Mutex<Vec<u8>>>,
    /// Kernel events
    pub events: Arc<WaitQueue<Event>>,
    /// The process environment
    pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>,
    /// The open files in the scheme
    pub files: Arc<Mutex<Vec<Option<File>>>>
}

impl Context {
    pub fn new(id: ContextId) -> Context {
        Context {
            id: id,
            ppid: ContextId::from(0),
            ruid: 0,
            rgid: 0,
            rns: SchemeNamespace::from(0),
            euid: 0,
            egid: 0,
            ens: SchemeNamespace::from(0),
            status: Status::Blocked,
            running: false,
            cpu_id: None,
            vfork: false,
            waitpid: Arc::new(WaitMap::new()),
            pending: VecDeque::new(),
            wake: None,
            arch: arch::context::Context::new(),
            kfx: None,
            kstack: None,
            image: Vec::new(),
            heap: None,
            stack: None,
            tls: None,
            grants: Arc::new(Mutex::new(Vec::new())),
            name: Arc::new(Mutex::new(Vec::new())),
            cwd: Arc::new(Mutex::new(Vec::new())),
            events: Arc::new(WaitQueue::new()),
            env: Arc::new(Mutex::new(BTreeMap::new())),
            files: Arc::new(Mutex::new(Vec::new()))
        }
    }

    /// Make a relative path absolute
    /// Given a cwd of "scheme:/path"
    /// This function will turn "foo" into "scheme:/path/foo"
    /// "/foo" will turn into "scheme:/foo"
    /// "bar:/foo" will be used directly, as it is already absolute
    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
        let mut canon = if path.iter().position(|&b| b == b':').is_none() {
            let cwd = self.cwd.lock();
            if path == b"." {
                cwd.clone()
            } else if path == b".." {
                cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec()
            } else {
                let mut canon = if !path.starts_with(b"/") {
                    let mut c = cwd.clone();
                    if ! c.ends_with(b"/") {
                        c.push(b'/');
                    }
                    c
                } else {
                    cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec()
                };

                canon.extend_from_slice(&path);
                canon
            }
        } else {
            path.to_vec()
        };

        // NOTE: assumes the scheme does not include anything like "../" or "./"
        let mut result = {
            let parts = canon.split(|&c| c == b'/')
                .filter(|&part| part != b".")
                .rev()
                .scan(0, |nskip, part| {
                    if part == b"." {
                        Some(None)
                    } else if part == b".." {
                        *nskip += 1;
                        Some(None)
                    } else {
                        if *nskip > 0 {
                            *nskip -= 1;
                            Some(None)
                        } else {
                            Some(Some(part))
                        }
                    }
                })
                .filter_map(|x| x)
                .collect::<Vec<_>>();
            parts
                .iter()
                .rev()
                .fold(Vec::new(), |mut vec, &part| {
                    vec.extend_from_slice(part);
                    vec.push(b'/');
                    vec
                })
        };
        result.pop(); // remove extra '/'

        // replace with the root of the scheme if it's empty
        if result.len() == 0 {
            let pos = canon.iter()
                            .position(|&b| b == b':')
                            .map_or(canon.len(), |p| p + 1);
            canon.truncate(pos);
            canon
        } else {
            result
        }
    }

    /// Block the context, and return true if it was runnable before being blocked
    pub fn block(&mut self) -> bool {
        if self.status == Status::Runnable {
            self.status = Status::Blocked;
            true
        } else {
            false
        }
    }

    /// Unblock context, and return true if it was blocked before being marked runnable
    pub fn unblock(&mut self) -> bool {
        if self.status == Status::Blocked {
            self.status = Status::Runnable;
            if let Some(cpu_id) = self.cpu_id {
                if cpu_id != ::cpu_id() {
                    // Send IPI if not on current CPU
                    // TODO: Make this more architecture independent
                    unsafe { arch::device::local_apic::LOCAL_APIC.ipi(cpu_id) };
                }
            }
            true
        } else {
            false
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&self, file: File) -> Option<FileHandle> {
        let mut files = self.files.lock();
        for (i, mut file_option) in files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(FileHandle::from(i));
            }
        }
        let len = files.len();
        if len < super::CONTEXT_MAX_FILES {
            files.push(Some(file));
            Some(FileHandle::from(len))
        } else {
            None
        }
    }

    /// Get a file
    pub fn get_file(&self, i: FileHandle) -> Option<File> {
        let files = self.files.lock();
        if i.into() < files.len() {
            files[i.into()]
        } else {
            None
        }
    }

    /// Insert a file with a specific handle number. This is used by dup2
    /// Return the file descriptor number or None if the slot was not empty, or i was invalid
    pub fn insert_file(&self, i: FileHandle, file: File) -> Option<FileHandle> {
        let mut files = self.files.lock();
        if i.into() < super::CONTEXT_MAX_FILES {
            while i.into() >= files.len() {
                files.push(None);
            }
            if files[i.into()].is_none() {
                files[i.into()] = Some(file);
                Some(i)
            } else {
                None
            }
        } else {
            None
        }
    }

    /// Remove a file
    // TODO: adjust files vector to smaller size if possible
    pub fn remove_file(&self, i: FileHandle) -> Option<File> {
        let mut files = self.files.lock();
        if i.into() < files.len() {
            files[i.into()].take()
        } else {
            None
        }
    }
}
<commit_msg>Simplify path parsing<commit_after>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::{BTreeMap, Vec, VecDeque};
use spin::Mutex;

use arch;
use context::file::File;
use context::memory::{Grant, Memory, SharedMemory, Tls};
use scheme::{SchemeNamespace, FileHandle};
use syscall::data::Event;
use sync::{WaitMap, WaitQueue};

/// Unique identifier for a context (i.e. `pid`).
use ::core::sync::atomic::AtomicUsize;
int_like!(ContextId, AtomicContextId, usize, AtomicUsize);

/// The status of a context - used for scheduling
/// See syscall::process::waitpid and the sync module for examples of usage
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Runnable,
    Blocked,
    Exited(usize)
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: ContextId,
    /// The ID of the parent context
    pub ppid: ContextId,
    /// The real user id
    pub ruid: u32,
    /// The real group id
    pub rgid: u32,
    /// The real namespace id
    pub rns: SchemeNamespace,
    /// The effective user id
    pub euid: u32,
    /// The effective group id
    pub egid: u32,
    /// The effective namespace id
    pub ens: SchemeNamespace,
    /// Status of context
    pub status: Status,
    /// Context running or not
    pub running: bool,
    /// CPU ID, if locked
    pub cpu_id: Option<usize>,
    /// Context is halting parent
    pub vfork: bool,
    /// Context is being waited on
    pub waitpid: Arc<WaitMap<ContextId, usize>>,
    /// Context should handle pending signals
    pub pending: VecDeque<u8>,
    /// Context should wake up at specified time
    pub wake: Option<(u64, u64)>,
    /// The architecture specific context
    pub arch: arch::context::Context,
    /// Kernel FX - used to store SIMD and FPU registers on context switch
    pub kfx: Option<Box<[u8]>>,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// Executable image
    pub image: Vec<SharedMemory>,
    /// User heap
    pub heap: Option<SharedMemory>,
    /// User stack
    pub stack: Option<Memory>,
    /// User Thread local storage
    pub tls: Option<Tls>,
    /// User grants
    pub grants: Arc<Mutex<Vec<Grant>>>,
    /// The name of the context
    pub name: Arc<Mutex<Vec<u8>>>,
    /// The current working directory
    pub cwd: Arc<Mutex<Vec<u8>>>,
    /// Kernel events
    pub events: Arc<WaitQueue<Event>>,
    /// The process environment
    pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>,
    /// The open files in the scheme
    pub files: Arc<Mutex<Vec<Option<File>>>>
}

impl Context {
    pub fn new(id: ContextId) -> Context {
        Context {
            id: id,
            ppid: ContextId::from(0),
            ruid: 0,
            rgid: 0,
            rns: SchemeNamespace::from(0),
            euid: 0,
            egid: 0,
            ens: SchemeNamespace::from(0),
            status: Status::Blocked,
            running: false,
            cpu_id: None,
            vfork: false,
            waitpid: Arc::new(WaitMap::new()),
            pending: VecDeque::new(),
            wake: None,
            arch: arch::context::Context::new(),
            kfx: None,
            kstack: None,
            image: Vec::new(),
            heap: None,
            stack: None,
            tls: None,
            grants: Arc::new(Mutex::new(Vec::new())),
            name: Arc::new(Mutex::new(Vec::new())),
            cwd: Arc::new(Mutex::new(Vec::new())),
            events: Arc::new(WaitQueue::new()),
            env: Arc::new(Mutex::new(BTreeMap::new())),
            files: Arc::new(Mutex::new(Vec::new()))
        }
    }

    /// Make a relative path absolute
    /// Given a cwd of "scheme:/path"
    /// This function will turn "foo" into "scheme:/path/foo"
    /// "/foo" will turn into "scheme:/foo"
    /// "bar:/foo" will be used directly, as it is already absolute
    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
        let mut canon = if path.iter().position(|&b| b == b':').is_none() {
            let cwd = self.cwd.lock();

            let mut canon = if !path.starts_with(b"/") {
                let mut c = cwd.clone();
                if ! c.ends_with(b"/") {
                    c.push(b'/');
                }
                c
            } else {
                cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec()
            };

            canon.extend_from_slice(&path);
            canon
        } else {
            path.to_vec()
        };

        // NOTE: assumes the scheme does not include anything like "../" or "./"
        let mut result = {
            let parts = canon.split(|&c| c == b'/')
                .filter(|&part| part != b".")
                .rev()
                .scan(0, |nskip, part| {
                    if part == b"." {
                        Some(None)
                    } else if part == b".." {
                        *nskip += 1;
                        Some(None)
                    } else {
                        if *nskip > 0 {
                            *nskip -= 1;
                            Some(None)
                        } else {
                            Some(Some(part))
                        }
                    }
                })
                .filter_map(|x| x)
                .collect::<Vec<_>>();
            parts
                .iter()
                .rev()
                .fold(Vec::new(), |mut vec, &part| {
                    vec.extend_from_slice(part);
                    vec.push(b'/');
                    vec
                })
        };
        result.pop(); // remove extra '/'

        // replace with the root of the scheme if it's empty
        if result.len() == 0 {
            let pos = canon.iter()
                            .position(|&b| b == b':')
                            .map_or(canon.len(), |p| p + 1);
            canon.truncate(pos);
            canon
        } else {
            result
        }
    }

    /// Block the context, and return true if it was runnable before being blocked
    pub fn block(&mut self) -> bool {
        if self.status == Status::Runnable {
            self.status = Status::Blocked;
            true
        } else {
            false
        }
    }

    /// Unblock context, and return true if it was blocked before being marked runnable
    pub fn unblock(&mut self) -> bool {
        if self.status == Status::Blocked {
            self.status = Status::Runnable;
            if let Some(cpu_id) = self.cpu_id {
                if cpu_id != ::cpu_id() {
                    // Send IPI if not on current CPU
                    // TODO: Make this more architecture independent
                    unsafe { arch::device::local_apic::LOCAL_APIC.ipi(cpu_id) };
                }
            }
            true
        } else {
            false
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&self, file: File) -> Option<FileHandle> {
        let mut files = self.files.lock();
        for (i, mut file_option) in files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(FileHandle::from(i));
            }
        }
        let len = files.len();
        if len < super::CONTEXT_MAX_FILES {
            files.push(Some(file));
            Some(FileHandle::from(len))
        } else {
            None
        }
    }

    /// Get a file
    pub fn get_file(&self, i: FileHandle) -> Option<File> {
        let files = self.files.lock();
        if i.into() < files.len() {
            files[i.into()]
        } else {
            None
        }
    }

    /// Insert a file with a specific handle number. This is used by dup2
    /// Return the file descriptor number or None if the slot was not empty, or i was invalid
    pub fn insert_file(&self, i: FileHandle, file: File) -> Option<FileHandle> {
        let mut files = self.files.lock();
        if i.into() < super::CONTEXT_MAX_FILES {
            while i.into() >= files.len() {
                files.push(None);
            }
            if files[i.into()].is_none() {
                files[i.into()] = Some(file);
                Some(i)
            } else {
                None
            }
        } else {
            None
        }
    }

    /// Remove a file
    // TODO: adjust files vector to smaller size if possible
    pub fn remove_file(&self, i: FileHandle) -> Option<File> {
        let mut files = self.files.lock();
        if i.into() < files.len() {
            files[i.into()].take()
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]
use crate::domains::{Transition, Observation::Terminal};
use crate::geometry::Vector;

pub trait Algorithm {
    /// Perform housekeeping after terminal state observation.
    fn handle_terminal(&mut self) {}
}

pub trait OnlineLearner<S, A>: Algorithm {
    /// Handle a single transition collected from the problem environment.
    fn handle_transition(&mut self, transition: &Transition<S, A>);

    /// Handle an arbitrary sequence of transitions collected from the problem environment.
    fn handle_sequence(&mut self, sequence: &[Transition<S, A>]) {
        sequence.into_iter().for_each(|ref t| self.handle_transition(t));
    }
}

pub trait BatchLearner<S, A>: Algorithm {
    /// Handle a batch of samples collected from the problem environment.
    fn handle_batch(&mut self, batch: &[Transition<S, A>]);
}

pub trait Controller<S, A> {
    /// Sample the target policy for a given state `s`.
    fn sample_target(&mut self, s: &S) -> A;

    /// Sample the behaviour policy for a given state `s`.
    fn sample_behaviour(&mut self, s: &S) -> A;
}

pub trait ValuePredictor<S> {
    /// Compute the estimated value of V(s).
    fn predict_v(&mut self, s: &S) -> f64;
}

pub trait ActionValuePredictor<S, A>: ValuePredictor<S> {
    /// Compute the estimated value of Q(s, a).
    fn predict_qsa(&mut self, s: &S, a: A) -> f64 {
        self.predict_v(s)
    }

    /// Compute the estimated value of Q(s, ·).
    fn predict_qs(&mut self, s: &S) -> Vector<f64> {
        unimplemented!()
    }
}
<commit_msg>feat(core): implement core::algorithms types for Shared<T><commit_after>#![allow(unused_variables)]
use crate::core::Shared;
use crate::domains::{Transition, Observation::Terminal};
use crate::geometry::Vector;

pub trait Algorithm {
    /// Perform housekeeping after terminal state observation.
    fn handle_terminal(&mut self) {}
}

pub trait OnlineLearner<S, A>: Algorithm {
    /// Handle a single transition collected from the problem environment.
    fn handle_transition(&mut self, transition: &Transition<S, A>);

    /// Handle an arbitrary sequence of transitions collected from the problem environment.
    fn handle_sequence(&mut self, sequence: &[Transition<S, A>]) {
        sequence.into_iter().for_each(|ref t| self.handle_transition(t));
    }
}

pub trait BatchLearner<S, A>: Algorithm {
    /// Handle a batch of samples collected from the problem environment.
    fn handle_batch(&mut self, batch: &[Transition<S, A>]);
}

pub trait Controller<S, A> {
    /// Sample the target policy for a given state `s`.
    fn sample_target(&mut self, s: &S) -> A;

    /// Sample the behaviour policy for a given state `s`.
    fn sample_behaviour(&mut self, s: &S) -> A;
}

pub trait ValuePredictor<S> {
    /// Compute the estimated value of V(s).
    fn predict_v(&mut self, s: &S) -> f64;
}

pub trait ActionValuePredictor<S, A>: ValuePredictor<S> {
    /// Compute the estimated value of Q(s, a).
    fn predict_qsa(&mut self, s: &S, a: A) -> f64 {
        self.predict_v(s)
    }

    /// Compute the estimated value of Q(s, ·).
    fn predict_qs(&mut self, s: &S) -> Vector<f64> {
        unimplemented!()
    }
}

// Shared<T> impls:
impl<T: Algorithm> Algorithm for Shared<T> {
    fn handle_terminal(&mut self) {
        self.borrow_mut().handle_terminal()
    }
}

impl<S, A, T: OnlineLearner<S, A>> OnlineLearner<S, A> for Shared<T> {
    fn handle_transition(&mut self, transition: &Transition<S, A>) {
        self.borrow_mut().handle_transition(transition)
    }

    fn handle_sequence(&mut self, sequence: &[Transition<S, A>]) {
        self.borrow_mut().handle_sequence(sequence)
    }
}

impl<S, A, T: BatchLearner<S, A>> BatchLearner<S, A> for Shared<T> {
    fn handle_batch(&mut self, batch: &[Transition<S, A>]) {
        self.borrow_mut().handle_batch(batch)
    }
}

impl<S, A, T: Controller<S, A>> Controller<S, A> for Shared<T> {
    fn sample_target(&mut self, s: &S) -> A {
        self.borrow_mut().sample_target(s)
    }

    fn sample_behaviour(&mut self, s: &S) -> A {
        self.borrow_mut().sample_behaviour(s)
    }
}

impl<S, T: ValuePredictor<S>> ValuePredictor<S> for Shared<T> {
    fn predict_v(&mut self, s: &S) -> f64 {
        self.borrow_mut().predict_v(s)
    }
}

impl<S, A, T: ActionValuePredictor<S, A>> ActionValuePredictor<S, A> for Shared<T> {
    fn predict_qsa(&mut self, s: &S, a: A) -> f64 {
        self.borrow_mut().predict_qsa(s, a)
    }

    fn predict_qs(&mut self, s: &S) -> Vector<f64> {
        self.borrow_mut().predict_qs(s)
    }
}
<|endoftext|>


<commit_before>//! The random module provides methods of randomizing tensors.
//!
//! Here is an example:
//!
//! ```
//! use numeric::Tensor;
//! use numeric::random::RandomState;
//!
//! // Create a random state with seed 1234 (it has to be mutable)
//! let mut rs = RandomState::new(1234);
//!
//! let t = rs.uniform(0.0, 1.0, &[3, 3]);
//! println!("{}", t);
//! //  0.820987  0.93044 0.507159
//! //  0.603939  0.31157 0.383515
//! //  0.702227 0.346673 0.737954
//! // [Tensor<f64> of shape 3x3]
//! ```
use rand::{Rng, SeedableRng, StdRng};
use tensor::Tensor;
use rand::distributions::range::SampleRange;
use Numeric;

pub struct RandomState {
    rng: StdRng,
}

impl RandomState {
    /// Creates a new `RandomState` object with the given seed. The object needs to be captured
    /// as mutable in order to draw samples from it (since its internal state changes).
    pub fn new(seed: usize) -> RandomState {
        let ss: &[_] = &[seed];
        RandomState{rng: SeedableRng::from_seed(ss)}
    }

    /// Generates a tensor by independently drawing samples from a uniform distribution in the
    /// range [`low`, `high`). This is appropriate for integer types as well.
    pub fn uniform<T>(&mut self, low: T, high: T, shape: &[usize]) -> Tensor<T>
            where T: Numeric + SampleRange {
        let mut t = Tensor::zeros(shape);
        for i in 0..t.size() {
            t[i] = self.rng.gen_range::<T>(low, high);
        }
        t
    }
}
<commit_msg>Added standard normal generation<commit_after>//! The random module provides methods of randomizing tensors.
//!
//! Here is an example:
//!
//! ```
//! use numeric::Tensor;
//! use numeric::random::RandomState;
//!
//! // Create a random state with seed 1234 (it has to be mutable)
//! let mut rs = RandomState::new(1234);
//!
//! let t = rs.uniform(0.0, 1.0, &[3, 3]);
//! println!("{}", t);
//! //  0.820987  0.93044 0.507159
//! //  0.603939  0.31157 0.383515
//! //  0.702227 0.346673 0.737954
//! // [Tensor<f64> of shape 3x3]
//! ```
use rand::{Rng, SeedableRng, StdRng};
use tensor::Tensor;
use rand::distributions::range::SampleRange;
use num::traits::Float;
use Numeric;
use math;
use std::f64;

pub struct RandomState {
    rng: StdRng,
}

impl RandomState {
    /// Creates a new `RandomState` object with the given seed. The object needs to be captured
    /// as mutable in order to draw samples from it (since its internal state changes).
    pub fn new(seed: usize) -> RandomState {
        let ss: &[_] = &[seed];
        RandomState{rng: SeedableRng::from_seed(ss)}
    }

    /// Generates a tensor by independently drawing samples from a uniform distribution in the
    /// range [`low`, `high`). This is appropriate for integer types as well.
    pub fn uniform<T>(&mut self, low: T, high: T, shape: &[usize]) -> Tensor<T>
            where T: Numeric + SampleRange {
        let mut t = Tensor::zeros(shape);
        for i in 0..t.size() {
            t[i] = self.rng.gen_range::<T>(low, high);
        }
        t
    }

    /// Generates a tensor by independentaly drawing samples from a standard normal
    pub fn normal<T>(&mut self, shape: &[usize]) -> Tensor<T>
            where T: Numeric + SampleRange + Float {
        let u1 = self.uniform(T::zero(), T::one(), shape);
        let u2 = self.uniform(T::zero(), T::one(), shape);

        let minustwo = Tensor::fscalar(-2.0);
        let twopi = Tensor::fscalar(2.0 * f64::consts::PI);

        math::sqrt(math::ln(u1) * &minustwo) * &math::cos(u2 * &twopi)
    }
}
<|endoftext|>


<commit_before>
// Copyright (c) 2017 Atsushi Miyake
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or http://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.

/// algorithm module
use super::{ Algorithm, CryptoValue };

pub struct Cryptor<T: Algorithm> {
    pub algorithm: T
}

impl<T: Algorithm> Cryptor<T> {

    pub fn encrypt(&mut self, string: &str) -> CryptoValue<T::V> {
        self.algorithm.encrypt(string)
    }

    pub fn decrypt(&mut self, string: &str) -> CryptoValue<T::V> {
        self.algorithm.decrypt(string)
    }
}
<commit_msg>defined associated function to builds new Cryptor<commit_after>
// Copyright (c) 2017 Atsushi Miyake
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or http://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.

/// algorithm module
use super::{ Algorithm, CryptoValue };

pub struct Cryptor<T: Algorithm> {
    pub algorithm: T
}

impl<T: Algorithm> Cryptor<T> {

    pub fn new(algorithm: T) -> Self {
        Cryptor {
            algorithm
        }
    }

    pub fn encrypt(&mut self, string: &str) -> CryptoValue<T::V> {
        self.algorithm.encrypt(string)
    }

    pub fn decrypt(&mut self, string: &str) -> CryptoValue<T::V> {
        self.algorithm.decrypt(string)
    }
}
<|endoftext|>


<commit_before>use std;
use super::DeepClone;

pub struct Region {
  opaque: *mut std::libc::c_void
}

pub struct Rectangle {
  x: i32,
  y: i32,
  width: i32,
  height: i32
}

impl Region {
  pub fn new() -> Region {
    unsafe {
      let foreign_result = cairo_region_create();
      return foreign_result;
    }
  }

  pub fn rectangle(rectangle: &Rectangle) -> Region {
    unsafe {
      let foreign_result = cairo_region_create_rectangle(rectangle);
      return foreign_result;
    }
  }

  pub fn rectangles(rectangles: &[Rectangle]) -> Region {
    unsafe {
      let foreign_result = cairo_region_create_rectangles(rectangles.as_ptr(), rectangles.len() as i32);
      return foreign_result;
    }
  }

  pub fn status(&mut self) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_status(self.opaque);
      return foreign_result;
    }
  }

  pub fn get_extents(&mut self) -> Rectangle {
    unsafe {
      let mut extents:Rectangle = std::intrinsics::init();
      cairo_region_get_extents(self.opaque, &mut extents);
      return extents;
    }
  }

  pub fn num_rectangles(&mut self) -> i32 {
    unsafe {
      let foreign_result = cairo_region_num_rectangles(self.opaque);
      return foreign_result;
    }
  }

  pub fn get_rectangle(&mut self, nth: i32) -> Rectangle {
    unsafe {
      let mut rectangle:Rectangle = std::intrinsics::init();
      cairo_region_get_rectangle(self.opaque, nth, &mut rectangle);
      return rectangle;
    }
  }

  pub fn is_empty(&mut self) -> bool {
    unsafe {
      let foreign_result = cairo_region_is_empty(self.opaque);
      return foreign_result != 0;
    }
  }

  pub fn contains_point(&mut self, x: i32, y: i32) -> bool {
    unsafe {
      let foreign_result = cairo_region_contains_point(self.opaque, x, y);
      return foreign_result != 0;
    }
  }

  pub fn containts_rectangle(&mut self, rectangle: &Rectangle) -> overlap::Overlap {
    unsafe {
      let foreign_result = cairo_region_contains_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  pub fn equal(&mut self, other: &Region) -> bool {
    unsafe {
      let foreign_result = cairo_region_equal(self.opaque, other.opaque as *std::libc::c_void);
      return foreign_result != 0;
    }
  }

  pub fn translate(&mut self, dx: i32, dy: i32) {
    unsafe {
      cairo_region_translate(self.opaque, dx, dy);
    }
  }

  pub fn intersect_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_intersect_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  pub fn subtract(&mut self, region: &Region) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_subtract(self.opaque, region);
      return foreign_result;
    }
  }

  pub fn subtract_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_subtract_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  pub fn union(&mut self, region: &Region) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_union(self.opaque, region);
      return foreign_result;
    }
  }

  pub fn union_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_union_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  pub fn xor(&mut self, region: &Region) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_xor(self.opaque, region);
      return foreign_result;
    }
  }

  pub fn xor_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_xor_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_region_create() -> Region;
  fn cairo_region_create_rectangle(rectangle: *Rectangle) -> Region;
  fn cairo_region_create_rectangles(rectangles: *Rectangle, rectangles_length: i32) -> Region;
  fn cairo_region_status(self_value: *mut std::libc::c_void) -> super::Status;
  fn cairo_region_get_extents(self_value: *mut std::libc::c_void, extents: *mut Rectangle);
  fn cairo_region_num_rectangles(self_value: *mut std::libc::c_void) -> i32;
  fn cairo_region_get_rectangle(self_value: *mut std::libc::c_void, nth: i32, rectangle: *mut Rectangle);
  fn cairo_region_is_empty(self_value: *mut std::libc::c_void) -> i32;
  fn cairo_region_contains_point(self_value: *mut std::libc::c_void, x: i32, y: i32) -> i32;
  fn cairo_region_contains_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> overlap::Overlap;
  fn cairo_region_equal(self_value: *mut std::libc::c_void, other: *std::libc::c_void) -> i32;
  fn cairo_region_translate(self_value: *mut std::libc::c_void, dx: i32, dy: i32);
  fn cairo_region_intersect_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
  fn cairo_region_subtract(self_value: *mut std::libc::c_void, region: *Region) -> super::Status;
  fn cairo_region_subtract_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
  fn cairo_region_union(self_value: *mut std::libc::c_void, region: *Region) -> super::Status;
  fn cairo_region_union_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
  fn cairo_region_xor(self_value: *mut std::libc::c_void, region: *Region) -> super::Status;
  fn cairo_region_xor_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
}

impl std::clone::Clone for Region {
  fn clone(&self) -> Region {
    unsafe {
      let foreign_result = cairo_region_reference(self.opaque as *std::libc::c_void);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_region_reference(self_value: *std::libc::c_void) -> Region;
}

impl DeepClone for Region {
  fn deep_clone(&self) -> Region {
    unsafe {
      let foreign_result = cairo_region_copy(self.opaque as *std::libc::c_void);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_region_copy(self_value: *std::libc::c_void) -> Region;
}

impl std::ops::Drop for Region {
  fn drop(&mut self) {
    unsafe {
      cairo_region_destroy(self.opaque);
    }
  }
}

extern {
  fn cairo_region_destroy(self_value: *mut std::libc::c_void);
}

pub mod overlap;
<commit_msg>Copied Cairo documentation for region<commit_after>//! Representing a pixel-aligned area

use std;
use super::DeepClone;

///  A cairo_region_t represents a set of integer-aligned rectangles.
///
/// It allows set-theoretical operations like cairo_region_union() and cairo_region_intersect() to be performed on them.
///
/// Memory management of cairo_region_t is done with cairo_region_reference() and cairo_region_destroy().
///
/// Since 1.10
pub struct Region {
  /// Wraps Cairo pointer for region.
  opaque: *mut std::libc::c_void
}

///  A data structure for holding a rectangle with integer coordinates.
///
/// Since 1.10
pub struct Rectangle {
  /// X coordinate of the left side of the rectangle
  x: i32,
  /// Y coordinate of the the top side of the rectangle
  y: i32,
  /// width of the rectangle
  width: i32,
  /// height of the rectangle
  height: i32
}

impl Region {
  ///  Allocates a new empty region object.
  ///
  /// Returns : A newly allocated cairo_region_t. Free with cairo_region_destroy(). This function always returns a valid pointer; if memory cannot be allocated, then a special error object is returned where all operations on the object do nothing. You can check for this with cairo_region_status().
  ///
  /// Since 1.10
  pub fn new() -> Region {
    unsafe {
      let foreign_result = cairo_region_create();
      return foreign_result;
    }
  }

  ///  Allocates a new region object containing rectangle.
  ///
  /// rectangle : a cairo_rectangle_int_t
  ///
  /// Returns : A newly allocated cairo_region_t. Free with cairo_region_destroy(). This function always returns a valid pointer; if memory cannot be allocated, then a special error object is returned where all operations on the object do nothing. You can check for this with cairo_region_status().
  ///
  /// Since 1.10
  pub fn rectangle(rectangle: &Rectangle) -> Region {
    unsafe {
      let foreign_result = cairo_region_create_rectangle(rectangle);
      return foreign_result;
    }
  }

  ///  Allocates a new region object containing the union of all given rects.
  ///
  /// rects : an array of count rectangles
  ///
  /// count : number of rectangles
  ///
  /// Returns : A newly allocated cairo_region_t. Free with cairo_region_destroy(). This function always returns a valid pointer; if memory cannot be allocated, then a special error object is returned where all operations on the object do nothing. You can check for this with cairo_region_status().
  ///
  /// Since 1.10
  pub fn rectangles(rectangles: &[Rectangle]) -> Region {
    unsafe {
      let foreign_result = cairo_region_create_rectangles(rectangles.as_ptr(), rectangles.len() as i32);
      return foreign_result;
    }
  }

  ///  Checks whether an error has previous occurred for this region object.
  ///
  /// region : a cairo_region_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn status(&mut self) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_status(self.opaque);
      return foreign_result;
    }
  }

  ///  Gets the bounding rectangle of region as a cairo_rectangle_int_t
  ///
  /// region : a cairo_region_t
  ///
  /// extents : rectangle into which to store the extents
  ///
  /// Since 1.10
  pub fn get_extents(&mut self) -> Rectangle {
    unsafe {
      let mut extents:Rectangle = std::intrinsics::init();
      cairo_region_get_extents(self.opaque, &mut extents);
      return extents;
    }
  }

  ///  Returns the number of rectangles contained in region.
  ///
  /// region : a cairo_region_t
  ///
  /// Returns : The number of rectangles contained in region.
  ///
  /// Since 1.10
  pub fn num_rectangles(&mut self) -> i32 {
    unsafe {
      let foreign_result = cairo_region_num_rectangles(self.opaque);
      return foreign_result;
    }
  }

  ///  Stores the nth rectangle from the region in rectangle.
  ///
  /// region : a cairo_region_t
  ///
  /// nth : a number indicating which rectangle should be returned
  ///
  /// rectangle : return location for a cairo_rectangle_int_t
  ///
  /// Since 1.10
  pub fn get_rectangle(&mut self, nth: i32) -> Rectangle {
    unsafe {
      let mut rectangle:Rectangle = std::intrinsics::init();
      cairo_region_get_rectangle(self.opaque, nth, &mut rectangle);
      return rectangle;
    }
  }

  ///  Checks whether region is empty.
  ///
  /// region : a cairo_region_t
  ///
  /// Returns : TRUE if region is empty, FALSE if it isn't.
  ///
  /// Since 1.1
  pub fn is_empty(&mut self) -> bool {
    unsafe {
      let foreign_result = cairo_region_is_empty(self.opaque);
      return foreign_result != 0;
    }
  }

  ///  Checks whether (x, y) is contained in region.
  ///
  /// region : a cairo_region_t
  ///
  /// x : the x coordinate of a point
  ///
  /// y : the y coordinate of a point
  ///
  /// Returns : TRUE if (x, y) is contained in region, FALSE if it is not.
  ///
  /// Since 1.10
  pub fn contains_point(&mut self, x: i32, y: i32) -> bool {
    unsafe {
      let foreign_result = cairo_region_contains_point(self.opaque, x, y);
      return foreign_result != 0;
    }
  }

  ///  Checks whether rectangle is inside, outside or partially contained in region
  ///
  /// region : a cairo_region_t
  ///
  /// rectangle : a cairo_rectangle_int_t
  ///
  /// Returns : CAIRO_REGION_OVERLAP_IN if rectangle is entirely inside region, CAIRO_REGION_OVERLAP_OUT if rectangle is entirely outside region, or CAIRO_REGION_OVERLAP_PART if rectangle is partially inside and partially outside region.
  ///
  /// Since 1.10
  pub fn containts_rectangle(&mut self, rectangle: &Rectangle) -> overlap::Overlap {
    unsafe {
      let foreign_result = cairo_region_contains_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  ///  Compares whether region_a is equivalent to region_b. NULL as an argument is equal to itself, but not to any non-NULL region.
  ///
  /// a : a cairo_region_t or NULL
  ///
  /// b : a cairo_region_t or NULL
  ///
  /// Returns : TRUE if both regions contained the same coverage, FALSE if it is not or any region is in an error status.
  ///
  /// Since 1.10
  pub fn equal(&mut self, other: &Region) -> bool {
    unsafe {
      let foreign_result = cairo_region_equal(self.opaque, other.opaque as *std::libc::c_void);
      return foreign_result != 0;
    }
  }

  ///  Translates region by (dx, dy).
  ///
  /// region : a cairo_region_t
  ///
  /// dx : Amount to translate in the x direction
  ///
  /// dy : Amount to translate in the y direction
  ///
  /// Since 1.10
  pub fn translate(&mut self, dx: i32, dy: i32) {
    unsafe {
      cairo_region_translate(self.opaque, dx, dy);
    }
  }

  ///  Computes the intersection of dst with rectangle and places the result in dst
  ///
  /// dst : a cairo_region_t
  ///
  /// rectangle : a cairo_rectangle_int_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn intersect_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_intersect_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  ///  Subtracts other from dst and places the result in dst
  ///
  /// dst : a cairo_region_t
  ///
  /// other : another cairo_region_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn subtract(&mut self, region: &Region) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_subtract(self.opaque, region);
      return foreign_result;
    }
  }

  ///  Subtracts rectangle from dst and places the result in dst
  ///
  /// dst : a cairo_region_t
  ///
  /// rectangle : a cairo_rectangle_int_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn subtract_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_subtract_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  ///  Computes the union of dst with other and places the result in dst
  ///
  /// dst : a cairo_region_t
  ///
  /// other : another cairo_region_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn union(&mut self, region: &Region) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_union(self.opaque, region);
      return foreign_result;
    }
  }

  ///  Computes the union of dst with rectangle and places the result in dst.
  ///
  /// dst : a cairo_region_t
  ///
  /// rectangle : a cairo_rectangle_int_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn union_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_union_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  ///  Computes the exclusive difference of dst with other and places the result in dst. That is, dst will be set to contain all areas that are either in dst or in other, but not in both.
  ///
  /// dst : a cairo_region_t
  ///
  /// other : another cairo_region_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn xor(&mut self, region: &Region) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_xor(self.opaque, region);
      return foreign_result;
    }
  }

  ///  Computes the exclusive difference of dst with rectangle and places the result in dst. That is, dst will be set to contain all areas that are either in dst or in rectangle, but not in both.
  ///
  /// dst : a cairo_region_t
  ///
  /// rectangle : a cairo_rectangle_int_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn xor_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_xor_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_region_create() -> Region;
  fn cairo_region_create_rectangle(rectangle: *Rectangle) -> Region;
  fn cairo_region_create_rectangles(rectangles: *Rectangle, rectangles_length: i32) -> Region;
  fn cairo_region_status(self_value: *mut std::libc::c_void) -> super::Status;
  fn cairo_region_get_extents(self_value: *mut std::libc::c_void, extents: *mut Rectangle);
  fn cairo_region_num_rectangles(self_value: *mut std::libc::c_void) -> i32;
  fn cairo_region_get_rectangle(self_value: *mut std::libc::c_void, nth: i32, rectangle: *mut Rectangle);
  fn cairo_region_is_empty(self_value: *mut std::libc::c_void) -> i32;
  fn cairo_region_contains_point(self_value: *mut std::libc::c_void, x: i32, y: i32) -> i32;
  fn cairo_region_contains_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> overlap::Overlap;
  fn cairo_region_equal(self_value: *mut std::libc::c_void, other: *std::libc::c_void) -> i32;
  fn cairo_region_translate(self_value: *mut std::libc::c_void, dx: i32, dy: i32);
  fn cairo_region_intersect_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
  fn cairo_region_subtract(self_value: *mut std::libc::c_void, region: *Region) -> super::Status;
  fn cairo_region_subtract_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
  fn cairo_region_union(self_value: *mut std::libc::c_void, region: *Region) -> super::Status;
  fn cairo_region_union_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
  fn cairo_region_xor(self_value: *mut std::libc::c_void, region: *Region) -> super::Status;
  fn cairo_region_xor_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
}

impl std::clone::Clone for Region {
  fn clone(&self) -> Region {
    unsafe {
      let foreign_result = cairo_region_reference(self.opaque as *std::libc::c_void);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_region_reference(self_value: *std::libc::c_void) -> Region;
}

impl DeepClone for Region {
  fn deep_clone(&self) -> Region {
    unsafe {
      let foreign_result = cairo_region_copy(self.opaque as *std::libc::c_void);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_region_copy(self_value: *std::libc::c_void) -> Region;
}

impl std::ops::Drop for Region {
  fn drop(&mut self) {
    unsafe {
      cairo_region_destroy(self.opaque);
    }
  }
}

extern {
  fn cairo_region_destroy(self_value: *mut std::libc::c_void);
}

pub mod overlap;
<|endoftext|>


<commit_before>use std::path::Path;
use url::Url;
use error::GhqError;
use vcs;

#[allow(dead_code)]
#[cfg_attr(rustfmt, rustfmt_skip)]
const KNOWN_HOSTS: &'static [(&'static str, usize)] = &[
    ("github.com", 2)
  , ("gist.github.com", 1)
  , ("bitbucket.org", 2)
  , ("gitlab.com", 2)
];

#[allow(dead_code)]
#[derive(Debug)]
pub struct Repository {
  vcs: vcs::VCS,
  pub path: String,
}

impl Repository {
  pub fn from_local(path: &Path) -> Result<Repository, ()> {
    let vcs = vcs::detect(path).ok_or(())?;
    let path = path.to_str().map(ToOwned::to_owned).ok_or(())?;
    Ok(Repository {
      vcs: vcs,
      path: path,
    })
  }
}

pub fn parse_token(s: &str) -> Result<(Url, String, String), GhqError> {
  let url = make_remote_url(s)?;

  let host = url.host_str().ok_or("cannot retrieve host information").map(ToOwned::to_owned)?;
  let path = url.path().trim_left_matches("/").trim_right_matches(".git").to_owned();

  Ok((url, host, path))
}

fn make_remote_url(s: &str) -> Result<Url, GhqError> {
  if let Ok(url) = Url::parse(s) {
    return Ok(url);
  }

  let path: Vec<_> = s.split("/").collect();
  let path = match path.len() {
    0 => return Err("unsupported pattern to resolve remote URL").map_err(Into::into),
    1 => vec!["github.com", path[0], path[0]],
    2 => vec!["github.com", path[0], path[1]],
    _ => path,
  };

  Url::parse(&format!("{}://{}.git", "https", path.join("/"))).map_err(Into::into)
}

#[cfg(test)]
mod test_parse_token {
  use super::parse_token;

  fn assert_helper(s: &str, _url: &str, _host: &str, _path: &str) {
    let (url, host, path) = parse_token(s).unwrap();
    assert_eq!(url.as_str(), _url);
    assert_eq!(host, _host);
    assert_eq!(path, _path);
  }

  #[test]
  fn user_project() {
    assert_helper("hoge/fuga",
                  "https://github.com/hoge/fuga.git",
                  "github.com",
                  "hoge/fuga");
  }

  #[test]
  fn domain_user_project() {
    assert_helper("github.com/hoge/fuga",
                  "https://github.com/hoge/fuga.git",
                  "github.com",
                  "hoge/fuga");
  }

  #[test]
  fn only_project_name() {
    assert_helper("fuga",
                  "https://github.com/fuga/fuga.git",
                  "github.com",
                  "fuga/fuga");
  }

  #[test]
  fn repository_url() {
    assert_helper("https://gitlab.com/funga-/pecopeco.git",
                  "https://gitlab.com/funga-/pecopeco.git",
                  "gitlab.com",
                  "funga-/pecopeco");
  }

  #[test]
  fn long_path() {
    assert_helper("github.com/hoge/fuga/foo/a/b/c",
                  "https://github.com/hoge/fuga/foo/a/b/c.git",
                  "github.com",
                  "hoge/fuga/foo/a/b/c");
  }
}
<commit_msg>fix test<commit_after>use std::path::Path;
use url::Url;
use error::GhqError;
use vcs;

#[allow(dead_code)]
#[cfg_attr(rustfmt, rustfmt_skip)]
const KNOWN_HOSTS: &'static [(&'static str, usize)] = &[
    ("github.com", 2)
  , ("gist.github.com", 1)
  , ("bitbucket.org", 2)
  , ("gitlab.com", 2)
];

#[allow(dead_code)]
#[derive(Debug)]
pub struct Repository {
  vcs: vcs::VCS,
  pub path: String,
}

impl Repository {
  pub fn from_local(path: &Path) -> Result<Repository, ()> {
    let vcs = vcs::detect(path).ok_or(())?;
    let path = path.to_str().map(ToOwned::to_owned).ok_or(())?;
    Ok(Repository {
      vcs: vcs,
      path: path,
    })
  }
}

pub fn parse_token(s: &str) -> Result<(Url, String, String), GhqError> {
  let url = make_remote_url(s)?;

  let host = url.host_str().ok_or("cannot retrieve host information").map(ToOwned::to_owned)?;
  let path = url.path().trim_left_matches("/").trim_right_matches(".git").to_owned();

  Ok((url, host, path))
}

fn make_remote_url(s: &str) -> Result<Url, GhqError> {
  if let Ok(url) = Url::parse(s) {
    return Ok(url);
  }

  let path: Vec<_> = s.split("/").collect();
  let path = match path.len() {
    0 => return Err("unsupported pattern to resolve remote URL").map_err(Into::into),
    1 => vec!["github.com", path[0], path[0]],
    2 => vec!["github.com", path[0], path[1]],
    _ => path,
  };

  Url::parse(&format!("{}://{}.git", "https", path.join("/"))).map_err(Into::into)
}

#[cfg(test)]
mod test_parse_token {
  use super::parse_token;

  macro_rules! def_test {
    ($name:ident, $s:expr, $url:expr, $host:expr, $path:expr) => {
      #[test]
      fn $name() {
        let (url, host, path) = parse_token($s).unwrap();
        assert_eq!(url.as_str(), $url);
        assert_eq!(host, $host);
        assert_eq!(path, $path);
      }
    }
  }

  def_test!(user_project,
            "hoge/fuga",
            "https://github.com/hoge/fuga.git",
            "github.com",
            "hoge/fuga");

  def_test!(domain_user_project,
            "github.com/hoge/fuga",
            "https://github.com/hoge/fuga.git",
            "github.com",
            "hoge/fuga");

  def_test!(only_project_name,
            "fuga",
            "https://github.com/fuga/fuga.git",
            "github.com",
            "fuga/fuga");

  def_test!(repository_url,
            "https://gitlab.com/funga-/pecopeco.git",
            "https://gitlab.com/funga-/pecopeco.git",
            "gitlab.com",
            "funga-/pecopeco");

  def_test!(long_path,
            "github.com/hoge/fuga/foo/a/b/c",
            "https://github.com/hoge/fuga.git",
            "github.com",
            "hoge/fuga/foo/a/b/c");
}
<|endoftext|>


<commit_before>/**
This is used to indicate why a scan has failed.
*/
#[deriving(Show)]
pub enum ScanError {
	NothingMatched,
	OtherScanError(String, uint),
	ScanIoError(::std::io::IoError),
}

impl ScanError {
	/**
	Takes two `ScanError` values and returns the "most interesting" one.  The general rules are:

	* An IO error takes precedence over anything else.
	* Scan errors which happened further along the input take precedence.  This should hopefully be the error from the most relevant arm.
	*/
	pub fn or(self, other: ScanError) -> ScanError {
		match (self, other) {
			(ScanIoError(ioerr), _) | (_, ScanIoError(ioerr)) => ScanIoError(ioerr),
			(NothingMatched, other) | (other, NothingMatched) => other,
			(OtherScanError(msga, offa), OtherScanError(msgb, offb)) => {
				if offa > offb {
					OtherScanError(msga, offa)
				} else {
					OtherScanError(msgb, offb)
				}
			}
		}
	}
}
<commit_msg>Removed doc comments because rustdoc is stupid.<commit_after>/*
This is used to indicate why a scan has failed.
*/
#[deriving(Show)]
pub enum ScanError {
	NothingMatched,
	OtherScanError(String, uint),
	ScanIoError(::std::io::IoError),
}

impl ScanError {
	/*
	Takes two `ScanError` values and returns the "most interesting" one.  The general rules are:

	* An IO error takes precedence over anything else.
	* Scan errors which happened further along the input take precedence.  This should hopefully be the error from the most relevant arm.
	*/
	pub fn or(self, other: ScanError) -> ScanError {
		match (self, other) {
			(ScanIoError(ioerr), _) | (_, ScanIoError(ioerr)) => ScanIoError(ioerr),
			(NothingMatched, other) | (other, NothingMatched) => other,
			(OtherScanError(msga, offa), OtherScanError(msgb, offb)) => {
				if offa > offb {
					OtherScanError(msga, offa)
				} else {
					OtherScanError(msgb, offb)
				}
			}
		}
	}
}
<|endoftext|>