<commit_before>use redox::Box;
use redox::fs::File;
use redox::io::*;
use redox::mem;
use redox::ops::DerefMut;
use redox::slice;
use redox::syscall::sys_yield;
use redox::String;
use redox::ToString;
use redox::to_num::ToNum;
use redox::Vec;

use super::Event;
use super::Color;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: isize,
    /// The y coordinate of the window
    y: isize,
    /// The width of the window
    w: usize,
    /// The height of the window
    h: usize,
    /// The title of the window
    t: String,
    /// The input scheme
    file: File,
    /// Font file
    font: Vec<u8>,
    /// Window data
    data: Vec<u32>,
}

impl Window {
    /// Create a new window
    pub fn new(x: isize, y: isize, w: usize, h: usize, title: &str) -> Option<Box<Self>> {
        let mut font = Vec::new();
        if let Some(mut font_file) = File::open("file:/ui/unifont.font") {
            font_file.read_to_end(&mut font);
        }

        match File::open(&format!("orbital:///{}/{}/{}/{}/{}", x, y, w, h, title)) {
            Some(file) => Some(box Window {
                x: x,
                y: y,
                w: w,
                h: h,
                t: title.to_string(),
                file: file,
                font: font,
                data: vec![0; w * h * 4],
            }),
            None => None
        }
    }

    //TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        if let Some(path) = self.file.path() {
            //orbital://x/y/w/h/t
            let parts: Vec<&str> = path.split('/').collect();
            if let Some(x) = parts.get(3) {
                self.x = x.to_num_signed();
            }
            if let Some(y) = parts.get(4) {
                self.y = y.to_num_signed();
            }
            if let Some(w) = parts.get(5) {
                self.w = w.to_num();
            }
            if let Some(h) = parts.get(6) {
                self.h = h.to_num();
            }
        }
    }

    /// Get x
    //TODO: Sync with window movements
    pub fn x(&self) -> isize {
        self.x
    }

    /// Get y
    //TODO: Sync with window movements
    pub fn y(&self) -> isize {
        self.y
    }

    /// Get width
    pub fn width(&self) -> usize {
        self.w
    }

    /// Get height
    pub fn height(&self) -> usize {
        self.h
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, title: &str) {
        //TODO
    }

    /// Draw a pixel
    pub fn pixel(&mut self, x: isize, y: isize, color: Color) {
        if x >= 0 && y >= 0 && x < self.w as isize && y < self.h as isize {
            let offset = y as usize * self.w + x as usize;
            self.data[offset] = color.data;
        }
    }

    /// Draw a character, using the loaded font
    pub fn char(&mut self, x: isize, y: isize, c: char, color: Color) {
        let mut offset = (c as usize) * 16;
        for row in 0..16 {
            let row_data;
            if offset < self.font.len() {
                row_data = self.font[offset];
            } else {
                row_data = 0;
            }

            for col in 0..8 {
                let pixel = (row_data >> (7 - col)) & 1;
                if pixel > 0 {
                    self.pixel(x + col as isize, y + row as isize, color);
                }
            }
            offset += 1;
        }
    }

    //TODO move, resize, set_title

    /// Set entire window to a color
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn set(&mut self, color: Color) {
        let w = self.w;
        let h = self.h;
        self.rect(0, 0, w, h, color);
    }

    /// Draw rectangle
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn rect(&mut self, start_x: isize, start_y: isize, w: usize, h: usize, color: Color) {
        for y in start_y..start_y + h as isize {
            for x in start_x..start_x + w as isize {
                self.pixel(x, y, color);
            }
        }
    }

    /// Display an image
    //TODO: Improve speed
    pub fn image(&mut self, start_x: isize, start_y: isize, w: usize, h: usize, data: &[Color]) {
        let mut i = 0;
        for y in start_y..start_y + h as isize {
            for x in start_x..start_x + w as isize {
                if i < data.len() {
                    self.pixel(x, y, data[i])
                }
                i += 1;
            }
        }
    }

    /// Poll for an event
    //TODO: clean this up
    pub fn poll(&mut self) -> Option<Event> {
        let mut event = box Event::new();
        let event_ptr: *mut Event = event.deref_mut();
        loop {
            match self.file.read(&mut unsafe {
                slice::from_raw_parts_mut(event_ptr as *mut u8, mem::size_of::<Event>())
            }) {
                Some(0) => unsafe { sys_yield() },
                Some(_) => return Some(*event),
                None => return None,
            }
        }
    }

    /// Flip the window buffer
    pub fn sync(&mut self) -> bool {
        self.file.seek(SeekFrom::Start(0));
        let to_write: &[u8] = unsafe{ mem::transmute::<&[u32],&[u8]>(&self.data) };
        self.file.write(to_write);
        return self.file.sync();
    }

    /// Return a iterator over events
    pub fn event_iter<'a>(&'a mut self) -> EventIter<'a> {
        EventIter {
            window: self,
        }
    }
}

/// Event iterator
pub struct EventIter<'a> {
    window: &'a mut Window,
}

impl<'a> Iterator for EventIter<'a> {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        self.window.poll()
    }
}
<commit_msg>Remove warnings (now there are 0 warnings!)<commit_after>use redox::Box;
use redox::fs::File;
use redox::io::*;
use redox::mem;
use redox::ops::DerefMut;
use redox::slice;
use redox::syscall::sys_yield;
use redox::String;
use redox::ToString;
use redox::to_num::ToNum;
use redox::Vec;

use super::Event;
use super::Color;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: isize,
    /// The y coordinate of the window
    y: isize,
    /// The width of the window
    w: usize,
    /// The height of the window
    h: usize,
    /// The title of the window
    t: String,
    /// The input scheme
    file: File,
    /// Font file
    font: Vec<u8>,
    /// Window data
    data: Vec<u32>,
}

impl Window {
    /// Create a new window
    pub fn new(x: isize, y: isize, w: usize, h: usize, title: &str) -> Option<Box<Self>> {
        let mut font = Vec::new();
        if let Some(mut font_file) = File::open("file:/ui/unifont.font") {
            font_file.read_to_end(&mut font);
        }

        match File::open(&format!("orbital:///{}/{}/{}/{}/{}", x, y, w, h, title)) {
            Some(file) => Some(box Window {
                x: x,
                y: y,
                w: w,
                h: h,
                t: title.to_string(),
                file: file,
                font: font,
                data: vec![0; w * h * 4],
            }),
            None => None
        }
    }

    //TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        if let Some(path) = self.file.path() {
            //orbital://x/y/w/h/t
            let parts: Vec<&str> = path.split('/').collect();
            if let Some(x) = parts.get(3) {
                self.x = x.to_num_signed();
            }
            if let Some(y) = parts.get(4) {
                self.y = y.to_num_signed();
            }
            if let Some(w) = parts.get(5) {
                self.w = w.to_num();
            }
            if let Some(h) = parts.get(6) {
                self.h = h.to_num();
            }
        }
    }

    /// Get x
    //TODO: Sync with window movements
    pub fn x(&self) -> isize {
        self.x
    }

    /// Get y
    //TODO: Sync with window movements
    pub fn y(&self) -> isize {
        self.y
    }

    /// Get width
    pub fn width(&self) -> usize {
        self.w
    }

    /// Get height
    pub fn height(&self) -> usize {
        self.h
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, _: &str) {
        //TODO
    }

    /// Draw a pixel
    pub fn pixel(&mut self, x: isize, y: isize, color: Color) {
        if x >= 0 && y >= 0 && x < self.w as isize && y < self.h as isize {
            let offset = y as usize * self.w + x as usize;
            self.data[offset] = color.data;
        }
    }

    /// Draw a character, using the loaded font
    pub fn char(&mut self, x: isize, y: isize, c: char, color: Color) {
        let mut offset = (c as usize) * 16;
        for row in 0..16 {
            let row_data;
            if offset < self.font.len() {
                row_data = self.font[offset];
            } else {
                row_data = 0;
            }

            for col in 0..8 {
                let pixel = (row_data >> (7 - col)) & 1;
                if pixel > 0 {
                    self.pixel(x + col as isize, y + row as isize, color);
                }
            }
            offset += 1;
        }
    }

    //TODO move, resize, set_title

    /// Set entire window to a color
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn set(&mut self, color: Color) {
        let w = self.w;
        let h = self.h;
        self.rect(0, 0, w, h, color);
    }

    /// Draw rectangle
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn rect(&mut self, start_x: isize, start_y: isize, w: usize, h: usize, color: Color) {
        for y in start_y..start_y + h as isize {
            for x in start_x..start_x + w as isize {
                self.pixel(x, y, color);
            }
        }
    }

    /// Display an image
    //TODO: Improve speed
    pub fn image(&mut self, start_x: isize, start_y: isize, w: usize, h: usize, data: &[Color]) {
        let mut i = 0;
        for y in start_y..start_y + h as isize {
            for x in start_x..start_x + w as isize {
                if i < data.len() {
                    self.pixel(x, y, data[i])
                }
                i += 1;
            }
        }
    }

    /// Poll for an event
    //TODO: clean this up
    pub fn poll(&mut self) -> Option<Event> {
        let mut event = box Event::new();
        let event_ptr: *mut Event = event.deref_mut();
        loop {
            match self.file.read(&mut unsafe {
                slice::from_raw_parts_mut(event_ptr as *mut u8, mem::size_of::<Event>())
            }) {
                Some(0) => unsafe { sys_yield() },
                Some(_) => return Some(*event),
                None => return None,
            }
        }
    }

    /// Flip the window buffer
    pub fn sync(&mut self) -> bool {
        self.file.seek(SeekFrom::Start(0));
        let to_write: &[u8] = unsafe{ mem::transmute::<&[u32],&[u8]>(&self.data) };
        self.file.write(to_write);
        return self.file.sync();
    }

    /// Return a iterator over events
    pub fn event_iter<'a>(&'a mut self) -> EventIter<'a> {
        EventIter {
            window: self,
        }
    }
}

