<commit_before>extern crate serde_json;

use self::super::{ERR_HOST, ERR_HTSI, ERR_INVALID, MAP, OK};
use self::super::super::http;

use base64::{encode, decode};
use std::slice;
use std::u16;

#[derive(Serialize)]
struct RequestData {
    dad: u8,
    sad: u8,
    lenc: usize,
    command: String,
    lenr: usize,
}

#[allow(non_snake_case)]
#[derive(Deserialize)]
struct ResponseData {
    dad: u8,
    sad: u8,
    lenr: usize,
    response: String,
    responseCode: i8,
}

pub fn data(ctn: u16,
            dad: *mut u8,
            sad: *mut u8,
            lenc: usize,
            command: *const u8,
            lenr: *mut usize,
            response: *mut u8)
            -> i8 {

    let _dad: &mut u8 = unsafe { &mut *dad };
    debug!("dad: {}", _dad);

    let _sad: &mut u8 = unsafe { &mut *sad };
    debug!("sad: {}", _sad);
    debug!("lenc: {}", lenc);

    let _command = unsafe { slice::from_raw_parts(command, lenc as usize) };
    debug!("command: {:?}", _command);

    let _lenr: &mut usize = unsafe { &mut *lenr };
    debug!("lenr: {}", _lenr);

    sanitize_lenr(&mut *_lenr);

    let _response = unsafe { slice::from_raw_parts_mut(response, *_lenr) };
    debug!("response with {} slices formed", _response.len());

    if !MAP.lock().unwrap().contains_key(&ctn) {
        debug!("Card terminal has not been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    let request_data = RequestData {
        dad: *_dad,
        sad: *_sad,
        lenc: lenc,
        command: encode(_command),
        lenr: *_lenr,
    };

    let path = get_request_path(ctn);
    let http_response = match http::post(path, &request_data) {
        Ok(http_response) => http_response,
        Err(error) => {
            debug!("Error: {:?}", error);
            error!("Request failed! Returning {}", ERR_HTSI);
            return ERR_HTSI;
        }
    };

    let (http_status, response_body) = http::extract_response(http_response);
    match http_status {
        http::HttpStatus::Ok => {
            let data: ResponseData = serde_json::from_str(&response_body).unwrap();

            if data.responseCode == OK {
                *_dad = data.dad;
                *_sad = data.sad;
                *_lenr = data.lenr;

                let decoded = decode(&data.response).unwrap();
                debug!("Decoded response field {:?}", decoded);

                for (place, element) in _response.iter_mut().zip(decoded.iter()) {
                    *place = *element;
                }
            }
            debug!("Returning {}", data.responseCode);
            return data.responseCode;
        }
        _ => {
            error!("Response not OK! Returning {}", ERR_HOST);
            ERR_HOST
        }
    }
}

fn get_request_path(ctn: u16) -> String {
    let pn = MAP.lock().unwrap();
    let pn = pn.get(&ctn).unwrap();

    let mut path = String::from("ct_data");
    path.push_str("/");
    path.push_str(&ctn.to_string());
    path.push_str("/");
    path.push_str(&pn.to_string());

    path
}

fn sanitize_lenr(lenr: &mut usize) {
    let max_usize = u16::MAX as usize;
    if *lenr > max_usize {
        debug!("... sanitize lenr to {}", u16::MAX);
        *lenr = max_usize;
    }
}
<commit_msg>add test of contract to ct_data<commit_after>extern crate serde_json;

use self::super::{ERR_HOST, ERR_HTSI, ERR_INVALID, MAP, OK};
use self::super::super::http;

use base64::{encode, decode};
use std::slice;
use std::u16;
use std::u8;

#[derive(Serialize)]
struct RequestData {
    dad: u8,
    sad: u8,
    lenc: usize,
    command: String,
    lenr: usize,
}

#[allow(non_snake_case)]
#[derive(Deserialize)]
struct ResponseData {
    dad: u8,
    sad: u8,
    lenr: usize,
    response: String,
    responseCode: i8,
}

pub fn data(ctn: u16,
            dad: *mut u8,
            sad: *mut u8,
            lenc: usize,
            command: *const u8,
            lenr: *mut usize,
            response: *mut u8)
            -> i8 {

    debug!("ctn: {}", ctn);
    if !(ctn >= u16::MIN && ctn <= u16::MAX) {
        error!("ctn is not an u16. Returning {}", ERR_INVALID);
        return ERR_INVALID;
    }

    let safe_dad: &mut u8 = unsafe { &mut *dad };
    debug!("dad: {}", safe_dad);
    if !(safe_dad >= &mut u8::MIN && safe_dad <= &mut u8::MAX) {
        error!("dad is not an u8. Returning {}", ERR_INVALID);
        return ERR_INVALID;
    }

    let safe_sad: &mut u8 = unsafe { &mut *sad };
    debug!("sad: {}", safe_sad);
    if !(safe_sad >= &mut u8::MIN && safe_sad <= &mut u8::MAX) {
        error!("sad is not an u8. Returning {}", ERR_INVALID);
        return ERR_INVALID;
    }

    debug!("lenc: {}", lenc);
    if !(lenc > u16::MIN as usize && lenc < u16::MAX as usize) {
        error!("lenc is not an u16. Returning {}", ERR_INVALID);
        return ERR_INVALID;
    }

    let safe_command = unsafe { slice::from_raw_parts(command, lenc) };
    debug!("command: {:?}", safe_command);

    let safe_lenr: &mut usize = unsafe { &mut *lenr };
    debug!("lenr: {}", safe_lenr);
    sanitize_lenr(&mut *safe_lenr);

    let safe_response = unsafe { slice::from_raw_parts_mut(response, *safe_lenr) };
    debug!("response with {} slices formed", safe_response.len());

    if !MAP.lock().unwrap().contains_key(&ctn) {
        debug!("Card terminal has not been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    let request_data = RequestData {
        dad: *safe_dad,
        sad: *safe_sad,
        lenc,
        command: encode(safe_command),
        lenr: *safe_lenr,
    };

    let path = get_request_path(ctn);
    let http_response = match http::post(path, &request_data) {
        Ok(http_response) => http_response,
        Err(error) => {
            debug!("Error: {:?}", error);
            error!("Request failed! Returning {}", ERR_HTSI);
            return ERR_HTSI;
        }
    };

    let (http_status, response_body) = http::extract_response(http_response);
    match http_status {
        http::HttpStatus::Ok => {
            let data: ResponseData = serde_json::from_str(&response_body).unwrap();

            if data.responseCode == OK {
                *safe_dad = data.dad;
                *safe_sad = data.sad;
                *safe_lenr = data.lenr;

                let decoded = decode(&data.response).unwrap();
                debug!("Decoded response field {:?}", decoded);

                for (place, element) in safe_response.iter_mut().zip(decoded.iter()) {
                    *place = *element;
                }
            }
            debug!("Returning {}", data.responseCode);
            return data.responseCode;
        }
        _ => {
            error!("Response not OK! Returning {}", ERR_HOST);
            ERR_HOST
        }
    }
}

fn get_request_path(ctn: u16) -> String {
    let pn = MAP.lock().unwrap();
    let pn = pn.get(&ctn).unwrap();

    let mut path = String::from("ct_data");
    path.push_str("/");
    path.push_str(&ctn.to_string());
    path.push_str("/");
    path.push_str(&pn.to_string());

    path
}

fn sanitize_lenr(lenr: &mut usize) {
    let max_usize = u16::MAX as usize;
    let min_usize = u16::MIN as usize;
    if *lenr < min_usize || *lenr > max_usize {
        debug!("... sanitize lenr to {}", u16::MAX);
        *lenr = max_usize;
    }
}
<|endoftext|>


<commit_before>use alga::general::SupersetOf;
use nalgebra::{Point3, Scalar, Unit};
use num::{Bounded, One, Zero}; // TODO: `use ::std::num::{One, Zero};`.
use std::ops::Range;

use clamp::{Clamped, ClampedRange};
use math::{self, FRay3, FPoint3, FromSpace, FScalar, FVector3, LowerBound, Mask, UPoint3,
           UpperBound, UScalar, UVector3};

/// Defines the bounds for `LogWidth` values.
pub struct LogWidthRange;

impl ClampedRange<u8> for LogWidthRange {
    fn max_value() -> u8 {
        31
    }

    fn min_value() -> u8 {
        4
    }
}

/// Logarithmic width. Most uses of the term "width" refer to `LogWidth`.
///
/// This is the base-2 logarithmic width of a space in a tree, such that a width
/// `x` exponentiates as `2ˣ`. Exponentiation is performed as a simple bit
/// shift.
///
/// Being logarithmic, if a cube has a width `x`, then its immediate
/// subdivisions have a width `x - 1` and its parent a width `x + 1`.
///
/// `LogWidth` is clamped to the open range `[4, 31]`.
pub type LogWidth = Clamped<u8, LogWidthRange>;

impl LogWidth {
    /// Reference width of `Cube`s.
    pub fn unit() -> Self {
        LogWidth::new(8)
    }

    /// Exponentiates a `LogWidth` into a `UScalar`.
    pub fn exp(&self) -> UScalar {
        UScalar::one() << self.to_inner()
    }
}

/// An axis in the tree space.
///
/// Defines and orders the axes in the tree space.
#[derive(Clone, Copy)]
pub enum Axis {
    X = 0,
    Y = 1,
    Z = 2,
}

impl Axis {
    /// Gets a `Range` over axes as `usize`s.
    pub fn range() -> Range<usize> {
        (Axis::X as usize)..(Axis::Z as usize + 1)
    }

    pub fn to_vector(&self) -> FVector3 {
        match *self {
            Axis::X => FVector3::x(),
            Axis::Y => FVector3::y(),
            Axis::Z => FVector3::z(),
        }
    }
}

impl From<usize> for Axis {
    fn from(index: usize) -> Self {
        match index {
            0 => Axis::X,
            1 => Axis::Y,
            2 => Axis::Z,
            _ => panic!(), // TODO: Use `TryFrom`.
        }
    }
}

/// A direction along an `Axis`.
pub enum Direction {
    Positive,
    Negative,
}

/// An orientation in the tree space.
///
/// This is akin to choosing a face of a cube in a tree and orienting that face
/// based on the axis and direction in which it deforms. For example, `Left` is
/// a face along the `X` axis that deforms in the `Positive` direction.
pub enum Orientation {
    Left,
    Right,
    Top,
    Bottom,
    Front,
    Back,
}

impl Orientation {
    /// Gets the `Axis` associated with the `Orientation`.
    pub fn axis(&self) -> Axis {
        match *self {
            Orientation::Left | Orientation::Right => Axis::X,
            Orientation::Top | Orientation::Bottom => Axis::Y,
            Orientation::Front | Orientation::Back => Axis::Z,
        }
    }

    /// Gets the `Direction` associated with the `Orientation`.
    pub fn direction(&self) -> Direction {
        match *self {
            Orientation::Left | Orientation::Bottom | Orientation::Back => Direction::Positive,
            Orientation::Right | Orientation::Top | Orientation::Front => Direction::Negative,
        }
    }
}

pub trait PointNormal {
    fn normal(&self, point: &FPoint3) -> FVector3;
}

/// Shape or primitive that can test for intersection with another shape or
/// primitive.
pub trait Intersects<T> {
    /// Tests for intersection.
    fn intersects(&self, other: &T) -> bool;
}

/// Details of intersection with an `FRay3`.
pub struct RayIntersection {
    /// The minimum time of impact.
    pub distance: FScalar,
    /// The minimum point of intersection.
    pub point: FPoint3,
    /// The normal at the point of intersection.
    pub normal: Unit<FVector3>,
}

impl RayIntersection {
    /// Creates a new `RayIntersection`. Normalizes `normal`.
    fn new(distance: FScalar, point: FPoint3, normal: FVector3) -> Self {
        RayIntersection {
            distance: distance,
            point: point,
            normal: Unit::new_normalize(normal),
        }
    }
}

/// Shape or primitive that can test for intersection with an `FRay3`, omitting
/// some details about the intersection.
pub trait PartialRayCast {
    /// Determines if an `FRay3` intersects the shape or primitive. Returns the
    /// minimum and maximum time of impact (distance), respectively.
    fn partial_ray_intersection(&self, ray: &FRay3) -> Option<(FScalar, FScalar)>;
}

/// Shape or primitive that can test for intersection with an `FRay3`.
pub trait RayCast: PartialRayCast {
    /// Determines if an `FRay3` intersects the shape or primitive and returns
    /// details about the intersection.
    fn ray_intersection(&self, ray: &FRay3) -> Option<RayIntersection>;
}

impl<T> Intersects<FRay3> for T
    where T: PartialRayCast
{
    fn intersects(&self, ray: &FRay3) -> bool {
        self.partial_ray_intersection(ray).is_some()
    }
}

impl<T> RayCast for T
    where T: PartialRayCast + PointNormal
{
    fn ray_intersection(&self, ray: &FRay3) -> Option<RayIntersection> {
        self.partial_ray_intersection(ray).map(|(distance, _)| {
            let point = ray.origin + (*ray.direction * distance);
            RayIntersection::new(distance, point, self.normal(&point))
        })
    }
}

/// Axis-aligned bounding box.
///
/// `AABB`s are represented as an origin and extent.
pub struct AABB {
    pub origin: UPoint3,
    pub extent: UVector3,
}

impl AABB {
    /// Constructs a new `AABB` at the given point in space with the given
    /// extent.
    pub fn new(origin: UPoint3, extent: UVector3) -> Self {
        AABB {
            origin: origin,
            extent: extent,
        }
    }

    /// Constructs the union of two `AABB`s.
    ///
    /// The union is the cuboid formed from the lower and upper bounds of the
    /// `AABB`s.
    pub fn union(&self, other: &Self) -> Self {
        let start = self.origin.lower_bound(&other.origin);
        let end = self.endpoint().upper_bound(&other.endpoint());
        AABB::new(start, end - start)
    }

    /// Gets the midpoint (center) of the `AABB`.
    pub fn midpoint(&self) -> UPoint3 {
        self.origin + (self.extent / 2)
    }

    /// Gets the absolute endpoint of the `AABB`.
    pub fn endpoint(&self) -> UPoint3 {
        self.origin + self.extent
    }
}

impl Intersects<AABB> for AABB {
    /// Determines if two `AABB`s intersect.
    fn intersects(&self, aabb: &AABB) -> bool {
        for axis in Axis::range() {
            if (self.origin[axis] + self.extent[axis]) < aabb.origin[axis] {
                return false;
            }
            if self.origin[axis] > (aabb.origin[axis] + aabb.extent[axis]) {
                return false;
            }
        }
        true
    }
}

impl<T> Intersects<Point3<T>> for AABB
    where T: PartialOrd + Scalar + SupersetOf<UScalar>
{
    /// Determines if a point intersects an `AABB`.
    fn intersects(&self, point: &Point3<T>) -> bool {
        use nalgebra::convert;

        for axis in Axis::range() {
            if convert::<UScalar, T>(self.origin[axis] + self.extent[axis]) < point[axis] {
                return false;
            }
            if convert::<UScalar, T>(self.origin[axis]) > point[axis] {
                return false;
            }
        }
        true
    }
}

impl PartialRayCast for AABB {
    /// Determines if an `FRay3` intersects an `AABB`. Returns the minimum and
    /// maximum times of impact as a tuple, respectively.
    fn partial_ray_intersection(&self, ray: &FRay3) -> Option<(FScalar, FScalar)> {
        let mut min = FVector3::zero();
        let mut max = FVector3::zero();
        for axis in Axis::range() {
            let lower = self.origin[axis] as FScalar;
            let upper = lower + self.extent[axis] as FScalar;
            let origin = ray.origin[axis];
            let direction = ray.direction[axis];

            let (low, high) = math::ordered_pair((lower - origin) / direction,
                                                 (upper - origin) / direction);
            min[axis] = low;
            max[axis] = high;
        }

        let tmin = math::partial_max(math::partial_max(min.x, min.y), min.z);
        let tmax = math::partial_min(math::partial_min(max.x, max.y), max.z);
        if tmax < 0.0 || tmin > tmax {
            None
        }
        else {
            Some((tmin, tmax))
        }
    }
}

impl PointNormal for AABB {
    /// Gets the normal at a point along or near the surface of the `AABB`.
    fn normal(&self, point: &FPoint3) -> FVector3 {
        let point = point - FPoint3::from_space(self.midpoint());
        let mut min_distance = FScalar::max_value();
        let mut normal = FVector3::zero();
        for axis in Axis::range() {
            let distance = (self.extent[axis] as FScalar - point[axis].abs()).abs();
            if distance < min_distance {
                min_distance = distance;
                normal = Axis::from(axis).to_vector() * point[axis].signum();
            }
        }
        normal
    }
}

/// A cubic spatial partition. `Partition`s are represented as an origin and a
/// width.
///
/// `Partition`s are associated with every `Cube` in a tree.
#[derive(Clone, Copy)]
pub struct Partition {
    origin: UPoint3,
    width: LogWidth,
}

impl Partition {
    /// Constructs a new `Partition` at the given point in space with the given
    /// width.
    pub fn at_point(point: &UPoint3, width: LogWidth) -> Self {
        Partition {
            origin: point.mask(!UScalar::zero() << width.to_inner()),
            width: width,
        }
    }

    /// Constructs the sub-`Partition` at the given index. Returns `None` if
    /// there is no such `Partition`, because the minimum width has been
    /// exceeded.
    ///
    /// # Panics
    ///
    /// Panics if `index` is not within the range [0, 8).
    pub fn at_index(&self, index: usize) -> Option<Self> {
        if self.is_min_width() {
            None
        }
        else {
            let width = self.width - 1;
            Some(Partition {
                origin: self.origin + vector_at_index(index, width),
                width: width,
            })
        }
    }

    /// Gets the origin of the `Partition`.
    pub fn origin(&self) -> &UPoint3 {
        &self.origin
    }

    /// Gets the width of the `Partition`.
    pub fn width(&self) -> LogWidth {
        self.width
    }

    /// Gets the midpoint of the `Partition`.
    pub fn midpoint(&self) -> UPoint3 {
        let m = (self.width - 1).exp();
        self.origin + UVector3::new(m, m, m)
    }

    pub fn extent(&self) -> UVector3 {
        (UVector3::new(1, 1, 1) * self.width.exp()) - UVector3::new(1, 1, 1)
    }

    /// Gets the `AABB` of the `Partition`.
    pub fn aabb(&self) -> AABB {
        AABB::new(self.origin, self.extent())
    }

    /// Returns `true` if the `Partition` has the minimum possible width.
    pub fn is_min_width(&self) -> bool {
        self.width == LogWidth::min_value()
    }
}

/// A spatial (cubic) element in a tree.
pub trait Spatial {
    /// Gets the `Partition` of the `Spatial`.
    fn partition(&self) -> &Partition;

    /// Gets the depth of the `Spatial` in the tree.
    fn depth(&self) -> u8;

    /// Gets the `AABB` of the `Spatial`.
    fn aabb(&self) -> AABB {
        self.partition().aabb()
    }
}

/// Gets the subdivision index in a tree for a given point at the given width.
#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn index_at_point(point: &UPoint3, width: LogWidth) -> usize {
    let width = width.to_inner();
    ((((point.x >> width) & UScalar::one()) << 0) |
     (((point.y >> width) & UScalar::one()) << 1) |
     (((point.z >> width) & UScalar::one()) << 2)) as usize
}

/// Gets a vector to the origin of a subdivision in a tree at a given index and
/// width.
pub fn vector_at_index(index: usize, width: LogWidth) -> UVector3 {
    assert!(index < 8);
    let index = index as UScalar;
    let width = width.exp();
    UVector3::new(((index >> 0) & UScalar::one()) * width,
                  ((index >> 1) & UScalar::one()) * width,
                  ((index >> 2) & UScalar::one()) * width)
}

#[cfg(test)]
mod tests {
    use super::*;
}
<commit_msg>Rename locals.<commit_after>use alga::general::SupersetOf;
use nalgebra::{Point3, Scalar, Unit};
use num::{Bounded, One, Zero}; // TODO: `use ::std::num::{One, Zero};`.
use std::ops::Range;

use clamp::{Clamped, ClampedRange};
use math::{self, FRay3, FPoint3, FromSpace, FScalar, FVector3, LowerBound, Mask, UPoint3,
           UpperBound, UScalar, UVector3};

/// Defines the bounds for `LogWidth` values.
pub struct LogWidthRange;

impl ClampedRange<u8> for LogWidthRange {
    fn max_value() -> u8 {
        31
    }

    fn min_value() -> u8 {
        4
    }
}

/// Logarithmic width. Most uses of the term "width" refer to `LogWidth`.
///
/// This is the base-2 logarithmic width of a space in a tree, such that a width
/// `x` exponentiates as `2ˣ`. Exponentiation is performed as a simple bit
/// shift.
///
/// Being logarithmic, if a cube has a width `x`, then its immediate
/// subdivisions have a width `x - 1` and its parent a width `x + 1`.
///
/// `LogWidth` is clamped to the open range `[4, 31]`.
pub type LogWidth = Clamped<u8, LogWidthRange>;

impl LogWidth {
    /// Reference width of `Cube`s.
    pub fn unit() -> Self {
        LogWidth::new(8)
    }

    /// Exponentiates a `LogWidth` into a `UScalar`.
    pub fn exp(&self) -> UScalar {
        UScalar::one() << self.to_inner()
    }
}

/// An axis in the tree space.
///
/// Defines and orders the axes in the tree space.
#[derive(Clone, Copy)]
pub enum Axis {
    X = 0,
    Y = 1,
    Z = 2,
}

impl Axis {
    /// Gets a `Range` over axes as `usize`s.
    pub fn range() -> Range<usize> {
        (Axis::X as usize)..(Axis::Z as usize + 1)
    }

    pub fn to_vector(&self) -> FVector3 {
        match *self {
            Axis::X => FVector3::x(),
            Axis::Y => FVector3::y(),
            Axis::Z => FVector3::z(),
        }
    }
}

impl From<usize> for Axis {
    fn from(index: usize) -> Self {
        match index {
            0 => Axis::X,
            1 => Axis::Y,
            2 => Axis::Z,
            _ => panic!(), // TODO: Use `TryFrom`.
        }
    }
}

/// A direction along an `Axis`.
pub enum Direction {
    Positive,
    Negative,
}

/// An orientation in the tree space.
///
/// This is akin to choosing a face of a cube in a tree and orienting that face
/// based on the axis and direction in which it deforms. For example, `Left` is
/// a face along the `X` axis that deforms in the `Positive` direction.
pub enum Orientation {
    Left,
    Right,
    Top,
    Bottom,
    Front,
    Back,
}

impl Orientation {
    /// Gets the `Axis` associated with the `Orientation`.
    pub fn axis(&self) -> Axis {
        match *self {
            Orientation::Left | Orientation::Right => Axis::X,
            Orientation::Top | Orientation::Bottom => Axis::Y,
            Orientation::Front | Orientation::Back => Axis::Z,
        }
    }

    /// Gets the `Direction` associated with the `Orientation`.
    pub fn direction(&self) -> Direction {
        match *self {
            Orientation::Left | Orientation::Bottom | Orientation::Back => Direction::Positive,
            Orientation::Right | Orientation::Top | Orientation::Front => Direction::Negative,
        }
    }
}

pub trait PointNormal {
    fn normal(&self, point: &FPoint3) -> FVector3;
}

/// Shape or primitive that can test for intersection with another shape or
/// primitive.
pub trait Intersects<T> {
    /// Tests for intersection.
    fn intersects(&self, other: &T) -> bool;
}

/// Details of intersection with an `FRay3`.
pub struct RayIntersection {
    /// The minimum time of impact.
    pub distance: FScalar,
    /// The minimum point of intersection.
    pub point: FPoint3,
    /// The normal at the point of intersection.
    pub normal: Unit<FVector3>,
}

impl RayIntersection {
    /// Creates a new `RayIntersection`. Normalizes `normal`.
    fn new(distance: FScalar, point: FPoint3, normal: FVector3) -> Self {
        RayIntersection {
            distance: distance,
            point: point,
            normal: Unit::new_normalize(normal),
        }
    }
}

/// Shape or primitive that can test for intersection with an `FRay3`, omitting
/// some details about the intersection.
pub trait PartialRayCast {
    /// Determines if an `FRay3` intersects the shape or primitive. Returns the
    /// minimum and maximum time of impact (distance), respectively.
    fn partial_ray_intersection(&self, ray: &FRay3) -> Option<(FScalar, FScalar)>;
}

/// Shape or primitive that can test for intersection with an `FRay3`.
pub trait RayCast: PartialRayCast {
    /// Determines if an `FRay3` intersects the shape or primitive and returns
    /// details about the intersection.
    fn ray_intersection(&self, ray: &FRay3) -> Option<RayIntersection>;
}

impl<T> Intersects<FRay3> for T
    where T: PartialRayCast
{
    fn intersects(&self, ray: &FRay3) -> bool {
        self.partial_ray_intersection(ray).is_some()
    }
}

impl<T> RayCast for T
    where T: PartialRayCast + PointNormal
{
    fn ray_intersection(&self, ray: &FRay3) -> Option<RayIntersection> {
        self.partial_ray_intersection(ray).map(|(distance, _)| {
            let point = ray.origin + (*ray.direction * distance);
            RayIntersection::new(distance, point, self.normal(&point))
        })
    }
}

/// Axis-aligned bounding box.
///
/// `AABB`s are represented as an origin and extent.
pub struct AABB {
    pub origin: UPoint3,
    pub extent: UVector3,
}

impl AABB {
    /// Constructs a new `AABB` at the given point in space with the given
    /// extent.
    pub fn new(origin: UPoint3, extent: UVector3) -> Self {
        AABB {
            origin: origin,
            extent: extent,
        }
    }

    /// Constructs the union of two `AABB`s.
    ///
    /// The union is the cuboid formed from the lower and upper bounds of the
    /// `AABB`s.
    pub fn union(&self, other: &Self) -> Self {
        let start = self.origin.lower_bound(&other.origin);
        let end = self.endpoint().upper_bound(&other.endpoint());
        AABB::new(start, end - start)
    }

    /// Gets the midpoint (center) of the `AABB`.
    pub fn midpoint(&self) -> UPoint3 {
        self.origin + (self.extent / 2)
    }

    /// Gets the absolute endpoint of the `AABB`.
    pub fn endpoint(&self) -> UPoint3 {
        self.origin + self.extent
    }
}

impl Intersects<AABB> for AABB {
    /// Determines if two `AABB`s intersect.
    fn intersects(&self, aabb: &AABB) -> bool {
        for axis in Axis::range() {
            if (self.origin[axis] + self.extent[axis]) < aabb.origin[axis] {
                return false;
            }
            if self.origin[axis] > (aabb.origin[axis] + aabb.extent[axis]) {
                return false;
            }
        }
        true
    }
}

impl<T> Intersects<Point3<T>> for AABB
    where T: PartialOrd + Scalar + SupersetOf<UScalar>
{
    /// Determines if a point intersects an `AABB`.
    fn intersects(&self, point: &Point3<T>) -> bool {
        use nalgebra::convert;

        for axis in Axis::range() {
            if convert::<UScalar, T>(self.origin[axis] + self.extent[axis]) < point[axis] {
                return false;
            }
            if convert::<UScalar, T>(self.origin[axis]) > point[axis] {
                return false;
            }
        }
        true
    }
}

impl PartialRayCast for AABB {
    /// Determines if an `FRay3` intersects an `AABB`. Returns the minimum and
    /// maximum times of impact as a tuple, respectively.
    fn partial_ray_intersection(&self, ray: &FRay3) -> Option<(FScalar, FScalar)> {
        let mut min = FVector3::zero();
        let mut max = FVector3::zero();
        for axis in Axis::range() {
            let lower = self.origin[axis] as FScalar;
            let upper = lower + self.extent[axis] as FScalar;
            let origin = ray.origin[axis];
            let direction = ray.direction[axis];

            let (lower, upper) = math::ordered_pair((lower - origin) / direction,
                                                    (upper - origin) / direction);
            min[axis] = lower;
            max[axis] = upper;
        }

        let min = math::partial_max(math::partial_max(min.x, min.y), min.z);
        let max = math::partial_min(math::partial_min(max.x, max.y), max.z);
        if max < 0.0 || min > max {
            None
        }
        else {
            Some((min, max))
        }
    }
}

impl PointNormal for AABB {
    /// Gets the normal at a point along or near the surface of the `AABB`.
    fn normal(&self, point: &FPoint3) -> FVector3 {
        let point = point - FPoint3::from_space(self.midpoint());
        let mut min_distance = FScalar::max_value();
        let mut normal = FVector3::zero();
        for axis in Axis::range() {
            let distance = (self.extent[axis] as FScalar - point[axis].abs()).abs();
            if distance < min_distance {
                min_distance = distance;
                normal = Axis::from(axis).to_vector() * point[axis].signum();
            }
        }
        normal
    }
}

/// A cubic spatial partition. `Partition`s are represented as an origin and a
/// width.
///
/// `Partition`s are associated with every `Cube` in a tree.
#[derive(Clone, Copy)]
pub struct Partition {
    origin: UPoint3,
    width: LogWidth,
}

impl Partition {
    /// Constructs a new `Partition` at the given point in space with the given
    /// width.
    pub fn at_point(point: &UPoint3, width: LogWidth) -> Self {
        Partition {
            origin: point.mask(!UScalar::zero() << width.to_inner()),
            width: width,
        }
    }

    /// Constructs the sub-`Partition` at the given index. Returns `None` if
    /// there is no such `Partition`, because the minimum width has been
    /// exceeded.
    ///
    /// # Panics
    ///
    /// Panics if `index` is not within the range [0, 8).
    pub fn at_index(&self, index: usize) -> Option<Self> {
        if self.is_min_width() {
            None
        }
        else {
            let width = self.width - 1;
            Some(Partition {
                origin: self.origin + vector_at_index(index, width),
                width: width,
            })
        }
    }

    /// Gets the origin of the `Partition`.
    pub fn origin(&self) -> &UPoint3 {
        &self.origin
    }

    /// Gets the width of the `Partition`.
    pub fn width(&self) -> LogWidth {
        self.width
    }

    /// Gets the midpoint of the `Partition`.
    pub fn midpoint(&self) -> UPoint3 {
        let m = (self.width - 1).exp();
        self.origin + UVector3::new(m, m, m)
    }

    pub fn extent(&self) -> UVector3 {
        (UVector3::new(1, 1, 1) * self.width.exp()) - UVector3::new(1, 1, 1)
    }

    /// Gets the `AABB` of the `Partition`.
    pub fn aabb(&self) -> AABB {
        AABB::new(self.origin, self.extent())
    }

    /// Returns `true` if the `Partition` has the minimum possible width.
    pub fn is_min_width(&self) -> bool {
        self.width == LogWidth::min_value()
    }
}

/// A spatial (cubic) element in a tree.
pub trait Spatial {
    /// Gets the `Partition` of the `Spatial`.
    fn partition(&self) -> &Partition;

    /// Gets the depth of the `Spatial` in the tree.
    fn depth(&self) -> u8;

    /// Gets the `AABB` of the `Spatial`.
    fn aabb(&self) -> AABB {
        self.partition().aabb()
    }
}

/// Gets the subdivision index in a tree for a given point at the given width.
#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn index_at_point(point: &UPoint3, width: LogWidth) -> usize {
    let width = width.to_inner();
    ((((point.x >> width) & UScalar::one()) << 0) |
     (((point.y >> width) & UScalar::one()) << 1) |
     (((point.z >> width) & UScalar::one()) << 2)) as usize
}

