<commit_before>use {IsZero, Dot, Lerp, Point};
use std::ops::*;
use std::fmt::{self, Debug, Formatter};

// VECTOR 3
// ================================================================================================

#[derive(Clone, Copy, PartialEq)]
#[repr(C)]
pub struct Vector3 {
    pub x: f32,
    pub y: f32,
    pub z: f32
}

impl Vector3 {
    pub fn new(x: f32, y: f32, z: f32) -> Vector3 {
        Vector3 {
            x: x,
            y: y,
            z: z
        }
    }

    pub fn from_vector2(from: Vector2, z: f32) -> Vector3 {
        Vector3 {
            x: from.x,
            y: from.y,
            z: z,
        }
    }

    pub fn zero() -> Vector3 {
        Vector3::new(0.0, 0.0, 0.0)
    }

    pub fn one() -> Vector3 {
        Vector3::new(1.0, 1.0, 1.0)
    }

    pub fn up() -> Vector3 {
        Vector3::new(0.0, 1.0, 0.0)
    }

    pub fn down() -> Vector3 {
        Vector3::new(0.0, -1.0, 0.0)
    }

    pub fn forward() -> Vector3 {
        Vector3::new(0.0, 0.0, -1.0)
    }

    pub fn cross(first: Vector3, second: Vector3) -> Vector3 {
        Vector3 {
            x: first.y * second.z - first.z * second.y,
            y: first.z * second.x - first.x * second.z,
            z: first.x * second.y - first.y * second.x,
        }
    }

    pub fn set_x(mut self, x: f32) -> Vector3 {
        self.x = x;
        self
    }

    pub fn set_y(mut self, y: f32) -> Vector3 {
        self.y = y;
        self
    }

    pub fn set_z(mut self, z: f32) -> Vector3 {
        self.z = z;
        self
    }

    /// Normalizes the vector, returning the old length.
    ///
    /// If the vector is the zero vector it is not altered.
    pub fn normalize(&mut self) -> f32 {
        if self.is_zero() {
            0.0
        } else {
            let magnitude = self.magnitude();
            let one_over_magnitude = 1.0 / magnitude;
            self.x *= one_over_magnitude;
            self.y *= one_over_magnitude;
            self.z *= one_over_magnitude;

            magnitude
        }
    }

    /// Returns the normalized version of the vector.
    ///
    /// If the vector is the zero vector a copy is returned.
    pub fn normalized(&self) -> Vector3 {
        if self.is_zero() {
            *self
        } else {
            let mut copy = *self;
            copy.normalize();
            copy
        }
    }

    pub fn is_normalized(&self) -> bool {
        (self.dot(self) - 1.0).is_zero()
    }

    pub fn magnitude(&self) -> f32 {
        self.magnitude_squared().sqrt()
    }

    pub fn magnitude_squared(&self) -> f32 {
        self.x * self.x + self.y * self.y + self.z * self.z
    }

    // Safely reinterprets a slice of Vector3s to a slice of f32s. This is a cheap operation and
    // does not copy any data.
    pub fn as_ref(vectors: &[Vector3]) -> &[f32] {
        unsafe {
            ::std::slice::from_raw_parts(
                vectors.as_ptr() as *const f32,
                vectors.len() * 3)
        }
    }

    // pub fn cross(&self, rhs: Vector3) -> Vector3 {
    //     Vector3::new(
    //         self.y * rhs.z - self.z * rhs.y,
    //         self.z * rhs.x - self.x * rhs.z,
    //         self.x * rhs.y - self.y * rhs.x)
    // }
}

impl Default for Vector3 {
    fn default() -> Vector3 {
        Vector3 {
            x: 0.0,
            y: 0.0,
            z: 0.0,
        }
    }
}

impl Debug for Vector3 {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        if let Some(precision) = fmt.precision() {
            write!(
                fmt,
                "Vector3 {{ x: {:+.3$}, y: {:+.3$}, z: {:+.3$} }}",
                self.x,
                self.y,
                self.z,
                precision,
            )
        } else {
            write!(fmt, "Vector3 {{ x: {}, y: {}, z: {} }}", self.x, self.y, self.z)
        }
    }
}

impl Dot for Vector3 {
    type Output = f32;

    fn dot(self, rhs: Vector3) -> f32 {
        self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
    }
}

impl Dot<[f32; 3]> for Vector3 {
    type Output = f32;

    fn dot(self, rhs: [f32; 3]) -> f32 {
        self.x * rhs[0] + self.y * rhs[1] + self.z * rhs[2]
    }
}

impl Dot<Vector3> for [f32; 3] {
    type Output = f32;

    fn dot(self, rhs: Vector3) -> f32 {
        rhs.dot(self)
    }
}

// impl<'a> Dot<&'a [f32; 3]> for Vector3 {
//     type Output = f32;
//
//     fn dot(self, rhs: &[f32; 3]) -> f32 {
//         self.dot(*rhs)
//     }
// }

impl AddAssign for Vector3 {
    fn add_assign(&mut self, rhs: Vector3) {
        self.x += rhs.x;
        self.y += rhs.y;
        self.z += rhs.z;
    }
}

impl Add for Vector3 {
    type Output = Vector3;

    fn add(mut self, rhs: Vector3) -> Vector3 {
        self += rhs;
        self
    }
}

impl SubAssign for Vector3 {
    fn sub_assign(&mut self, rhs: Vector3) {
        self.x -= rhs.x;
        self.y -= rhs.y;
        self.z -= rhs.z;
    }
}

impl Sub for Vector3 {
    type Output = Vector3;

    fn sub(mut self, rhs: Vector3) -> Vector3 {
        self -= rhs;
        self
    }
}

impl MulAssign for Vector3 {
    fn mul_assign(&mut self, rhs: Vector3) {
        self.x *= rhs.x;
        self.y *= rhs.y;
        self.z *= rhs.z;
    }
}

impl Mul for Vector3 {
    type Output = Vector3;

    fn mul(mut self, rhs: Vector3) -> Vector3 {
        self *= rhs;
        self
    }
}

impl MulAssign<f32> for Vector3 {
    fn mul_assign(&mut self, rhs: f32) {
        self.x *= rhs;
        self.y *= rhs;
        self.z *= rhs;
    }
}

impl Mul<f32> for Vector3 {
    type Output = Vector3;

    fn mul(mut self, rhs: f32) -> Vector3 {
        self *= rhs;
        self
    }
}

impl Mul<Vector3> for f32 {
    type Output = Vector3;

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

impl Neg for Vector3 {
    type Output = Vector3;

    fn neg(self) -> Vector3 {
        Vector3::new(-self.x, -self.y, -self.z)
    }
}

impl DivAssign<f32> for Vector3 {
    fn div_assign(&mut self, rhs: f32) {
        self.x /= rhs;
        self.y /= rhs;
        self.z /= rhs;
    }
}

impl Div<f32> for Vector3 {
    type Output = Vector3;

    fn div(mut self, rhs: f32) -> Vector3 {
        self /= rhs;
        self
    }
}

impl Div<Vector3> for f32 {
    type Output = Vector3;

    fn div(self, rhs: Vector3) -> Vector3 {
        rhs / self
    }
}

impl IsZero for Vector3 {
    fn is_zero(self) -> bool {
        self.dot(self).is_zero()
    }
}

// TODO: Is `usize` an appropriate index? Especially considering the valid values are 0..3?
impl Index<usize> for Vector3 {
    type Output = f32;

    fn index(&self, index: usize) -> &f32 {
        match index {
            0 => &self.x,
            1 => &self.y,
            2 => &self.z,
            // TODO: Use `unreachable()` intrinsic in release mode.
            _ => panic!("Index {} is out of bounds for Vector3", index),
        }
    }
}

impl IndexMut<usize> for Vector3 {
    fn index_mut(&mut self, index: usize) -> &mut f32 {
        match index {
            0 => &mut self.x,
            1 => &mut self.y,
            2 => &mut self.z,
            // TODO: Use `unreachable()` intrinsic in release mode.
            _ => panic!("Index {} is out of bounds for Vector3", index),
        }
    }
}

impl<'a> From<&'a [f32]> for Vector3 {
    fn from(from: &[f32]) -> Vector3 {
        assert!(from.len() == 3);

        Vector3 {
            x: from[0],
            y: from[1],
            z: from[2],
        }
    }
}

impl <'a> From<[f32; 3]> for Vector3 {
    fn from(from: [f32; 3]) -> Vector3 {
        Vector3 {
            x: from[0],
            y: from[1],
            z: from[2],
        }
    }
}

impl From<Point> for Vector3 {
    /// Creates a new `Vector3` from a `Point`.
    ///
    /// This behaves as if the point had been subtracted from the origin, yielding a `Vector3` with
    /// the same x, y, and z coordinates as the original point. The conversion can be expressed as
    /// `(x, y, z, 1.0) => <x, y, z>`.
    fn from(from: Point) -> Vector3 {
        Vector3 {
            x: from.x,
            y: from.y,
            z: from.z,
        }
    }
}

impl From<(f32, f32, f32)> for Vector3 {
    fn from(from: (f32, f32, f32)) -> Vector3 {
        Vector3 {
            x: from.0,
            y: from.1,
            z: from.2,
        }
    }
}

impl Into<[f32; 3]> for Vector3 {
    fn into(self) -> [f32; 3] {
        [self.x, self.y, self.z]
    }
}

impl Into<(f32, f32, f32)> for Vector3 {
    fn into(self) -> (f32, f32, f32) {
        (self.x, self.y, self.z)
    }
}

// VECTOR 2
// ================================================================================================

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct Vector2 {
    pub x: f32,
    pub y: f32,
}

impl Vector2 {
    pub fn new(x: f32, y: f32) -> Vector2 {
        Vector2 {
            x: x,
            y: y,
        }
    }

    pub fn as_ref(vectors: &[Vector2]) -> &[f32] {
        use std::slice;

        unsafe {
            slice::from_raw_parts(
                vectors.as_ptr() as *const f32,
                vectors.len() * 2)
        }
    }

    pub fn slice_from_f32_slice(data: &[f32]) -> &[Vector2] {
        use std::slice;

        assert!(data.len() % 2 == 0, "Slice must have an even number of elements to be converted to a slice of Vector2");
        unsafe {
            slice::from_raw_parts(
                data.as_ptr() as *const Vector2,
                data.len() / 2,
            )
        }
    }
}

impl Default for Vector2 {
    fn default() -> Vector2 {
        Vector2 {
            x: 0.0,
            y: 0.0,
        }
    }
}

impl Lerp for Vector2 {
    fn lerp(t: f32, from: Vector2, to: Vector2) -> Vector2 {
        from + (to - from) * t
    }
}

impl Add for Vector2 {
    type Output = Vector2;