/// Event iterator
pub struct EventIter<'a> {
    window: &'a mut Window,
}

impl<'a> Iterator for EventIter<'a> {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        self.window.poll()
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::marker::PhantomData;
use approx;
use num;
use channel::{BoundedChannel, BoundedChannelScalarTraits};
use color::{Color, Invert, Lerp, Bounded, PolarColor};

pub struct AlphaTag<T>(pub PhantomData<T>);

#[derive(Clone, Debug, PartialEq, PartialOrd, Hash)]
pub struct Alpha<T, InnerColor> {
    color: InnerColor,
    alpha: BoundedChannel<T>,
}

impl<T, InnerColor> Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits,
          InnerColor: Color
{
    pub fn from_color_and_alpha(color: InnerColor, alpha: T) -> Self {
        Alpha {
            color: color,
            alpha: BoundedChannel(alpha),
        }
    }
    pub fn decompose(self) -> (InnerColor, T) {
        (self.color, self.alpha.0)
    }

    pub fn color(&self) -> &InnerColor {
        &self.color
    }
    pub fn alpha(&self) -> T {
        self.alpha.0.clone()
    }
    pub fn color_mut(&mut self) -> &mut InnerColor {
        &mut self.color
    }
    pub fn alpha_mut(&mut self) -> &mut T {
        &mut self.alpha.0
    }
    pub fn set_color(&mut self, color: InnerColor) {
        self.color = color;
    }
    pub fn set_alpha(&mut self, alpha: T) {
        self.alpha.0 = alpha
    }
}

impl<T, InnerColor> Color for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits,
          InnerColor: Color
{
    type Tag = AlphaTag<InnerColor::Tag>;
    type ChannelsTuple = (InnerColor::ChannelsTuple, T);

    fn num_channels() -> u32 {
        InnerColor::num_channels() + 1
    }

    fn to_tuple(self) -> Self::ChannelsTuple {
        (self.color.to_tuple(), self.alpha.0)
    }
    fn from_tuple(values: Self::ChannelsTuple) -> Self {
        Alpha {
            color: InnerColor::from_tuple(values.0),
            alpha: BoundedChannel(values.1),
        }
    }
}

impl<T, InnerColor> Invert for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits,
          InnerColor: Color + Invert
{
    fn invert(self) -> Self {
        Alpha {
            color: self.color.invert(),
            alpha: self.alpha.invert(),
        }
    }
}

impl<T, InnerColor> Lerp for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits + Lerp<Position = InnerColor::Position>,
          InnerColor: Color + Lerp
{
    type Position = InnerColor::Position;

    fn lerp(&self, right: &Self, pos: Self::Position) -> Self {
        Alpha {
            color: self.color.lerp(&right.color, pos.clone()),
            alpha: self.alpha.lerp(&right.alpha, pos),
        }
    }
}

impl<T, InnerColor> Bounded for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits + Bounded,
          InnerColor: Color + Bounded
{
    fn normalize(self) -> Self {
        Alpha {
            color: self.color.normalize(),
            alpha: self.alpha.normalize(),
        }
    }
    fn is_normalized(&self) -> bool {
        self.color.is_normalized() && self.alpha.is_normalized()
    }
}

impl<T, InnerColor> PolarColor for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits,
          InnerColor: Color + PolarColor<Cartesian = T>
{
    type Angular = InnerColor::Angular;
    type Cartesian = InnerColor::Cartesian;
}

impl<T, InnerColor> approx::ApproxEq for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits + approx::ApproxEq<Epsilon = InnerColor::Epsilon>,
          InnerColor: Color + approx::ApproxEq,
          InnerColor::Epsilon: Clone + num::Float
{
    impl_approx_eq!({color, alpha});
}

impl<T, InnerColor> Default for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits + Default + num::Zero,
          InnerColor: Color + Default + num::Zero
{
    fn default() -> Self {
        Alpha {
            color: InnerColor::default(),
            alpha: BoundedChannel::default(),
        }
    }
}

impl<T, InnerColor> fmt::Display for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits + fmt::Display,
          InnerColor: Color + fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Alpha({}, {})", self.color, self.alpha)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use rgb::*;
    use hsv::*;
    use angle::*;
    use color::*;

    #[test]
    fn test_construct() {
        let c1 = Rgba::from_color_and_alpha(Rgb::from_channels(30u8, 120u8, 255u8), 222u8);
        assert_eq!(c1.alpha(), 222u8);
        assert_eq!(c1.color().red(), 30u8);
        assert_eq!(c1.color().green(), 120u8);
        assert_eq!(c1.color().blue(), 255u8);

        let mut c2 = Hsva::from_color_and_alpha(Hsv::from_channels(Deg(0.3f32), 0.66, 0.9),
                                                0.25f32);
        assert_eq!(c2.alpha(), 0.25f32);
        assert_ulps_eq!(*c2.color(), Hsv::from_channels(Deg(0.3f32), 0.66, 0.9));
        *c2.alpha_mut() = 0.75;
        *c2.color_mut().saturation_mut() = 0.01;
        assert_ulps_eq!(c2,
            Hsva::from_color_and_alpha(Hsv::from_channels(Deg(0.3f32), 0.01, 0.9), 0.75f32));

        let (c, a) = c2.clone().decompose();
        assert_eq!(c, *c2.color());
        assert_eq!(a, c2.alpha());
    }

    #[test]
    fn test_invert() {
        let c1 = Rgba::from_color_and_alpha(Rgb::from_channels(30u8, 255u8, 200u8), 155u8);
        assert_eq!(c1.clone().invert().invert(), c1);
        assert_eq!(c1.invert(), Rgba::from_color_and_alpha(
                Rgb::from_channels(225u8, 0, 55), 100u8));

        let c2 = Hsva::from_color_and_alpha(Hsv::from_channels(Deg(120.0f32), 0.3f32, 0.85),
                                            0.3f32);
        assert_relative_eq!(c2.clone().invert().invert(), c2, epsilon=1e-6);
        assert_relative_eq!(c2.invert(),
            Hsva::from_color_and_alpha(Hsv::from_channels(
                Deg(300.0f32), 0.7f32, 0.15), 0.7f32), epsilon=1e-4);
    }

    #[test]
    fn test_lerp() {
        let c1 = Rgba::from_color_and_alpha(Rgb::from_channels(120u8, 200, 0), 150);
        let c2 = Rgba::from_color_and_alpha(Rgb::from_channels(250u8, 100, 220), 55);
        assert_eq!(c1.lerp(&c2, 0.0), c1);
        assert_eq!(c1.lerp(&c2, 1.0), c2);
        assert_eq!(c1.lerp(&c2, 0.5),
            Rgba::from_color_and_alpha(Rgb::from_channels(185u8, 150, 110), 102));

        let c3 = Hsva::from_color_and_alpha(Hsv::from_channels(Deg(60.0), 0.25, 0.55), 0.95);
        let c4 = Hsva::from_color_and_alpha(Hsv::from_channels(Deg(340.0), 0.95, 0.0), 0.25);
        assert_relative_eq!(c3.lerp(&c4, 0.0), c3);
        assert_relative_eq!(c3.lerp(&c4, 1.0), c4);
        assert_relative_eq!(c3.lerp(&c4, 0.25),
            Hsva::from_color_and_alpha(Hsv::from_channels(
                Deg(40.0), 0.425, 0.41250), 0.7750));
    }
}
<commit_msg>Implemented remaining traits on Alpha.<commit_after>use std::fmt;
use std::marker::PhantomData;
use std::slice;
use std::mem;
use approx;
use num;
use channel::{BoundedChannel, BoundedChannelScalarTraits, ColorChannel};
use color::{Color, Invert, Lerp, Bounded, PolarColor, HomogeneousColor, Flatten};