/// Gets a vector to the origin of a subdivision in a tree at a given index and
/// width.
pub fn vector_at_index(index: usize, width: LogWidth) -> UVector3 {
    assert!(index < 8);
    let index = index as UScalar;
    let width = width.exp();
    UVector3::new(((index >> 0) & UScalar::one()) * width,
                  ((index >> 1) & UScalar::one()) * width,
                  ((index >> 2) & UScalar::one()) * width)
}

#[cfg(test)]
mod tests {
    use super::*;
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::process;

use clap::ArgMatches;
use tempdir::TempDir;
use hyper::{Client, Url};
use kuchiki;

use extractor;
use downloader;
use profile;
use config::Config;

pub fn init() {
    let config = Config::new();
    if config.install_dir.exists() || config.shim_dir.exists() {
        println!("Already initalized. Reinitializing....");
    }
    fs::create_dir_all(&config.install_dir).expect("Could not create installation directory.");
    fs::create_dir_all(&config.shim_dir).expect("Could not create shims directory.");
    fs::create_dir_all(&config.versions_dir).expect("Could not create versions directory.");
    if !env::home_dir()
        .unwrap_or_else(|| panic!("Cound not found homedir."))
        .join("Documents")
        .join("WindowsPowerShell")
        .join("profile.ps1")
        .exists() {
        println!(r#"Please create profile.ps1 the following place:

$Env:USERPROFILE\Documents\WindowsPowerShell\profile.ps1

And write the following thing:

. $Env:USERPROFILE\.groonga\shims\bin\source-groonga.ps1
"#)
    }
}

pub fn install(m: &ArgMatches) {
    extern crate env_proxy;

    const BASE_URL: &'static str = "http://packages.groonga.org/windows/groonga";
    let maybe_proxy = env_proxy::for_url(&Url::parse(BASE_URL).unwrap());
    let config = Config::from_matches(m);
    println!("Value for architecture: {}",
             config.arch.clone().expect("unsupported platform"));
    println!("Obtaining Groonga version: {}",
             config.version.clone().unwrap());
    let groonga_dir = format!("groonga-{}-{}",
                              config.version.unwrap(),
                              config.arch.unwrap());
    let groonga_binary = format!("{}.zip", groonga_dir.clone());
    if config.versions_dir.join(groonga_dir.clone()).exists() {
        println!("Already installed. Ready to use it.");
        return ();
    }

    let download_dir = TempDir::new("grnenv-rs")
        .expect("Could not create temp dir.")
        .into_path();

    let client = match maybe_proxy {
        None => Client::new(),
        Some(host_port) => Client::with_http_proxy(host_port.0, host_port.1),
    };
    let filename = downloader::file_download(&client,
                                             &*format!("{}/{}", BASE_URL, groonga_binary),
                                             download_dir,
                                             "groonga.zip")
        .expect("Failed to download");
    extractor::extract_zip(&filename, &config.versions_dir);
}

pub fn switch(m: &ArgMatches) {
    let config = Config::from_matches(m);
    println!("Value for architecture: {}",
             config.arch.clone().expect("unsupported platform"));
    println!("Using Groonga version: {}", config.version.clone().unwrap());
    let groonga_dir = format!("groonga-{}-{}",
                              config.version.unwrap(),
                              config.arch.unwrap());
    match config.version {
        Some("system") => {
            profile::windows::remove_grnenv_profile(&config.shim_dir).unwrap();
            return ();
        }
        Some(_) => {
            profile::windows::create_profile_source(&config.shim_dir,
                                                    &groonga_dir,
                                                    &config.versions_dir)
                .expect("Could not create source-groonga.ps1")
        }
        None => unreachable!(),
    }
}

pub fn uninstall(m: &ArgMatches) {
    let config = Config::from_matches(m);
    let groonga_dir = format!("groonga-{}-{}",
                              config.version.unwrap(),
                              config.arch.unwrap());
    if config.versions_dir.join(groonga_dir.clone()).exists() {
        println!("Removing {}....", groonga_dir.clone());
        fs::remove_dir_all(&config.versions_dir.join(groonga_dir))
            .expect("Could not remove specified directory.");
    } else {
        println!("{} is not installed!", groonga_dir.clone());
        process::exit(1);
    }
}

pub fn list() {
    use kuchiki::traits::*;

    if let Ok(doc) = kuchiki::parse_html()
        .from_http("http://packages.groonga.org/windows/groonga") {
        let docs = doc.select("tr").unwrap().collect::<Vec<_>>();
        println!("Installable Groonga:");
        for handle in &docs {
            let texts = handle.as_node().descendants().text_nodes().collect::<Vec<_>>();
            if let Some(text) = texts.first() {
                let package = text.as_node().text_contents();
                if package.contains("groonga") && package.contains("zip") &&
                   (package.contains("x86") || package.contains("x64")) {
                    let package = package.split(".zip").collect::<Vec<_>>();
                    let pkg =
                        package.first().unwrap_or(&"").to_owned().split("-").collect::<Vec<_>>();
                    println!("\t{} --arch {}",
                             pkg.get(1).unwrap_or(&""),
                             pkg.get(2).unwrap_or(&""));
                }
            }
        }
    } else {
        println!("{}", "The page couldn't be fetched");
    }
}
<commit_msg>windows list: Support proxy<commit_after>use std::env;
use std::fs;
use std::process;

use clap::ArgMatches;
use tempdir::TempDir;
use hyper::{Client, Url};
use kuchiki;

use extractor;
use downloader;
use profile;
use config::Config;

pub fn init() {
    let config = Config::new();
    if config.install_dir.exists() || config.shim_dir.exists() {
        println!("Already initalized. Reinitializing....");
    }
    fs::create_dir_all(&config.install_dir).expect("Could not create installation directory.");
    fs::create_dir_all(&config.shim_dir).expect("Could not create shims directory.");
    fs::create_dir_all(&config.versions_dir).expect("Could not create versions directory.");
    if !env::home_dir()
        .unwrap_or_else(|| panic!("Cound not found homedir."))
        .join("Documents")
        .join("WindowsPowerShell")
        .join("profile.ps1")
        .exists() {
        println!(r#"Please create profile.ps1 the following place:

$Env:USERPROFILE\Documents\WindowsPowerShell\profile.ps1

And write the following thing:

. $Env:USERPROFILE\.groonga\shims\bin\source-groonga.ps1
"#)
    }
}

pub fn install(m: &ArgMatches) {
    extern crate env_proxy;

    const BASE_URL: &'static str = "http://packages.groonga.org/windows/groonga";
    let maybe_proxy = env_proxy::for_url(&Url::parse(BASE_URL).unwrap());
    let config = Config::from_matches(m);
    println!("Value for architecture: {}",
             config.arch.clone().expect("unsupported platform"));
    println!("Obtaining Groonga version: {}",
             config.version.clone().unwrap());
    let groonga_dir = format!("groonga-{}-{}",
                              config.version.unwrap(),
                              config.arch.unwrap());
    let groonga_binary = format!("{}.zip", groonga_dir.clone());
    if config.versions_dir.join(groonga_dir.clone()).exists() {
        println!("Already installed. Ready to use it.");
        return ();
    }

    let download_dir = TempDir::new("grnenv-rs")
        .expect("Could not create temp dir.")
        .into_path();

    let client = match maybe_proxy {
        None => Client::new(),
        Some(host_port) => Client::with_http_proxy(host_port.0, host_port.1),
    };
    let filename = downloader::file_download(&client,
                                             &*format!("{}/{}", BASE_URL, groonga_binary),
                                             download_dir,
                                             "groonga.zip")
        .expect("Failed to download");
    extractor::extract_zip(&filename, &config.versions_dir);
}

pub fn switch(m: &ArgMatches) {
    let config = Config::from_matches(m);
    println!("Value for architecture: {}",
             config.arch.clone().expect("unsupported platform"));
    println!("Using Groonga version: {}", config.version.clone().unwrap());
    let groonga_dir = format!("groonga-{}-{}",
                              config.version.unwrap(),
                              config.arch.unwrap());
    match config.version {
        Some("system") => {
            profile::windows::remove_grnenv_profile(&config.shim_dir).unwrap();
            return ();
        }
        Some(_) => {
            profile::windows::create_profile_source(&config.shim_dir,
                                                    &groonga_dir,
                                                    &config.versions_dir)
                .expect("Could not create source-groonga.ps1")
        }
        None => unreachable!(),
    }
}

pub fn uninstall(m: &ArgMatches) {
    let config = Config::from_matches(m);
    let groonga_dir = format!("groonga-{}-{}",
                              config.version.unwrap(),
                              config.arch.unwrap());
    if config.versions_dir.join(groonga_dir.clone()).exists() {
        println!("Removing {}....", groonga_dir.clone());
        fs::remove_dir_all(&config.versions_dir.join(groonga_dir))
            .expect("Could not remove specified directory.");
    } else {
        println!("{} is not installed!", groonga_dir.clone());
        process::exit(1);
    }
}

pub fn list() {
    use kuchiki::traits::*;
    use command::common::MaybeProxyUrl;

    let base_url: &'static str = "http://packages.groonga.org/windows/groonga";
    let maybe_proxy_url = MaybeProxyUrl {
        url: Url::parse(base_url).unwrap()
    };
    if let Ok(doc) = kuchiki::parse_html().from_http(maybe_proxy_url) {
        let docs = doc.select("tr").unwrap().collect::<Vec<_>>();
        println!("Installable Groonga:");
        for handle in &docs {
            let texts = handle.as_node().descendants().text_nodes().collect::<Vec<_>>();
            if let Some(text) = texts.first() {
                let package = text.as_node().text_contents();
                if package.contains("groonga") && package.contains("zip") &&
                   (package.contains("x86") || package.contains("x64")) {
                    let package = package.split(".zip").collect::<Vec<_>>();
                    let pkg =
                        package.first().unwrap_or(&"").to_owned().split("-").collect::<Vec<_>>();
                    println!("\t{} --arch {}",
                             pkg.get(1).unwrap_or(&""),
                             pkg.get(2).unwrap_or(&""));
                }
            }
        }
    } else {
        println!("{}", "The page couldn't be fetched");
    }
}
<|endoftext|>


<commit_before>pub use std::collections::HashMap;
pub use crate::api::*;
use crate::array::JsonApiArray;
use crate::errors::*;
use serde::{Deserialize, Serialize};
use serde_json::{from_value, to_value, Value, Map};

/// A trait for any struct that can be converted from/into a Resource.
/// The only requirement is that your struct has an 'id: String' field.
/// You shouldn't be implementing JsonApiModel manually, look at the
/// `jsonapi_model!` macro instead.
pub trait JsonApiModel: Serialize
where
    for<'de> Self: Deserialize<'de>,
{
    #[doc(hidden)]
    fn jsonapi_type(&self) -> String;
    #[doc(hidden)]
    fn jsonapi_id(&self) -> String;
    #[doc(hidden)]
    fn relationship_fields() -> Option<&'static [&'static str]>;
    #[doc(hidden)]
    fn build_relationships(&self) -> Option<Relationships>;
    #[doc(hidden)]
    fn build_included(&self) -> Option<Resources>;

    fn from_jsonapi_resource(resource: &Resource, included: &Option<Resources>) -> Result<Self> {
        Self::from_serializable(Self::resource_to_attrs(resource, included))
    }

    fn from_jsonapi_document(doc: &JsonApiDocument) -> Result<Self> {
        match doc.data.as_ref() {
            Some(primary_data) => {
                match *primary_data {
                    PrimaryData::None => bail!("Document had no data"),
                    PrimaryData::Single(ref resource) => {
                        Self::from_jsonapi_resource(resource, &doc.included)
                    }
                    PrimaryData::Multiple(ref resources) => {
                        let all: Vec<ResourceAttributes> = resources
                            .iter()
                            .map(|r| Self::resource_to_attrs(r, &doc.included))
                            .collect();
                        Self::from_serializable(all)
                    }
                }
            }
            None => bail!("Document had no data"),
        }
    }

    fn to_jsonapi_resource(&self) -> (Resource, Option<Resources>) {
        if let Value::Object(mut attrs) = to_value(self).unwrap() {
            let _ = attrs.remove("id");
            let resource = Resource {
                _type: self.jsonapi_type(),
                id: self.jsonapi_id(),
                relationships: self.build_relationships(),
                attributes: Self::extract_attributes(&attrs),
                ..Default::default()
            };

            (resource, self.build_included())
        } else {
            panic!(format!("{} is not a Value::Object", self.jsonapi_type()))
        }
    }

    fn to_jsonapi_document(&self) -> JsonApiDocument {
        let (resource, included) = self.to_jsonapi_resource();
        JsonApiDocument {
            data: Some(PrimaryData::Single(Box::new(resource))),
            included,
            ..Default::default()
        }
    }

    #[doc(hidden)]
    fn build_has_one<M: JsonApiModel>(model: &M) -> Relationship {
        Relationship {
            data: IdentifierData::Single(model.as_resource_identifier()),
            links: None,
        }
    }

    #[doc(hidden)]
    fn build_has_many<M: JsonApiModel>(models: &[M]) -> Relationship {
        Relationship {
            data: IdentifierData::Multiple(
                models.iter().map(|m| m.as_resource_identifier()).collect(),
            ),
            links: None,
        }
    }

    #[doc(hidden)]
    fn as_resource_identifier(&self) -> ResourceIdentifier {
        ResourceIdentifier {
            _type: self.jsonapi_type(),
            id: self.jsonapi_id(),
        }
    }

    /* Attribute corresponding to the model is removed from the Map
     * before calling this, so there's no need to ignore it like we do
     * with the attributes that correspond with relationships.
     * */
    #[doc(hidden)]
    fn extract_attributes(attrs: &Map<String, Value>) -> ResourceAttributes {
        attrs
            .iter()
            .filter(|&(key, _)| {
                if let Some(fields) = Self::relationship_fields() {
                    if fields.contains(&key.as_str()) {
                        return false;
                    }
                }
                true
            })
            .map(|(k, v)| (k.clone(), v.clone()))
            .collect()
    }

    #[doc(hidden)]
    fn to_resources(&self) -> Resources {
        let (me, maybe_others) = self.to_jsonapi_resource();
        let mut flattened = vec![me];
        if let Some(mut others) = maybe_others {
            flattened.append(&mut others);
        }
        flattened
    }

    #[doc(hidden)]
    fn lookup<'a>(needle: &ResourceIdentifier, haystack: &'a [Resource]) -> Option<&'a Resource> {
        for resource in haystack {
            if resource._type == needle._type && resource.id == needle.id {
                return Some(resource);
            }
        }
        None
    }