    fn add(self, rhs: Vector2) -> Vector2 {
        Vector2 {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

impl Sub for Vector2 {
    type Output = Vector2;

    fn sub(self, rhs: Vector2) -> Vector2 {
        Vector2 {
            x: self.x - rhs.x,
            y: self.y - rhs.y,
        }
    }
}

impl Mul for Vector2 {
    type Output = Vector2;

    fn mul(self, rhs: Vector2) -> Vector2 {
        Vector2 {
            x: self.x * rhs.x,
            y: self.y * rhs.y,
        }
    }
}

impl Mul<f32> for Vector2 {
    type Output = Vector2;

    fn mul(self, rhs: f32) -> Vector2 {
        Vector2 {
            x: self.x * rhs,
            y: self.y * rhs,
        }
    }
}

impl Mul<Vector2> for f32 {
    type Output = Vector2;

    fn mul(self, rhs: Vector2) -> Vector2 {
        rhs * self
    }
}
<commit_msg>Add vector constructors for all cardinal directions<commit_after>use {IsZero, Dot, Lerp, Point};
use std::ops::*;
use std::fmt::{self, Debug, Formatter};

// VECTOR 3
// ================================================================================================

#[derive(Clone, Copy, PartialEq)]
#[repr(C)]
pub struct Vector3 {
    pub x: f32,
    pub y: f32,
    pub z: f32
}

impl Vector3 {
    pub fn new(x: f32, y: f32, z: f32) -> Vector3 {
        Vector3 {
            x: x,
            y: y,
            z: z
        }
    }

    pub fn from_vector2(from: Vector2, z: f32) -> Vector3 {
        Vector3 {
            x: from.x,
            y: from.y,
            z: z,
        }
    }

    pub fn zero() -> Vector3 {
        Vector3::new(0.0, 0.0, 0.0)
    }

    pub fn one() -> Vector3 {
        Vector3::new(1.0, 1.0, 1.0)
    }

    pub fn right() -> Vector3 {
        Vector3::new(1.0, 0.0, 0.0)
    }

    pub fn left() -> Vector3 {
        Vector3::new(-1.0, 0.0, 0.0)
    }

    pub fn up() -> Vector3 {
        Vector3::new(0.0, 1.0, 0.0)
    }

    pub fn down() -> Vector3 {
        Vector3::new(0.0, -1.0, 0.0)
    }

    pub fn forward() -> Vector3 {
        Vector3::new(0.0, 0.0, -1.0)
    }

    pub fn back() -> Vector3 {
        Vector3::new(0.0, 0.0, 1.0)
    }

    pub fn cross(first: Vector3, second: Vector3) -> Vector3 {
        Vector3 {
            x: first.y * second.z - first.z * second.y,
            y: first.z * second.x - first.x * second.z,
            z: first.x * second.y - first.y * second.x,
        }
    }

    pub fn set_x(mut self, x: f32) -> Vector3 {
        self.x = x;
        self
    }

    pub fn set_y(mut self, y: f32) -> Vector3 {
        self.y = y;
        self
    }

    pub fn set_z(mut self, z: f32) -> Vector3 {
        self.z = z;
        self
    }

    /// Normalizes the vector, returning the old length.
    ///
    /// If the vector is the zero vector it is not altered.
    pub fn normalize(&mut self) -> f32 {
        if self.is_zero() {
            0.0
        } else {
            let magnitude = self.magnitude();
            let one_over_magnitude = 1.0 / magnitude;
            self.x *= one_over_magnitude;
            self.y *= one_over_magnitude;
            self.z *= one_over_magnitude;

            magnitude
        }
    }

    /// Returns the normalized version of the vector.
    ///
    /// If the vector is the zero vector a copy is returned.
    pub fn normalized(&self) -> Vector3 {
        if self.is_zero() {
            *self
        } else {
            let mut copy = *self;
            copy.normalize();
            copy
        }
    }

    pub fn is_normalized(&self) -> bool {
        (self.dot(self) - 1.0).is_zero()
    }

    pub fn magnitude(&self) -> f32 {
        self.magnitude_squared().sqrt()
    }

    pub fn magnitude_squared(&self) -> f32 {
        self.x * self.x + self.y * self.y + self.z * self.z
    }

    // Safely reinterprets a slice of Vector3s to a slice of f32s. This is a cheap operation and
    // does not copy any data.
    pub fn as_ref(vectors: &[Vector3]) -> &[f32] {
        unsafe {
            ::std::slice::from_raw_parts(
                vectors.as_ptr() as *const f32,
                vectors.len() * 3)
        }
    }

    // pub fn cross(&self, rhs: Vector3) -> Vector3 {
    //     Vector3::new(
    //         self.y * rhs.z - self.z * rhs.y,
    //         self.z * rhs.x - self.x * rhs.z,
    //         self.x * rhs.y - self.y * rhs.x)
    // }
}

impl Default for Vector3 {
    fn default() -> Vector3 {
        Vector3 {
            x: 0.0,
            y: 0.0,
            z: 0.0,
        }
    }
}

impl Debug for Vector3 {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        if let Some(precision) = fmt.precision() {
            write!(
                fmt,
                "Vector3 {{ x: {:+.3$}, y: {:+.3$}, z: {:+.3$} }}",
                self.x,
                self.y,
                self.z,
                precision,
            )
        } else {
            write!(fmt, "Vector3 {{ x: {}, y: {}, z: {} }}", self.x, self.y, self.z)
        }
    }
}

impl Dot for Vector3 {
    type Output = f32;

    fn dot(self, rhs: Vector3) -> f32 {
        self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
    }
}

impl Dot<[f32; 3]> for Vector3 {
    type Output = f32;

    fn dot(self, rhs: [f32; 3]) -> f32 {
        self.x * rhs[0] + self.y * rhs[1] + self.z * rhs[2]
    }
}

impl Dot<Vector3> for [f32; 3] {
    type Output = f32;

    fn dot(self, rhs: Vector3) -> f32 {
        rhs.dot(self)
    }
}

// impl<'a> Dot<&'a [f32; 3]> for Vector3 {
//     type Output = f32;
//
//     fn dot(self, rhs: &[f32; 3]) -> f32 {
//         self.dot(*rhs)
//     }
// }

impl AddAssign for Vector3 {
    fn add_assign(&mut self, rhs: Vector3) {
        self.x += rhs.x;
        self.y += rhs.y;
        self.z += rhs.z;
    }
}

impl Add for Vector3 {
    type Output = Vector3;

    fn add(mut self, rhs: Vector3) -> Vector3 {
        self += rhs;
        self
    }
}

impl SubAssign for Vector3 {
    fn sub_assign(&mut self, rhs: Vector3) {
        self.x -= rhs.x;
        self.y -= rhs.y;
        self.z -= rhs.z;
    }
}

impl Sub for Vector3 {
    type Output = Vector3;

    fn sub(mut self, rhs: Vector3) -> Vector3 {
        self -= rhs;
        self
    }
}

impl MulAssign for Vector3 {
    fn mul_assign(&mut self, rhs: Vector3) {
        self.x *= rhs.x;
        self.y *= rhs.y;
        self.z *= rhs.z;
    }
}

impl Mul for Vector3 {
    type Output = Vector3;

    fn mul(mut self, rhs: Vector3) -> Vector3 {
        self *= rhs;
        self
    }
}

impl MulAssign<f32> for Vector3 {
    fn mul_assign(&mut self, rhs: f32) {
        self.x *= rhs;
        self.y *= rhs;
        self.z *= rhs;
    }
}

impl Mul<f32> for Vector3 {
    type Output = Vector3;

    fn mul(mut self, rhs: f32) -> Vector3 {
        self *= rhs;
        self
    }
}

impl Mul<Vector3> for f32 {
    type Output = Vector3;

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

impl Neg for Vector3 {
    type Output = Vector3;

    fn neg(self) -> Vector3 {
        Vector3::new(-self.x, -self.y, -self.z)
    }
}

impl DivAssign<f32> for Vector3 {
    fn div_assign(&mut self, rhs: f32) {
        self.x /= rhs;
        self.y /= rhs;
        self.z /= rhs;
    }
}

impl Div<f32> for Vector3 {
    type Output = Vector3;

    fn div(mut self, rhs: f32) -> Vector3 {
        self /= rhs;
        self
    }
}

impl Div<Vector3> for f32 {
    type Output = Vector3;

    fn div(self, rhs: Vector3) -> Vector3 {
        rhs / self
    }
}

impl IsZero for Vector3 {
    fn is_zero(self) -> bool {
        self.dot(self).is_zero()
    }
}

// TODO: Is `usize` an appropriate index? Especially considering the valid values are 0..3?
impl Index<usize> for Vector3 {
    type Output = f32;

    fn index(&self, index: usize) -> &f32 {
        match index {
            0 => &self.x,
            1 => &self.y,
            2 => &self.z,
            // TODO: Use `unreachable()` intrinsic in release mode.
            _ => panic!("Index {} is out of bounds for Vector3", index),
        }
    }
}

impl IndexMut<usize> for Vector3 {
    fn index_mut(&mut self, index: usize) -> &mut f32 {
        match index {
            0 => &mut self.x,
            1 => &mut self.y,
            2 => &mut self.z,
            // TODO: Use `unreachable()` intrinsic in release mode.
            _ => panic!("Index {} is out of bounds for Vector3", index),
        }
    }
}

impl<'a> From<&'a [f32]> for Vector3 {
    fn from(from: &[f32]) -> Vector3 {
        assert!(from.len() == 3);

        Vector3 {
            x: from[0],
            y: from[1],
            z: from[2],
        }
    }
}

impl <'a> From<[f32; 3]> for Vector3 {
    fn from(from: [f32; 3]) -> Vector3 {
        Vector3 {
            x: from[0],
            y: from[1],
            z: from[2],
        }
    }
}

impl From<Point> for Vector3 {
    /// Creates a new `Vector3` from a `Point`.
    ///
    /// This behaves as if the point had been subtracted from the origin, yielding a `Vector3` with
    /// the same x, y, and z coordinates as the original point. The conversion can be expressed as
    /// `(x, y, z, 1.0) => <x, y, z>`.
    fn from(from: Point) -> Vector3 {
        Vector3 {
            x: from.x,
            y: from.y,
            z: from.z,
        }
    }
}

impl From<(f32, f32, f32)> for Vector3 {
    fn from(from: (f32, f32, f32)) -> Vector3 {
        Vector3 {
            x: from.0,
            y: from.1,
            z: from.2,
        }
    }
}

impl Into<[f32; 3]> for Vector3 {
    fn into(self) -> [f32; 3] {
        [self.x, self.y, self.z]
    }
}

impl Into<(f32, f32, f32)> for Vector3 {
    fn into(self) -> (f32, f32, f32) {
        (self.x, self.y, self.z)
    }
}

// VECTOR 2
// ================================================================================================

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct Vector2 {
    pub x: f32,
    pub y: f32,
}

impl Vector2 {
    pub fn new(x: f32, y: f32) -> Vector2 {
        Vector2 {
            x: x,
            y: y,
        }
    }

    pub fn right() -> Vector2 {
        Vector2::new(1.0, 0.0)
    }

    pub fn left() -> Vector2 {
        Vector2::new(-1.0, 0.0)
    }

    pub fn up() -> Vector2 {
        Vector2::new(0.0, 1.0)
    }

    pub fn down() -> Vector2 {
        Vector2::new(0.0, -1.0)
    }

    pub fn as_ref(vectors: &[Vector2]) -> &[f32] {
        use std::slice;

        unsafe {
            slice::from_raw_parts(
                vectors.as_ptr() as *const f32,
                vectors.len() * 2)
        }
    }

    pub fn slice_from_f32_slice(data: &[f32]) -> &[Vector2] {
        use std::slice;

        assert!(data.len() % 2 == 0, "Slice must have an even number of elements to be converted to a slice of Vector2");
        unsafe {
            slice::from_raw_parts(
                data.as_ptr() as *const Vector2,
                data.len() / 2,
            )
        }
    }
}

impl Default for Vector2 {
    fn default() -> Vector2 {
        Vector2 {
            x: 0.0,
            y: 0.0,
        }
    }
}

impl Lerp for Vector2 {
    fn lerp(t: f32, from: Vector2, to: Vector2) -> Vector2 {
        from + (to - from) * t
    }
}

impl Add for Vector2 {
    type Output = Vector2;

    fn add(self, rhs: Vector2) -> Vector2 {
        Vector2 {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

impl Sub for Vector2 {
    type Output = Vector2;

    fn sub(self, rhs: Vector2) -> Vector2 {
        Vector2 {
            x: self.x - rhs.x,
            y: self.y - rhs.y,
        }
    }
}

impl Mul for Vector2 {
    type Output = Vector2;

    fn mul(self, rhs: Vector2) -> Vector2 {
        Vector2 {
            x: self.x * rhs.x,
            y: self.y * rhs.y,
        }
    }
}

impl Mul<f32> for Vector2 {
    type Output = Vector2;

    fn mul(self, rhs: f32) -> Vector2 {
        Vector2 {
            x: self.x * rhs,
            y: self.y * rhs,
        }
    }
}

impl Mul<Vector2> for f32 {
    type Output = Vector2;

    fn mul(self, rhs: Vector2) -> Vector2 {
        rhs * self
    }
}
<|endoftext|>


<commit_before>use scraping::{Html, Selector};
use scraping::element_ref::ElementRef;
use hyper::Client;
use hyper::header::Connection;
use hyper::header::ConnectionOption;
use std::io::Read;
use std::error;
use std::fmt;
use regex::Regex;

static BASE_URL:  &'static str = "http://tools.applemusic.com/embed/v1/";
static MUSIC_URL: &'static str = r#"musicUrl = "([\x00-\x21\x23-\x7F]+)""#; // except \x22(")

#[derive(Debug)]
pub struct Song {
    pub id:          String,
    pub country:     String,
    pub title:       String,
    pub artwork_url: String,
    pub artist:      String,
    pub audio_url:   String,
    pub music_url:   String,
}

#[derive(Debug)]
pub struct Album {
    pub id:           String,
    pub country:      String,
    pub title:        String,
    pub artwork_url:  String,
    pub album_artist: String,
    pub music_url:    String,
    pub genre:        String,
}

#[derive(Debug)]
pub struct Playlist {
    pub id:          String,
    pub country:     String,
    pub title:       String,
    pub curator:     String,
    pub description: String,
    pub artwork_url: String,
    pub music_url:   String,
    pub count:       String,
}

#[derive(Debug)]
pub struct Track {
    pub title:       String,
    pub artwork_url: String,
    pub artist:      String,
    pub audio_url:   String,
}

#[derive(Debug)]
pub struct ScrapeError {
    reason: String,
}

impl fmt::Display for ScrapeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.reason)
    }
}

type ScrapeResult<T> = Result<T, ScrapeError>;

impl error::Error for ScrapeError {
    fn description(&self) -> &str {
        &self.reason
    }
}

pub fn fetch_song(id: &str, country: &str) -> ScrapeResult<Song> {
    let client = Client::new();
    let url = format!("{}/song/{}?country={}", BASE_URL, id, country);
    let mut res = client.get(&url)
        .header(Connection(vec![ConnectionOption::Close]))
        .send()
        .unwrap();
    if !res.status.is_success() {
        return Err(ScrapeError { reason: "network error".to_string() })
    }
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    let fragment = Html::parse_fragment(&body);

    let artwork_url = try!(extract_artwork_url(fragment.clone()));
    let title       = try!(extract_song_title(fragment.clone()));
    let artist      = try!(extract_song_artist(fragment.clone()));
    let audio_url   = try!(extract_audio_url(fragment.clone()));
    let music_url   = try!(extract_music_url(fragment.clone()));
    Ok(Song {
        id:          id.to_string(),
        country:     country.to_string(),
        title:       title,
        artist:      artist,
        artwork_url: artwork_url,
        audio_url:   audio_url,
        music_url:   music_url,
    })
}

pub fn fetch_album(id: &str, country: &str) -> ScrapeResult<Album> {
    let client = Client::new();
    let url = format!("{}/album/{}?country={}", BASE_URL, id, country);
    let mut res = client.get(&url)
        .header(Connection(vec![ConnectionOption::Close]))
        .send()
        .unwrap();
    if !res.status.is_success() {
        return Err(ScrapeError { reason: "network error".to_string() })
    }
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    let fragment = Html::parse_fragment(&body);

    let artwork_url  = try!(extract_artwork_url(fragment.clone()));
    let title        = try!(extract_title(fragment.clone()));
    let album_artist = try!(extract_album_artist(fragment.clone()));
    let count        = try!(extract_count(fragment.clone()));
    let music_url    = try!(extract_music_url(fragment.clone()));
    let mut tracks   = Vec::new();
    let tracks_selector = Selector::parse(".track").unwrap();
    for node in fragment.select(&tracks_selector) {
        tracks.push(extract_track(node));
    }
    Ok(Album {
        id:           id.to_string(),
        country:      country.to_string(),
        title:        title,
        album_artist: album_artist,
        artwork_url:  artwork_url,
        music_url:    music_url,
        genre:        count,
    })
}

pub fn fetch_playlist(id: &str, country: &str) -> ScrapeResult<Playlist> {
    let client = Client::new();
    let url = format!("{}/playlist/{}?country={}", BASE_URL, id, country);
    let mut res = client.get(&url)
        .header(Connection(vec![ConnectionOption::Close]))
        .send()
        .unwrap();
    if !res.status.is_success() {
        return Err(ScrapeError { reason: "network error".to_string() })
    }
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    let fragment = Html::parse_fragment(&body);

    let artwork_url = try!(extract_artwork_url(fragment.clone()));
    let title       = try!(extract_title(fragment.clone()));
    let description = try!(extract_description(fragment.clone()));
    let curator     = try!(extract_curator(fragment.clone()));
    let count       = try!(extract_count(fragment.clone()));
    let music_url   = try!(extract_music_url(fragment.clone()));
    let mut tracks  = Vec::new();
    let tracks_selector = Selector::parse(".track").unwrap();
    for node in fragment.select(&tracks_selector) {
        let track = extract_track(node);
        tracks.push(track);
    }
    Ok(Playlist {
        id:          id.to_string(),
        country:     country.to_string(),
        title:       title,
        curator:     curator,
        description: description,
        artwork_url: artwork_url,
        music_url:   music_url,
        count:       count,
    })
}

fn extract_music_url(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse("script").unwrap();
    html.select(&selector)
        .last()
        .and_then(|img| img.text().next())
        .and_then(|script| match Regex::new(MUSIC_URL) {
            Ok(re) => match re.captures(script) {
                Some(cap) => Some(cap[1].to_string()),
                None => None
            },
            Err(_) => None
        })
        .ok_or(ScrapeError { reason: "music url is not found".to_string() })
}

fn extract_artwork_url(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse("#heroArtImage > img").unwrap();
    html.select(&selector)
        .next()
        .and_then(|img| img.value().attr("src"))
        .map(|url| url.trim().to_string())
        .ok_or(ScrapeError { reason: "artwork url is not found".to_string() })
}

fn extract_audio_url(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse("#heroArtImage > .song-audio").unwrap();
    html.select(&selector)
        .next()
        .and_then(|img| img.value().attr("data-url"))
        .map(|url| url.trim().to_string())
        .ok_or(ScrapeError { reason: "audio url is not found".to_string() })
}

fn extract_description(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse("#description").unwrap();
    html.select(&selector)
        .next()
        .and_then(|div| div.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "description is not found".to_string() })
}

fn extract_title(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse(".heroMeta > .title > a").unwrap();
    html.select(&selector)
        .next()
        .and_then(|a| a.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "title is not found".to_string() })
}