pub struct AlphaTag<T>(pub PhantomData<T>);

#[repr(C)]
#[derive(Clone, Debug, PartialEq, PartialOrd, Hash)]
pub struct Alpha<T, InnerColor> {
    color: InnerColor,
    alpha: BoundedChannel<T>,
}

impl<T, InnerColor> Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits,
          InnerColor: Color
{
    pub fn from_color_and_alpha(color: InnerColor, alpha: T) -> Self {
        Alpha {
            color: color,
            alpha: BoundedChannel(alpha),
        }
    }
    pub fn decompose(self) -> (InnerColor, T) {
        (self.color, self.alpha.0)
    }

    pub fn color(&self) -> &InnerColor {
        &self.color
    }
    pub fn alpha(&self) -> T {
        self.alpha.0.clone()
    }
    pub fn color_mut(&mut self) -> &mut InnerColor {
        &mut self.color
    }
    pub fn alpha_mut(&mut self) -> &mut T {
        &mut self.alpha.0
    }
    pub fn set_color(&mut self, color: InnerColor) {
        self.color = color;
    }
    pub fn set_alpha(&mut self, alpha: T) {
        self.alpha.0 = alpha
    }
}

impl<T, InnerColor> Color for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits,
          InnerColor: Color
{
    type Tag = AlphaTag<InnerColor::Tag>;
    type ChannelsTuple = (InnerColor::ChannelsTuple, T);

    fn num_channels() -> u32 {
        InnerColor::num_channels() + 1
    }

    fn to_tuple(self) -> Self::ChannelsTuple {
        (self.color.to_tuple(), self.alpha.0)
    }
    fn from_tuple(values: Self::ChannelsTuple) -> Self {
        Alpha {
            color: InnerColor::from_tuple(values.0),
            alpha: BoundedChannel(values.1),
        }
    }
}

impl<T, InnerColor> Invert for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits,
          InnerColor: Color + Invert
{
    fn invert(self) -> Self {
        Alpha {
            color: self.color.invert(),
            alpha: self.alpha.invert(),
        }
    }
}

impl<T, InnerColor> Lerp for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits + Lerp<Position = InnerColor::Position>,
          InnerColor: Color + Lerp
{
    type Position = InnerColor::Position;

    fn lerp(&self, right: &Self, pos: Self::Position) -> Self {
        Alpha {
            color: self.color.lerp(&right.color, pos.clone()),
            alpha: self.alpha.lerp(&right.alpha, pos),
        }
    }
}

impl<T, InnerColor> Bounded for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits,
          InnerColor: Color + Bounded
{
    fn normalize(self) -> Self {
        Alpha {
            color: self.color.normalize(),
            alpha: self.alpha.normalize(),
        }
    }
    fn is_normalized(&self) -> bool {
        self.color.is_normalized() && self.alpha.is_normalized()
    }
}

impl<T, InnerColor> HomogeneousColor for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits,
          InnerColor: Color + HomogeneousColor<ChannelFormat = T>
{
    type ChannelFormat = T;
    fn broadcast(value: T) -> Self {
        Alpha {
            color: InnerColor::broadcast(value.clone()),
            alpha: BoundedChannel(value),
        }
    }
    fn clamp(self, min: T, max: T) -> Self {
        Alpha {
            color: self.color.clamp(min.clone(), max.clone()),
            alpha: self.alpha.clamp(min, max),
        }
    }
}

impl<T, InnerColor> Flatten for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits,
          InnerColor: Color + Flatten<ScalarFormat = T>
{
    type ScalarFormat = T;

    impl_color_as_slice!(T);

    fn from_slice(values: &[T]) -> Self {
        Alpha {
            color: InnerColor::from_slice(values),
            alpha: BoundedChannel(values[Self::num_channels() as usize - 1].clone()),
        }
    }
}

impl<T, InnerColor> PolarColor for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits,
          InnerColor: Color + PolarColor<Cartesian = T>
{
    type Angular = InnerColor::Angular;
    type Cartesian = InnerColor::Cartesian;
}

impl<T, InnerColor> approx::ApproxEq for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits + approx::ApproxEq<Epsilon = InnerColor::Epsilon>,
          InnerColor: Color + approx::ApproxEq,
          InnerColor::Epsilon: Clone + num::Float
{
    impl_approx_eq!({color, alpha});
}

impl<T, InnerColor> Default for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits + Default + num::Zero,
          InnerColor: Color + Default + num::Zero
{
    fn default() -> Self {
        Alpha {
            color: InnerColor::default(),
            alpha: BoundedChannel::default(),
        }
    }
}

impl<T, InnerColor> fmt::Display for Alpha<T, InnerColor>
    where T: BoundedChannelScalarTraits + fmt::Display,
          InnerColor: Color + fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Alpha({}, {})", self.color, self.alpha)
    }
}

#[cfg(test)]
mod test {
    use rgb::*;
    use hsv::*;
    use angle::*;
    use color::*;

    #[test]
    fn test_construct() {
        let c1 = Rgba::from_color_and_alpha(Rgb::from_channels(30u8, 120u8, 255u8), 222u8);
        assert_eq!(c1.alpha(), 222u8);
        assert_eq!(c1.color().red(), 30u8);
        assert_eq!(c1.color().green(), 120u8);
        assert_eq!(c1.color().blue(), 255u8);
        let (ic1, a) = c1.to_tuple();
        assert_eq!(ic1, (30u8, 120, 255));
        assert_eq!(a, 222u8);

        let mut c2 = Hsva::from_color_and_alpha(Hsv::from_channels(Deg(0.3f32), 0.66, 0.9),
                                                0.25f32);
        assert_eq!(c2.alpha(), 0.25f32);
        assert_ulps_eq!(*c2.color(), Hsv::from_channels(Deg(0.3f32), 0.66, 0.9));
        assert_eq!(c2, Hsva::from_tuple(((Deg(0.3f32), 0.66f32, 0.9), 0.25)));
        *c2.alpha_mut() = 0.75;
        *c2.color_mut().saturation_mut() = 0.01;
        assert_ulps_eq!(c2,
            Hsva::from_color_and_alpha(Hsv::from_channels(Deg(0.3f32), 0.01, 0.9), 0.75f32));

        let (c, a) = c2.clone().decompose();
        assert_eq!(c, *c2.color());
        assert_eq!(a, c2.alpha());

        let c3 = Rgba::broadcast(50u8);
        assert_eq!(c3, Rgba::from_tuple(((50u8, 50, 50), 50)));

        let c4 = Rgba::from_color_and_alpha(Rgb::from_channels(0.2, 0.6, 0.99), 0.05);
        assert_relative_eq!(c4.clamp(0.25, 0.75),
            Rgba::from_color_and_alpha(Rgb::from_channels(0.25, 0.6, 0.75), 0.25));
    }

    #[test]
    fn test_invert() {
        let c1 = Rgba::from_color_and_alpha(Rgb::from_channels(30u8, 255u8, 200u8), 155u8);
        assert_eq!(c1.clone().invert().invert(), c1);
        assert_eq!(c1.invert(), Rgba::from_color_and_alpha(
                Rgb::from_channels(225u8, 0, 55), 100u8));

        let c2 = Hsva::from_color_and_alpha(Hsv::from_channels(Deg(120.0f32), 0.3f32, 0.85),
                                            0.3f32);
        assert_relative_eq!(c2.clone().invert().invert(), c2, epsilon=1e-6);
        assert_relative_eq!(c2.invert(),
            Hsva::from_color_and_alpha(Hsv::from_channels(
                Deg(300.0f32), 0.7f32, 0.15), 0.7f32), epsilon=1e-4);
    }