    #[doc(hidden)]
    fn resource_to_attrs(resource: &Resource, included: &Option<Resources>) -> ResourceAttributes {
        let mut new_attrs = HashMap::new();
        new_attrs.clone_from(&resource.attributes);
        new_attrs.insert("id".into(), resource.id.clone().into());

        if let Some(relations) = resource.relationships.as_ref() {
            if let Some(inc) = included.as_ref() {
                for (name, relation) in relations {
                    let value =
                        match relation.data {
                            IdentifierData::None => Value::Null,
                            IdentifierData::Single(ref identifier) => {
                                let found = Self::lookup(identifier, inc).map(|r| {
                                    Self::resource_to_attrs(r, included)
                                });
                                to_value(found).expect("Casting Single relation to value")
                            }
                            IdentifierData::Multiple(ref identifiers) => {
                                let found: Vec<Option<ResourceAttributes>> =
                                identifiers.iter().map(|id|{
                                    Self::lookup(id, inc).map(|r|{
                                        Self::resource_to_attrs(r, included)
                                    })
                                }).collect();
                                to_value(found).expect("Casting Multiple relation to value")
                            }
                        };
                    new_attrs.insert(name.to_string(), value);
                }
            }
        }

        new_attrs
    }

    #[doc(hidden)]
    fn from_serializable<S: Serialize>(s: S) -> Result<Self> {
        from_value(to_value(s)?).map_err(Error::from)
    }
}