fn extract_song_title(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse(".heroMeta > .details > .title-explicit > .title > a").unwrap();
    html.select(&selector)
        .next()
        .and_then(|a| a.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "title is not found".to_string() })
}

fn extract_curator(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse(".heroMeta > .curator > a").unwrap();
    html.select(&selector)
        .next()
        .and_then(|a| a.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "curator is not found".to_string() })
}

fn extract_album_artist(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse(".heroMeta > .album-artist > a").unwrap();
    html.select(&selector)
        .next()
        .and_then(|a| a.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "album artist is not found".to_string() })
}

fn extract_song_artist(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse(".heroMeta > .details > .song-artist > a").unwrap();
    html.select(&selector)
        .next()
        .and_then(|a| a.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "song artist is not found".to_string() })
}

fn extract_count(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse(".heroMeta > .count").unwrap();
    html.select(&selector)
        .next()
        .and_then(|a| a.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "count is not found".to_string() })
}

fn extract_track(node: ElementRef) -> Track {
    let img_selector    = Selector::parse(".artworkImage > img").unwrap();
    let title_selector  = Selector::parse(".title").unwrap();
    let artist_selector = Selector::parse(".artist").unwrap();
    let audio_selector  = Selector::parse(".playlist-audio").unwrap();

    let mut title:       String = "".to_string();
    let mut artwork_url: String = "".to_string();
    let mut artist:      String = "".to_string();
    let mut audio_url:   String = "".to_string();
    if let Some(n) = node.select(&title_selector).next() {
        if let Some(text) = n.text().next() {
            title = text.trim().to_string();
        }
    }

    if let Some(n) = node.select(&artist_selector).next() {
        if let Some(text) = n.text().next() {
            artist = text.trim().to_string();
        }
    }

    if let Some(n) = node.select(&img_selector).next() {
        if let Some(url) = n.value().attr("src") {
            artwork_url = url.trim().to_string();
        }
    }

    if let Some(n) = node.select(&audio_selector).next() {
        if let Some(url) = n.value().attr("data-url") {
            audio_url = url.trim().to_string();
        }
    }

    Track {
        title:       title,
        artwork_url: artwork_url,
        artist:      artist,
        audio_url:   audio_url,
    }
}

#[cfg(test)]
mod test {
    use super::fetch_playlist;
    use super::fetch_album;
    use super::fetch_song;
    #[test]
    fn test_fetch_playlist() {
        let playlist = fetch_playlist("pl.2ff0e502db0c44a598a7cb2261a5e6b2", "jp").unwrap();
        assert_eq!(playlist.id, "pl.2ff0e502db0c44a598a7cb2261a5e6b2");
        assert_eq!(playlist.music_url, "https://itunes.apple.com/jp/playlist/lili-limit-ga-xuanbu-maipureirisuto/idpl.2ff0e502db0c44a598a7cb2261a5e6b2?app=music");
    }
    #[test]
    fn test_fetch_album() {
        let album = fetch_album("1160715126", "jp").unwrap();
        assert_eq!(album.id, "1160715126");
    }
    #[test]
    fn test_fetch_song() {
        let song = fetch_song("1160715431", "jp").unwrap();
        assert_eq!(song.id, "1160715431");
    }
}
<commit_msg>apple_musci<commit_after>use scraping::{Html, Selector};
use scraping::element_ref::ElementRef;
use hyper::Client;
use hyper::header::Connection;
use hyper::header::ConnectionOption;
use std::io::Read;
use std::error;
use std::fmt;
use regex::Regex;