    #[test]
    fn test_lerp() {
        let c1 = Rgba::from_color_and_alpha(Rgb::from_channels(120u8, 200, 0), 150);
        let c2 = Rgba::from_color_and_alpha(Rgb::from_channels(250u8, 100, 220), 55);
        assert_eq!(c1.lerp(&c2, 0.0), c1);
        assert_eq!(c1.lerp(&c2, 1.0), c2);
        assert_eq!(c1.lerp(&c2, 0.5),
            Rgba::from_color_and_alpha(Rgb::from_channels(185u8, 150, 110), 102));

        let c3 = Hsva::from_color_and_alpha(Hsv::from_channels(Deg(60.0), 0.25, 0.55), 0.95);
        let c4 = Hsva::from_color_and_alpha(Hsv::from_channels(Deg(340.0), 0.95, 0.0), 0.25);
        assert_relative_eq!(c3.lerp(&c4, 0.0), c3);
        assert_relative_eq!(c3.lerp(&c4, 1.0), c4);
        assert_relative_eq!(c3.lerp(&c4, 0.25),
            Hsva::from_color_and_alpha(Hsv::from_channels(
                Deg(40.0), 0.425, 0.41250), 0.7750));
    }

    #[test]
    fn test_flatten() {
        let c1 = Rgba::from_color_and_alpha(Rgb::from_channels(100u8, 50, 175), 254);
        assert_eq!(c1.as_slice(), &[100u8, 50, 175, 254]);
        assert_eq!(Rgba::from_slice(c1.as_slice()), c1);

        let c2 = Hsva::from_color_and_alpha(Hsv::from_channels(Turns(0.5f32), 0.77f32, 0.5),
                                            0.8765);
        assert_eq!(c2.as_slice(), &[0.5f32, 0.77, 0.5, 0.8765]);
        assert_eq!(Hsva::from_slice(c2.as_slice()), c2);
    }
}
<|endoftext|>


<commit_before><commit_msg>avoid need for mutable borrow when looking up tensor id<commit_after><|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

pub mod metadata;
pub mod startup;

use crate::session::{self, Session, Task};

pub trait Request: Sized {
    type Proto: prost::Message + Default;
    fn from_proto(proto: Self::Proto) -> Result<Self, session::ParseError>;
}

pub trait Response: Sized {
    const RDF_NAME: Option<&'static str>;
    type Proto: prost::Message + Default;
    fn into_proto(self) -> Self::Proto;
}

impl Request for () {

    type Proto = ();

    fn from_proto(unit: ()) -> Result<(), session::ParseError> {
        Ok(unit)
    }
}

impl Response for () {

    const RDF_NAME: Option<&'static str> = None;

    type Proto = ();

    fn into_proto(self) {
    }
}

/// Dispatches `task` to a handler appropriate for the given `action`.
///
/// This method is a mapping between action names (as specified in the protocol)
/// and action handlers (implemented on the agent).
///
/// If the given action is unknown (or not yet implemented), this function will
/// return an error.
pub fn dispatch<'s, S>(action: &str, task: Task<'s, S>) -> session::Result<()>
where
    S: Session,
{
    match action {
        "SendStartupInfo" => task.execute(self::startup::handle),
        "GetClientInfo" => task.execute(self::metadata::handle),
        action => return Err(session::Error::Dispatch(String::from(action))),
    }
}
<commit_msg>Write doc comments for the action traits.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

pub mod metadata;
pub mod startup;

use crate::session::{self, Session, Task};

/// Abstraction for action-specific requests.
///
/// Protocol Buffer messages received from the GRR server are not necessarily
/// easy to work with and are hardly idiomatic to Rust. For this reason, actions
/// should define more structured data types to represent their input and should
/// be able to parse raw messages into them.
pub trait Request: Sized {

    /// A type of the corresponding raw proto message.
    type Proto: prost::Message + Default;

    /// A method for converting raw proto messages into structured requests.
    fn from_proto(proto: Self::Proto) -> Result<Self, session::ParseError>;
}

/// Abstraction for action-specific responses.
///
/// Like with the [`Request`] type, Protocol Buffer messages sent to the GRR
/// server are very idiomatic to Rust. For this reason, actions should define
/// more structured data types to represent responses and provide a way to
/// convert them into the wire format.
///
/// Note that because of the design flaws in the protocol, actions also need to
/// specify a name of the wrapper RDF class from the Python implementation.
/// Hopefully, one day this issue would be fixed and class names will not leak
/// into the specification.
///
/// [`Request`]: trait.Request.html
pub trait Response: Sized {

    /// A name of the corresponding RDF class.
    const RDF_NAME: Option<&'static str>;

    /// A type of the corresponding raw proto message.
    type Proto: prost::Message + Default;

    /// A method for converting structured responses into raw proto messages.
    fn into_proto(self) -> Self::Proto;
}

impl Request for () {

    type Proto = ();

    fn from_proto(unit: ()) -> Result<(), session::ParseError> {
        Ok(unit)
    }
}

impl Response for () {

    const RDF_NAME: Option<&'static str> = None;

    type Proto = ();

    fn into_proto(self) {
    }
}

/// Dispatches `task` to a handler appropriate for the given `action`.
///
/// This method is a mapping between action names (as specified in the protocol)
/// and action handlers (implemented on the agent).
///
/// If the given action is unknown (or not yet implemented), this function will
/// return an error.
pub fn dispatch<'s, S>(action: &str, task: Task<'s, S>) -> session::Result<()>
where
    S: Session,
{
    match action {
        "SendStartupInfo" => task.execute(self::startup::handle),
        "GetClientInfo" => task.execute(self::metadata::handle),
        action => return Err(session::Error::Dispatch(String::from(action))),
    }
}
<|endoftext|>


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

use cg::{self, WhereClause};
use darling::util::Override;
use quote::{ToTokens, Tokens};
use syn::{self, Data, Ident};
use synstructure::{BindingInfo, Structure, VariantInfo};

pub fn derive(input: syn::DeriveInput) -> Tokens {
    let name = &input.ident;
    let trait_path = parse_quote!(::style_traits::ToCss);
    let (impl_generics, ty_generics, mut where_clause) =
        cg::trait_parts(&input, &trait_path);

    let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
    if let Data::Enum(_) = input.data {
        assert!(input_attrs.function.is_none(), "#[css(function)] is not allowed on enums");
        assert!(!input_attrs.comma, "#[css(comma)] is not allowed on enums");
    }
    let s = Structure::new(&input);

    let match_body = s.each_variant(|variant| {
        derive_variant_arm(variant, &mut where_clause)
    });

    let mut impls = quote! {
        impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
            #[allow(unused_variables)]
            #[inline]
            fn to_css<W>(
                &self,
                dest: &mut ::style_traits::CssWriter<W>,
            ) -> ::std::fmt::Result
            where
                W: ::std::fmt::Write
            {
                match *self {
                    #match_body
                }
            }
        }
    };

    if input_attrs.derive_debug {
        impls.append_all(quote! {
            impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    ::style_traits::ToCss::to_css(
                        self,
                        &mut ::style_traits::CssWriter::new(f),
                    )
                }
            }
        });
    }

    impls
}