pub fn vec_to_jsonapi_resources<T: JsonApiModel>(
    objects: Vec<T>,
) -> (Resources, Option<Resources>) {
    let mut included = vec![];
    let resources = objects
        .iter()
        .map(|obj| {
            let (res, mut opt_incl) = obj.to_jsonapi_resource();
            if let Some(ref mut incl) = opt_incl {
                included.append(incl);
            }
            res
        })
        .collect::<Vec<_>>();
    let opt_included = if included.is_empty() {
        None
    } else {
        Some(included)
    };
    (resources, opt_included)
}

pub fn vec_to_jsonapi_document<T: JsonApiModel>(objects: Vec<T>) -> JsonApiDocument {
    let (resources, included) = vec_to_jsonapi_resources(objects);
    JsonApiDocument {
        data: Some(PrimaryData::Multiple(resources)),
        included,
        ..Default::default()
    }
}

impl<M: JsonApiModel> JsonApiModel for Box<M> {
    fn jsonapi_type(&self) -> String {
        self.as_ref().jsonapi_type()
    }

    fn jsonapi_id(&self) -> String {
        self.as_ref().jsonapi_id()
    }

    fn relationship_fields() -> Option<&'static [&'static str]> {
        M::relationship_fields()
    }

    fn build_relationships(&self) -> Option<Relationships> {
        self.as_ref().build_relationships()
    }

    fn build_included(&self) -> Option<Resources> {
        self.as_ref().build_included()
    }
}