static BASE_URL:  &'static str = "http://tools.applemusic.com/embed/v1/";
static MUSIC_URL: &'static str = r#"musicUrl = "([\x00-\x21\x23-\x7F]+)""#; // except \x22(")

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Song {
    pub id:          String,
    pub country:     String,
    pub title:       String,
    pub artwork_url: String,
    pub artist:      String,
    pub audio_url:   String,
    pub music_url:   String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Album {
    pub id:           String,
    pub country:      String,
    pub title:        String,
    pub artwork_url:  String,
    pub album_artist: String,
    pub music_url:    String,
    pub genre:        String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Playlist {
    pub id:          String,
    pub country:     String,
    pub title:       String,
    pub curator:     String,
    pub description: String,
    pub artwork_url: String,
    pub music_url:   String,
    pub count:       String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Track {
    pub title:       String,
    pub artwork_url: String,
    pub artist:      String,
    pub audio_url:   String,
}

#[derive(Debug)]
pub struct ScrapeError {
    reason: String,
}

impl fmt::Display for ScrapeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.reason)
    }
}

type ScrapeResult<T> = Result<T, ScrapeError>;

impl error::Error for ScrapeError {
    fn description(&self) -> &str {
        &self.reason
    }
}

pub fn fetch_song(id: &str, country: &str) -> ScrapeResult<Song> {
    let client = Client::new();
    let url = format!("{}/song/{}?country={}", BASE_URL, id, country);
    let mut res = client.get(&url)
        .header(Connection(vec![ConnectionOption::Close]))
        .send()
        .unwrap();
    if !res.status.is_success() {
        return Err(ScrapeError { reason: "network error".to_string() })
    }
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    let fragment = Html::parse_fragment(&body);

    let artwork_url = try!(extract_artwork_url(fragment.clone()));
    let title       = try!(extract_song_title(fragment.clone()));
    let artist      = try!(extract_song_artist(fragment.clone()));
    let audio_url   = try!(extract_audio_url(fragment.clone()));
    let music_url   = try!(extract_music_url(fragment.clone()));
    Ok(Song {
        id:          id.to_string(),
        country:     country.to_string(),
        title:       title,
        artist:      artist,
        artwork_url: artwork_url,
        audio_url:   audio_url,
        music_url:   music_url,
    })
}

pub fn fetch_album(id: &str, country: &str) -> ScrapeResult<Album> {
    let client = Client::new();
    let url = format!("{}/album/{}?country={}", BASE_URL, id, country);
    let mut res = client.get(&url)
        .header(Connection(vec![ConnectionOption::Close]))
        .send()
        .unwrap();
    if !res.status.is_success() {
        return Err(ScrapeError { reason: "network error".to_string() })
    }
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    let fragment = Html::parse_fragment(&body);

    let artwork_url  = try!(extract_artwork_url(fragment.clone()));
    let title        = try!(extract_title(fragment.clone()));
    let album_artist = try!(extract_album_artist(fragment.clone()));
    let count        = try!(extract_count(fragment.clone()));
    let music_url    = try!(extract_music_url(fragment.clone()));
    let mut tracks   = Vec::new();
    let tracks_selector = Selector::parse(".track").unwrap();
    for node in fragment.select(&tracks_selector) {
        tracks.push(extract_track(node));
    }
    Ok(Album {
        id:           id.to_string(),
        country:      country.to_string(),
        title:        title,
        album_artist: album_artist,
        artwork_url:  artwork_url,
        music_url:    music_url,
        genre:        count,
    })
}

pub fn fetch_playlist(id: &str, country: &str) -> ScrapeResult<Playlist> {
    let client = Client::new();
    let url = format!("{}/playlist/{}?country={}", BASE_URL, id, country);
    let mut res = client.get(&url)
        .header(Connection(vec![ConnectionOption::Close]))
        .send()
        .unwrap();
    if !res.status.is_success() {
        return Err(ScrapeError { reason: "network error".to_string() })
    }
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    let fragment = Html::parse_fragment(&body);

    let artwork_url = try!(extract_artwork_url(fragment.clone()));
    let title       = try!(extract_title(fragment.clone()));
    let description = try!(extract_description(fragment.clone()));
    let curator     = try!(extract_curator(fragment.clone()));
    let count       = try!(extract_count(fragment.clone()));
    let music_url   = try!(extract_music_url(fragment.clone()));
    let mut tracks  = Vec::new();
    let tracks_selector = Selector::parse(".track").unwrap();
    for node in fragment.select(&tracks_selector) {
        let track = extract_track(node);
        tracks.push(track);
    }
    Ok(Playlist {
        id:          id.to_string(),
        country:     country.to_string(),
        title:       title,
        curator:     curator,
        description: description,
        artwork_url: artwork_url,
        music_url:   music_url,
        count:       count,
    })
}

fn extract_music_url(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse("script").unwrap();
    html.select(&selector)
        .last()
        .and_then(|img| img.text().next())
        .and_then(|script| match Regex::new(MUSIC_URL) {
            Ok(re) => match re.captures(script) {
                Some(cap) => Some(cap[1].to_string()),
                None => None
            },
            Err(_) => None
        })
        .ok_or(ScrapeError { reason: "music url is not found".to_string() })
}

fn extract_artwork_url(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse("#heroArtImage > img").unwrap();
    html.select(&selector)
        .next()
        .and_then(|img| img.value().attr("src"))
        .map(|url| url.trim().to_string())
        .ok_or(ScrapeError { reason: "artwork url is not found".to_string() })
}

fn extract_audio_url(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse("#heroArtImage > .song-audio").unwrap();
    html.select(&selector)
        .next()
        .and_then(|img| img.value().attr("data-url"))
        .map(|url| url.trim().to_string())
        .ok_or(ScrapeError { reason: "audio url is not found".to_string() })
}

fn extract_description(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse("#description").unwrap();
    html.select(&selector)
        .next()
        .and_then(|div| div.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "description is not found".to_string() })
}

fn extract_title(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse(".heroMeta > .title > a").unwrap();
    html.select(&selector)
        .next()
        .and_then(|a| a.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "title is not found".to_string() })
}

fn extract_song_title(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse(".heroMeta > .details > .title-explicit > .title > a").unwrap();
    html.select(&selector)
        .next()
        .and_then(|a| a.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "title is not found".to_string() })
}

fn extract_curator(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse(".heroMeta > .curator > a").unwrap();
    html.select(&selector)
        .next()
        .and_then(|a| a.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "curator is not found".to_string() })
}

fn extract_album_artist(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse(".heroMeta > .album-artist > a").unwrap();
    html.select(&selector)
        .next()
        .and_then(|a| a.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "album artist is not found".to_string() })
}

fn extract_song_artist(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse(".heroMeta > .details > .song-artist > a").unwrap();
    html.select(&selector)
        .next()
        .and_then(|a| a.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "song artist is not found".to_string() })
}

fn extract_count(html: Html) -> ScrapeResult<String> {
    let selector = Selector::parse(".heroMeta > .count").unwrap();
    html.select(&selector)
        .next()
        .and_then(|a| a.text().next())
        .map(|text| text.trim().to_string())
        .ok_or(ScrapeError { reason: "count is not found".to_string() })
}

fn extract_track(node: ElementRef) -> Track {
    let img_selector    = Selector::parse(".artworkImage > img").unwrap();
    let title_selector  = Selector::parse(".title").unwrap();
    let artist_selector = Selector::parse(".artist").unwrap();
    let audio_selector  = Selector::parse(".playlist-audio").unwrap();

    let mut title:       String = "".to_string();
    let mut artwork_url: String = "".to_string();
    let mut artist:      String = "".to_string();
    let mut audio_url:   String = "".to_string();
    if let Some(n) = node.select(&title_selector).next() {
        if let Some(text) = n.text().next() {
            title = text.trim().to_string();
        }
    }

    if let Some(n) = node.select(&artist_selector).next() {
        if let Some(text) = n.text().next() {
            artist = text.trim().to_string();
        }
    }

    if let Some(n) = node.select(&img_selector).next() {
        if let Some(url) = n.value().attr("src") {
            artwork_url = url.trim().to_string();
        }
    }

    if let Some(n) = node.select(&audio_selector).next() {
        if let Some(url) = n.value().attr("data-url") {
            audio_url = url.trim().to_string();
        }
    }

    Track {
        title:       title,
        artwork_url: artwork_url,
        artist:      artist,
        audio_url:   audio_url,
    }
}

#[cfg(test)]
mod test {
    use super::fetch_playlist;
    use super::fetch_album;
    use super::fetch_song;
    #[test]
    fn test_fetch_playlist() {
        let playlist = fetch_playlist("pl.2ff0e502db0c44a598a7cb2261a5e6b2", "jp").unwrap();
        assert_eq!(playlist.id, "pl.2ff0e502db0c44a598a7cb2261a5e6b2");
    }
    #[test]
    fn test_fetch_album() {
        let album = fetch_album("1160715126", "jp").unwrap();
        assert_eq!(album.id, "1160715126");
    }
    #[test]
    fn test_fetch_song() {
        let song = fetch_song("1160715431", "jp").unwrap();
        assert_eq!(song.id, "1160715431");
    }
}
<|endoftext|>


<commit_before>use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("{} from spawned thread", i);
        }
    });

    for i in 1..5 {
        println!("{} from main thread", i);
    }

    handle.join();
}
<commit_msg>Example of moving ownership of v to closure<commit_after>use std::thread;

fn main() {
    let v = vec![1, 2, 3, 4];

    let handle = thread::spawn(move || {
        println!("Hello from spawned thread: {:?}", v);
    });

    for i in 1..5 {
        println!("{} from main thread", i);
    }

    handle.join();
}
<|endoftext|>


<commit_before>extern crate allergies;

use allergies::*;

#[test]
fn test_no_allergies_means_not_allergic() {
    let allergies = Allergies::new(0);
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Peanuts));
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Cats));
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Strawberries));
}

#[test]
#[ignore]
fn test_is_allergic_to_eggs() {
    assert_eq!(true, Allergies::new(1).is_allergic_to(&Allergen::Eggs));
}

#[test]
#[ignore]
fn test_has_the_right_allergies() {
    let allergies = Allergies::new(5);
    assert_eq!(true, allergies.is_allergic_to(&Allergen::Eggs));
    assert_eq!(true, allergies.is_allergic_to(&Allergen::Shellfish));
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Strawberries));
}

#[test]
#[ignore]
fn test_no_allergies_at_all() {
    assert_eq!(Vec::<Allergen>::new(), Allergies::new(0).allergies());
}