fn derive_variant_arm(
    variant: &VariantInfo,
    where_clause: &mut WhereClause,
) -> Tokens {
    let bindings = variant.bindings();
    let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
    let ast = variant.ast();
    let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&ast);
    let separator = if variant_attrs.comma { ", " } else { " " };

    if variant_attrs.dimension {
        assert_eq!(bindings.len(), 1);
        assert!(
            variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
            "That makes no sense"
        );
    }

    let mut expr = if let Some(keyword) = variant_attrs.keyword {
        assert!(bindings.is_empty());
        quote! {
            ::std::fmt::Write::write_str(dest, #keyword)
        }
    } else if !bindings.is_empty() {
        derive_variant_fields_expr(bindings, where_clause, separator)
    } else {
        quote! {
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    };

    if variant_attrs.dimension {
        expr = quote! {
            #expr?;
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    } else if let Some(function) = variant_attrs.function {
        let mut identifier = function.explicit().map_or(identifier, |name| name);
        identifier.push_str("(");
        expr = quote! {
            ::std::fmt::Write::write_str(dest, #identifier)?;
            #expr?;
            ::std::fmt::Write::write_str(dest, ")")
        }
    }
    expr
}

fn derive_variant_fields_expr(
    bindings: &[BindingInfo],
    where_clause: &mut WhereClause,
    separator: &str,
) -> Tokens {
    let mut iter = bindings.iter().filter_map(|binding| {
        let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
        if attrs.skip {
            return None;
        }
        Some((binding, attrs))
    }).peekable();

    let (first, attrs) = match iter.next() {
        Some(pair) => pair,
        None => return quote! { Ok(()) },
    };
    if !attrs.iterable && iter.peek().is_none() {
        if !attrs.ignore_bound {
            where_clause.add_trait_bound(&first.ast().ty);
        }
        let mut expr = quote! { ::style_traits::ToCss::to_css(#first, dest) };
        if let Some(condition) = attrs.skip_if {
            expr = quote! {
                if !#first.#condition() {
                    #expr
                }
            }
        }
        return expr;
    }

    let mut expr = derive_single_field_expr(first, attrs, where_clause);
    for (binding, attrs) in iter {
        derive_single_field_expr(binding, attrs, where_clause).to_tokens(&mut expr)
    }

    quote! {{
        let mut writer = ::style_traits::values::SequenceWriter::new(dest, #separator);
        #expr
        Ok(())
    }}
}

fn derive_single_field_expr(
    field: &BindingInfo,
    attrs: CssFieldAttrs,
    where_clause: &mut WhereClause,
) -> Tokens {
    let mut expr = if attrs.iterable {
        if let Some(if_empty) = attrs.if_empty {
            return quote! {
                {
                    let mut iter = #field.iter().peekable();
                    if iter.peek().is_none() {
                        writer.item(&::style_traits::values::Verbatim(#if_empty))?;
                    } else {
                        for item in iter {
                            writer.item(&item)?;
                        }
                    }
                }
            };
        }
        quote! {
            for item in #field.iter() {
                writer.item(&item)?;
            }
        }
    } else {
        if !attrs.ignore_bound {
            where_clause.add_trait_bound(&field.ast().ty);
        }
        quote! { writer.item(#field)?; }
    };

    if let Some(condition) = attrs.skip_if {
        expr = quote! {
            if !#field.#condition() {
                #expr
            }
        }
    }

    expr
}

#[darling(attributes(css), default)]
#[derive(Default, FromDeriveInput)]
struct CssInputAttrs {
    derive_debug: bool,
    // Here because structs variants are also their whole type definition.
    function: Option<Override<String>>,
    // Here because structs variants are also their whole type definition.
    comma: bool,
}

#[darling(attributes(css), default)]
#[derive(Default, FromVariant)]
pub struct CssVariantAttrs {
    pub function: Option<Override<String>>,
    pub comma: bool,
    pub dimension: bool,
    pub keyword: Option<String>,
    pub aliases: Option<String>,
}

#[darling(attributes(css), default)]
#[derive(Default, FromField)]
struct CssFieldAttrs {
    if_empty: Option<String>,
    ignore_bound: bool,
    iterable: bool,
    skip: bool,
    skip_if: Option<Ident>,
}
<commit_msg>style: Switch css(skip_if) to use a Path for consistency.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cg::{self, WhereClause};
use darling::util::Override;
use quote::{ToTokens, Tokens};
use syn::{self, Data, Path};
use synstructure::{BindingInfo, Structure, VariantInfo};

pub fn derive(input: syn::DeriveInput) -> Tokens {
    let name = &input.ident;
    let trait_path = parse_quote!(::style_traits::ToCss);
    let (impl_generics, ty_generics, mut where_clause) =
        cg::trait_parts(&input, &trait_path);

    let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
    if let Data::Enum(_) = input.data {
        assert!(input_attrs.function.is_none(), "#[css(function)] is not allowed on enums");
        assert!(!input_attrs.comma, "#[css(comma)] is not allowed on enums");
    }
    let s = Structure::new(&input);

    let match_body = s.each_variant(|variant| {
        derive_variant_arm(variant, &mut where_clause)
    });

    let mut impls = quote! {
        impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
            #[allow(unused_variables)]
            #[inline]
            fn to_css<W>(
                &self,
                dest: &mut ::style_traits::CssWriter<W>,
            ) -> ::std::fmt::Result
            where
                W: ::std::fmt::Write
            {
                match *self {
                    #match_body
                }
            }
        }
    };

    if input_attrs.derive_debug {
        impls.append_all(quote! {
            impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    ::style_traits::ToCss::to_css(
                        self,
                        &mut ::style_traits::CssWriter::new(f),
                    )
                }
            }
        });
    }

    impls
}

fn derive_variant_arm(
    variant: &VariantInfo,
    where_clause: &mut WhereClause,
) -> Tokens {
    let bindings = variant.bindings();
    let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
    let ast = variant.ast();
    let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&ast);
    let separator = if variant_attrs.comma { ", " } else { " " };

    if variant_attrs.dimension {
        assert_eq!(bindings.len(), 1);
        assert!(
            variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
            "That makes no sense"
        );
    }

    let mut expr = if let Some(keyword) = variant_attrs.keyword {
        assert!(bindings.is_empty());
        quote! {
            ::std::fmt::Write::write_str(dest, #keyword)
        }
    } else if !bindings.is_empty() {
        derive_variant_fields_expr(bindings, where_clause, separator)
    } else {
        quote! {
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    };

    if variant_attrs.dimension {
        expr = quote! {
            #expr?;
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    } else if let Some(function) = variant_attrs.function {
        let mut identifier = function.explicit().map_or(identifier, |name| name);
        identifier.push_str("(");
        expr = quote! {
            ::std::fmt::Write::write_str(dest, #identifier)?;
            #expr?;
            ::std::fmt::Write::write_str(dest, ")")
        }
    }
    expr
}

fn derive_variant_fields_expr(
    bindings: &[BindingInfo],
    where_clause: &mut WhereClause,
    separator: &str,
) -> Tokens {
    let mut iter = bindings.iter().filter_map(|binding| {
        let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
        if attrs.skip {
            return None;
        }
        Some((binding, attrs))
    }).peekable();

    let (first, attrs) = match iter.next() {
        Some(pair) => pair,
        None => return quote! { Ok(()) },
    };
    if !attrs.iterable && iter.peek().is_none() {
        if !attrs.ignore_bound {
            where_clause.add_trait_bound(&first.ast().ty);
        }
        let mut expr = quote! { ::style_traits::ToCss::to_css(#first, dest) };
        if let Some(condition) = attrs.skip_if {
            expr = quote! {
                if !#condition(#first) {
                    #expr
                }
            }
        }
        return expr;
    }

    let mut expr = derive_single_field_expr(first, attrs, where_clause);
    for (binding, attrs) in iter {
        derive_single_field_expr(binding, attrs, where_clause).to_tokens(&mut expr)
    }

    quote! {{
        let mut writer = ::style_traits::values::SequenceWriter::new(dest, #separator);
        #expr
        Ok(())
    }}
}

fn derive_single_field_expr(
    field: &BindingInfo,
    attrs: CssFieldAttrs,
    where_clause: &mut WhereClause,
) -> Tokens {
    let mut expr = if attrs.iterable {
        if let Some(if_empty) = attrs.if_empty {
            return quote! {
                {
                    let mut iter = #field.iter().peekable();
                    if iter.peek().is_none() {
                        writer.item(&::style_traits::values::Verbatim(#if_empty))?;
                    } else {
                        for item in iter {
                            writer.item(&item)?;
                        }
                    }
                }
            };
        }
        quote! {
            for item in #field.iter() {
                writer.item(&item)?;
            }
        }
    } else {
        if !attrs.ignore_bound {
            where_clause.add_trait_bound(&field.ast().ty);
        }
        quote! { writer.item(#field)?; }
    };

    if let Some(condition) = attrs.skip_if {
        expr = quote! {
            if !#condition(#field) {
                #expr
            }
        }
    }

    expr
}

#[darling(attributes(css), default)]
#[derive(Default, FromDeriveInput)]
struct CssInputAttrs {
    derive_debug: bool,
    // Here because structs variants are also their whole type definition.
    function: Option<Override<String>>,
    // Here because structs variants are also their whole type definition.
    comma: bool,
}

#[darling(attributes(css), default)]
#[derive(Default, FromVariant)]
pub struct CssVariantAttrs {
    pub function: Option<Override<String>>,
    pub comma: bool,
    pub dimension: bool,
    pub keyword: Option<String>,
    pub aliases: Option<String>,
}

#[darling(attributes(css), default)]
#[derive(Default, FromField)]
struct CssFieldAttrs {
    if_empty: Option<String>,
    ignore_bound: bool,
    iterable: bool,
    skip: bool,
    skip_if: Option<Path>,
}
<|endoftext|>


<commit_before><commit_msg>change fields on a .pbxproj target<commit_after><|endoftext|>


<commit_before>#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
#![allow(dead_code)]

use std::os::raw::{c_void, c_char, c_int};

pub const RTLD_LAZY: c_int = 0x001;
pub const RTLD_NOW: c_int = 0x002;

#[link="dl"]
extern {
    pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
    pub fn dlerror() -> *mut c_char;
    pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
    pub fn dlclose(handle: *mut c_void) -> c_int;
}
<commit_msg>Fix broken `link` in dlopen (#1093)<commit_after>#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
#![allow(dead_code)]

use std::os::raw::{c_void, c_char, c_int};

pub const RTLD_LAZY: c_int = 0x001;
pub const RTLD_NOW: c_int = 0x002;

#[link(name = "dl")]
extern {
    pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
    pub fn dlerror() -> *mut c_char;
    pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
    pub fn dlclose(handle: *mut c_void) -> c_int;
}
<|endoftext|>


<commit_before>//! Exposes the `chain` trait and `StackChain` type.

use std::fmt::Show;

use super::response::Response;
use super::request::Request;
use super::middleware::{Middleware, Status, Continue, Error};

/// `Chains` are the backbone of `Iron`. They coordinate `Middleware`
/// to ensure they are resolved and called in the right order.
///
/// `Chains` are internal tools. Unless you want additional
/// or unusual behavior such as enhanced debug logging you
/// probably don't need to mess with `Chain` internals.
///
/// That being said, custom `Chains` are extremely powerful as they
/// allow you to completely control the resolution of `Middleware`.
pub trait Chain: Send + Clone {
    /// `dispatch` will be called once per `Request` and is responsible
    /// for delegating the request to the correct `Middleware` and in the correct
    /// order. Effectively, 99% of the work done by a `chain` is done here.
    fn dispatch(&mut self,
                request: &mut Request,
                response: &mut Response) -> Status {

        let mut status = self.chain_enter(request, response);
        match status {
            Error(ref mut e) => {
                let error: &mut Show = *e;
                let _ = self.chain_error(request, response, error);
            },
            _ => {
                let _ = self.chain_exit(request, response);
            }
        };

        status
    }

    #[doc(hidden)]
    fn chain_enter(&mut self,
             request: &mut Request,
             response: &mut Response) -> Status;

    #[doc(hidden)]
    fn chain_exit(&mut self,
                  _request: &mut Request,
                  _response: &mut Response) -> Status {
        Continue
    }

    #[doc(hidden)]
    fn chain_error(&mut self,
                  _request: &mut Request,
                  _response: &mut Response,
                  _error: &mut Show) { () }

    /// `link` is responsible for adding new `Middleware` to the `chain's` internal
    /// storage of `Middleware`. Different `chains` may implement different behavior
    /// for `link`, but - ideally - `Middleware` added here will be delegated to during
    /// `Requests`.
    fn link<M: Middleware>(&mut self, _middleware: M);

    /// Create a new instance of `chain`.
    fn new() -> Self;

    #[doc(hidden)]
    fn clone_box(&self) -> Box<Chain + Send> { box self.clone() as Box<Chain + Send> }
}

impl Clone for Box<Chain + Send> {
    fn clone(&self) -> Box<Chain + Send> { self.clone_box() }
}

/// The default `chain` used by `Iron`.
pub mod stackchain {
    use std::fmt::Show;

    use super::super::request::Request;
    use super::super::response::Response;
    use super::super::middleware::{Middleware, Continue, Unwind, Error, Status};

    use super::Chain;

    /// The default `Chain` used by `Iron`.
    /// `StackChain` runs each `Request` through all `Middleware` in its stack.
    ///
    /// When it hits `Middleware` which returns `Unwind`, it passes
    /// the `Request` back up through all `Middleware` it has hit so far.
    ///
    /// If no `Middleware` return `Unwind` to indicate that they handled
    /// the request, then a 404 is automatically returned.
    #[deriving(Clone)]
    pub struct StackChain {
        /// The storage used by `StackChain` to hold all `Middleware`
        /// that have been `linked` to it.
        stack: Vec<Box<Middleware + Send>>,
        status: ChainStatus,
    }

    #[deriving(Clone)]
    enum ChainStatus { Unwound(uint), Errored(uint), Unhandled }

    /// `StackChain` is a `Chain`
    impl Chain for StackChain {
        fn chain_enter(&mut self,
                 request: &mut Request,
                 response: &mut Response) -> Status {
            // The `exit_stack` will hold all `Middleware` that are passed through
            // in the enter loop. This is so we know to take exactly the same
            // path through `Middleware` in reverse order than we did on the way in.
            self.status = Unhandled;

            'enter: for (i, middleware) in self.stack.mut_iter().enumerate() {
                match middleware.enter(request, response) {
                    Unwind   => {
                        self.status = Unwound(i);
                        return Unwind;
                    },
                    e @ Error(_) => {
                        self.status = Errored(i);
                        return e;
                    }
                    // Mark the middleware for traversal on exit.
                    Continue => ()
                }
            }

            self.status = Unhandled;
            Continue
        }

        fn chain_exit(&mut self,
                 request: &mut Request,
                 response: &mut Response) -> Status {
            match self.status {
                Unwound(i) => {
                    for middleware in self.stack.mut_slice_to(i).mut_iter().rev() {
                        let _ = middleware.exit(request, response);
                    }
                },
                Unhandled => {
                    for middleware in self.stack.mut_iter().rev() {
                        let _ = middleware.exit(request, response);
                    }
                },
                Errored(_) => fail!("chain_exit called on a StackChain which Errored.")
            }

            Continue
        }

        fn chain_error(&mut self,
                      request: &mut Request,
                      response: &mut Response,
                      error: &mut Show) {
            match self.status {
                Errored(i) => {
                    for middleware in self.stack.mut_slice_to(i).mut_iter().rev() {
                        let _ = middleware.on_error(request, response, error);
                    }
                },
                _ => fail!("chain_error called on a chain which did not error.")
            }
        }

        /// Add `Middleware` to the `Chain`.
        fn link<M: Middleware>(&mut self, middleware: M) {
            self.stack.push(box middleware);
        }

        /// Create a new instance of `StackChain`.
        fn new() -> StackChain {
            StackChain {
                stack: vec![],
                status: Unhandled
            }
        }
    }

    impl FromIterator<Box<Middleware + Send>> for StackChain {
        fn from_iter<T: Iterator<Box<Middleware + Send>>>(mut iterator: T) -> StackChain {
            StackChain {
                stack: iterator.collect(),
                status: Unhandled
            }
        }
    }

    #[cfg(test)]
    mod test {
        pub use super::*;
        pub use super::super::super::request::Request;
        pub use super::super::super::response::Response;
        pub use super::super::super::middleware::{Middleware, Status, Continue, Unwind};
        pub use std::sync::{Arc, Mutex};

        #[deriving(Clone)]
        pub struct CallCount {
            enter: Arc<Mutex<u64>>,
            exit: Arc<Mutex<u64>>
        }

        impl Middleware for CallCount {
            fn enter(&mut self, _req: &mut Request,
                     _res: &mut Response) -> Status {
                let mut enter = self.enter.lock();
                *enter += 1;
                Continue
            }

            fn exit(&mut self, _req: &mut Request,
                    _res: &mut Response) -> Status {
                let mut exit = self.exit.lock();
                *exit += 1;
                Continue
            }
        }

        #[deriving(Clone)]
        pub struct Stopper;

        impl Middleware for Stopper {
            fn enter(&mut self, _req: &mut Request,
                     _res: &mut Response) -> Status {
                Unwind // Stop .status from being accessed, which fails.
            }
        }

        mod dispatch {
            use super::{CallCount, Arc, Mutex, Stopper};
            use super::super::StackChain;
            use super::super::super::Chain;
            use std::mem::uninitialized;

            #[test]
            fn calls_middleware_enter() {
                let mut testchain: StackChain = Chain::new();
                let enter = Arc::new(Mutex::new(0));
                let exit = Arc::new(Mutex::new(0));
                testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
                testchain.link(Stopper);
                unsafe {
                    let _ = testchain.dispatch(
                        uninitialized(),
                        uninitialized()
                    );
                }
                assert_eq!(*enter.lock(), 1);
            }

            #[test]
            fn calls_middleware_exit() {
                let mut testchain: StackChain = Chain::new();
                let enter = Arc::new(Mutex::new(0));
                let exit = Arc::new(Mutex::new(0));
                testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
                testchain.link(Stopper);
                unsafe {
                    let _ = testchain.dispatch(
                        uninitialized(),
                        uninitialized()
                    );
                }
                assert_eq!(*exit.lock(), 1);
            }

            #[test]
            fn calls_all_middleware_enter_exit() {
                let mut testchain: StackChain = Chain::new();
                let enter_exits: Vec<(Arc<Mutex<u64>>, Arc<Mutex<u64>>)> = vec![];

                for _ in range(0u8, 10) {
                    let (enter, exit) = (Arc::new(Mutex::new(0)), Arc::new(Mutex::new(0)));
                    testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
                }

                testchain.link(Stopper);
                unsafe {
                    let _ = testchain.dispatch(
                        uninitialized(),
                        uninitialized()
                    );
                }

                for (enter, exit) in enter_exits.move_iter() {
                    assert_eq!(*enter.lock(), 1);
                    assert_eq!(*exit.lock(), 1);
                }
            }
        }

        mod chain_enter {
            use super::{CallCount, Arc, Mutex, Stopper};
            use super::super::StackChain;
            use super::super::super::Chain;
            use std::mem::{uninitialized};

            #[test]
            fn calls_middleware_enter() {
                let mut testchain: StackChain = Chain::new();
                let enter = Arc::new(Mutex::new(0));
                let exit = Arc::new(Mutex::new(0));
                testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
                testchain.link(Stopper);
                unsafe {
                    let _ = testchain.chain_enter(
                        uninitialized(),
                        uninitialized()
                    );
                }
                assert_eq!(*enter.lock(), 1);
            }

            #[test]
            fn doesnt_call_middleware_exit() {
                let mut testchain: StackChain = Chain::new();
                let enter = Arc::new(Mutex::new(0));
                let exit = Arc::new(Mutex::new(0));
                testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
                testchain.link(Stopper);
                unsafe {
                    let _ = testchain.chain_enter(
                        uninitialized(),
                        uninitialized()
                    );
                }
                assert_eq!(*exit.lock(), 0);
            }
        }

        mod chain_exit {
            use super::{CallCount, Arc, Mutex, Stopper};
            use super::super::{StackChain, Unwound};
            use super::super::super::Chain;
            use std::mem::uninitialized;

            #[test]
            fn calls_middleware_exit() {
                let mut testchain: StackChain = Chain::new();
                let enter = Arc::new(Mutex::new(0));
                let exit = Arc::new(Mutex::new(0));
                testchain.link(CallCount {
                    enter: enter.clone(), exit: exit.clone()
                });
                testchain.link(Stopper);
                unsafe {
                    let _  = testchain.chain_enter(
                        uninitialized(),
                        uninitialized()
                    );

                    let _  = testchain.chain_exit(
                        uninitialized(),
                        uninitialized()
                    );
                }
                assert_eq!(*exit.lock(), 1);
            }

            #[test]
            fn doesnt_call_middleware_enter() {
                let mut testchain: StackChain = Chain::new();
                let enter = Arc::new(Mutex::new(0));
                let exit = Arc::new(Mutex::new(0));
                testchain.link(CallCount {
                    enter: enter.clone(), exit: exit.clone()
                });
                testchain.status = Unwound(1);
                unsafe {
                    let _  = testchain.chain_exit(
                        uninitialized(),
                        uninitialized()
                    );
                }
                assert_eq!(*enter.lock(), 0);
            }
        }

        mod bench {
            use super::super::super::super::middleware::Middleware;
            pub use super::Stopper;

            #[deriving(Clone)]
            struct Noop;

            impl Middleware for Noop {}

            macro_rules! bench_noop_x (
                ($name:ident, $num:expr, $method:ident) => {
                    #[bench]
                    fn $name(b: &mut Bencher) {
                        let mut testchain: StackChain = Chain::new();
                        for _ in range(0, $num) {
                            testchain.link(Noop);
                        }
                        testchain.link(Stopper);
                        b.iter(|| {
                            black_box(unsafe {
                                let _ = testchain.$method(
                                    uninitialized(),
                                    uninitialized()
                                );
                            })
                        });
                    }
                }
            )

            macro_rules! bench_method (
                ($method:ident) => {
                    mod $method {
                        use std::mem::uninitialized;
                        use test::{Bencher, black_box};
                        use super::{Noop, Stopper};
                        use super::super::super::StackChain;
                        use super::super::super::super::Chain;

                        bench_noop_x!(bench_empty, 0u8, $method)
                        bench_noop_x!(bench_1, 1u8, $method)
                        bench_noop_x!(bench_2, 2u8, $method)
                        bench_noop_x!(bench_3, 3u8, $method)
                        bench_noop_x!(bench_4, 4u8, $method)
                        bench_noop_x!(bench_10, 10u8, $method)
                        bench_noop_x!(bench_100, 100u8, $method)
                    }
                }
            )

            bench_method!(dispatch)
            bench_method!(chain_enter)
        }
    }
}
<commit_msg>(fix) Fixed test shadowing, which was causing build failures.<commit_after>//! Exposes the `chain` trait and `StackChain` type.

use std::fmt::Show;

use super::response::Response;
use super::request::Request;
use super::middleware::{Middleware, Status, Continue, Error};

/// `Chains` are the backbone of `Iron`. They coordinate `Middleware`
/// to ensure they are resolved and called in the right order.
///
/// `Chains` are internal tools. Unless you want additional
/// or unusual behavior such as enhanced debug logging you
/// probably don't need to mess with `Chain` internals.
///
/// That being said, custom `Chains` are extremely powerful as they
/// allow you to completely control the resolution of `Middleware`.
pub trait Chain: Send + Clone {
    /// `dispatch` will be called once per `Request` and is responsible
    /// for delegating the request to the correct `Middleware` and in the correct
    /// order. Effectively, 99% of the work done by a `chain` is done here.
    fn dispatch(&mut self,
                request: &mut Request,
                response: &mut Response) -> Status {

        let mut status = self.chain_enter(request, response);
        match status {
            Error(ref mut e) => {
                let error: &mut Show = *e;
                let _ = self.chain_error(request, response, error);
            },
            _ => {
                let _ = self.chain_exit(request, response);
            }
        };

        status
    }

    #[doc(hidden)]
    fn chain_enter(&mut self,
             request: &mut Request,
             response: &mut Response) -> Status;

    #[doc(hidden)]
    fn chain_exit(&mut self,
                  _request: &mut Request,
                  _response: &mut Response) -> Status {
        Continue
    }

    #[doc(hidden)]
    fn chain_error(&mut self,
                  _request: &mut Request,
                  _response: &mut Response,
                  _error: &mut Show) { () }

    /// `link` is responsible for adding new `Middleware` to the `chain's` internal
    /// storage of `Middleware`. Different `chains` may implement different behavior
    /// for `link`, but - ideally - `Middleware` added here will be delegated to during
    /// `Requests`.
    fn link<M: Middleware>(&mut self, _middleware: M);

    /// Create a new instance of `chain`.
    fn new() -> Self;

    #[doc(hidden)]
    fn clone_box(&self) -> Box<Chain + Send> { box self.clone() as Box<Chain + Send> }
}

impl Clone for Box<Chain + Send> {
    fn clone(&self) -> Box<Chain + Send> { self.clone_box() }
}

/// The default `chain` used by `Iron`.
pub mod stackchain {
    use std::fmt::Show;

    use super::super::request::Request;
    use super::super::response::Response;
    use super::super::middleware::{Middleware, Continue, Unwind, Error, Status};

    use super::Chain;

    /// The default `Chain` used by `Iron`.
    /// `StackChain` runs each `Request` through all `Middleware` in its stack.
    ///
    /// When it hits `Middleware` which returns `Unwind`, it passes
    /// the `Request` back up through all `Middleware` it has hit so far.
    ///
    /// If no `Middleware` return `Unwind` to indicate that they handled
    /// the request, then a 404 is automatically returned.
    #[deriving(Clone)]
    pub struct StackChain {
        /// The storage used by `StackChain` to hold all `Middleware`
        /// that have been `linked` to it.
        stack: Vec<Box<Middleware + Send>>,
        status: ChainStatus,
    }

    #[deriving(Clone)]
    enum ChainStatus { Unwound(uint), Errored(uint), Unhandled }

    /// `StackChain` is a `Chain`
    impl Chain for StackChain {
        fn chain_enter(&mut self,
                 request: &mut Request,
                 response: &mut Response) -> Status {
            // The `exit_stack` will hold all `Middleware` that are passed through
            // in the enter loop. This is so we know to take exactly the same
            // path through `Middleware` in reverse order than we did on the way in.
            self.status = Unhandled;

            'enter: for (i, middleware) in self.stack.mut_iter().enumerate() {
                match middleware.enter(request, response) {
                    Unwind   => {
                        self.status = Unwound(i);
                        return Unwind;
                    },
                    e @ Error(_) => {
                        self.status = Errored(i);
                        return e;
                    }
                    // Mark the middleware for traversal on exit.
                    Continue => ()
                }
            }

            self.status = Unhandled;
            Continue
        }

        fn chain_exit(&mut self,
                 request: &mut Request,
                 response: &mut Response) -> Status {
            match self.status {
                Unwound(i) => {
                    for middleware in self.stack.mut_slice_to(i).mut_iter().rev() {
                        let _ = middleware.exit(request, response);
                    }
                },
                Unhandled => {
                    for middleware in self.stack.mut_iter().rev() {
                        let _ = middleware.exit(request, response);
                    }
                },
                Errored(_) => fail!("chain_exit called on a StackChain which Errored.")
            }

            Continue
        }

        fn chain_error(&mut self,
                      request: &mut Request,
                      response: &mut Response,
                      error: &mut Show) {
            match self.status {
                Errored(i) => {
                    for middleware in self.stack.mut_slice_to(i).mut_iter().rev() {
                        let _ = middleware.on_error(request, response, error);
                    }
                },
                _ => fail!("chain_error called on a chain which did not error.")
            }
        }

        /// Add `Middleware` to the `Chain`.
        fn link<M: Middleware>(&mut self, middleware: M) {
            self.stack.push(box middleware);
        }

        /// Create a new instance of `StackChain`.
        fn new() -> StackChain {
            StackChain {
                stack: vec![],
                status: Unhandled
            }
        }
    }

    impl FromIterator<Box<Middleware + Send>> for StackChain {
        fn from_iter<T: Iterator<Box<Middleware + Send>>>(mut iterator: T) -> StackChain {
            StackChain {
                stack: iterator.collect(),
                status: Unhandled
            }
        }
    }

    #[cfg(test)]
    mod test {
        pub use super::StackChain;
        pub use super::super::super::request::Request;
        pub use super::super::super::response::Response;
        pub use super::super::super::middleware::{Middleware, Status, Continue, Unwind};
        pub use std::sync::{Arc, Mutex};

        #[deriving(Clone)]
        pub struct CallCount {
            enter: Arc<Mutex<u64>>,
            exit: Arc<Mutex<u64>>
        }

        impl Middleware for CallCount {
            fn enter(&mut self, _req: &mut Request,
                     _res: &mut Response) -> Status {
                let mut enter = self.enter.lock();
                *enter += 1;
                Continue
            }

            fn exit(&mut self, _req: &mut Request,
                    _res: &mut Response) -> Status {
                let mut exit = self.exit.lock();
                *exit += 1;
                Continue
            }
        }

        #[deriving(Clone)]
        pub struct Stopper;

        impl Middleware for Stopper {
            fn enter(&mut self, _req: &mut Request,
                     _res: &mut Response) -> Status {
                Unwind // Stop .status from being accessed, which fails.
            }
        }

        mod dispatch {
            use super::{CallCount, Arc, Mutex, Stopper};
            use super::super::StackChain;
            use super::super::super::Chain;
            use std::mem::uninitialized;

            #[test]
            fn calls_middleware_enter() {
                let mut testchain: StackChain = Chain::new();
                let enter = Arc::new(Mutex::new(0));
                let exit = Arc::new(Mutex::new(0));
                testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
                testchain.link(Stopper);
                unsafe {
                    let _ = testchain.dispatch(
                        uninitialized(),
                        uninitialized()
                    );
                }
                assert_eq!(*enter.lock(), 1);
            }

            #[test]
            fn calls_middleware_exit() {
                let mut testchain: StackChain = Chain::new();
                let enter = Arc::new(Mutex::new(0));
                let exit = Arc::new(Mutex::new(0));
                testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
                testchain.link(Stopper);
                unsafe {
                    let _ = testchain.dispatch(
                        uninitialized(),
                        uninitialized()
                    );
                }
                assert_eq!(*exit.lock(), 1);
            }

            #[test]
            fn calls_all_middleware_enter_exit() {
                let mut testchain: StackChain = Chain::new();
                let enter_exits: Vec<(Arc<Mutex<u64>>, Arc<Mutex<u64>>)> = vec![];

                for _ in range(0u8, 10) {
                    let (enter, exit) = (Arc::new(Mutex::new(0)), Arc::new(Mutex::new(0)));
                    testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
                }

                testchain.link(Stopper);
                unsafe {
                    let _ = testchain.dispatch(
                        uninitialized(),
                        uninitialized()
                    );
                }

                for (enter, exit) in enter_exits.move_iter() {
                    assert_eq!(*enter.lock(), 1);
                    assert_eq!(*exit.lock(), 1);
                }
            }
        }

        mod chain_enter {
            use super::{CallCount, Arc, Mutex, Stopper};
            use super::super::StackChain;
            use super::super::super::Chain;
            use std::mem::{uninitialized};

            #[test]
            fn calls_middleware_enter() {
                let mut testchain: StackChain = Chain::new();
                let enter = Arc::new(Mutex::new(0));
                let exit = Arc::new(Mutex::new(0));
                testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
                testchain.link(Stopper);
                unsafe {
                    let _ = testchain.chain_enter(
                        uninitialized(),
                        uninitialized()
                    );
                }
                assert_eq!(*enter.lock(), 1);
            }

            #[test]
            fn doesnt_call_middleware_exit() {
                let mut testchain: StackChain = Chain::new();
                let enter = Arc::new(Mutex::new(0));
                let exit = Arc::new(Mutex::new(0));
                testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
                testchain.link(Stopper);
                unsafe {
                    let _ = testchain.chain_enter(
                        uninitialized(),
                        uninitialized()
                    );
                }
                assert_eq!(*exit.lock(), 0);
            }
        }

        mod chain_exit {
            use super::{CallCount, Arc, Mutex, Stopper};
            use super::super::{StackChain, Unwound};
            use super::super::super::Chain;
            use std::mem::uninitialized;

            #[test]
            fn calls_middleware_exit() {
                let mut testchain: StackChain = Chain::new();
                let enter = Arc::new(Mutex::new(0));
                let exit = Arc::new(Mutex::new(0));
                testchain.link(CallCount {
                    enter: enter.clone(), exit: exit.clone()
                });
                testchain.link(Stopper);
                unsafe {
                    let _  = testchain.chain_enter(
                        uninitialized(),
                        uninitialized()
                    );

                    let _  = testchain.chain_exit(
                        uninitialized(),
                        uninitialized()
                    );
                }
                assert_eq!(*exit.lock(), 1);
            }

            #[test]
            fn doesnt_call_middleware_enter() {
                let mut testchain: StackChain = Chain::new();
                let enter = Arc::new(Mutex::new(0));
                let exit = Arc::new(Mutex::new(0));
                testchain.link(CallCount {
                    enter: enter.clone(), exit: exit.clone()
                });
                testchain.status = Unwound(1);
                unsafe {
                    let _  = testchain.chain_exit(
                        uninitialized(),
                        uninitialized()
                    );
                }
                assert_eq!(*enter.lock(), 0);
            }
        }

        mod bench {
            use super::super::super::super::middleware::Middleware;
            pub use super::Stopper;

            #[deriving(Clone)]
            struct Noop;

            impl Middleware for Noop {}

            macro_rules! bench_noop_x (
                ($name:ident, $num:expr, $method:ident) => {
                    #[bench]
                    fn $name(b: &mut Bencher) {
                        let mut testchain: StackChain = Chain::new();
                        for _ in range(0, $num) {
                            testchain.link(Noop);
                        }
                        testchain.link(Stopper);
                        b.iter(|| {
                            black_box(unsafe {
                                let _ = testchain.$method(
                                    uninitialized(),
                                    uninitialized()
                                );
                            })
                        });
                    }
                }
            )

            macro_rules! bench_method (
                ($method:ident) => {
                    mod $method {
                        use std::mem::uninitialized;
                        use test::{Bencher, black_box};
                        use super::{Noop, Stopper};
                        use super::super::super::StackChain;
                        use super::super::super::super::Chain;

                        bench_noop_x!(bench_empty, 0u8, $method)
                        bench_noop_x!(bench_1, 1u8, $method)
                        bench_noop_x!(bench_2, 2u8, $method)
                        bench_noop_x!(bench_3, 3u8, $method)
                        bench_noop_x!(bench_4, 4u8, $method)
                        bench_noop_x!(bench_10, 10u8, $method)
                        bench_noop_x!(bench_100, 100u8, $method)
                    }
                }
            )

            bench_method!(dispatch)
            bench_method!(chain_enter)
        }
    }
}
<|endoftext|>