#[macro_export]
macro_rules! jsonapi_model {
    ($model:ty; $type:expr) => (
        impl JsonApiModel for $model {
            fn jsonapi_type(&self) -> String { $type.to_string() }
            fn jsonapi_id(&self) -> String { self.id.to_string() }
            fn relationship_fields() -> Option<&'static [&'static str]> { None }
            fn build_relationships(&self) -> Option<Relationships> { None }
            fn build_included(&self) -> Option<Resources> { None }
        }
    );
    ($model:ty; $type:expr;
        has one $( $has_one:ident ),*
    ) => (
        jsonapi_model!($model; $type; has one $( $has_one ),*; has many);
    );
    ($model:ty; $type:expr;
        has many $( $has_many:ident ),*
    ) => (
        jsonapi_model!($model; $type; has one; has many $( $has_many ),*);
    );
    ($model:ty; $type:expr;
        has one $( $has_one:ident ),*;
        has many $( $has_many:ident ),*
    ) => (
        impl JsonApiModel for $model {
            fn jsonapi_type(&self) -> String { $type.to_string() }
            fn jsonapi_id(&self) -> String { self.id.to_string() }

            fn relationship_fields() -> Option<&'static [&'static str]> {
                static FIELDS: &'static [&'static str] = &[
                     $( stringify!($has_one),)*
                     $( stringify!($has_many),)*
                ];

                Some(FIELDS)
            }

            fn build_relationships(&self) -> Option<Relationships> {
                let mut relationships = HashMap::new();
                $(
                    relationships.insert(stringify!($has_one).into(),
                        Self::build_has_one(&self.$has_one)
                    );
                )*
                $(
                    relationships.insert(
                        stringify!($has_many).into(),
                        {
                            let values = &self.$has_many.get_models();
                            Self::build_has_many(values)
                        }
                    );
                )*
                Some(relationships)
            }

            fn build_included(&self) -> Option<Resources> {
                let mut included:Resources = vec![];
                $( included.append(&mut self.$has_one.to_resources()); )*
                $(
                    for model in self.$has_many.get_models() {
                        included.append(&mut model.to_resources());
                    }
                )*
                Some(included)
            }
        }
    );
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Dog {
    id: String,
    name: String,
    age: i32,
    main_flea: Flea,
    fleas: Vec<Flea>,
}
jsonapi_model!(Dog; "dog"; has one main_flea; has many fleas);
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Flea {
    id: String,
    name: String,
}
jsonapi_model!(Flea; "flea");
<commit_msg>refactor: remove test-related structs from src/model<commit_after>pub use std::collections::HashMap;
pub use crate::api::*;
use crate::errors::*;
use serde::{Deserialize, Serialize};
use serde_json::{from_value, to_value, Value, Map};