#[test]
#[ignore]
fn test_just_to_peanuts() {
    assert_eq!(vec![Allergen::Peanuts], Allergies::new(2).allergies());
}

#[test]
#[ignore]
fn test_allergic_to_everything() {
    let all = vec![Allergen::Eggs, Allergen::Peanuts, Allergen::Shellfish,
                   Allergen::Strawberries, Allergen::Tomatoes,
                   Allergen::Chocolate, Allergen::Pollen, Allergen::Cats];
    let allergies = Allergies::new(255).allergies();

    for allergy in &all {
        assert!(allergies.contains(&allergy));
    }
}

#[test]
#[ignore]
fn test_ignore_non_allergen_score_parts() {
    assert_eq!(vec![Allergen::Eggs], Allergies::new(257).allergies());
}
<commit_msg>Assert that allergies and all are same length<commit_after>extern crate allergies;

use allergies::*;

#[test]
fn test_no_allergies_means_not_allergic() {
    let allergies = Allergies::new(0);
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Peanuts));
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Cats));
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Strawberries));
}

#[test]
#[ignore]
fn test_is_allergic_to_eggs() {
    assert_eq!(true, Allergies::new(1).is_allergic_to(&Allergen::Eggs));
}

#[test]
#[ignore]
fn test_has_the_right_allergies() {
    let allergies = Allergies::new(5);
    assert_eq!(true, allergies.is_allergic_to(&Allergen::Eggs));
    assert_eq!(true, allergies.is_allergic_to(&Allergen::Shellfish));
    assert_eq!(false, allergies.is_allergic_to(&Allergen::Strawberries));
}

#[test]
#[ignore]
fn test_no_allergies_at_all() {
    assert_eq!(Vec::<Allergen>::new(), Allergies::new(0).allergies());
}

#[test]
#[ignore]
fn test_just_to_peanuts() {
    assert_eq!(vec![Allergen::Peanuts], Allergies::new(2).allergies());
}

#[test]
#[ignore]
fn test_allergic_to_everything() {
    let all = vec![Allergen::Eggs, Allergen::Peanuts, Allergen::Shellfish,
                   Allergen::Strawberries, Allergen::Tomatoes,
                   Allergen::Chocolate, Allergen::Pollen, Allergen::Cats];
    let allergies = Allergies::new(255).allergies();

    assert_eq!(allergies.len(), all.len());

    for allergy in &all {
        assert!(allergies.contains(&allergy));
    }
}

#[test]
#[ignore]
fn test_ignore_non_allergen_score_parts() {
    assert_eq!(vec![Allergen::Eggs], Allergies::new(257).allergies());
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{borrow::Cow, fmt::Display, io, path::PathBuf, process};

use anyhow::Error;
use clap::{crate_authors, crate_version, Arg, ArgMatches, Command};
use itertools::Itertools;
use mdbook::{book::Book, preprocess::CmdPreprocessor};
use proc_macro2::{Span, TokenStream};
use syn::{spanned::Spanned, Expr};

static LONG_ABOUT: &str =
    "This is an mdbook preprocessor tailored for autocxx code examples. Autocxx
code examples don't fit well 'mdbook test' or even alternatives such as
'skeptic' or 'doc_comment' for these reasons:

a) A single code example consists of both Rust and C++ code. They must be
   linked into a separate executable, i.e. we must make one executable per
   doc test.
b) The code examples must be presented/formatted nicely with suitable
   separate blocks for the Rust and C++ code.
c) mdbook test is not good at handling doctests which have dependencies.

This preprocessor will find code snippets like this:
```rust,autocxx
autocxx_integration_tests::doctest(
\" /* any C++ implementation code */\",
\" /* C++ header code */\",
{
/* complete Rust code including 'main' */
)
```

and will build and run them, while emitting better formatted markdown blocks
for subsequent preprocessors and renderers.
";

fn main() {
    let matches = Command::new("autocxx-mdbook-preprocessor")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Expands and tests code examples in the autocxx book.")
        .long_about(LONG_ABOUT)
        .subcommand(
            Command::new("supports")
                .arg(Arg::new("renderer").required(true))
                .about("Whether a given renderer is supported by this preprocessor"),
        )
        .arg(
            Arg::new("skip_tests")
                .short('s')
                .help("Skip running doctests"),
        )
        .arg(
            Arg::new("manifest_dir")
            .long("manifest-dir")
            .help("Path to directory containing outermost autocxx Cargo.toml; necessary for trybuild to build test code successfully")
            .default_value_os(calculate_cargo_dir().as_os_str())
        )
        .get_matches();
    if matches.subcommand_matches("supports").is_some() {
        process::exit(0); // we support all renderers.
    }
    preprocess(&matches).unwrap();
}

fn calculate_cargo_dir() -> PathBuf {
    let mut path = std::env::current_exe().unwrap();
    for _ in 0..3 {
        path = path.parent().map(|p| p.to_path_buf()).unwrap_or(path);
    }
    path.join("integration-tests")
}

fn preprocess(args: &ArgMatches) -> Result<(), Error> {
    let (_, mut book) = CmdPreprocessor::parse_input(io::stdin())?;

    let mut test_cases = Vec::new();

    Book::for_each_mut(&mut book, |sec| {
        if let mdbook::BookItem::Chapter(chapter) = sec {
            let filename = chapter
                .path
                .as_ref()
                .map(|pb| pb.to_string_lossy())
                .unwrap_or_default()
                .to_string();
            chapter.content = substitute_chapter(&chapter.content, &filename, &mut test_cases);
        }
    });

    // Now run any test cases we accumulated.
    if !args.is_present("skip_tests") {
        let num_tests = test_cases.len();
        for (counter, case) in test_cases.into_iter().enumerate() {
            eprintln!(
                "Running doctest {}/{} at {}",
                counter + 1,
                num_tests,
                &case.location
            );
            autocxx_integration_tests::doctest(
                &case.cpp,
                &case.hdr,
                case.rs,
                args.value_of_os("manifest_dir").unwrap(),
            );
            eprintln!(
                "Doctest {}/{} at {} passed.",
                counter + 1,
                num_tests,
                &case.location
            );
        }
    }

    serde_json::to_writer(io::stdout(), &book)?;

    Ok(())
}

fn substitute_chapter(chapter: &str, filename: &str, test_cases: &mut Vec<TestCase>) -> String {
    let mut state = ChapterParseState::Start;
    let mut out = Vec::new();
    for (line_no, line) in chapter.lines().enumerate() {
        let line_type = recognize_line(line);
        let mut push_line = true;
        state = match state {
            ChapterParseState::Start => match line_type {
                LineType::CodeBlockStart | LineType::CodeBlockEnd => {
                    ChapterParseState::OtherCodeBlock
                }
                LineType::CodeBlockStartAutocxx => {
                    push_line = false;
                    ChapterParseState::OurCodeBlock(Vec::new())
                }
                LineType::Misc => ChapterParseState::Start,
            },
            ChapterParseState::OtherCodeBlock => match line_type {
                LineType::CodeBlockEnd => ChapterParseState::Start,
                LineType::Misc => ChapterParseState::OtherCodeBlock,
                _ => panic!("Found confusing conflicting block markers"),
            },
            ChapterParseState::OurCodeBlock(mut lines) => match line_type {
                LineType::Misc => {
                    push_line = false;
                    lines.push(line.to_string());
                    ChapterParseState::OurCodeBlock(lines)
                }
                LineType::CodeBlockEnd => {
                    let location = MiniSpan {
                        filename: filename.to_string(),
                        start_line: line_no - lines.len(),
                    };
                    out.extend(handle_code_block(lines, location, test_cases));
                    push_line = false;
                    ChapterParseState::Start
                }
                _ => panic!("Found something unexpected in one of our code blocks"),
            },
        };
        if push_line {
            out.push(line.to_string());
        }
    }

    out.join("\n")
}

/// Like `proc_macro2::Span` but only has the starting line. For basic
/// diagnostics.
struct MiniSpan {
    filename: String,
    start_line: usize,
}

impl Display for MiniSpan {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{} line {}", self.filename, self.start_line)
    }
}

struct TestCase {
    cpp: String,
    hdr: String,
    rs: TokenStream,
    location: MiniSpan,
}

enum ChapterParseState {
    Start,
    OtherCodeBlock,
    OurCodeBlock(Vec<String>), // have found rust,autocxx
}

enum LineType {
    CodeBlockStart,
    CodeBlockStartAutocxx,
    CodeBlockEnd,
    Misc,
}

fn recognize_line(line: &str) -> LineType {
    if line == "```rust" {
        LineType::CodeBlockStart
    } else if line == "```rust,autocxx" {
        LineType::CodeBlockStartAutocxx
    } else if line == "```" {
        LineType::CodeBlockEnd
    } else {
        LineType::Misc
    }
}

fn handle_code_block(
    lines: Vec<String>,
    location: MiniSpan,
    test_cases: &mut Vec<TestCase>,
) -> impl Iterator<Item = String> {
    let input_str = lines.join("\n");
    let fn_call = syn::parse_str::<syn::Expr>(&input_str).expect("Unable to parse");
    let fn_call = match fn_call {
        Expr::Call(expr) => expr,
        _ => panic!("Parsing unexpected"),
    };
    let mut args_iter = fn_call.args.iter();
    let cpp = extract_span(&lines, args_iter.next().unwrap().span());
    let hdr = extract_span(&lines, args_iter.next().unwrap().span());
    let rs = extract_span(&lines, args_iter.next().unwrap().span());
    let mut output = vec![
        "#### C++ header:".to_string(),
        "```cpp".to_string(),
        hdr.to_string(),
        "```".to_string(),
    ];
    if !cpp.is_empty() {
        output.push("#### C++ implementation:".to_string());
        output.push("```cpp".to_string());
        output.push(cpp.to_string());
        output.push("```".to_string());
    }
    output.push("#### Rust:".to_string());
    output.push("```rust,noplayground".to_string());
    output.push(escape_hexathorpes(&rs).to_string());
    output.push("```".to_string());

    // Don't run the test cases yet, because we want the preprocessor to spot
    // basic formatting errors before getting into the time consuming business of
    // running tests.
    test_cases.push(TestCase {
        cpp: cpp.to_string(),
        hdr: hdr.to_string(),
        rs: rs.parse().unwrap(),
        location,
    });

    output.into_iter()
}

fn extract_span(text: &[String], span: Span) -> Cow<str> {
    let start_line = span.start().line - 1;
    let start_col = span.start().column;
    let end_line = span.end().line - 1;
    let end_col = span.end().column;
    if start_line == end_line {
        Cow::Borrowed(&text[start_line][start_col + 1..end_col - 1])
    } else {
        let start_subset = &text[start_line][start_col + 1..];
        let end_subset = &text[end_line][..end_col - 1];
        let mid_lines = &text[start_line + 1..end_line];
        Cow::Owned(
            std::iter::once(start_subset.to_string())
                .chain(mid_lines.iter().cloned())
                .chain(std::iter::once(end_subset.to_string()))
                .join("\n"),
        )
    }
}

fn escape_hexathorpes(input: &str) -> Cow<str> {
    let re = regex::Regex::new(r"(?m)^(?P<ws>\s*)#(?P<c>.*)").unwrap();
    re.replace_all(input, "$ws##$c")
}
<commit_msg>Allow hiding C++ sections.<commit_after>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{borrow::Cow, collections::HashSet, fmt::Display, io, path::PathBuf, process};

use anyhow::Error;
use clap::{crate_authors, crate_version, Arg, ArgMatches, Command};
use itertools::Itertools;
use mdbook::{book::Book, preprocess::CmdPreprocessor};
use proc_macro2::Span;
use syn::{spanned::Spanned, Expr, __private::ToTokens};

static LONG_ABOUT: &str =
    "This is an mdbook preprocessor tailored for autocxx code examples. Autocxx
code examples don't fit well 'mdbook test' or even alternatives such as
'skeptic' or 'doc_comment' for these reasons:

a) A single code example consists of both Rust and C++ code. They must be
   linked into a separate executable, i.e. we must make one executable per
   doc test.
b) The code examples must be presented/formatted nicely with suitable
   separate blocks for the Rust and C++ code.
c) mdbook test is not good at handling doctests which have dependencies.

This preprocessor will find code snippets like this:
```rust,autocxx
autocxx_integration_tests::doctest(
\" /* any C++ implementation code */\",
\" /* C++ header code */\",
{
/* complete Rust code including 'main' */
)
```

and will build and run them, while emitting better formatted markdown blocks
for subsequent preprocessors and renderers.
";

fn main() {
    let matches = Command::new("autocxx-mdbook-preprocessor")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Expands and tests code examples in the autocxx book.")
        .long_about(LONG_ABOUT)
        .subcommand(
            Command::new("supports")
                .arg(Arg::new("renderer").required(true))
                .about("Whether a given renderer is supported by this preprocessor"),
        )
        .arg(
            Arg::new("skip_tests")
                .short('s')
                .help("Skip running doctests"),
        )
        .arg(
            Arg::new("manifest_dir")
            .long("manifest-dir")
            .help("Path to directory containing outermost autocxx Cargo.toml; necessary for trybuild to build test code successfully")
            .default_value_os(calculate_cargo_dir().as_os_str())
        )
        .get_matches();
    if matches.subcommand_matches("supports").is_some() {
        process::exit(0); // we support all renderers.
    }
    preprocess(&matches).unwrap();
}

fn calculate_cargo_dir() -> PathBuf {
    let mut path = std::env::current_exe().unwrap();
    for _ in 0..3 {
        path = path.parent().map(|p| p.to_path_buf()).unwrap_or(path);
    }
    path.join("integration-tests")
}

fn preprocess(args: &ArgMatches) -> Result<(), Error> {
    let (_, mut book) = CmdPreprocessor::parse_input(io::stdin())?;

    let mut test_cases = Vec::new();

    Book::for_each_mut(&mut book, |sec| {
        if let mdbook::BookItem::Chapter(chapter) = sec {
            let filename = chapter
                .path
                .as_ref()
                .map(|pb| pb.to_string_lossy())
                .unwrap_or_default()
                .to_string();
            chapter.content = substitute_chapter(&chapter.content, &filename, &mut test_cases);
        }
    });

    // Now run any test cases we accumulated.
    if !args.is_present("skip_tests") {
        let num_tests = test_cases.len();
        for (counter, case) in test_cases.into_iter().enumerate() {
            eprintln!(
                "Running doctest {}/{} at {}",
                counter + 1,
                num_tests,
                &case.location
            );
            autocxx_integration_tests::doctest(
                &case.cpp,
                &case.hdr,
                case.rs.to_token_stream(),
                args.value_of_os("manifest_dir").unwrap(),
            );
            eprintln!(
                "Doctest {}/{} at {} passed.",
                counter + 1,
                num_tests,
                &case.location
            );
        }
    }

    serde_json::to_writer(io::stdout(), &book)?;

    Ok(())
}

fn substitute_chapter(chapter: &str, filename: &str, test_cases: &mut Vec<TestCase>) -> String {
    let mut state = ChapterParseState::Start;
    let mut out = Vec::new();
    for (line_no, line) in chapter.lines().enumerate() {
        let line_type = recognize_line(line);
        let mut push_line = true;
        state = match state {
            ChapterParseState::Start => match line_type {
                LineType::CodeBlockStart | LineType::CodeBlockEnd => {
                    ChapterParseState::OtherCodeBlock
                }
                LineType::CodeBlockStartAutocxx(block_flags) => {
                    push_line = false;
                    ChapterParseState::OurCodeBlock(block_flags, Vec::new())
                }
                LineType::Misc => ChapterParseState::Start,
            },
            ChapterParseState::OtherCodeBlock => match line_type {
                LineType::CodeBlockEnd => ChapterParseState::Start,
                LineType::Misc => ChapterParseState::OtherCodeBlock,
                _ => panic!("Found confusing conflicting block markers"),
            },
            ChapterParseState::OurCodeBlock(flags, mut lines) => match line_type {
                LineType::Misc => {
                    push_line = false;
                    lines.push(line.to_string());
                    ChapterParseState::OurCodeBlock(flags, lines)
                }
                LineType::CodeBlockEnd => {
                    let location = MiniSpan {
                        filename: filename.to_string(),
                        start_line: line_no - lines.len(),
                    };
                    out.extend(handle_code_block(flags, lines, location, test_cases));
                    push_line = false;
                    ChapterParseState::Start
                }
                _ => panic!("Found something unexpected in one of our code blocks"),
            },
        };
        if push_line {
            out.push(line.to_string());
        }
    }

    out.join("\n")
}

/// Like `proc_macro2::Span` but only has the starting line. For basic
/// diagnostics.
struct MiniSpan {
    filename: String,
    start_line: usize,
}

impl Display for MiniSpan {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{} line {}", self.filename, self.start_line)
    }
}

struct TestCase {
    cpp: String,
    hdr: String,
    rs: syn::File,
    location: MiniSpan,
}

enum ChapterParseState {
    Start,
    OtherCodeBlock,
    OurCodeBlock(HashSet<String>, Vec<String>), // have found rust,autocxx
}

enum LineType {
    CodeBlockStart,
    CodeBlockStartAutocxx(HashSet<String>),
    CodeBlockEnd,
    Misc,
}

fn code_block_flags(line: &str) -> HashSet<String> {
    let line = &line[3..];
    line.split(',').map(|s| s.to_string()).collect()
}

fn recognize_line(line: &str) -> LineType {
    if line.starts_with("```rust") {
        let flags = code_block_flags(line);
        if flags.contains("autocxx") {
            LineType::CodeBlockStartAutocxx(flags)
        } else {
            LineType::CodeBlockStart
        }
    } else if line == "```" {
        LineType::CodeBlockEnd
    } else {
        LineType::Misc
    }
}

fn handle_code_block(
    flags: HashSet<String>,
    lines: Vec<String>,
    location: MiniSpan,
    test_cases: &mut Vec<TestCase>,
) -> impl Iterator<Item = String> {
    let input_str = lines.join("\n");
    let fn_call = syn::parse_str::<syn::Expr>(&input_str).expect("Unable to parse");
    let fn_call = match fn_call {
        Expr::Call(expr) => expr,
        _ => panic!("Parsing unexpected"),
    };
    let mut args_iter = fn_call.args.iter();
    let cpp = extract_span(&lines, args_iter.next().unwrap().span());
    let hdr = extract_span(&lines, args_iter.next().unwrap().span());
    let rs = extract_span(&lines, args_iter.next().unwrap().span());
    let mut output = vec![
        "#### C++ header:".to_string(),
        "```cpp".to_string(),
        hdr.to_string(),
        "```".to_string(),
    ];
    if !cpp.is_empty() && !flags.contains("hidecpp") {
        output.push("#### C++ implementation:".to_string());
        output.push("```cpp".to_string());
        output.push(cpp.to_string());
        output.push("```".to_string());
    }
    output.push("#### Rust:".to_string());
    output.push("```rust,noplayground".to_string());
    output.push(escape_hexathorpes(&rs).to_string());
    output.push("```".to_string());

    // Don't run the test cases yet, because we want the preprocessor to spot
    // basic formatting errors before getting into the time consuming business of
    // running tests.
    test_cases.push(TestCase {
        cpp: cpp.to_string(),
        hdr: hdr.to_string(),
        rs: syn::parse_file(&rs).unwrap(),
        location,
    });

    output.into_iter()
}

fn extract_span(text: &[String], span: Span) -> Cow<str> {
    let start_line = span.start().line - 1;
    let start_col = span.start().column;
    let end_line = span.end().line - 1;
    let end_col = span.end().column;
    if start_line == end_line {
        Cow::Borrowed(&text[start_line][start_col + 1..end_col - 1])
    } else {
        let start_subset = &text[start_line][start_col + 1..];
        let end_subset = &text[end_line][..end_col - 1];
        let mid_lines = &text[start_line + 1..end_line];
        Cow::Owned(
            std::iter::once(start_subset.to_string())
                .chain(mid_lines.iter().cloned())
                .chain(std::iter::once(end_subset.to_string()))
                .join("\n"),
        )
    }
}