/// A trait for any struct that can be converted from/into a Resource.
/// The only requirement is that your struct has an 'id: String' field.
/// You shouldn't be implementing JsonApiModel manually, look at the
/// `jsonapi_model!` macro instead.
pub trait JsonApiModel: Serialize
where
    for<'de> Self: Deserialize<'de>,
{
    #[doc(hidden)]
    fn jsonapi_type(&self) -> String;
    #[doc(hidden)]
    fn jsonapi_id(&self) -> String;
    #[doc(hidden)]
    fn relationship_fields() -> Option<&'static [&'static str]>;
    #[doc(hidden)]
    fn build_relationships(&self) -> Option<Relationships>;
    #[doc(hidden)]
    fn build_included(&self) -> Option<Resources>;

    fn from_jsonapi_resource(resource: &Resource, included: &Option<Resources>) -> Result<Self> {
        Self::from_serializable(Self::resource_to_attrs(resource, included))
    }

    fn from_jsonapi_document(doc: &JsonApiDocument) -> Result<Self> {
        match doc.data.as_ref() {
            Some(primary_data) => {
                match *primary_data {
                    PrimaryData::None => bail!("Document had no data"),
                    PrimaryData::Single(ref resource) => {
                        Self::from_jsonapi_resource(resource, &doc.included)
                    }
                    PrimaryData::Multiple(ref resources) => {
                        let all: Vec<ResourceAttributes> = resources
                            .iter()
                            .map(|r| Self::resource_to_attrs(r, &doc.included))
                            .collect();
                        Self::from_serializable(all)
                    }
                }
            }
            None => bail!("Document had no data"),
        }
    }

    fn to_jsonapi_resource(&self) -> (Resource, Option<Resources>) {
        if let Value::Object(mut attrs) = to_value(self).unwrap() {
            let _ = attrs.remove("id");
            let resource = Resource {
                _type: self.jsonapi_type(),
                id: self.jsonapi_id(),
                relationships: self.build_relationships(),
                attributes: Self::extract_attributes(&attrs),
                ..Default::default()
            };

            (resource, self.build_included())
        } else {
            panic!(format!("{} is not a Value::Object", self.jsonapi_type()))
        }
    }

    fn to_jsonapi_document(&self) -> JsonApiDocument {
        let (resource, included) = self.to_jsonapi_resource();
        JsonApiDocument {
            data: Some(PrimaryData::Single(Box::new(resource))),
            included,
            ..Default::default()
        }
    }

    #[doc(hidden)]
    fn build_has_one<M: JsonApiModel>(model: &M) -> Relationship {
        Relationship {
            data: IdentifierData::Single(model.as_resource_identifier()),
            links: None,
        }
    }

    #[doc(hidden)]
    fn build_has_many<M: JsonApiModel>(models: &[M]) -> Relationship {
        Relationship {
            data: IdentifierData::Multiple(
                models.iter().map(|m| m.as_resource_identifier()).collect(),
            ),
            links: None,
        }
    }

    #[doc(hidden)]
    fn as_resource_identifier(&self) -> ResourceIdentifier {
        ResourceIdentifier {
            _type: self.jsonapi_type(),
            id: self.jsonapi_id(),
        }
    }

    /* Attribute corresponding to the model is removed from the Map
     * before calling this, so there's no need to ignore it like we do
     * with the attributes that correspond with relationships.
     * */
    #[doc(hidden)]
    fn extract_attributes(attrs: &Map<String, Value>) -> ResourceAttributes {
        attrs
            .iter()
            .filter(|&(key, _)| {
                if let Some(fields) = Self::relationship_fields() {
                    if fields.contains(&key.as_str()) {
                        return false;
                    }
                }
                true
            })
            .map(|(k, v)| (k.clone(), v.clone()))
            .collect()
    }

    #[doc(hidden)]
    fn to_resources(&self) -> Resources {
        let (me, maybe_others) = self.to_jsonapi_resource();
        let mut flattened = vec![me];
        if let Some(mut others) = maybe_others {
            flattened.append(&mut others);
        }
        flattened
    }

    #[doc(hidden)]
    fn lookup<'a>(needle: &ResourceIdentifier, haystack: &'a [Resource]) -> Option<&'a Resource> {
        for resource in haystack {
            if resource._type == needle._type && resource.id == needle.id {
                return Some(resource);
            }
        }
        None
    }

    #[doc(hidden)]
    fn resource_to_attrs(resource: &Resource, included: &Option<Resources>) -> ResourceAttributes {
        let mut new_attrs = HashMap::new();
        new_attrs.clone_from(&resource.attributes);
        new_attrs.insert("id".into(), resource.id.clone().into());

        if let Some(relations) = resource.relationships.as_ref() {
            if let Some(inc) = included.as_ref() {
                for (name, relation) in relations {
                    let value =
                        match relation.data {
                            IdentifierData::None => Value::Null,
                            IdentifierData::Single(ref identifier) => {
                                let found = Self::lookup(identifier, inc).map(|r| {
                                    Self::resource_to_attrs(r, included)
                                });
                                to_value(found).expect("Casting Single relation to value")
                            }
                            IdentifierData::Multiple(ref identifiers) => {
                                let found: Vec<Option<ResourceAttributes>> =
                                identifiers.iter().map(|id|{
                                    Self::lookup(id, inc).map(|r|{
                                        Self::resource_to_attrs(r, included)
                                    })
                                }).collect();
                                to_value(found).expect("Casting Multiple relation to value")
                            }
                        };
                    new_attrs.insert(name.to_string(), value);
                }
            }
        }

        new_attrs
    }

    #[doc(hidden)]
    fn from_serializable<S: Serialize>(s: S) -> Result<Self> {
        from_value(to_value(s)?).map_err(Error::from)
    }
}

pub fn vec_to_jsonapi_resources<T: JsonApiModel>(
    objects: Vec<T>,
) -> (Resources, Option<Resources>) {
    let mut included = vec![];
    let resources = objects
        .iter()
        .map(|obj| {
            let (res, mut opt_incl) = obj.to_jsonapi_resource();
            if let Some(ref mut incl) = opt_incl {
                included.append(incl);
            }
            res
        })
        .collect::<Vec<_>>();
    let opt_included = if included.is_empty() {
        None
    } else {
        Some(included)
    };
    (resources, opt_included)
}

pub fn vec_to_jsonapi_document<T: JsonApiModel>(objects: Vec<T>) -> JsonApiDocument {
    let (resources, included) = vec_to_jsonapi_resources(objects);
    JsonApiDocument {
        data: Some(PrimaryData::Multiple(resources)),
        included,
        ..Default::default()
    }
}

impl<M: JsonApiModel> JsonApiModel for Box<M> {
    fn jsonapi_type(&self) -> String {
        self.as_ref().jsonapi_type()
    }

    fn jsonapi_id(&self) -> String {
        self.as_ref().jsonapi_id()
    }

    fn relationship_fields() -> Option<&'static [&'static str]> {
        M::relationship_fields()
    }

    fn build_relationships(&self) -> Option<Relationships> {
        self.as_ref().build_relationships()
    }

    fn build_included(&self) -> Option<Resources> {
        self.as_ref().build_included()
    }
}

#[macro_export]
macro_rules! jsonapi_model {
    ($model:ty; $type:expr) => (
        impl JsonApiModel for $model {
            fn jsonapi_type(&self) -> String { $type.to_string() }
            fn jsonapi_id(&self) -> String { self.id.to_string() }
            fn relationship_fields() -> Option<&'static [&'static str]> { None }
            fn build_relationships(&self) -> Option<Relationships> { None }
            fn build_included(&self) -> Option<Resources> { None }
        }
    );
    ($model:ty; $type:expr;
        has one $( $has_one:ident ),*
    ) => (
        jsonapi_model!($model; $type; has one $( $has_one ),*; has many);
    );
    ($model:ty; $type:expr;
        has many $( $has_many:ident ),*
    ) => (
        jsonapi_model!($model; $type; has one; has many $( $has_many ),*);
    );
    ($model:ty; $type:expr;
        has one $( $has_one:ident ),*;
        has many $( $has_many:ident ),*
    ) => (
        impl JsonApiModel for $model {
            fn jsonapi_type(&self) -> String { $type.to_string() }
            fn jsonapi_id(&self) -> String { self.id.to_string() }

            fn relationship_fields() -> Option<&'static [&'static str]> {
                static FIELDS: &'static [&'static str] = &[
                     $( stringify!($has_one),)*
                     $( stringify!($has_many),)*
                ];

                Some(FIELDS)
            }

            fn build_relationships(&self) -> Option<Relationships> {
                let mut relationships = HashMap::new();
                $(
                    relationships.insert(stringify!($has_one).into(),
                        Self::build_has_one(&self.$has_one)
                    );
                )*
                $(
                    relationships.insert(
                        stringify!($has_many).into(),
                        {
                            let values = &self.$has_many.get_models();
                            Self::build_has_many(values)
                        }
                    );
                )*
                Some(relationships)
            }

            fn build_included(&self) -> Option<Resources> {
                let mut included:Resources = vec![];
                $( included.append(&mut self.$has_one.to_resources()); )*
                $(
                    for model in self.$has_many.get_models() {
                        included.append(&mut model.to_resources());
                    }
                )*
                Some(included)
            }
        }
    );
}
<|endoftext|>


<commit_before>extern crate mtl;

use mtl::{CommandQueue, Device};

#[test]
fn get_device() {
    let device = Device::system_default_device();
    assert!(device.is_ok());
}

#[test]
fn get_device_name() {
    let device = Device::system_default_device().unwrap();
    assert!(!device.get_name().into_owned().is_empty());
}

#[test]
fn set_get_command_queue_label() {
    let device = Device::system_default_device().unwrap();
    let command_queue = CommandQueue::new(&device).unwrap();

    let dummy_command_queue_name = "foo";
    command_queue.set_label(dummy_command_queue_name);

    assert_eq!(command_queue.get_label().into_owned(), dummy_command_queue_name.to_string());
}
<commit_msg>Add test: insert_debug_capture_boundary_on_command_queue<commit_after>extern crate mtl;

use mtl::{CommandQueue, Device};

#[test]
fn get_device() {
    let device = Device::system_default_device();
    assert!(device.is_ok());
}