fn escape_hexathorpes(input: &str) -> Cow<str> {
    let re = regex::Regex::new(r"(?m)^(?P<ws>\s*)#(?P<c>.*)").unwrap();
    re.replace_all(input, "$ws##$c")
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use rustc_serialize::json;
use auth;
use user;
use error;
use error::Error::InvalidResponse;
use entities;
use common::*;

///Represents a single status update.
#[derive(Debug)]
pub struct Tweet {
    //If the user has contributors enabled, this will show which accounts contributed to this
    //tweet.
    //pub contributors: Option<Contributors>,
    //The location point attached to the tweet, if present.
    //pub coordinates: Option<Coordinates>,
    ///UTC timestamp showing when the tweet was posted, formatted like "Wed Aug 27 13:08:45 +0000
    ///2008".
    pub created_at: String,
    ///If the authenticated user has retweeted this tweet, contains the ID of the retweet.
    pub current_user_retweet: Option<i64>,
    ///Link, hashtag, and user mention information extracted from the tweet text.
    pub entities: TweetEntities,
    ///Extended media information attached to the tweet, if media is available.
    ///
    ///If a tweet has a photo, set of photos, gif, or video attached to it, this field will be
    ///present and contain the real media information. The information available in the `media`
    ///field of `entities` will only contain the first photo of a set, or a thumbnail of a gif or
    ///video.
    pub extended_entities: Option<ExtendedTweetEntities>,
    ///"Approximately" how many times this tweet has been liked by users.
    pub favorite_count: i32,
    ///Indicates whether the authenticated user has liked this tweet.
    pub favorited: Option<bool>,
    //Indicates the maximum `FilterLevel` parameter that can be applied to a stream and still show
    //this tweet.
    //pub filter_level: FilterLevel,
    ///Numeric ID for this tweet.
    pub id: i64,
    ///If the tweet is a reply, contains the ID of the user that was replied to.
    pub in_reply_to_user_id: Option<i64>,
    ///If the tweet is a reply, contains the screen name of the user that was replied to.
    pub in_reply_to_screen_name: Option<String>,
    ///If the tweet is a reply, contains the ID of the tweet that was replied to.
    pub in_reply_to_status_id: Option<i64>,
    ///Can contain a language ID indicating the machine-detected language of the text, or "und" if
    ///no language could be detected.
    pub lang: String,
    //TODO: Is this the user-entered location field?
    //When present, the `Place` that this tweet is associated with (but not necessarily where it
    //originated from).
    //pub place: Option<Place>,
    ///If the tweet has a link, indicates whether the link may contain content that could be
    ///identified as sensitive.
    pub possibly_sensitive: Option<bool>,
    ///If this tweet is quoting another by link, contains the ID of the quoted tweet.
    pub quoted_status_id: Option<i64>,
    ///If this tweet is quoting another by link, contains the quoted tweet.
    pub quoted_status: Option<Box<Tweet>>,
    //"A set of key-value pairs indicating the intended contextual delivery of the containing
    //Tweet. Currently used by Twitter’s Promoted Products."
    //pub scopes: Option<Scopes>,
    ///The number of times this tweet has been retweeted (with native retweets).
    pub retweet_count: i32,
    ///Indicates whether the authenticated user has retweeted this tweet.
    pub retweeted: Option<bool>,
    ///If this tweet is a retweet, then this field contains the original status information.
    ///
    ///The separation between retweet and original is so that retweets can be recalled by deleting
    ///the retweet, and so that liking a retweet results in an additional notification to the user
    ///who retweeted the status, as well as the original poster.
    pub retweeted_status: Option<Box<Tweet>>,
    ///The application used to post the tweet, as an HTML anchor tag containing the app's URL and
    ///name.
    pub source: String, //TODO: this is html, i want to parse this eventually
    ///The text of the tweet.
    pub text: String,
    ///The user who posted this tweet.
    pub user: Box<user::TwitterUser>,
    ///If present and `true`, indicates that this tweet has been withheld due to a DMCA complaint.
    pub withheld_copyright: bool,
    ///If present, contains two-letter country codes indicating where this tweet is being withheld.
    ///
    ///The following special codes exist:
    ///
    ///- `XX`: Withheld in all countries
    ///- `XY`: Withheld due to DMCA complaint.
    pub withheld_in_countries: Option<Vec<String>>,
    ///If present, indicates whether the content being withheld is the `status` or the `user`.
    pub withheld_scope: Option<String>,
}

impl FromJson for Tweet {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse("Tweet received json that wasn't an object", Some(input.to_string())));
        }

        Ok(Tweet {
            //contributors: Option<Contributors>,
            //coordinates: Option<Coordinates>,
            created_at: try!(field(input, "created_at")),
            current_user_retweet: try!(current_user_retweet(input, "current_user_retweet")),
            entities: try!(field(input, "entities")),
            extended_entities: field(input, "extended_entities").ok(),
            favorite_count: field(input, "favorite_count").unwrap_or(0),
            favorited: field(input, "favorited").ok(),
            //filter_level: FilterLevel,
            id: try!(field(input, "id")),
            in_reply_to_user_id: field(input, "in_reply_to_user_id").ok(),
            in_reply_to_screen_name: field(input, "in_reply_to_screen_name").ok(),
            in_reply_to_status_id: field(input, "in_reply_to_status_id").ok(),
            lang: try!(field(input, "lang")),
            //place: Option<Place>,
            possibly_sensitive: field(input, "possibly_sensitive").ok(),
            quoted_status_id: field(input, "quoted_status_id").ok(),
            quoted_status: field(input, "quoted_status").map(Box::new).ok(),
            //scopes: Option<Scopes>,
            retweet_count: try!(field(input, "retweet_count")),
            retweeted: field(input, "retweeted").ok(),
            retweeted_status: field(input, "retweeted_status").map(Box::new).ok(),
            source: try!(field(input, "source")),
            text: try!(field(input, "text")),
            user: try!(field(input, "user").map(Box::new)),
            withheld_copyright: field(input, "withheld_copyright").unwrap_or(false),
            withheld_in_countries: field(input, "withheld_in_countries").ok(),
            withheld_scope: field(input, "withheld_scope").ok(),
        })
    }
}

fn current_user_retweet(input: &json::Json, field: &'static str) -> Result<Option<i64>, error::Error> {
    if let Some(obj) = input.find(field).and_then(|f| f.as_object()) {
        match obj.get("id").and_then(|o| o.as_i64()) {
            Some(id) => Ok(Some(id)),
            None => Err(InvalidResponse("invalid structure inside current_user_retweet", None)),
        }
    }
    else {
        Ok(None)
    }
}

///Container for URL, hashtag, mention, and media information associated with a tweet.
#[derive(Debug)]
pub struct TweetEntities {
    ///Collection of hashtags parsed from the tweet.
    pub hashtags: Vec<entities::HashtagEntity>,
    ///Collection of financial symbols, or "cashtags", parsed from the tweet.
    pub symbols: Vec<entities::HashtagEntity>,
    ///Collection of URLs parsed from the tweet.
    pub urls: Vec<entities::UrlEntity>,
    ///Collection of user mentions parsed from the tweet.
    pub user_mentions: Vec<entities::MentionEntity>,
    ///If the tweet contains any attached media, this contains a collection of media information
    ///from the tweet.
    pub media: Option<Vec<entities::MediaEntity>>,
}

impl FromJson for TweetEntities {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse("TweetEntities received json that wasn't an object", Some(input.to_string())));
        }

        Ok(TweetEntities {
            hashtags: try!(field(input, "hashtags")),
            symbols: try!(field(input, "symbols")),
            urls: try!(field(input, "urls")),
            user_mentions: try!(field(input, "user_mentions")),
            media: field(input, "media").ok(),
        })
    }
}

///Container for extended media information for a tweet.
///
///If a tweet has a photo, set of photos, gif, or video attached to it, this field will be present
///and contain the real media information. The information available in the `media` field of
///`entities` will only contain the first photo of a set, or a thumbnail of a gif or video.
#[derive(Debug)]
pub struct ExtendedTweetEntities {
    ///Collection of extended media information attached to the tweet.
    pub media: Vec<entities::MediaEntity>,
}

impl FromJson for ExtendedTweetEntities {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse("ExtendedTweetEntities received json that wasn't an object", Some(input.to_string())));
        }

        Ok(ExtendedTweetEntities {
            media: try!(field(input, "media")),
        })
    }
}

///Helper struct to navigate collections of tweets by requesting tweets older or newer than certain
///IDs.
pub struct Timeline<'a> {
    ///The URL to request tweets from.
    link: &'static str,
    ///The consumer token to authenticate requests with.
    con_token: &'a auth::Token<'a>,
    ///The access token to authenticate requests with.
    access_token: &'a auth::Token<'a>,
    ///The maximum number of tweets to return in a single call. Twitter doesn't guarantee returning
    ///exactly this number, as suspended or deleted content is removed after retrieving the initial
    ///collection of tweets.
    pub count: i32,
    ///The largest/most recent tweet ID returned in the last call to `start`, `older`, or `newer`.
    pub max_id: Option<i64>,
    ///The smalles/oldest tweet ID returned in the last call to `start`, `older`, or `newer`.
    pub min_id: Option<i64>,
}

impl<'a> Timeline<'a> {
    ///Clear the saved IDs on this timeline, and return the most recent set of tweets.
    pub fn start(&mut self) -> WebResponse<Vec<Tweet>> {
        self.max_id = None;
        self.min_id = None;

        self.older(None)
    }

    ///Return the set of tweets older than the last set pulled, optionally placing a minimum tweet
    ///ID to bound with.
    pub fn older(&mut self, since_id: Option<i64>) -> WebResponse<Vec<Tweet>> {
        let resp = try!(self.call(since_id, self.min_id.map(|id| id - 1)));

        self.map_ids(&resp.response);

        Ok(resp)
    }

    ///Return the set of tweets newer than the last set pulled, optionall placing a maximum tweet
    ///ID to bound with.
    pub fn newer(&mut self, max_id: Option<i64>) -> WebResponse<Vec<Tweet>> {
        let resp = try!(self.call(self.max_id, max_id));

        self.map_ids(&resp.response);

        Ok(resp)
    }

    ///Return the set of twets between the IDs given.
    ///
    ///Note that the range is not fully inclusive; the tweet ID given by `since_id` will not be
    ///returned, but the tweet ID in `max_id` will be returned.
    ///
    ///If the range of tweets given by the IDs would return more than `self.count`, the newest set
    ///of tweets will be returned.
    pub fn call(&self, since_id: Option<i64>, max_id: Option<i64>) -> WebResponse<Vec<Tweet>> {
        let mut params = HashMap::new();
        add_param(&mut params, "count", self.count.to_string());

        if let Some(id) = since_id {
            add_param(&mut params, "since_id", id.to_string());
        }

        if let Some(id) = max_id {
            add_param(&mut params, "max_id", id.to_string());
        }

        let mut resp = try!(auth::get(self.link, self.con_token, self.access_token, Some(&params)));

        parse_response(&mut resp)
    }

    ///Helper builder function to set the page size.
    pub fn with_page_size(self, page_size: i32) -> Self {
        Timeline {
            link: self.link,
            con_token: self.con_token,
            access_token: self.access_token,
            count: page_size,
            max_id: self.max_id,
            min_id: self.min_id,
        }
    }

    ///With the returned slice of Tweets, set the min_id and max_id on self.
    fn map_ids(&mut self, resp: &[Tweet]) {
        self.max_id = resp.first().map(|status| status.id);
        self.min_id = resp.last().map(|status| status.id);
    }

    ///Create an instance of `Timeline` with the given link and tokens.
    pub fn new(link: &'static str, con_token: &'a auth::Token, access_token: &'a auth::Token) -> Self {
        Timeline {
            link: link,
            con_token: con_token,
            access_token: access_token,
            count: 20,
            max_id: None,
            min_id: None,
        }
    }
}
<commit_msg>typo fix<commit_after>use std::collections::HashMap;
use rustc_serialize::json;
use auth;
use user;
use error;
use error::Error::InvalidResponse;
use entities;
use common::*;

///Represents a single status update.
#[derive(Debug)]
pub struct Tweet {
    //If the user has contributors enabled, this will show which accounts contributed to this
    //tweet.
    //pub contributors: Option<Contributors>,
    //The location point attached to the tweet, if present.
    //pub coordinates: Option<Coordinates>,
    ///UTC timestamp showing when the tweet was posted, formatted like "Wed Aug 27 13:08:45 +0000
    ///2008".
    pub created_at: String,
    ///If the authenticated user has retweeted this tweet, contains the ID of the retweet.
    pub current_user_retweet: Option<i64>,
    ///Link, hashtag, and user mention information extracted from the tweet text.
    pub entities: TweetEntities,
    ///Extended media information attached to the tweet, if media is available.
    ///
    ///If a tweet has a photo, set of photos, gif, or video attached to it, this field will be
    ///present and contain the real media information. The information available in the `media`
    ///field of `entities` will only contain the first photo of a set, or a thumbnail of a gif or
    ///video.
    pub extended_entities: Option<ExtendedTweetEntities>,
    ///"Approximately" how many times this tweet has been liked by users.
    pub favorite_count: i32,
    ///Indicates whether the authenticated user has liked this tweet.
    pub favorited: Option<bool>,
    //Indicates the maximum `FilterLevel` parameter that can be applied to a stream and still show
    //this tweet.
    //pub filter_level: FilterLevel,
    ///Numeric ID for this tweet.
    pub id: i64,
    ///If the tweet is a reply, contains the ID of the user that was replied to.
    pub in_reply_to_user_id: Option<i64>,
    ///If the tweet is a reply, contains the screen name of the user that was replied to.
    pub in_reply_to_screen_name: Option<String>,
    ///If the tweet is a reply, contains the ID of the tweet that was replied to.
    pub in_reply_to_status_id: Option<i64>,
    ///Can contain a language ID indicating the machine-detected language of the text, or "und" if
    ///no language could be detected.
    pub lang: String,
    //TODO: Is this the user-entered location field?
    //When present, the `Place` that this tweet is associated with (but not necessarily where it
    //originated from).
    //pub place: Option<Place>,
    ///If the tweet has a link, indicates whether the link may contain content that could be
    ///identified as sensitive.
    pub possibly_sensitive: Option<bool>,
    ///If this tweet is quoting another by link, contains the ID of the quoted tweet.
    pub quoted_status_id: Option<i64>,
    ///If this tweet is quoting another by link, contains the quoted tweet.
    pub quoted_status: Option<Box<Tweet>>,
    //"A set of key-value pairs indicating the intended contextual delivery of the containing
    //Tweet. Currently used by Twitter’s Promoted Products."
    //pub scopes: Option<Scopes>,
    ///The number of times this tweet has been retweeted (with native retweets).
    pub retweet_count: i32,
    ///Indicates whether the authenticated user has retweeted this tweet.
    pub retweeted: Option<bool>,
    ///If this tweet is a retweet, then this field contains the original status information.
    ///
    ///The separation between retweet and original is so that retweets can be recalled by deleting
    ///the retweet, and so that liking a retweet results in an additional notification to the user
    ///who retweeted the status, as well as the original poster.
    pub retweeted_status: Option<Box<Tweet>>,
    ///The application used to post the tweet, as an HTML anchor tag containing the app's URL and
    ///name.
    pub source: String, //TODO: this is html, i want to parse this eventually
    ///The text of the tweet.
    pub text: String,
    ///The user who posted this tweet.
    pub user: Box<user::TwitterUser>,
    ///If present and `true`, indicates that this tweet has been withheld due to a DMCA complaint.
    pub withheld_copyright: bool,
    ///If present, contains two-letter country codes indicating where this tweet is being withheld.
    ///
    ///The following special codes exist:
    ///
    ///- `XX`: Withheld in all countries
    ///- `XY`: Withheld due to DMCA complaint.
    pub withheld_in_countries: Option<Vec<String>>,
    ///If present, indicates whether the content being withheld is the `status` or the `user`.
    pub withheld_scope: Option<String>,
}

impl FromJson for Tweet {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse("Tweet received json that wasn't an object", Some(input.to_string())));
        }

        Ok(Tweet {
            //contributors: Option<Contributors>,
            //coordinates: Option<Coordinates>,
            created_at: try!(field(input, "created_at")),
            current_user_retweet: try!(current_user_retweet(input, "current_user_retweet")),
            entities: try!(field(input, "entities")),
            extended_entities: field(input, "extended_entities").ok(),
            favorite_count: field(input, "favorite_count").unwrap_or(0),
            favorited: field(input, "favorited").ok(),
            //filter_level: FilterLevel,
            id: try!(field(input, "id")),
            in_reply_to_user_id: field(input, "in_reply_to_user_id").ok(),
            in_reply_to_screen_name: field(input, "in_reply_to_screen_name").ok(),
            in_reply_to_status_id: field(input, "in_reply_to_status_id").ok(),
            lang: try!(field(input, "lang")),
            //place: Option<Place>,
            possibly_sensitive: field(input, "possibly_sensitive").ok(),
            quoted_status_id: field(input, "quoted_status_id").ok(),
            quoted_status: field(input, "quoted_status").map(Box::new).ok(),
            //scopes: Option<Scopes>,
            retweet_count: try!(field(input, "retweet_count")),
            retweeted: field(input, "retweeted").ok(),
            retweeted_status: field(input, "retweeted_status").map(Box::new).ok(),
            source: try!(field(input, "source")),
            text: try!(field(input, "text")),
            user: try!(field(input, "user").map(Box::new)),
            withheld_copyright: field(input, "withheld_copyright").unwrap_or(false),
            withheld_in_countries: field(input, "withheld_in_countries").ok(),
            withheld_scope: field(input, "withheld_scope").ok(),
        })
    }
}

fn current_user_retweet(input: &json::Json, field: &'static str) -> Result<Option<i64>, error::Error> {
    if let Some(obj) = input.find(field).and_then(|f| f.as_object()) {
        match obj.get("id").and_then(|o| o.as_i64()) {
            Some(id) => Ok(Some(id)),
            None => Err(InvalidResponse("invalid structure inside current_user_retweet", None)),
        }
    }
    else {
        Ok(None)
    }
}

///Container for URL, hashtag, mention, and media information associated with a tweet.
#[derive(Debug)]
pub struct TweetEntities {
    ///Collection of hashtags parsed from the tweet.
    pub hashtags: Vec<entities::HashtagEntity>,
    ///Collection of financial symbols, or "cashtags", parsed from the tweet.
    pub symbols: Vec<entities::HashtagEntity>,
    ///Collection of URLs parsed from the tweet.
    pub urls: Vec<entities::UrlEntity>,
    ///Collection of user mentions parsed from the tweet.
    pub user_mentions: Vec<entities::MentionEntity>,
    ///If the tweet contains any attached media, this contains a collection of media information
    ///from the tweet.
    pub media: Option<Vec<entities::MediaEntity>>,
}

impl FromJson for TweetEntities {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse("TweetEntities received json that wasn't an object", Some(input.to_string())));
        }

        Ok(TweetEntities {
            hashtags: try!(field(input, "hashtags")),
            symbols: try!(field(input, "symbols")),
            urls: try!(field(input, "urls")),
            user_mentions: try!(field(input, "user_mentions")),
            media: field(input, "media").ok(),
        })
    }
}

///Container for extended media information for a tweet.
///
///If a tweet has a photo, set of photos, gif, or video attached to it, this field will be present
///and contain the real media information. The information available in the `media` field of
///`entities` will only contain the first photo of a set, or a thumbnail of a gif or video.
#[derive(Debug)]
pub struct ExtendedTweetEntities {
    ///Collection of extended media information attached to the tweet.
    pub media: Vec<entities::MediaEntity>,
}

impl FromJson for ExtendedTweetEntities {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse("ExtendedTweetEntities received json that wasn't an object", Some(input.to_string())));
        }

        Ok(ExtendedTweetEntities {
            media: try!(field(input, "media")),
        })
    }
}

///Helper struct to navigate collections of tweets by requesting tweets older or newer than certain
///IDs.
pub struct Timeline<'a> {
    ///The URL to request tweets from.
    link: &'static str,
    ///The consumer token to authenticate requests with.
    con_token: &'a auth::Token<'a>,
    ///The access token to authenticate requests with.
    access_token: &'a auth::Token<'a>,
    ///The maximum number of tweets to return in a single call. Twitter doesn't guarantee returning
    ///exactly this number, as suspended or deleted content is removed after retrieving the initial
    ///collection of tweets.
    pub count: i32,
    ///The largest/most recent tweet ID returned in the last call to `start`, `older`, or `newer`.
    pub max_id: Option<i64>,
    ///The smalles/oldest tweet ID returned in the last call to `start`, `older`, or `newer`.
    pub min_id: Option<i64>,
}

impl<'a> Timeline<'a> {
    ///Clear the saved IDs on this timeline, and return the most recent set of tweets.
    pub fn start(&mut self) -> WebResponse<Vec<Tweet>> {
        self.max_id = None;
        self.min_id = None;

        self.older(None)
    }

    ///Return the set of tweets older than the last set pulled, optionally placing a minimum tweet
    ///ID to bound with.
    pub fn older(&mut self, since_id: Option<i64>) -> WebResponse<Vec<Tweet>> {
        let resp = try!(self.call(since_id, self.min_id.map(|id| id - 1)));

        self.map_ids(&resp.response);

        Ok(resp)
    }

    ///Return the set of tweets newer than the last set pulled, optionall placing a maximum tweet
    ///ID to bound with.
    pub fn newer(&mut self, max_id: Option<i64>) -> WebResponse<Vec<Tweet>> {
        let resp = try!(self.call(self.max_id, max_id));

        self.map_ids(&resp.response);

        Ok(resp)
    }

    ///Return the set of tweets between the IDs given.
    ///
    ///Note that the range is not fully inclusive; the tweet ID given by `since_id` will not be
    ///returned, but the tweet ID in `max_id` will be returned.
    ///
    ///If the range of tweets given by the IDs would return more than `self.count`, the newest set
    ///of tweets will be returned.
    pub fn call(&self, since_id: Option<i64>, max_id: Option<i64>) -> WebResponse<Vec<Tweet>> {
        let mut params = HashMap::new();
        add_param(&mut params, "count", self.count.to_string());

        if let Some(id) = since_id {
            add_param(&mut params, "since_id", id.to_string());
        }

        if let Some(id) = max_id {
            add_param(&mut params, "max_id", id.to_string());
        }

        let mut resp = try!(auth::get(self.link, self.con_token, self.access_token, Some(&params)));

        parse_response(&mut resp)
    }

    ///Helper builder function to set the page size.
    pub fn with_page_size(self, page_size: i32) -> Self {
        Timeline {
            link: self.link,
            con_token: self.con_token,
            access_token: self.access_token,
            count: page_size,
            max_id: self.max_id,
            min_id: self.min_id,
        }
    }

    ///With the returned slice of Tweets, set the min_id and max_id on self.
    fn map_ids(&mut self, resp: &[Tweet]) {
        self.max_id = resp.first().map(|status| status.id);
        self.min_id = resp.last().map(|status| status.id);
    }

    ///Create an instance of `Timeline` with the given link and tokens.
    pub fn new(link: &'static str, con_token: &'a auth::Token, access_token: &'a auth::Token) -> Self {
        Timeline {
            link: link,
            con_token: con_token,
            access_token: access_token,
            count: 20,
            max_id: None,
            min_id: None,
        }
    }
}
<|endoftext|>


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

// aux-build:thread-local-extern-static.rs

#![feature(thread_local)]
#![feature(cfg_target_thread_local)]

extern crate thread_local_extern_static;

extern {
    #[cfg_attr(target_thread_local, thread_local)]
    static FOO: u32;
}

fn main() {
    assert_eq!(FOO, 3);
}
<commit_msg>Ignore test case on Windows.<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-windows
// aux-build:thread-local-extern-static.rs

#![feature(thread_local)]
#![feature(cfg_target_thread_local)]

extern crate thread_local_extern_static;

extern {
    #[cfg_attr(target_thread_local, thread_local)]
    static FOO: u32;
}

fn main() {
    assert_eq!(FOO, 3);
}
<|endoftext|>