#[test]
fn get_device_name() {
    let device = Device::system_default_device().unwrap();
    assert!(!device.get_name().into_owned().is_empty());
}

#[test]
fn set_get_command_queue_label() {
    let device = Device::system_default_device().unwrap();
    let command_queue = CommandQueue::new(&device).unwrap();

    let dummy_command_queue_name = "foo";
    command_queue.set_label(dummy_command_queue_name);

    assert_eq!(command_queue.get_label().into_owned(), dummy_command_queue_name.to_string());
}

#[test]
fn insert_debug_capture_boundary_on_command_queue() {
    let device = Device::system_default_device().unwrap();
    let command_queue = CommandQueue::new(&device).unwrap();
    command_queue.insert_debug_capture_boundary();

    // if nothing panics/fails here, everything is okay
}
<|endoftext|>


<commit_before>use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::ptr;
use core::sync::atomic::{AtomicBool, AtomicPtr, Ordering, fence};

use pause::pause;

pub struct Slot {
    next: AtomicPtr<AtomicBool>
}

/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
///
/// The data protected by the mutex can be access through this guard via its
/// `Deref` and `DerefMut` implementations
#[must_use]
pub struct Guard<'a, T: ?Sized + 'a> {
    lock: &'a Mutex<T>,
    slot: &'a Slot
}

/// A mutual exclusion primitive useful for protecting shared data
///
/// This mutex will block threads waiting for the lock to become available. The
/// mutex can also be statically initialized or created via a `new`
/// constructor. Each mutex has a type parameter which represents the data that
/// it is protecting. The data can only be accessed through the RAII guards
/// returned from `lock` and `try_lock`, which guarantees that the data is only
/// ever accessed when the mutex is locked.
///
/// # Examples
///
/// ```
/// use std::sync::Arc;
/// use std::thread;
/// use std::sync::mpsc::channel;
/// use mcs::{Mutex, Slot};
///
/// const N: usize = 10;
///
/// // Spawn a few threads to increment a shared variable (non-atomically), and
/// // let the main thread know once all increments are done.
/// //
/// // Here we're using an Arc to share memory among threads, and the data inside
/// // the Arc is protected with a mutex.
/// let data = Arc::new(Mutex::new(0));
///
/// let (tx, rx) = channel();
/// for _ in 0..10 {
///     let (data, tx) = (data.clone(), tx.clone());
///     thread::spawn(move || {
///         let mut slot = Slot::new();
///
///         // The shared state can only be accessed once the lock is held.
///         // Our non-atomic increment is safe because we're the only thread
///         // which can access the shared state when the lock is held.
///         //
///         // We unwrap() the return value to assert that we are not expecting
///         // threads to ever fail while holding the lock.
///         let mut data = data.lock(&mut slot);
///         *data += 1;
///         if *data == N {
///             tx.send(()).unwrap();
///         }
///         // the lock is unlocked here when `data` goes out of scope.
///     });
/// }
///
/// rx.recv().unwrap();
/// ```
pub struct Mutex<T: ?Sized> {
    queue: AtomicPtr<Slot>,
    data: UnsafeCell<T>
}

unsafe impl<T: Send> Sync for Mutex<T> { }
unsafe impl<T: Send> Send for Mutex<T> { }

impl Slot {
    pub const fn new() -> Slot {
        Slot {
            next: AtomicPtr::new(ptr::null_mut())
        }
    }
}

impl<T> Mutex<T> {
    /// Creates a new mutex in an unlocked state ready for use.
    pub const fn new(value: T) -> Mutex<T> {
        Mutex {
            queue: AtomicPtr::new(ptr::null_mut()),
            data: UnsafeCell::new(value)
        }
    }

    /// Consumes this mutex, returning the underlying data.
    pub fn into_inner(self) -> T {
        unsafe {
            self.data.into_inner()
        }
    }
}

impl<T: ?Sized> Mutex<T> {
    /// Attempts to acquire this lock.
    ///
    /// If the lock could not be acquired at this time, then `Err` is returned.
    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
    /// guard is dropped.
    ///
    /// This function does not block.
    pub fn try_lock<'a>(&'a self, slot: &'a mut Slot) -> Result<Guard<'a, T>, ()> {
        slot.next = AtomicPtr::new(ptr::null_mut());

        if self.queue.compare_and_swap(ptr::null_mut(), slot, Ordering::AcqRel).is_null() {
            Ok(Guard {
                lock: self,
                slot: slot
            })
        } else {
            Err(())
        }
    }

    /// Acquires a mutex, blocking the current thread until it is able to do so.
    ///
    /// This function will block the local thread until it is available to acquire
    /// the mutex. Upon returning, the thread is the only thread with the mutex
    /// held. An RAII guard is returned to allow scoped unlock of the lock. When
    /// the guard goes out of scope, the mutex will be unlocked.
    pub fn lock<'a>(&'a self, slot: &'a mut Slot) -> Guard<'a, T> {
        slot.next = AtomicPtr::new(ptr::null_mut());
        let pred = self.queue.swap(slot, Ordering::AcqRel);
        if !pred.is_null() {
            let pred = unsafe { &*pred };
            let locked = AtomicBool::new(true);
            pred.next.store(&locked as *const _ as *mut _, Ordering::Release);
            while locked.load(Ordering::Relaxed) {
                pause();
            }
            fence(Ordering::Acquire);
        }

        Guard {
            lock: self,
            slot: slot
        }
    }

    /// Returns a mutable reference to the underlying data.
    ///
    /// Since this call borrows the `Mutex` mutably, no actual locking needs to
    /// take place---the mutable borrow statically guarantees no locks exist.
    pub fn get_mut(&mut self) -> &mut T {
        unsafe { &mut *self.data.get() }
    }
}

impl<'a, T: ?Sized> Deref for Guard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.lock.data.get() }
    }
}

impl<'a, T: ?Sized> DerefMut for Guard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.lock.data.get() }
    }
}

impl<'a, T: ?Sized> Drop for Guard<'a, T> {
    #[unsafe_destructor_blind_to_params]
    fn drop(&mut self) {
        let succ = self.slot.next.load(Ordering::Relaxed);
        if succ.is_null() {
            let slot_ptr = self.slot as *const _ as *mut _;
            if self.lock.queue.compare_and_swap(slot_ptr, ptr::null_mut(), Ordering::Release) != slot_ptr {
                let mut succ;
                loop {
                    succ = self.slot.next.load(Ordering::Relaxed);
                    if !succ.is_null() {
                        break;
                    }
                    pause();
                }
                fence(Ordering::Acquire);
                let succ = unsafe { &*succ };
                succ.store(false, Ordering::Release);
            }
        } else {
            fence(Ordering::Acquire);
            let succ = unsafe { &*succ };
            succ.store(false, Ordering::Release);
        }
    }
}

#[cfg(test)]
mod test {
    extern crate std;

    use super::{Mutex, Slot};

    // Mostly stoled from the Rust standard Mutex implementation's tests, so

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

    use self::std::sync::Arc;
    use self::std::sync::mpsc::channel;
    use self::std::sync::atomic::{AtomicUsize, Ordering};
    use self::std::thread;

    #[derive(Eq, PartialEq, Debug)]
    struct NonCopy(i32);

    #[test]
    fn smoke() {
        let mut slot = Slot::new();
        let m = Mutex::new(());
        drop(m.lock(&mut slot));
        drop(m.lock(&mut slot));
    }

    #[test]
    fn lots_and_lots() {
        static LOCK: Mutex<u32> = Mutex::new(0);
        const ITERS: u32 = 1000;
        const CONCURRENCY: u32 = 3;

        fn inc() {
            let mut slot = Slot::new();
            for _ in 0..ITERS {
                let mut g = LOCK.lock(&mut slot);
                *g += 1;
            }
        };

        let (tx, rx) = channel();
        for _ in 0..CONCURRENCY {
            let tx2 = tx.clone();
            thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
            let tx2 = tx.clone();
            thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
        }

        drop(tx);
        for _ in 0..2 * CONCURRENCY {
            rx.recv().unwrap();
        }
        let mut slot = Slot::new();
        assert_eq!(*LOCK.lock(&mut slot), ITERS * CONCURRENCY * 2);
    }

    #[test]
    fn try_lock() {
        let mut slot = Slot::new();
        let m = Mutex::new(());
        *m.try_lock(&mut slot).unwrap() = ();
    }

    #[test]
    fn test_into_inner() {
        let m = Mutex::new(NonCopy(10));
        assert_eq!(m.into_inner(), NonCopy(10));
    }

    #[test]
    fn test_into_inner_drop() {
        struct Foo(Arc<AtomicUsize>);
        impl Drop for Foo {
            fn drop(&mut self) {
                self.0.fetch_add(1, Ordering::SeqCst);
            }
        }
        let num_drops = Arc::new(AtomicUsize::new(0));
        let m = Mutex::new(Foo(num_drops.clone()));
        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        {
            let _inner = m.into_inner();
            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        }
        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
    }

    #[test]
    fn test_get_mut() {
        let mut m = Mutex::new(NonCopy(10));
        *m.get_mut() = NonCopy(20);
        assert_eq!(m.into_inner(), NonCopy(20));
    }

    #[test]
    fn test_lock_arc_nested() {
        // Tests nested locks and access
        // to underlying data.
        let arc = Arc::new(Mutex::new(1));
        let arc2 = Arc::new(Mutex::new(arc));
        let (tx, rx) = channel();
        let _t = thread::spawn(move|| {
            let mut slot1 = Slot::new();
            let mut slot2 = Slot::new();

            let lock = arc2.lock(&mut slot1);
            let lock2 = lock.lock(&mut slot2);
            assert_eq!(*lock2, 1);
            tx.send(()).unwrap();
        });
        rx.recv().unwrap();
    }

    #[test]
    fn test_lock_arc_access_in_unwind() {
        let arc = Arc::new(Mutex::new(1));
        let arc2 = arc.clone();
        let _ = thread::spawn(move|| -> () {
            struct Unwinder {
                i: Arc<Mutex<i32>>,
            }
            impl Drop for Unwinder {
                fn drop(&mut self) {
                    let mut slot = Slot::new();
                    *self.i.lock(&mut slot) += 1;
                }
            }
            let _u = Unwinder { i: arc2 };
            panic!();
        }).join();
        let mut slot = Slot::new();
        let lock = arc.lock(&mut slot);
        assert_eq!(*lock, 2);
    }

    #[test]
    fn test_lock_unsized() {
        let mut slot = Slot::new();
        let lock: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
        {
            let b = &mut *lock.lock(&mut slot);
            b[0] = 4;
            b[2] = 5;
        }
        let comp: &[i32] = &[4, 2, 5];
        assert_eq!(&*lock.lock(&mut slot), comp);
    }
}
<commit_msg>Slightly rearrange Guard's Drop impl<commit_after>use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::ptr;
use core::sync::atomic::{AtomicBool, AtomicPtr, Ordering, fence};

use pause::pause;

pub struct Slot {
    next: AtomicPtr<AtomicBool>
}

/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
///
/// The data protected by the mutex can be access through this guard via its
/// `Deref` and `DerefMut` implementations
#[must_use]
pub struct Guard<'a, T: ?Sized + 'a> {
    lock: &'a Mutex<T>,
    slot: &'a Slot
}

/// A mutual exclusion primitive useful for protecting shared data
///
/// This mutex will block threads waiting for the lock to become available. The
/// mutex can also be statically initialized or created via a `new`
/// constructor. Each mutex has a type parameter which represents the data that
/// it is protecting. The data can only be accessed through the RAII guards
/// returned from `lock` and `try_lock`, which guarantees that the data is only
/// ever accessed when the mutex is locked.
///
/// # Examples
///
/// ```
/// use std::sync::Arc;
/// use std::thread;
/// use std::sync::mpsc::channel;
/// use mcs::{Mutex, Slot};
///
/// const N: usize = 10;
///
/// // Spawn a few threads to increment a shared variable (non-atomically), and
/// // let the main thread know once all increments are done.
/// //
/// // Here we're using an Arc to share memory among threads, and the data inside
/// // the Arc is protected with a mutex.
/// let data = Arc::new(Mutex::new(0));
///
/// let (tx, rx) = channel();
/// for _ in 0..10 {
///     let (data, tx) = (data.clone(), tx.clone());
///     thread::spawn(move || {
///         let mut slot = Slot::new();
///
///         // The shared state can only be accessed once the lock is held.
///         // Our non-atomic increment is safe because we're the only thread
///         // which can access the shared state when the lock is held.
///         //
///         // We unwrap() the return value to assert that we are not expecting
///         // threads to ever fail while holding the lock.
///         let mut data = data.lock(&mut slot);
///         *data += 1;
///         if *data == N {
///             tx.send(()).unwrap();
///         }
///         // the lock is unlocked here when `data` goes out of scope.
///     });
/// }
///
/// rx.recv().unwrap();
/// ```
pub struct Mutex<T: ?Sized> {
    queue: AtomicPtr<Slot>,
    data: UnsafeCell<T>
}

unsafe impl<T: Send> Sync for Mutex<T> { }
unsafe impl<T: Send> Send for Mutex<T> { }

impl Slot {
    pub const fn new() -> Slot {
        Slot {
            next: AtomicPtr::new(ptr::null_mut())
        }
    }
}

impl<T> Mutex<T> {
    /// Creates a new mutex in an unlocked state ready for use.
    pub const fn new(value: T) -> Mutex<T> {
        Mutex {
            queue: AtomicPtr::new(ptr::null_mut()),
            data: UnsafeCell::new(value)
        }
    }

    /// Consumes this mutex, returning the underlying data.
    pub fn into_inner(self) -> T {
        unsafe {
            self.data.into_inner()
        }
    }
}

impl<T: ?Sized> Mutex<T> {
    /// Attempts to acquire this lock.
    ///
    /// If the lock could not be acquired at this time, then `Err` is returned.
    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
    /// guard is dropped.
    ///
    /// This function does not block.
    pub fn try_lock<'a>(&'a self, slot: &'a mut Slot) -> Result<Guard<'a, T>, ()> {
        slot.next = AtomicPtr::new(ptr::null_mut());

        if self.queue.compare_and_swap(ptr::null_mut(), slot, Ordering::AcqRel).is_null() {
            Ok(Guard {
                lock: self,
                slot: slot
            })
        } else {
            Err(())
        }
    }

    /// Acquires a mutex, blocking the current thread until it is able to do so.
    ///
    /// This function will block the local thread until it is available to acquire
    /// the mutex. Upon returning, the thread is the only thread with the mutex
    /// held. An RAII guard is returned to allow scoped unlock of the lock. When
    /// the guard goes out of scope, the mutex will be unlocked.
    pub fn lock<'a>(&'a self, slot: &'a mut Slot) -> Guard<'a, T> {
        slot.next = AtomicPtr::new(ptr::null_mut());
        let pred = self.queue.swap(slot, Ordering::AcqRel);
        if !pred.is_null() {
            let pred = unsafe { &*pred };
            let locked = AtomicBool::new(true);
            pred.next.store(&locked as *const _ as *mut _, Ordering::Release);
            while locked.load(Ordering::Relaxed) {
                pause();
            }
            fence(Ordering::Acquire);
        }

        Guard {
            lock: self,
            slot: slot
        }
    }

    /// Returns a mutable reference to the underlying data.
    ///
    /// Since this call borrows the `Mutex` mutably, no actual locking needs to
    /// take place---the mutable borrow statically guarantees no locks exist.
    pub fn get_mut(&mut self) -> &mut T {
        unsafe { &mut *self.data.get() }
    }
}

impl<'a, T: ?Sized> Deref for Guard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.lock.data.get() }
    }
}

impl<'a, T: ?Sized> DerefMut for Guard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.lock.data.get() }
    }
}

impl<'a, T: ?Sized> Drop for Guard<'a, T> {
    #[unsafe_destructor_blind_to_params]
    fn drop(&mut self) {
        let mut succ = self.slot.next.load(Ordering::Relaxed);
        if succ.is_null() {
            // No one has registered as waiting.
            let slot_ptr = self.slot as *const _ as *mut _;
            if self.lock.queue.compare_and_swap(slot_ptr, ptr::null_mut(), Ordering::Release) == slot_ptr {
                // No one was waiting.
                return;
            }

            // Some thread is waiting, but hasn't registered yet. Spin waiting for them to register themselves.
            loop {
                succ = self.slot.next.load(Ordering::Relaxed);
                if !succ.is_null() {
                    break;
                }
                pause();
            }
        }

        // Announce to the next waiter that the lock is free.
        fence(Ordering::Acquire);
        let succ = unsafe { &*succ };
        succ.store(false, Ordering::Release);
    }
}

#[cfg(test)]
mod test {
    extern crate std;

    use super::{Mutex, Slot};

    // Mostly stoled from the Rust standard Mutex implementation's tests, so

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

    use self::std::sync::Arc;
    use self::std::sync::mpsc::channel;
    use self::std::sync::atomic::{AtomicUsize, Ordering};
    use self::std::thread;

    #[derive(Eq, PartialEq, Debug)]
    struct NonCopy(i32);

    #[test]
    fn smoke() {
        let mut slot = Slot::new();
        let m = Mutex::new(());
        drop(m.lock(&mut slot));
        drop(m.lock(&mut slot));
    }

    #[test]
    fn lots_and_lots() {
        static LOCK: Mutex<u32> = Mutex::new(0);
        const ITERS: u32 = 1000;
        const CONCURRENCY: u32 = 3;

        fn inc() {
            let mut slot = Slot::new();
            for _ in 0..ITERS {
                let mut g = LOCK.lock(&mut slot);
                *g += 1;
            }
        };

        let (tx, rx) = channel();
        for _ in 0..CONCURRENCY {
            let tx2 = tx.clone();
            thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
            let tx2 = tx.clone();
            thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
        }

        drop(tx);
        for _ in 0..2 * CONCURRENCY {
            rx.recv().unwrap();
        }
        let mut slot = Slot::new();
        assert_eq!(*LOCK.lock(&mut slot), ITERS * CONCURRENCY * 2);
    }

    #[test]
    fn try_lock() {
        let mut slot = Slot::new();
        let m = Mutex::new(());
        *m.try_lock(&mut slot).unwrap() = ();
    }

    #[test]
    fn test_into_inner() {
        let m = Mutex::new(NonCopy(10));
        assert_eq!(m.into_inner(), NonCopy(10));
    }

    #[test]
    fn test_into_inner_drop() {
        struct Foo(Arc<AtomicUsize>);
        impl Drop for Foo {
            fn drop(&mut self) {
                self.0.fetch_add(1, Ordering::SeqCst);
            }
        }
        let num_drops = Arc::new(AtomicUsize::new(0));
        let m = Mutex::new(Foo(num_drops.clone()));
        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        {
            let _inner = m.into_inner();
            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        }
        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
    }

    #[test]
    fn test_get_mut() {
        let mut m = Mutex::new(NonCopy(10));
        *m.get_mut() = NonCopy(20);
        assert_eq!(m.into_inner(), NonCopy(20));
    }

    #[test]
    fn test_lock_arc_nested() {
        // Tests nested locks and access
        // to underlying data.
        let arc = Arc::new(Mutex::new(1));
        let arc2 = Arc::new(Mutex::new(arc));
        let (tx, rx) = channel();
        let _t = thread::spawn(move|| {
            let mut slot1 = Slot::new();
            let mut slot2 = Slot::new();

            let lock = arc2.lock(&mut slot1);
            let lock2 = lock.lock(&mut slot2);
            assert_eq!(*lock2, 1);
            tx.send(()).unwrap();
        });
        rx.recv().unwrap();
    }

    #[test]
    fn test_lock_arc_access_in_unwind() {
        let arc = Arc::new(Mutex::new(1));
        let arc2 = arc.clone();
        let _ = thread::spawn(move|| -> () {
            struct Unwinder {
                i: Arc<Mutex<i32>>,
            }
            impl Drop for Unwinder {
                fn drop(&mut self) {
                    let mut slot = Slot::new();
                    *self.i.lock(&mut slot) += 1;
                }
            }
            let _u = Unwinder { i: arc2 };
            panic!();
        }).join();
        let mut slot = Slot::new();
        let lock = arc.lock(&mut slot);
        assert_eq!(*lock, 2);
    }

    #[test]
    fn test_lock_unsized() {
        let mut slot = Slot::new();
        let lock: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
        {
            let b = &mut *lock.lock(&mut slot);
            b[0] = 4;
            b[2] = 5;
        }
        let comp: &[i32] = &[4, 2, 5];
        assert_eq!(&*lock.lock(&mut slot), comp);
    }
}
<|endoftext|>