<commit_before>use std::slice;
use std::fmt;
use std::ops::Index;

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum YUVRange {
    Limited,
    Full
}

impl fmt::Display for YUVRange {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            YUVRange::Limited => write!(f, "Limited range"),
            YUVRange::Full => write!(f, "Full range")
        }
    }
}

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum YUVSystem {
    YCbCr(YUVRange),
    YCoCg,
    ICtCp
}

impl fmt::Display for YUVSystem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::YUVSystem::*;
        match *self {
            YCbCr(range) => write!(f, "YCbCr ({})", range),
            YCoCg => write!(f, "YCbCg"),
            ICtCp => write!(f, "ICtCp"),
        }
    }
}

#[derive(Debug, Clone,Copy,PartialEq)]
pub enum TrichromaticEncodingSystem {
    RGB,
    YUV(YUVSystem),
    XYZ
}

impl fmt::Display for TrichromaticEncodingSystem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::TrichromaticEncodingSystem::*;
        match *self {
            YUV(system) => write!(f, "{}", system),
            RGB => write!(f, "RGB"),
            XYZ => write!(f, "XYZ"),
        }
    }
}

#[derive(Debug, Clone,Copy,PartialEq)]
pub enum ColorModel {
    Trichromatic(TrichromaticEncodingSystem),
    CMYK,
    HSV,
    LAB,
}

impl fmt::Display for ColorModel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::ColorModel::*;
        match *self {
            Trichromatic(system) => write!(f, "{}", system),
            CMYK => write!(f, "CMYK"),
            HSV => write!(f, "HSV"),
            LAB => write!(f, "LAB"),
        }
    }
}

impl ColorModel {
    pub fn get_default_components(&self) -> usize {
        match *self {
            ColorModel::CMYK => 4,
            _ => 3,
        }
    }
}

#[derive(Clone,Copy,Debug,PartialEq)]
pub struct Chromaton {
    h_ss: u8,
    v_ss: u8,
    packed: bool,
    depth: u8,
    shift: u8,
    comp_offs: u8,
    next_elem: u8,
}

fn align(v: usize, a: usize) -> usize {
    (v + a - 1) & !(a - 1)
}

impl Chromaton {
    pub fn get_subsampling(&self) -> (u8, u8) {
        (self.h_ss, self.v_ss)
    }
    pub fn is_packed(&self) -> bool {
        self.packed
    }
    pub fn get_depth(&self) -> u8 {
        self.depth
    }
    pub fn get_shift(&self) -> u8 {
        self.shift
    }
    pub fn get_offset(&self) -> u8 {
        self.comp_offs
    }
    pub fn get_step(&self) -> u8 {
        self.next_elem
    }

    pub fn get_width(&self, width: usize) -> usize {
        (width + ((1 << self.v_ss) - 1)) >> self.v_ss
    }
    pub fn get_height(&self, height: usize) -> usize {
        (height + ((1 << self.h_ss) - 1)) >> self.h_ss
    }
    pub fn get_linesize(&self, width: usize, alignment: usize) -> usize {
        let d = self.depth as usize;
        align((self.get_width(width) * d + d - 1) >> 3, alignment)
    }
    pub fn get_data_size(&self, width: usize, height: usize, align: usize) -> usize {
        let nh = (height + ((1 << self.v_ss) - 1)) >> self.v_ss;
        self.get_linesize(width, align) * nh
    }
}

impl fmt::Display for Chromaton {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let pfmt = if self.packed {
            let mask = ((1 << self.depth) - 1) << self.shift;
            format!("packed(+{},{:X}, step {})",
                    self.comp_offs,
                    mask,
                    self.next_elem)
        } else {
            format!("planar({},{})", self.comp_offs, self.next_elem)
        };
        write!(f, "({}x{}, {})", self.h_ss, self.v_ss, pfmt)
    }
}

#[derive(Clone,Copy,PartialEq,Debug)]
pub struct Formaton {
    model: ColorModel,
    components: u8,
    comp_info: [Option<Chromaton>; 5],
    elem_size: u8,
    be: bool,
    alpha: bool,
    palette: bool,
}

bitflags! {
    pub flags Flags: u8 {
        const BE       = 0x01,
        const ALPHA    = 0x02,
        const PALETTE  = 0x04,
    }
}

impl Formaton {
    pub fn new(model: ColorModel, components: &[Chromaton], flags: Flags, elem_size: u8) -> Self {
        let be = flags.contains(BE);
        let alpha = flags.contains(ALPHA);
        let palette = flags.contains(PALETTE);
        let mut c: [Option<Chromaton>; 5] = [None; 5];

        if components.len() > 5 {
            panic!("too many components");
        }

        for (i, v) in components.iter().enumerate() {
            c[i] = Some(*v);
        }

        Formaton {
            model: model,
            components: components.len() as u8,
            comp_info: c,
            elem_size: elem_size,
            be: be,
            alpha: alpha,
            palette: palette,
        }
    }

    pub fn get_model(&self) -> ColorModel {
        self.model
    }
    pub fn get_num_comp(&self) -> usize {
        self.components as usize
    }
    pub fn get_chromaton(&self, idx: usize) -> Option<Chromaton> {
        if idx < self.comp_info.len() {
            return self.comp_info[idx];
        }
        None
    }
    pub fn is_be(&self) -> bool {
        self.be
    }
    pub fn has_alpha(&self) -> bool {
        self.alpha
    }
    pub fn is_paletted(&self) -> bool {
        self.palette
    }
    pub fn get_elem_size(&self) -> u8 {
        self.elem_size
    }

    pub fn iter<'a>(&'a self) -> slice::Iter<'a, Option<Chromaton>> {
        self.comp_info.iter()
    }
}

impl<'a> Index<usize> for &'a Formaton {
    type Output = Option<Chromaton>;

    fn index(&self, index: usize) -> &Self::Output {
        self.comp_info.index(index)
    }
}

impl<'a> IntoIterator for &'a Formaton {
    type Item = &'a Option<Chromaton>;
    type IntoIter = slice::Iter<'a, Option<Chromaton>>;

    fn into_iter(self) -> Self::IntoIter {
        self.comp_info.iter()
    }
}

impl fmt::Display for Formaton {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let end = if self.be {
            "BE"
        } else {
            "LE"
        };
        let palstr = if self.palette {
            "palette "
        } else {
            ""
        };
        let astr = if self.alpha {
            "alpha "
        } else {
            ""
        };
        let mut str = format!("Formaton for {} ({}{}elem {} size {}): ",
                              self.model,
                              palstr,
                              astr,
                              end,
                              self.elem_size);
        for &i in self.into_iter() {
            if let Some(chr) = i {
                str = format!("{} {}", str, chr);
            }
        }
        write!(f, "[{}]", str)
    }
}

macro_rules! chromaton {
    ($hs: expr, $vs: expr, $pck: expr, $d: expr, $sh: expr, $co: expr, $ne: expr) => ({
        Some(Chromaton {
                h_ss: $hs,
                v_ss: $vs,
                packed: $pck,
                depth: $d,
                shift: $sh,
                comp_offs: $co,
                next_elem: $ne })
    });
    (yuv8; $hs: expr, $vs: expr, $co: expr) => ({
        chromaton!($hs, $vs, false, 8, 0, $co, 1)
    });
    (packrgb; $d: expr, $s: expr, $co: expr, $ne: expr) => ({
        chromaton!(0, 0, true, $d, $s, $co, $ne)
    });
    (pal8; $co: expr) => ({
        chromaton!(0, 0, true, 8, 0, $co, 3)
    });
}

pub mod formats {
    use pixel::*;
    use self::ColorModel::*;
    use self::TrichromaticEncodingSystem::*;
    use self::YUVSystem::*;
    use self::YUVRange::*;

    pub const YUV444: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 0, 0, 1),
                    chromaton!(yuv8; 0, 0, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV422: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 0, 1, 1),
                    chromaton!(yuv8; 0, 1, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV420: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 1, 1, 1),
                    chromaton!(yuv8; 1, 1, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV411: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 2, 0, 1),
                    chromaton!(yuv8; 2, 0, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV410: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 2, 1, 1),
                    chromaton!(yuv8; 2, 1, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const PAL8: &Formaton = &Formaton {
        model: Trichromatic(RGB),
        components: 3,
        comp_info: [chromaton!(pal8; 0), chromaton!(pal8; 1), chromaton!(pal8; 2), None, None],
        elem_size: 3,
        be: false,
        alpha: false,
        palette: true,
    };

    pub const RGB565: &Formaton = &Formaton {
        model: Trichromatic(RGB),
        components: 3,
        comp_info: [chromaton!(packrgb; 5, 11, 0, 2),
                    chromaton!(packrgb; 6,  5, 0, 2),
                    chromaton!(packrgb; 5,  0, 0, 2),
                    None,
                    None],
        elem_size: 2,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const RGB24: &Formaton = &Formaton {
        model: Trichromatic(RGB),
        components: 3,
        comp_info: [chromaton!(packrgb; 8, 0, 2, 3),
                    chromaton!(packrgb; 8, 0, 1, 3),
                    chromaton!(packrgb; 8, 0, 0, 3),
                    None,
                    None],
        elem_size: 3,
        be: false,
        alpha: false,
        palette: false,
    };
}

#[cfg(test)]
mod test {
    mod formats {
        use super::super::*;
        #[test]
        fn fmt() {
            println!("formaton yuv- {}", formats::YUV420);
            println!("formaton pal- {}", formats::PAL8);
            println!("formaton rgb565- {}", formats::RGB565);
        }

        #[test]
        fn comparison() {
            use std::sync::Arc;
            let rcf = Arc::new(*formats::YUV420);
            let ref cf = formats::YUV420.clone();

            if cf != formats::YUV420 {
                panic!("cf");
            }

            if *rcf != *formats::YUV420 {
                panic!("rcf");
            }
        }
    }
}
<commit_msg>data: Add bitdepth 10 YUV Formatons<commit_after>use std::slice;
use std::fmt;
use std::ops::Index;

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum YUVRange {
    Limited,
    Full
}

impl fmt::Display for YUVRange {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            YUVRange::Limited => write!(f, "Limited range"),
            YUVRange::Full => write!(f, "Full range")
        }
    }
}

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum YUVSystem {
    YCbCr(YUVRange),
    YCoCg,
    ICtCp
}

impl fmt::Display for YUVSystem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::YUVSystem::*;
        match *self {
            YCbCr(range) => write!(f, "YCbCr ({})", range),
            YCoCg => write!(f, "YCbCg"),
            ICtCp => write!(f, "ICtCp"),
        }
    }
}

#[derive(Debug, Clone,Copy,PartialEq)]
pub enum TrichromaticEncodingSystem {
    RGB,
    YUV(YUVSystem),
    XYZ
}

impl fmt::Display for TrichromaticEncodingSystem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::TrichromaticEncodingSystem::*;
        match *self {
            YUV(system) => write!(f, "{}", system),
            RGB => write!(f, "RGB"),
            XYZ => write!(f, "XYZ"),
        }
    }
}

#[derive(Debug, Clone,Copy,PartialEq)]
pub enum ColorModel {
    Trichromatic(TrichromaticEncodingSystem),
    CMYK,
    HSV,
    LAB,
}

impl fmt::Display for ColorModel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::ColorModel::*;
        match *self {
            Trichromatic(system) => write!(f, "{}", system),
            CMYK => write!(f, "CMYK"),
            HSV => write!(f, "HSV"),
            LAB => write!(f, "LAB"),
        }
    }
}

impl ColorModel {
    pub fn get_default_components(&self) -> usize {
        match *self {
            ColorModel::CMYK => 4,
            _ => 3,
        }
    }
}

#[derive(Clone,Copy,Debug,PartialEq)]
pub struct Chromaton {
    h_ss: u8,
    v_ss: u8,
    packed: bool,
    depth: u8,
    shift: u8,
    comp_offs: u8,
    next_elem: u8,
}

fn align(v: usize, a: usize) -> usize {
    (v + a - 1) & !(a - 1)
}

impl Chromaton {
    pub fn get_subsampling(&self) -> (u8, u8) {
        (self.h_ss, self.v_ss)
    }
    pub fn is_packed(&self) -> bool {
        self.packed
    }
    pub fn get_depth(&self) -> u8 {
        self.depth
    }
    pub fn get_shift(&self) -> u8 {
        self.shift
    }
    pub fn get_offset(&self) -> u8 {
        self.comp_offs
    }
    pub fn get_step(&self) -> u8 {
        self.next_elem
    }

    pub fn get_width(&self, width: usize) -> usize {
        (width + ((1 << self.v_ss) - 1)) >> self.v_ss
    }
    pub fn get_height(&self, height: usize) -> usize {
        (height + ((1 << self.h_ss) - 1)) >> self.h_ss
    }
    pub fn get_linesize(&self, width: usize, alignment: usize) -> usize {
        let d = self.depth as usize;
        align((self.get_width(width) * d + d - 1) >> 3, alignment)
    }
    pub fn get_data_size(&self, width: usize, height: usize, align: usize) -> usize {
        let nh = (height + ((1 << self.v_ss) - 1)) >> self.v_ss;
        self.get_linesize(width, align) * nh
    }
}

impl fmt::Display for Chromaton {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let pfmt = if self.packed {
            let mask = ((1 << self.depth) - 1) << self.shift;
            format!("packed(+{},{:X}, step {})",
                    self.comp_offs,
                    mask,
                    self.next_elem)
        } else {
            format!("planar({},{})", self.comp_offs, self.next_elem)
        };
        write!(f, "({}x{}, {})", self.h_ss, self.v_ss, pfmt)
    }
}

#[derive(Clone,Copy,PartialEq,Debug)]
pub struct Formaton {
    model: ColorModel,
    components: u8,
    comp_info: [Option<Chromaton>; 5],
    elem_size: u8,
    be: bool,
    alpha: bool,
    palette: bool,
}

bitflags! {
    pub flags Flags: u8 {
        const BE       = 0x01,
        const ALPHA    = 0x02,
        const PALETTE  = 0x04,
    }
}

impl Formaton {
    pub fn new(model: ColorModel, components: &[Chromaton], flags: Flags, elem_size: u8) -> Self {
        let be = flags.contains(BE);
        let alpha = flags.contains(ALPHA);
        let palette = flags.contains(PALETTE);
        let mut c: [Option<Chromaton>; 5] = [None; 5];

        if components.len() > 5 {
            panic!("too many components");
        }

        for (i, v) in components.iter().enumerate() {
            c[i] = Some(*v);
        }

        Formaton {
            model: model,
            components: components.len() as u8,
            comp_info: c,
            elem_size: elem_size,
            be: be,
            alpha: alpha,
            palette: palette,
        }
    }

    pub fn get_model(&self) -> ColorModel {
        self.model
    }
    pub fn get_num_comp(&self) -> usize {
        self.components as usize
    }
    pub fn get_chromaton(&self, idx: usize) -> Option<Chromaton> {
        if idx < self.comp_info.len() {
            return self.comp_info[idx];
        }
        None
    }
    pub fn is_be(&self) -> bool {
        self.be
    }
    pub fn has_alpha(&self) -> bool {
        self.alpha
    }
    pub fn is_paletted(&self) -> bool {
        self.palette
    }
    pub fn get_elem_size(&self) -> u8 {
        self.elem_size
    }

    pub fn iter<'a>(&'a self) -> slice::Iter<'a, Option<Chromaton>> {
        self.comp_info.iter()
    }
}

impl<'a> Index<usize> for &'a Formaton {
    type Output = Option<Chromaton>;

    fn index(&self, index: usize) -> &Self::Output {
        self.comp_info.index(index)
    }
}

impl<'a> IntoIterator for &'a Formaton {
    type Item = &'a Option<Chromaton>;
    type IntoIter = slice::Iter<'a, Option<Chromaton>>;

    fn into_iter(self) -> Self::IntoIter {
        self.comp_info.iter()
    }
}

impl fmt::Display for Formaton {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let end = if self.be {
            "BE"
        } else {
            "LE"
        };
        let palstr = if self.palette {
            "palette "
        } else {
            ""
        };
        let astr = if self.alpha {
            "alpha "
        } else {
            ""
        };
        let mut str = format!("Formaton for {} ({}{}elem {} size {}): ",
                              self.model,
                              palstr,
                              astr,
                              end,
                              self.elem_size);
        for &i in self.into_iter() {
            if let Some(chr) = i {
                str = format!("{} {}", str, chr);
            }
        }
        write!(f, "[{}]", str)
    }
}

macro_rules! chromaton {
    ($hs: expr, $vs: expr, $pck: expr, $d: expr, $sh: expr, $co: expr, $ne: expr) => ({
        Some(Chromaton {
                h_ss: $hs,
                v_ss: $vs,
                packed: $pck,
                depth: $d,
                shift: $sh,
                comp_offs: $co,
                next_elem: $ne })
    });
    (yuv8; $hs: expr, $vs: expr, $co: expr) => ({
        chromaton!($hs, $vs, false, 8, 0, $co, 1)
    });
    (yuv_hb; $hs: expr, $vs: expr, $co: expr, $d: expr) => ({
        chromaton!($hs, $vs, false, $d, 0, $co, 1)
    });
    (packrgb; $d: expr, $s: expr, $co: expr, $ne: expr) => ({
        chromaton!(0, 0, true, $d, $s, $co, $ne)
    });
    (pal8; $co: expr) => ({
        chromaton!(0, 0, true, 8, 0, $co, 3)
    });
}

pub mod formats {
    use pixel::*;
    use self::ColorModel::*;
    use self::TrichromaticEncodingSystem::*;
    use self::YUVSystem::*;
    use self::YUVRange::*;

    pub const YUV444: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 0, 0, 1),
                    chromaton!(yuv8; 0, 0, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV422: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 0, 1, 1),
                    chromaton!(yuv8; 0, 1, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV420: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 1, 1, 1),
                    chromaton!(yuv8; 1, 1, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV411: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 2, 0, 1),
                    chromaton!(yuv8; 2, 0, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV410: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 2, 1, 1),
                    chromaton!(yuv8; 2, 1, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV444_10: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 10, 0, 0, 1),
                    chromaton!(yuv_hb; 0, 0, 1, 10),
                    chromaton!(yuv_hb; 0, 0, 2, 10),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV422_10: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 10, 0, 0, 1),
                    chromaton!(yuv_hb; 0, 1, 1, 10),
                    chromaton!(yuv_hb; 0, 1, 2, 10),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV420_10: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 10, 0, 0, 1),
                    chromaton!(yuv_hb; 1, 1, 1, 10),
                    chromaton!(yuv_hb; 1, 1, 2, 10),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV411_10: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 10, 0, 0, 1),
                    chromaton!(yuv_hb; 2, 0, 1, 10),
                    chromaton!(yuv_hb; 2, 0, 2, 10),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV410_10: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 10, 0, 0, 1),
                    chromaton!(yuv_hb; 2, 1, 1, 10),
                    chromaton!(yuv_hb; 2, 1, 2, 10),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const PAL8: &Formaton = &Formaton {
        model: Trichromatic(RGB),
        components: 3,
        comp_info: [chromaton!(pal8; 0), chromaton!(pal8; 1), chromaton!(pal8; 2), None, None],
        elem_size: 3,
        be: false,
        alpha: false,
        palette: true,
    };

    pub const RGB565: &Formaton = &Formaton {
        model: Trichromatic(RGB),
        components: 3,
        comp_info: [chromaton!(packrgb; 5, 11, 0, 2),
                    chromaton!(packrgb; 6,  5, 0, 2),
                    chromaton!(packrgb; 5,  0, 0, 2),
                    None,
                    None],
        elem_size: 2,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const RGB24: &Formaton = &Formaton {
        model: Trichromatic(RGB),
        components: 3,
        comp_info: [chromaton!(packrgb; 8, 0, 2, 3),
                    chromaton!(packrgb; 8, 0, 1, 3),
                    chromaton!(packrgb; 8, 0, 0, 3),
                    None,
                    None],
        elem_size: 3,
        be: false,
        alpha: false,
        palette: false,
    };
}

#[cfg(test)]
mod test {
    mod formats {
        use super::super::*;
        #[test]
        fn fmt() {
            println!("formaton yuv- {}", formats::YUV420);
            println!("formaton pal- {}", formats::PAL8);
            println!("formaton rgb565- {}", formats::RGB565);
        }

        #[test]
        fn comparison() {
            use std::sync::Arc;
            let rcf = Arc::new(*formats::YUV420);
            let ref cf = formats::YUV420.clone();

            if cf != formats::YUV420 {
                panic!("cf");
            }

            if *rcf != *formats::YUV420 {
                panic!("rcf");
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Wrapper for wlr_seat. For more information about what a seat is, please
//! consult the Wayland documentation ([libinput docs](https://wayland.freedesktop.org/libinput/doc/latest/seats.html), [wayland docs](https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_seat))

use std::time::Duration;

use wlroots_sys::{wlr_axis_orientation, wlr_seat, wlr_seat_client, wlr_seat_create,
                  wlr_seat_destroy, wlr_seat_keyboard_clear_focus, wlr_seat_keyboard_end_grab,
                  wlr_seat_keyboard_enter, wlr_seat_keyboard_has_grab,
                  wlr_seat_keyboard_notify_enter, wlr_seat_keyboard_notify_key,
                  wlr_seat_keyboard_notify_modifiers, wlr_seat_keyboard_send_key,
                  wlr_seat_keyboard_send_modifiers, wlr_seat_keyboard_start_grab,
                  wlr_seat_pointer_clear_focus, wlr_seat_pointer_end_grab, wlr_seat_pointer_enter,
                  wlr_seat_pointer_has_grab, wlr_seat_pointer_notify_axis,
                  wlr_seat_pointer_notify_button, wlr_seat_pointer_notify_enter,
                  wlr_seat_pointer_notify_motion, wlr_seat_pointer_send_axis,
                  wlr_seat_pointer_send_button, wlr_seat_pointer_send_motion,
                  wlr_seat_pointer_start_grab, wlr_seat_pointer_surface_has_focus,
                  wlr_seat_set_capabilities, wlr_seat_set_keyboard, wlr_seat_set_name,
                  wlr_seat_touch_end_grab, wlr_seat_touch_has_grab, wlr_seat_touch_notify_down,
                  wlr_seat_touch_notify_motion, wlr_seat_touch_notify_up,
                  wlr_seat_touch_num_points, wlr_seat_touch_point_clear_focus,
                  wlr_seat_touch_point_focus, wlr_seat_touch_send_down,
                  wlr_seat_touch_send_motion, wlr_seat_touch_send_up, wlr_seat_touch_start_grab,
                  wlr_touch_point};
use wlroots_sys::wayland_server::protocol::wl_seat::Capability;

use compositor::Compositor;
use utils::{c_to_rust_string, safe_as_cstring};

use super::grab::{KeyboardGrab, PointerGrab, TouchGrab};
use super::touch_point::{TouchId, TouchPoint};
use types::surface::Surface;

/// A wrapper around `wlr_seat`.
pub struct Seat {
    seat: *mut wlr_seat
}

impl Seat {
    /// Allocates a new `wlr_seat` and adds a wl_seat global to the display.
    pub fn create(compositor: &mut Compositor, name: String) -> Option<Self> {
        unsafe {
            let name = safe_as_cstring(name);
            let seat = wlr_seat_create(compositor.display() as _, name.as_ptr());
            if seat.is_null() {
                None
            } else {
                Some(Seat { seat })
            }
        }
    }

    /// Get the name of the seat.
    pub fn name(&self) -> Option<String> {
        unsafe {
            let name_ptr = (*self.seat).name;
            if name_ptr.is_null() {
                return None
            }
            c_to_rust_string(name_ptr)
        }
    }

    /// Updates the name of this seat.
    /// Will automatically send it to all clients.
    pub fn set_name(&mut self, name: String) {
        let name = safe_as_cstring(name);
        unsafe {
            wlr_seat_set_name(self.seat, name.as_ptr());
        }
    }

    /// Gets the capabilities of this seat.
    pub fn capabilities(&self) -> Capability {
        unsafe {
            Capability::from_raw((*self.seat).capabilities).expect("Invalid capabilities")
        }
    }

    /// Updates the capabilities available on this seat.
    /// Will automatically send it to all clients.
    pub fn set_capabilities(&mut self, capabilities: Capability) {
        unsafe { wlr_seat_set_capabilities(self.seat, capabilities.bits()) }
    }

    /// Determines if the surface has pointer focus.
    pub fn pointer_surface_has_focus(&mut self, surface: Surface) -> bool {
        unsafe { wlr_seat_pointer_surface_has_focus(self.seat, surface.as_ptr()) }
    }

    // Sends a pointer enter event to the given surface and considers it to be
    // the focused surface for the pointer.
    //
    // This will send a leave event to the last surface that was entered.
    //
    // Coordinates for the enter event are surface-local.
    //
    // Compositor should use `Seat::pointer_notify_enter` to
    // change pointer focus to respect pointer grabs.
    pub fn pointer_enter(&mut self, surface: Surface, sx: f64, sy: f64) {
        unsafe {
            wlr_seat_pointer_enter(self.seat, surface.as_ptr(), sx, sy);
        }
    }

    /// Clears the focused surface for the pointer and leaves all entered
    /// surfaces.
    pub fn clear_focus(&mut self) {
        unsafe { wlr_seat_pointer_clear_focus(self.seat) }
    }

    /// Sends a motion event to the surface with pointer focus.
    ///
    /// Coordinates for the motion event are surface-local.
    ///
    /// Compositors should use `Seat::notify_motion` to
    /// send motion events to the respect pointer grabs.
    pub fn send_motion(&mut self, time: Duration, sx: f64, sy: f64) {
        let seconds_delta = time.as_secs() as u32;
        let nano_delta = time.subsec_nanos();
        let ms = (seconds_delta * 1000) + nano_delta / 1000000;
        unsafe {
            // TODO FIXME what kind of time? ms? s?
            // I'm just guessing it's ms, there's no documentation on this.
            wlr_seat_pointer_send_motion(self.seat, ms, sx, sy)
        }
    }

    // TODO Button and State should probably be wrapped in some sort of type...

    /// Send a button event to the surface with pointer focus.
    ///
    /// Coordinates for the button event are surface-local.
    ///
    /// Returns the serial.
    ///
    /// Compositors should use `Seat::notify_button` to
    /// send button events to respect pointer grabs.
    pub fn send_button(&mut self, time: Duration, button: u32, state: u32) -> u32 {
        let seconds_delta = time.as_secs() as u32;
        let nano_delta = time.subsec_nanos();
        let ms = (seconds_delta * 1000) + nano_delta / 1000000;
        unsafe { wlr_seat_pointer_send_button(self.seat, ms, button, state) }
    }

    /// Send an axis event to the surface with pointer focus.
    ///
    /// Compositors should use `Seat::notify_axis` to
    /// send axis events to respect pointer grabs.
    pub fn send_axis(&mut self, time: Duration, orientation: wlr_axis_orientation, value: f64) {
        let seconds_delta = time.as_secs() as u32;
        let nano_delta = time.subsec_nanos();
        let ms = (seconds_delta * 1000) + nano_delta / 1000000;
        unsafe {
            wlr_seat_pointer_send_axis(self.seat, ms, orientation, value);
        }
    }

    /// Start a grab of the pointer of this seat. The grabber is responsible for
    /// handling all pointer events until the grab ends.
    pub fn pointer_start_grab(&mut self, grab: PointerGrab) {
        unsafe { wlr_seat_pointer_start_grab(self.seat, grab.as_ptr()) }
    }

    /// End the grab of the pointer of this seat. This reverts the grab back to the
    /// default grab for the pointer.
    pub fn pointer_end_grab(&mut self) {
        unsafe { wlr_seat_pointer_end_grab(self.seat) }
    }

    /// Whether or not the pointer has a grab other than the default grab.
    pub fn pointer_has_grab(&self) -> bool {
        unsafe { wlr_seat_pointer_has_grab(self.seat) }
    }

    /// Clear the focused surface for the pointer and leave all entered
    /// surfaces.
    pub fn pointer_clear_focus(&mut self) {
        unsafe { wlr_seat_pointer_clear_focus(self.seat) }
    }

    /// Send a keyboard enter event to the given surface and consider it to be the
    /// focused surface for the keyboard.
    ///
    /// This will send a leave event to the last surface that was entered.
    ///
    /// Compositors should use `Seat::keyboard_notify_enter()` to
    /// change keyboard focus to respect keyboard grabs.
    pub fn keyboard_enter(&mut self, surface: Surface) {
        unsafe { wlr_seat_keyboard_enter(self.seat, surface.as_ptr()) }
    }

    /// Start a grab of the keyboard of this seat. The grabber is responsible for
    /// handling all keyboard events until the grab ends.
    pub fn keyboard_start_grab(&mut self, grab: KeyboardGrab) {
        unsafe { wlr_seat_keyboard_start_grab(self.seat, grab.as_ptr()) }
    }

    /// End the grab of the keyboard of this seat. This reverts the grab back to the
    /// default grab for the keyboard.
    pub fn keyboard_end_grab(&mut self) {
        unsafe { wlr_seat_keyboard_end_grab(self.seat) }
    }

    /// Whether or not the keyboard has a grab other than the default grab
    pub fn keyboard_has_grab(&self) -> bool {
        unsafe { wlr_seat_keyboard_has_grab(self.seat) }
    }

    /// Clear the focused surface for the keyboard and leave all entered
    /// surfaces.
    pub fn keyboard_clear_focus(&mut self) {
        unsafe { wlr_seat_keyboard_clear_focus(self.seat) }
    }

    /// Start a grab of the touch device of this seat. The grabber is responsible for
    /// handling all touch events until the grab ends.
    pub fn touch_start_grab(&mut self, grab: TouchGrab) {
        unsafe { wlr_seat_touch_start_grab(self.seat, grab.as_ptr()) }
    }

    /// End the grab of the touch device of this seat. This reverts the grab back to
    /// the default grab for the touch device.
    pub fn touch_end_grab(&mut self) {
        unsafe { wlr_seat_touch_end_grab(self.seat) }
    }

    /// Whether or not the seat has a touch grab other than the default grab.
    pub fn touch_has_grab(&self) -> bool {
        unsafe { wlr_seat_touch_has_grab(self.seat) }
    }

    // TODO notify and some other specific input misc functions

    pub unsafe fn to_ptr(&self) -> *mut wlr_seat {
        self.seat
    }
}

impl Drop for Seat {
    fn drop(&mut self) {
        unsafe { wlr_seat_destroy(self.seat) }
    }
}
<commit_msg>Added touch point get and notify functions<commit_after>//! Wrapper for wlr_seat. For more information about what a seat is, please
//! consult the Wayland documentation ([libinput docs](https://wayland.freedesktop.org/libinput/doc/latest/seats.html), [wayland docs](https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_seat))

use std::time::Duration;

use wlroots_sys::{wlr_axis_orientation, wlr_seat, wlr_seat_client, wlr_seat_create,
                  wlr_seat_destroy, wlr_seat_keyboard_clear_focus, wlr_seat_keyboard_end_grab,
                  wlr_seat_keyboard_enter, wlr_seat_keyboard_has_grab,
                  wlr_seat_keyboard_notify_enter, wlr_seat_keyboard_notify_key,
                  wlr_seat_keyboard_notify_modifiers, wlr_seat_keyboard_send_key,
                  wlr_seat_keyboard_send_modifiers, wlr_seat_keyboard_start_grab,
                  wlr_seat_pointer_clear_focus, wlr_seat_pointer_end_grab, wlr_seat_pointer_enter,
                  wlr_seat_pointer_has_grab, wlr_seat_pointer_notify_axis,
                  wlr_seat_pointer_notify_button, wlr_seat_pointer_notify_enter,
                  wlr_seat_pointer_notify_motion, wlr_seat_pointer_send_axis,
                  wlr_seat_pointer_send_button, wlr_seat_pointer_send_motion,
                  wlr_seat_pointer_start_grab, wlr_seat_pointer_surface_has_focus,
                  wlr_seat_set_capabilities, wlr_seat_set_keyboard, wlr_seat_set_name,
                  wlr_seat_touch_end_grab, wlr_seat_touch_get_point, wlr_seat_touch_has_grab,
                  wlr_seat_touch_notify_down, wlr_seat_touch_notify_motion,
                  wlr_seat_touch_notify_up, wlr_seat_touch_num_points,
                  wlr_seat_touch_point_clear_focus, wlr_seat_touch_point_focus,
                  wlr_seat_touch_send_down, wlr_seat_touch_send_motion, wlr_seat_touch_send_up,
                  wlr_seat_touch_start_grab, wlr_touch_point};
use wlroots_sys::wayland_server::protocol::wl_seat::Capability;

use compositor::Compositor;
use utils::{c_to_rust_string, safe_as_cstring};

use super::grab::{KeyboardGrab, PointerGrab, TouchGrab};
use super::touch_point::{TouchId, TouchPoint};
use types::surface::Surface;

/// A wrapper around `wlr_seat`.
pub struct Seat {
    seat: *mut wlr_seat
}

impl Seat {
    /// Allocates a new `wlr_seat` and adds a wl_seat global to the display.
    pub fn create(compositor: &mut Compositor, name: String) -> Option<Self> {
        unsafe {
            let name = safe_as_cstring(name);
            let seat = wlr_seat_create(compositor.display() as _, name.as_ptr());
            if seat.is_null() {
                None
            } else {
                Some(Seat { seat })
            }
        }
    }

    /// Get the name of the seat.
    pub fn name(&self) -> Option<String> {
        unsafe {
            let name_ptr = (*self.seat).name;
            if name_ptr.is_null() {
                return None
            }
            c_to_rust_string(name_ptr)
        }
    }

    /// Updates the name of this seat.
    /// Will automatically send it to all clients.
    pub fn set_name(&mut self, name: String) {
        let name = safe_as_cstring(name);
        unsafe {
            wlr_seat_set_name(self.seat, name.as_ptr());
        }
    }

    /// Gets the capabilities of this seat.
    pub fn capabilities(&self) -> Capability {
        unsafe {
            Capability::from_raw((*self.seat).capabilities).expect("Invalid capabilities")
        }
    }

    /// Updates the capabilities available on this seat.
    /// Will automatically send it to all clients.
    pub fn set_capabilities(&mut self, capabilities: Capability) {
        unsafe { wlr_seat_set_capabilities(self.seat, capabilities.bits()) }
    }

    /// Determines if the surface has pointer focus.
    pub fn pointer_surface_has_focus(&mut self, surface: Surface) -> bool {
        unsafe { wlr_seat_pointer_surface_has_focus(self.seat, surface.as_ptr()) }
    }

    // Sends a pointer enter event to the given surface and considers it to be
    // the focused surface for the pointer.
    //
    // This will send a leave event to the last surface that was entered.
    //
    // Coordinates for the enter event are surface-local.
    //
    // Compositor should use `Seat::pointer_notify_enter` to
    // change pointer focus to respect pointer grabs.
    pub fn pointer_enter(&mut self, surface: Surface, sx: f64, sy: f64) {
        unsafe {
            wlr_seat_pointer_enter(self.seat, surface.as_ptr(), sx, sy);
        }
    }

    /// Clears the focused surface for the pointer and leaves all entered
    /// surfaces.
    pub fn clear_focus(&mut self) {
        unsafe { wlr_seat_pointer_clear_focus(self.seat) }
    }

    /// Sends a motion event to the surface with pointer focus.
    ///
    /// Coordinates for the motion event are surface-local.
    ///
    /// Compositors should use `Seat::notify_motion` to
    /// send motion events to the respect pointer grabs.
    pub fn send_motion(&mut self, time: Duration, sx: f64, sy: f64) {
        let seconds_delta = time.as_secs() as u32;
        let nano_delta = time.subsec_nanos();
        let ms = (seconds_delta * 1000) + nano_delta / 1000000;
        unsafe {
            // TODO FIXME what kind of time? ms? s?
            // I'm just guessing it's ms, there's no documentation on this.
            wlr_seat_pointer_send_motion(self.seat, ms, sx, sy)
        }
    }

    // TODO Button and State should probably be wrapped in some sort of type...

    /// Send a button event to the surface with pointer focus.
    ///
    /// Coordinates for the button event are surface-local.
    ///
    /// Returns the serial.
    ///
    /// Compositors should use `Seat::notify_button` to
    /// send button events to respect pointer grabs.
    pub fn send_button(&mut self, time: Duration, button: u32, state: u32) -> u32 {
        let seconds_delta = time.as_secs() as u32;
        let nano_delta = time.subsec_nanos();
        let ms = (seconds_delta * 1000) + nano_delta / 1000000;
        unsafe { wlr_seat_pointer_send_button(self.seat, ms, button, state) }
    }

    /// Send an axis event to the surface with pointer focus.
    ///
    /// Compositors should use `Seat::notify_axis` to
    /// send axis events to respect pointer grabs.
    pub fn send_axis(&mut self, time: Duration, orientation: wlr_axis_orientation, value: f64) {
        let seconds_delta = time.as_secs() as u32;
        let nano_delta = time.subsec_nanos();
        let ms = (seconds_delta * 1000) + nano_delta / 1000000;
        unsafe {
            wlr_seat_pointer_send_axis(self.seat, ms, orientation, value);
        }
    }

    /// Start a grab of the pointer of this seat. The grabber is responsible for
    /// handling all pointer events until the grab ends.
    pub fn pointer_start_grab(&mut self, grab: PointerGrab) {
        unsafe { wlr_seat_pointer_start_grab(self.seat, grab.as_ptr()) }
    }

    /// End the grab of the pointer of this seat. This reverts the grab back to the
    /// default grab for the pointer.
    pub fn pointer_end_grab(&mut self) {
        unsafe { wlr_seat_pointer_end_grab(self.seat) }
    }

    /// Whether or not the pointer has a grab other than the default grab.
    pub fn pointer_has_grab(&self) -> bool {
        unsafe { wlr_seat_pointer_has_grab(self.seat) }
    }

    /// Clear the focused surface for the pointer and leave all entered
    /// surfaces.
    pub fn pointer_clear_focus(&mut self) {
        unsafe { wlr_seat_pointer_clear_focus(self.seat) }
    }

    /// Send a keyboard enter event to the given surface and consider it to be the
    /// focused surface for the keyboard.
    ///
    /// This will send a leave event to the last surface that was entered.
    ///
    /// Compositors should use `Seat::keyboard_notify_enter()` to
    /// change keyboard focus to respect keyboard grabs.
    pub fn keyboard_enter(&mut self, surface: Surface) {
        unsafe { wlr_seat_keyboard_enter(self.seat, surface.as_ptr()) }
    }

    /// Start a grab of the keyboard of this seat. The grabber is responsible for
    /// handling all keyboard events until the grab ends.
    pub fn keyboard_start_grab(&mut self, grab: KeyboardGrab) {
        unsafe { wlr_seat_keyboard_start_grab(self.seat, grab.as_ptr()) }
    }

    /// End the grab of the keyboard of this seat. This reverts the grab back to the
    /// default grab for the keyboard.
    pub fn keyboard_end_grab(&mut self) {
        unsafe { wlr_seat_keyboard_end_grab(self.seat) }
    }

    /// Whether or not the keyboard has a grab other than the default grab
    pub fn keyboard_has_grab(&self) -> bool {
        unsafe { wlr_seat_keyboard_has_grab(self.seat) }
    }

    /// Clear the focused surface for the keyboard and leave all entered
    /// surfaces.
    pub fn keyboard_clear_focus(&mut self) {
        unsafe { wlr_seat_keyboard_clear_focus(self.seat) }
    }

    /// Start a grab of the touch device of this seat. The grabber is responsible for
    /// handling all touch events until the grab ends.
    pub fn touch_start_grab(&mut self, grab: TouchGrab) {
        unsafe { wlr_seat_touch_start_grab(self.seat, grab.as_ptr()) }
    }

    /// End the grab of the touch device of this seat. This reverts the grab back to
    /// the default grab for the touch device.
    pub fn touch_end_grab(&mut self) {
        unsafe { wlr_seat_touch_end_grab(self.seat) }
    }

    /// Whether or not the seat has a touch grab other than the default grab.
    pub fn touch_has_grab(&self) -> bool {
        unsafe { wlr_seat_touch_has_grab(self.seat) }
    }

    // Get the active touch point with the given `touch_id`. If the touch point does
    // not exist or is no longer active, returns None.
    pub fn get_touch_point(&self, touch_id: TouchId) -> Option<TouchPoint> {
        unsafe {
            let touch_point = wlr_seat_touch_get_point(self.seat, touch_id.into());
            if touch_point.is_null() {
                return None
            } else {
                Some(TouchPoint::from_ptr(touch_point))
            }
        }
    }

    // TODO Should this be returning a u32? Should I wrap whatever that number is?

    /// Notify the seat of a touch down on the given surface. Defers to any grab of
    /// the touch device.
    pub fn touch_notify_down(&mut self,
                             surface: Surface,
                             time: Duration,
                             touch_id: TouchId,
                             sx: f64,
                             sy: f64)
                             -> u32 {
        // TODO Is this the correct amount of time to pass?
        let seconds_delta = time.as_secs() as u32;
        let nano_delta = time.subsec_nanos();
        let ms = (seconds_delta * 1000) + nano_delta / 1000000;
        unsafe {
            wlr_seat_touch_notify_down(self.seat, surface.as_ptr(), ms, touch_id.into(), sx, sy)
        }
    }

    /// Notify the seat that the touch point given by `touch_id` is up. Defers to any
    /// grab of the touch device.
    pub fn touch_notify_up(&mut self, time: Duration, touch_id: TouchId) {
        // TODO Is this the correct amount of time to pass?
        let seconds_delta = time.as_secs() as u32;
        let nano_delta = time.subsec_nanos();
        let ms = (seconds_delta * 1000) + nano_delta / 1000000;
        unsafe { wlr_seat_touch_notify_up(self.seat, ms, touch_id.into()) }
    }

    pub fn touch_notify_motion(&mut self, time: Duration, touch_id: TouchId, sx: f64, sy: f64) {
        // TODO Is this the correct amount of time to pass?
        let seconds_delta = time.as_secs() as u32;
        let nano_delta = time.subsec_nanos();
        let ms = (seconds_delta * 1000) + nano_delta / 1000000;
        unsafe { wlr_seat_touch_notify_motion(self.seat, ms, touch_id.into(), sx, sy) }
    }
    // TODO notify and some other specific input misc functions

    pub unsafe fn to_ptr(&self) -> *mut wlr_seat {
        self.seat
    }
}

impl Drop for Seat {
    fn drop(&mut self) {
        unsafe { wlr_seat_destroy(self.seat) }
    }
}
<|endoftext|>


<commit_before>use super::Vector;
use super::Vector2;

pub struct Vector2f {
    pub x: f32,
    pub y: f32,
}

impl Vector<Vector2f, f32> for Vector2f {
    fn new() -> Self {
        Vector2f {
            x: 0f32,
            y: 0f32,
        }
    }

    fn add(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn add_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn angle(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn angle_cos(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn distance(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn distance_squared(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn dot(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn fma_scalar(&mut self, a: f32, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_scalar_into(&self, a: f32, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn fma_vector(&mut self, a: &Vector2f, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_vector_into(&self, a: &Vector2f, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn length(&self) -> f32 {
        unimplemented!()
    }

    fn length_squared(&self) -> f32 {
        unimplemented!()
    }

    fn lerp(&mut self, other: &Vector2f, t: f32) -> &mut Self {
        unimplemented!()
    }

    fn lerp_into(&self, other: &Vector2f, t: f32, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn mul_scalar(&mut self, s: f32) -> &mut Self {
        unimplemented!()
    }

    fn mul_scalar_into(&self, s: f32, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn mul_vector(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn mul_vector_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn negate(&mut self) -> &mut Self {
        unimplemented!()
    }

    fn negate_into(&self, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn normalize(&mut self) -> &mut Self {
        unimplemented!()
    }

    fn normalize_into(&self, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn set(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn sub(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn sub_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn zero(&mut self) -> &mut Self {
        unimplemented!()
    }
}

impl Vector2<Vector2f, f32> for Vector2f {
    fn add_components(&mut self, x: f32, y: f32) -> &mut Self {
        unimplemented!()
    }

    fn add_components_into(&self, x: f32, y: f32, dest: &mut Vector2f) {
        unimplemented!()
    }
}
<commit_msg>add first few tests<commit_after>use super::Vector;
use super::Vector2;

pub struct Vector2f {
    pub x: f32,
    pub y: f32,
}

impl Vector<Vector2f, f32> for Vector2f {
    fn new() -> Self {
        Vector2f {
            x: 0f32,
            y: 0f32,
        }
    }

    fn add(&mut self, v: &Vector2f) -> &mut Self {
        self.x += v.x;
        self.y += v.y;
        self
    }

    fn add_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn angle(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn angle_cos(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn distance(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn distance_squared(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn dot(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn fma_scalar(&mut self, a: f32, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_scalar_into(&self, a: f32, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn fma_vector(&mut self, a: &Vector2f, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_vector_into(&self, a: &Vector2f, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn length(&self) -> f32 {
        unimplemented!()
    }

    fn length_squared(&self) -> f32 {
        unimplemented!()
    }

    fn lerp(&mut self, other: &Vector2f, t: f32) -> &mut Self {
        unimplemented!()
    }

    fn lerp_into(&self, other: &Vector2f, t: f32, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn mul_scalar(&mut self, s: f32) -> &mut Self {
        unimplemented!()
    }

    fn mul_scalar_into(&self, s: f32, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn mul_vector(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn mul_vector_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn negate(&mut self) -> &mut Self {
        unimplemented!()
    }

    fn negate_into(&self, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn normalize(&mut self) -> &mut Self {
        unimplemented!()
    }

    fn normalize_into(&self, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn set(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn sub(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn sub_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn zero(&mut self) -> &mut Self {
        unimplemented!()
    }
}

impl Vector2<Vector2f, f32> for Vector2f {
    fn add_components(&mut self, x: f32, y: f32) -> &mut Self {
        unimplemented!()
    }

    fn add_components_into(&self, x: f32, y: f32, dest: &mut Vector2f) {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use super::super::Vector;
    use super::Vector2f;

    #[test]
    fn test_new() {
        let a = Vector2f::new();

        assert_eq!(a.x, 0f32);
        assert_eq!(a.y, 0f32);
    }

    #[test]
    fn test_add() {
        let mut a = Vector2f::new();
        let mut b = Vector2f::new();
        b.x = 1f32;
        b.y = 2f32;

        a.add(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);

        assert_eq!(b.x, 1f32);
        assert_eq!(b.y, 2f32);
    }
}
<|endoftext|>


<commit_before>/* AES ECB/CBC mode oracle
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

extern crate aes_lib;

use std::rand::{random, task_rng, Rng, Rand};
use std::fmt;
use std::fmt::{Show, Formatter};
use std::collections::HashSet;
use std::io::File;

use aes_lib::{AES_BLOCK_SIZE, encrypt_aes_ecb, encrypt_aes_cbc};

#[deriving(PartialEq, Eq)]
enum Mode {
    ECB,
    CBC
}

impl Rand for Mode {
    fn rand<R: Rng>(rng: &mut R) -> Mode {
        match rng.gen() {
            true => Mode::ECB,
            false => Mode::CBC
        }
    }
}

impl Show for Mode {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Mode::ECB => write!(f, "ECB"),
            Mode::CBC => write!(f, "CBC"),
        }
    }
}

#[inline]
fn random_bytes(len: uint) -> Vec<u8> {
    Vec::from_fn(len, |_| random::<u8>())
}

#[inline]
fn random_uint(low: uint, high: uint) -> uint {
    task_rng().gen_range(low, high)
}

fn aes_oracle(input: &[u8]) -> (Vec<u8>, Mode) {
    let key = random_bytes(AES_BLOCK_SIZE);
    let prepend = random_bytes(random_uint(5, 10));
    let append = random_bytes(random_uint(5, 10));
    let data = prepend + input + append.as_slice();
    match random::<Mode>() {
        Mode::ECB =>
            (encrypt_aes_ecb(data.as_slice(), key.as_slice()), Mode::ECB),
        Mode::CBC => {
            let iv = random_bytes(AES_BLOCK_SIZE);
            (encrypt_aes_cbc(data.as_slice(), key.as_slice(),
                             iv.as_slice()), Mode::CBC)
        }
    }
}

fn guess_aes_mode(buffer: &[u8]) -> Mode {
    let mut blocks = HashSet::new();
    match buffer.chunks(AES_BLOCK_SIZE).any(|b| !blocks.insert(b)) {
        true => Mode::ECB,
        false => Mode::CBC
    }
}

fn read_example_text() -> Vec<u8> {
    File::open(&Path::new("text.txt")).read_to_end().unwrap()
}

fn main() {
    let data = read_example_text();
    let (encrypted, mode) = aes_oracle(data.as_slice());
    print!("Mode: {} - ", mode);
    if guess_aes_mode(encrypted.as_slice()) == mode {
        println!("Matched");
    } else {
        println!("Not matched");
    }
}
<commit_msg>std::rand::task_rng => thread_rng<commit_after>/* AES ECB/CBC mode oracle
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

extern crate aes_lib;

use std::rand::{random, thread_rng, Rng, Rand};
use std::fmt;
use std::fmt::{Show, Formatter};
use std::collections::HashSet;
use std::io::File;

use aes_lib::{AES_BLOCK_SIZE, encrypt_aes_ecb, encrypt_aes_cbc};

#[deriving(PartialEq, Eq)]
enum Mode {
    ECB,
    CBC
}

impl Rand for Mode {
    fn rand<R: Rng>(rng: &mut R) -> Mode {
        match rng.gen() {
            true => Mode::ECB,
            false => Mode::CBC
        }
    }
}

impl Show for Mode {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Mode::ECB => write!(f, "ECB"),
            Mode::CBC => write!(f, "CBC"),
        }
    }
}

#[inline]
fn random_bytes(len: uint) -> Vec<u8> {
    Vec::from_fn(len, |_| random::<u8>())
}

#[inline]
fn random_uint(low: uint, high: uint) -> uint {
    thread_rng().gen_range(low, high)
}

fn aes_oracle(input: &[u8]) -> (Vec<u8>, Mode) {
    let key = random_bytes(AES_BLOCK_SIZE);
    let prepend = random_bytes(random_uint(5, 10));
    let append = random_bytes(random_uint(5, 10));
    let data = prepend + input + append.as_slice();
    match random::<Mode>() {
        Mode::ECB =>
            (encrypt_aes_ecb(data.as_slice(), key.as_slice()), Mode::ECB),
        Mode::CBC => {
            let iv = random_bytes(AES_BLOCK_SIZE);
            (encrypt_aes_cbc(data.as_slice(), key.as_slice(),
                             iv.as_slice()), Mode::CBC)
        }
    }
}

fn guess_aes_mode(buffer: &[u8]) -> Mode {
    let mut blocks = HashSet::new();
    match buffer.chunks(AES_BLOCK_SIZE).any(|b| !blocks.insert(b)) {
        true => Mode::ECB,
        false => Mode::CBC
    }
}

fn read_example_text() -> Vec<u8> {
    File::open(&Path::new("text.txt")).read_to_end().unwrap()
}

fn main() {
    let data = read_example_text();
    let (encrypted, mode) = aes_oracle(data.as_slice());
    print!("Mode: {} - ", mode);
    if guess_aes_mode(encrypted.as_slice()) == mode {
        println!("Matched");
    } else {
        println!("Not matched");
    }
}
<|endoftext|>


<commit_before>use sdl2;

/// A simple 2D point.
#[derive(Copy, Clone, PartialEq, Debug, Default)]
pub struct Point {
    pub x: f32,
    pub y: f32,
}

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

    /// Creates a new `Point` at coordinates 0,0.
    pub fn zero() -> Self {
        Self::new(0.0, 0.0)
    }
}

impl From<Point> for [f32; 2] {
    fn from(p: Point) -> [f32; 2] {
        [p.x, p.y]
    }
}

impl From<[f32; 2]> for Point {
    fn from(p: [f32; 2]) -> Point {
        Point::new(p[0], p[1])
    }
}

/// A simple 2D rectangle.
#[derive(Copy, Clone, PartialEq, Debug, Default)]
pub struct Rect {
    pub x: f32,
    pub y: f32,
    pub w: f32,
    pub h: f32,
}

impl Rect {
    pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
        Rect {
            x: x,
            y: y,
            w: w,
            h: h,
        }
    }

    /// Ceates a new rect a la Love2D's love.graphics.newQuad,
    /// as a fraction of the reference rect's size.
    pub fn fraction(x: f32, y: f32, w: f32, h: f32, reference: &Rect) -> Rect {
        Rect {
            x: x / reference.w,
            y: y / reference.h,
            w: w / reference.w,
            h: h / reference.h,
        }
    }

    pub fn new_i32(x: i32, y: i32, w: i32, h: i32) -> Self {
        Rect {
            x: x as f32,
            y: y as f32,
            w: w as f32,
            h: h as f32,
        }
    }

    /// Create a new `Rect` with all values zero.
    pub fn zero() -> Self {
        Self::new(0.0, 0.0, 0.0, 0.0)
    }

    /// Creates a new `Rect` at 0,0 with width and height 1.
    pub fn one() -> Self {
        Self::new(0.0, 0.0, 1.0, 1.0)
    }

    /// Gets the `Rect`'s x and y coordinates as a `Point`.
    pub fn point(&self) -> Point {
        Point {
            x: self.x,
            y: self.y,
        }
    }
}

impl From<[f32; 4]> for Rect {
    fn from(val: [f32; 4]) -> Self {
        Rect::new(val[0], val[1], val[2], val[3])
    }
}

impl From<Rect> for [f32; 4] {
    fn from(val: Rect) -> Self {
        [val.x, val.y, val.w, val.h]
    }
}

/// A RGBA color.
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Color {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32,
}

pub const WHITE: Color = Color {
    r: 1.0,
    g: 1.0,
    b: 1.0,
    a: 1.0,
};

pub const BLACK: Color = Color {
    r: 0.0,
    g: 0.0,
    b: 0.0,
    a: 1.0,
};

impl Color {
    pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
        Color {
            r: r,
            g: g,
            b: b,
            a: a,
        }
    }
}

impl From<(u8, u8, u8, u8)> for Color {
    fn from(val: (u8, u8, u8, u8)) -> Self {
        let (r, g, b, a) = val;
        let rf = (r as f32) / 255.0;
        let gf = (g as f32) / 255.0;
        let bf = (b as f32) / 255.0;
        let af = (a as f32) / 255.0;
        Color::new(rf, gf, bf, af)
    }
}

impl From<(u8, u8, u8)> for Color {
    fn from(val: (u8, u8, u8)) -> Self {
        let (r, g, b) = val;
        Color::from((r, g, b, 255))
    }
}

impl From<[f32; 4]> for Color {
    fn from(val: [f32; 4]) -> Self {
        Color::new(val[0], val[1], val[2], val[3])
    }
}

impl From<Color> for (u8, u8, u8, u8) {
    fn from(color: Color) -> Self {
        let r = (color.r * 255.0) as u8;
        let g = (color.g * 255.0) as u8;
        let b = (color.b * 255.0) as u8;
        let a = (color.a * 255.0) as u8;
        (r, g, b, a)
    }
}

impl From<Color> for [u8; 4] {
    fn from(color: Color) -> Self {
        let (r, g, b, a) = color.into();
        [r, g, b, a]
    }
}

impl From<Color> for [f32; 4] {
    fn from(color: Color) -> Self {
        [color.r, color.g, color.b, color.a]
    }
}

impl From<Color> for (u8, u8, u8) {
    fn from(color: Color) -> Self {
        let (r, g, b, _) = color.into();
        (r, g, b)
    }
}

impl From<Color> for u32 {
    fn from(color: Color) -> Self {
        let (r, g, b, a): (u8, u8, u8, u8) = color.into();
        let rp = (r as u32) << 24;
        let gp = (g as u32) << 16;
        let bp = (b as u32) << 8;
        let ap = a as u32;
        (rp | gp | bp | ap)
    }
}

/// Specifies whether a shape should be drawn
/// filled or as an outline.
#[derive(Debug, Copy, Clone)]
pub enum DrawMode {
    Line,
    Fill,
}

/// Specifies what blending method to use when scaling up/down images.
#[derive(Debug, Copy, Clone)]
pub enum FilterMode {
    Linear,
    Nearest,
}

use gfx::texture;
use gfx::texture::FilterMethod;

impl From<FilterMethod> for FilterMode {
    fn from(f: FilterMethod) -> Self {
        match f {
            FilterMethod::Scale => FilterMode::Nearest,
            _other => FilterMode::Linear,
        }
    }
}

impl From<FilterMode> for FilterMethod {
    fn from(f: FilterMode) -> Self {
        match f {
            FilterMode::Nearest => FilterMethod::Scale,
            FilterMode::Linear => FilterMethod::Bilinear,
        }
    }
}

/// Specifies how to wrap textures.
pub type WrapMode = texture::WrapMode;

pub type FullscreenType = sdl2::video::FullscreenType;

/// A builder structure containing flags for defining window settings.
#[derive(Debug, Copy, Clone)]
pub struct WindowMode {
    pub borderless: bool,
    pub fullscreen_type: FullscreenType,
    pub vsync: bool,
}

impl Default for WindowMode {
    fn default() -> Self {
        Self {
            borderless: false,
            fullscreen_type: sdl2::video::FullscreenType::Off,
            vsync: true
        }
    }
}

impl WindowMode {
    pub fn borderless(mut self, borderless: bool) -> Self {
        self.borderless = borderless;
        self
    }

    pub fn fullscreen_type(mut self, fullscreen_type: FullscreenType) -> Self {
        self.fullscreen_type = fullscreen_type;
        self
    }

    pub fn vsync(mut self, vsync: bool) -> Self {
        self.vsync = vsync;
        self
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_color_conversions() {
        let white = Color::new(1.0, 1.0, 1.0, 1.0);
        let w1 = Color::from((255, 255, 255, 255));
        assert_eq!(white, w1);
        let w2: u32 = white.into();
        assert_eq!(w2, 0xFFFFFFFF);

        let grey = Color::new(0.5019608, 0.5019608, 0.5019608, 1.0);
        let g1 = Color::from((128, 128, 128, 255));
        assert_eq!(grey, g1);
        let g2: u32 = grey.into();
        assert_eq!(g2, 0x808080FF);

        let black = Color::new(0.0, 0.0, 0.0, 1.0);
        let b1 = Color::from((0, 0, 0, 255));
        assert_eq!(black, b1);
        let b2: u32 = black.into();
        assert_eq!(b2, 0x000000FF);
    }

    #[test]
    fn test_rect_scaling() {
        let r1 = Rect::new(0.0, 0.0, 128.0, 128.0);
        let r2 = Rect::fraction(0.0, 0.0, 32.0, 32.0, &r1);
        assert_eq!(r2, Rect::new(0.0, 0.0, 0.25, 0.25));

        let r2 = Rect::fraction(32.0, 32.0, 32.0, 32.0, &r1);
        assert_eq!(r2, Rect::new(0.25, 0.25, 0.25, 0.25));
    }
}
<commit_msg>Added docs explicitly saying Rect's coordinates are based on its center<commit_after>use sdl2;

/// A simple 2D point.
#[derive(Copy, Clone, PartialEq, Debug, Default)]
pub struct Point {
    pub x: f32,
    pub y: f32,
}

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

    /// Creates a new `Point` at coordinates 0,0.
    pub fn zero() -> Self {
        Self::new(0.0, 0.0)
    }
}

impl From<Point> for [f32; 2] {
    fn from(p: Point) -> [f32; 2] {
        [p.x, p.y]
    }
}

impl From<[f32; 2]> for Point {
    fn from(p: [f32; 2]) -> Point {
        Point::new(p[0], p[1])
    }
}

/// A simple 2D rectangle.
///
/// The ggez convention is that `x` and `y` are the **center** of the rectangle,
/// with `width` and `height` being the total width and height, because this
/// is generally also how OpenGL tends to think about the world.
#[derive(Copy, Clone, PartialEq, Debug, Default)]
pub struct Rect {
    pub x: f32,
    pub y: f32,
    pub w: f32,
    pub h: f32,
}

impl Rect {
    pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
        Rect {
            x: x,
            y: y,
            w: w,
            h: h,
        }
    }

    /// Ceates a new rect a la Love2D's love.graphics.newQuad,
    /// as a fraction of the reference rect's size.
    pub fn fraction(x: f32, y: f32, w: f32, h: f32, reference: &Rect) -> Rect {
        Rect {
            x: x / reference.w,
            y: y / reference.h,
            w: w / reference.w,
            h: h / reference.h,
        }
    }

    pub fn new_i32(x: i32, y: i32, w: i32, h: i32) -> Self {
        Rect {
            x: x as f32,
            y: y as f32,
            w: w as f32,
            h: h as f32,
        }
    }

    /// Create a new `Rect` with all values zero.
    pub fn zero() -> Self {
        Self::new(0.0, 0.0, 0.0, 0.0)
    }

    /// Creates a new `Rect` at 0,0 with width and height 1.
    pub fn one() -> Self {
        Self::new(0.0, 0.0, 1.0, 1.0)
    }

    /// Gets the `Rect`'s x and y coordinates as a `Point`.
    pub fn point(&self) -> Point {
        Point {
            x: self.x,
            y: self.y,
        }
    }

    /// Returns the left edge of the `Rect`
    pub fn left(&self) -> f32 {
        self.x - (self.w / 2.0)
    }

    /// Returns the right edge of the `Rect`
    pub fn right(&self) -> f32 {
        self.x + (self.w / 2.0)
    }

    /// Returns the top edge of the `Rect`
    pub fn top(&self) -> f32 {
        self.y + (self.h / 2.0)
    }

    /// Returns the bottom edge of the `Rect`
    pub fn bottom(&self) -> f32 {
        self.y - (self.h / 2.0)
    }
}

impl From<[f32; 4]> for Rect {
    fn from(val: [f32; 4]) -> Self {
        Rect::new(val[0], val[1], val[2], val[3])
    }
}

impl From<Rect> for [f32; 4] {
    fn from(val: Rect) -> Self {
        [val.x, val.y, val.w, val.h]
    }
}

/// A RGBA color.
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Color {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32,
}

pub const WHITE: Color = Color {
    r: 1.0,
    g: 1.0,
    b: 1.0,
    a: 1.0,
};

pub const BLACK: Color = Color {
    r: 0.0,
    g: 0.0,
    b: 0.0,
    a: 1.0,
};

impl Color {
    pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
        Color {
            r: r,
            g: g,
            b: b,
            a: a,
        }
    }
}

impl From<(u8, u8, u8, u8)> for Color {
    fn from(val: (u8, u8, u8, u8)) -> Self {
        let (r, g, b, a) = val;
        let rf = (r as f32) / 255.0;
        let gf = (g as f32) / 255.0;
        let bf = (b as f32) / 255.0;
        let af = (a as f32) / 255.0;
        Color::new(rf, gf, bf, af)
    }
}

impl From<(u8, u8, u8)> for Color {
    fn from(val: (u8, u8, u8)) -> Self {
        let (r, g, b) = val;
        Color::from((r, g, b, 255))
    }
}

impl From<[f32; 4]> for Color {
    fn from(val: [f32; 4]) -> Self {
        Color::new(val[0], val[1], val[2], val[3])
    }
}

impl From<Color> for (u8, u8, u8, u8) {
    fn from(color: Color) -> Self {
        let r = (color.r * 255.0) as u8;
        let g = (color.g * 255.0) as u8;
        let b = (color.b * 255.0) as u8;
        let a = (color.a * 255.0) as u8;
        (r, g, b, a)
    }
}

impl From<Color> for [u8; 4] {
    fn from(color: Color) -> Self {
        let (r, g, b, a) = color.into();
        [r, g, b, a]
    }
}

impl From<Color> for [f32; 4] {
    fn from(color: Color) -> Self {
        [color.r, color.g, color.b, color.a]
    }
}

impl From<Color> for (u8, u8, u8) {
    fn from(color: Color) -> Self {
        let (r, g, b, _) = color.into();
        (r, g, b)
    }
}

impl From<Color> for u32 {
    fn from(color: Color) -> Self {
        let (r, g, b, a): (u8, u8, u8, u8) = color.into();
        let rp = (r as u32) << 24;
        let gp = (g as u32) << 16;
        let bp = (b as u32) << 8;
        let ap = a as u32;
        (rp | gp | bp | ap)
    }
}

/// Specifies whether a shape should be drawn
/// filled or as an outline.
#[derive(Debug, Copy, Clone)]
pub enum DrawMode {
    Line,
    Fill,
}

/// Specifies what blending method to use when scaling up/down images.
#[derive(Debug, Copy, Clone)]
pub enum FilterMode {
    Linear,
    Nearest,
}

use gfx::texture;
use gfx::texture::FilterMethod;

impl From<FilterMethod> for FilterMode {
    fn from(f: FilterMethod) -> Self {
        match f {
            FilterMethod::Scale => FilterMode::Nearest,
            _other => FilterMode::Linear,
        }
    }
}

impl From<FilterMode> for FilterMethod {
    fn from(f: FilterMode) -> Self {
        match f {
            FilterMode::Nearest => FilterMethod::Scale,
            FilterMode::Linear => FilterMethod::Bilinear,
        }
    }
}

/// Specifies how to wrap textures.
pub type WrapMode = texture::WrapMode;

pub type FullscreenType = sdl2::video::FullscreenType;

/// A builder structure containing flags for defining window settings.
#[derive(Debug, Copy, Clone)]
pub struct WindowMode {
    pub borderless: bool,
    pub fullscreen_type: FullscreenType,
    pub vsync: bool,
}

impl Default for WindowMode {
    fn default() -> Self {
        Self {
            borderless: false,
            fullscreen_type: sdl2::video::FullscreenType::Off,
            vsync: true
        }
    }
}

impl WindowMode {
    pub fn borderless(mut self, borderless: bool) -> Self {
        self.borderless = borderless;
        self
    }

    pub fn fullscreen_type(mut self, fullscreen_type: FullscreenType) -> Self {
        self.fullscreen_type = fullscreen_type;
        self
    }

    pub fn vsync(mut self, vsync: bool) -> Self {
        self.vsync = vsync;
        self
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_color_conversions() {
        let white = Color::new(1.0, 1.0, 1.0, 1.0);
        let w1 = Color::from((255, 255, 255, 255));
        assert_eq!(white, w1);
        let w2: u32 = white.into();
        assert_eq!(w2, 0xFFFFFFFF);

        let grey = Color::new(0.5019608, 0.5019608, 0.5019608, 1.0);
        let g1 = Color::from((128, 128, 128, 255));
        assert_eq!(grey, g1);
        let g2: u32 = grey.into();
        assert_eq!(g2, 0x808080FF);

        let black = Color::new(0.0, 0.0, 0.0, 1.0);
        let b1 = Color::from((0, 0, 0, 255));
        assert_eq!(black, b1);
        let b2: u32 = black.into();
        assert_eq!(b2, 0x000000FF);
    }

    #[test]
    fn test_rect_scaling() {
        let r1 = Rect::new(0.0, 0.0, 128.0, 128.0);
        let r2 = Rect::fraction(0.0, 0.0, 32.0, 32.0, &r1);
        assert_eq!(r2, Rect::new(0.0, 0.0, 0.25, 0.25));

        let r2 = Rect::fraction(32.0, 32.0, 32.0, 32.0, &r1);
        assert_eq!(r2, Rect::new(0.25, 0.25, 0.25, 0.25));
    }
}
<|endoftext|>


<commit_before>use resize::Pixel::Gray8;
use resize::Type::Triangle;
use resize::Type::Lanczos3;
use std::fs;
use std::path::Path;

fn load_png(mut data: &[u8]) -> (usize, usize, Vec<u8>) {
    let decoder = png::Decoder::new(&mut data);
    let (info, mut reader) = decoder.read_info().unwrap();
    let mut src = vec![0; info.buffer_size()];
    reader.next_frame(&mut src).unwrap();

    (info.width as usize, info.height as usize, src)
}

fn write_png(path: &Path, w2: usize, h2: usize, pixels: &[u8]) {
    let outfh = fs::File::create(path).unwrap();
    let encoder = png::Encoder::new(outfh, w2 as u32, h2 as u32);
    encoder.write_header().unwrap().write_image_data(pixels).unwrap();
}

fn img_diff(a: &[u8], b: &[u8]) -> f64 {
    assert_eq!(a.len(), b.len());
    let sum = a.iter().cloned().zip(b.iter().cloned()).map(|(a,b)| {
        (a as i32 - b as i32).pow(2) as u32
    }).sum::<u32>();
    sum as f64 / a.len() as f64
}

fn assert_equals(img: &[u8], w2: usize, h2: usize, expected_filename: &str) {
    let (_, _, expected) = load_png(&fs::read(&expected_filename).expect(expected_filename));

    let diff = img_diff(&img, &expected);
    if diff > 0.0004 {
        let bad_file = Path::new(expected_filename).with_extension("failed-test.png");
        write_png(&bad_file, w2, h2, img);
        panic!("Test failed: {} differs by {}; see {} ", expected_filename, diff, bad_file.display());
    }
}

fn test_width(w2: usize) {
    let tiger = &include_bytes!("../examples/tiger.png")[..];
    let (w1, h1, src) = load_png(&tiger);
    let mut res1 = vec![];
    let mut res2 = vec![];

    for h2 in [1, 2, 9, 99, 999, 1555].iter().copied() {
        res1.clear();
        res1.resize(w2 * h2, 0);

        resize::new(w1, h1, w2, h2, Gray8, Lanczos3).resize(&src, &mut res1);
        assert_equals(&res1, w2, h2, &format!("tests/t{}x{}.png", w2, h2));

        res2.clear();
        res2.resize(100 * 100, 255);

        resize::new(w2, h2, 100, 100, Gray8, Triangle).resize(&res1, &mut res2);
        assert_equals(&res2, 100, 100, &format!("tests/t{}x{}-100.png", w2, h2));
    }
}

#[test]
fn test_w2000() {
    test_width(2000);
}
#[test]
fn test_w1000() {
    test_width(1000);
}
#[test]
fn test_w100() {
    test_width(100);
}
#[test]
fn test_w10() {
    test_width(10);
}
#[test]
fn test_w2() {
    test_width(2);
}
#[test]
fn test_w1() {
    test_width(1);
}
<commit_msg>Show failing path in tests<commit_after>use resize::Pixel::Gray8;
use resize::Type::Triangle;
use resize::Type::Lanczos3;
use std::fs;
use std::path::Path;

fn load_png(mut data: &[u8]) -> Result<(usize, usize, Vec<u8>), png::DecodingError> {
    let decoder = png::Decoder::new(&mut data);
    let (info, mut reader) = decoder.read_info()?;
    let mut src = vec![0; info.buffer_size()];
    reader.next_frame(&mut src)?;

    Ok((info.width as usize, info.height as usize, src))
}

fn write_png(path: &Path, w2: usize, h2: usize, pixels: &[u8]) {
    let outfh = fs::File::create(path).unwrap();
    let encoder = png::Encoder::new(outfh, w2 as u32, h2 as u32);
    encoder.write_header().unwrap().write_image_data(pixels).unwrap();
}

fn img_diff(a: &[u8], b: &[u8]) -> f64 {
    assert_eq!(a.len(), b.len());
    let sum = a.iter().cloned().zip(b.iter().cloned()).map(|(a,b)| {
        (a as i32 - b as i32).pow(2) as u32
    }).sum::<u32>();
    sum as f64 / a.len() as f64
}

fn assert_equals(img: &[u8], w2: usize, h2: usize, expected_filename: &str) {
    let (_, _, expected) = load_png(&fs::read(&expected_filename).expect(expected_filename)).expect(expected_filename);

    let diff = img_diff(&img, &expected);
    if diff > 0.0004 {
        let bad_file = Path::new(expected_filename).with_extension("failed-test.png");
        write_png(&bad_file, w2, h2, img);
        panic!("Test failed: {} differs by {}; see {} ", expected_filename, diff, bad_file.display());
    }
}

fn test_width(w2: usize) {
    let tiger = &include_bytes!("../examples/tiger.png")[..];
    let (w1, h1, src) = load_png(&tiger).unwrap();
    let mut res1 = vec![];
    let mut res2 = vec![];

    for h2 in [1, 2, 9, 99, 999, 1555].iter().copied() {
        res1.clear();
        res1.resize(w2 * h2, 0);

        resize::new(w1, h1, w2, h2, Gray8, Lanczos3).resize(&src, &mut res1);
        assert_equals(&res1, w2, h2, &format!("tests/t{}x{}.png", w2, h2));

        res2.clear();
        res2.resize(100 * 100, 255);

        resize::new(w2, h2, 100, 100, Gray8, Triangle).resize(&res1, &mut res2);
        assert_equals(&res2, 100, 100, &format!("tests/t{}x{}-100.png", w2, h2));
    }
}

#[test]
fn test_w2000() {
    test_width(2000);
}
#[test]
fn test_w1000() {
    test_width(1000);
}
#[test]
fn test_w100() {
    test_width(100);
}
#[test]
fn test_w10() {
    test_width(10);
}
#[test]
fn test_w2() {
    test_width(2);
}
#[test]
fn test_w1() {
    test_width(1);
}
<|endoftext|>


<commit_before>use std::{collections::HashSet, fs, time::Duration};

// use flexi_logger::Logger;
use crossbeam_channel::RecvTimeoutError;
use ra_vfs::{Vfs, VfsChange};
use tempfile::tempdir;

fn process_tasks(vfs: &mut Vfs, num_tasks: u32) {
    for _ in 0..num_tasks {
        let task = vfs.task_receiver().recv_timeout(Duration::from_secs(3)).unwrap();
        log::debug!("{:?}", task);
        vfs.handle_task(task);
    }
}

macro_rules! assert_match {
    ($x:expr, $pat:pat) => {
        assert_match!($x, $pat, ())
    };
    ($x:expr, $pat:pat, $assert:expr) => {
        match $x {
            $pat => $assert,
            x => assert!(false, "Expected {}, got {:?}", stringify!($pat), x),
        };
    };
}

#[test]
fn test_vfs_works() -> std::io::Result<()> {
    // Logger::with_str("vfs=debug,ra_vfs=debug").start().unwrap();

    let files = [("a/foo.rs", "hello"), ("a/bar.rs", "world"), ("a/b/baz.rs", "nested hello")];

    let dir = tempdir().unwrap();
    for (path, text) in files.iter() {
        let file_path = dir.path().join(path);
        fs::create_dir_all(file_path.parent().unwrap()).unwrap();
        fs::write(file_path, text)?
    }

    let a_root = dir.path().join("a");
    let b_root = dir.path().join("a/b");

    let (mut vfs, _) = Vfs::new(vec![a_root, b_root]);
    process_tasks(&mut vfs, 2);
    {
        let files = vfs
            .commit_changes()
            .into_iter()
            .flat_map(|change| {
                let files = match change {
                    VfsChange::AddRoot { files, .. } => files,
                    _ => panic!("unexpected change"),
                };
                files.into_iter().map(|(_id, path, text)| {
                    let text: String = (&*text).clone();
                    (format!("{}", path.display()), text)
                })
            })
            .collect::<HashSet<_>>();

        let expected_files = [("foo.rs", "hello"), ("bar.rs", "world"), ("baz.rs", "nested hello")]
            .iter()
            .map(|(path, text)| (path.to_string(), text.to_string()))
            .collect::<HashSet<_>>();

        assert_eq!(files, expected_files);
    }

    fs::write(&dir.path().join("a/b/baz.rs"), "quux").unwrap();
    process_tasks(&mut vfs, 1);
    assert_match!(
        vfs.commit_changes().as_slice(),
        [VfsChange::ChangeFile { text, .. }],
        assert_eq!(text.as_str(), "quux")
    );

    vfs.add_file_overlay(&dir.path().join("a/b/baz.rs"), "m".to_string());
    assert_match!(
        vfs.commit_changes().as_slice(),
        [VfsChange::ChangeFile { text, .. }],
        assert_eq!(text.as_str(), "m")
    );

    // changing file on disk while overlayed doesn't generate a VfsChange
    fs::write(&dir.path().join("a/b/baz.rs"), "corge").unwrap();
    process_tasks(&mut vfs, 1);
    assert_match!(vfs.commit_changes().as_slice(), []);

    // removing overlay restores data on disk
    vfs.remove_file_overlay(&dir.path().join("a/b/baz.rs"));
    assert_match!(
        vfs.commit_changes().as_slice(),
        [VfsChange::ChangeFile { text, .. }],
        assert_eq!(text.as_str(), "corge")
    );

    vfs.add_file_overlay(&dir.path().join("a/b/spam.rs"), "spam".to_string());
    assert_match!(vfs.commit_changes().as_slice(), [VfsChange::AddFile { text, path, .. }], {
        assert_eq!(text.as_str(), "spam");
        assert_eq!(path, "spam.rs");
    });

    vfs.remove_file_overlay(&dir.path().join("a/b/spam.rs"));
    assert_match!(
        vfs.commit_changes().as_slice(),
        [VfsChange::RemoveFile { path, .. }],
        assert_eq!(path, "spam.rs")
    );

    fs::create_dir_all(dir.path().join("a/sub1/sub2")).unwrap();
    fs::write(dir.path().join("a/sub1/sub2/new.rs"), "new hello").unwrap();
    process_tasks(&mut vfs, 1);
    assert_match!(vfs.commit_changes().as_slice(), [VfsChange::AddFile { text, path, .. }], {
        assert_eq!(text.as_str(), "new hello");
        assert_eq!(path, "sub1/sub2/new.rs");
    });

    fs::rename(&dir.path().join("a/sub1/sub2/new.rs"), &dir.path().join("a/sub1/sub2/new1.rs"))
        .unwrap();
    // NOTE: Windows generates extra `Write` events when renaming?
    // meaning we have extra tasks to process
    process_tasks(&mut vfs, if cfg!(windows) { 4 } else { 2 });
    assert_match!(
        vfs.commit_changes().as_slice(),
        [VfsChange::RemoveFile { path: removed_path, .. }, VfsChange::AddFile { text, path: added_path, .. }],
        {
            assert_eq!(removed_path, "sub1/sub2/new.rs");
            assert_eq!(added_path, "sub1/sub2/new1.rs");
            assert_eq!(text.as_str(), "new hello");
        }
    );

    fs::remove_file(&dir.path().join("a/sub1/sub2/new1.rs")).unwrap();
    process_tasks(&mut vfs, 1);
    assert_match!(
        vfs.commit_changes().as_slice(),
        [VfsChange::RemoveFile { path, .. }],
        assert_eq!(path, "sub1/sub2/new1.rs")
    );

    {
        vfs.add_file_overlay(&dir.path().join("a/memfile.rs"), "memfile".to_string());
        assert_match!(
            vfs.commit_changes().as_slice(),
            [VfsChange::AddFile { text, .. }],
            assert_eq!(text.as_str(), "memfile")
        );
        fs::write(&dir.path().join("a/memfile.rs"), "ignore me").unwrap();
        process_tasks(&mut vfs, 1);
        assert_match!(vfs.commit_changes().as_slice(), []);
    }

    // should be ignored
    fs::create_dir_all(dir.path().join("a/target")).unwrap();
    fs::write(&dir.path().join("a/target/new.rs"), "ignore me").unwrap();

    assert_match!(
        vfs.task_receiver().recv_timeout(Duration::from_millis(300)), // slightly more than watcher debounce delay
        Err(RecvTimeoutError::Timeout)
    );

    Ok(())
}
<commit_msg>Generalize `tests/vfs.rs` processing to address wildly-varying time-dependent behavior on Mac OS X.<commit_after>use std::{collections::HashSet, fs, time::Duration};

// use flexi_logger::Logger;
use crossbeam_channel::RecvTimeoutError;
use ra_vfs::{Vfs, VfsChange};
use tempfile::tempdir;

/// Processes exactly `num_tasks` events waiting in the `vfs` message queue.
///
/// Panics if there are not exactly that many tasks enqueued for processing.
fn process_tasks(vfs: &mut Vfs, num_tasks: u32) {
    process_tasks_in_range(vfs, num_tasks, num_tasks);
}

/// Processes up to `max_count` events waiting in the `vfs` message queue.
///
/// Panics if it cannot process at least `min_count` events.
/// Panics if more than `max_count` events are enqueued for processing.
fn process_tasks_in_range(vfs: &mut Vfs, min_count: u32, max_count: u32) {
    for i in 0..max_count {
        let task = match vfs.task_receiver().recv_timeout(Duration::from_secs(3)) {
            Err(RecvTimeoutError::Timeout) if i >= min_count => return,
            otherwise => otherwise.unwrap(),
        };
        log::debug!("{:?}", task);
        vfs.handle_task(task);
    }
    assert!(vfs.task_receiver().is_empty());
}

macro_rules! assert_match {
    ($x:expr, $pat:pat) => {
        assert_match!($x, $pat, ())
    };
    ($x:expr, $pat:pat, $assert:expr) => {
        match $x {
            $pat => $assert,
            x => assert!(false, "Expected {}, got {:?}", stringify!($pat), x),
        };
    };
}

#[test]
fn test_vfs_works() -> std::io::Result<()> {
    // Logger::with_str("vfs=debug,ra_vfs=debug").start().unwrap();

    let files = [("a/foo.rs", "hello"), ("a/bar.rs", "world"), ("a/b/baz.rs", "nested hello")];

    let dir = tempdir().unwrap();
    for (path, text) in files.iter() {
        let file_path = dir.path().join(path);
        fs::create_dir_all(file_path.parent().unwrap()).unwrap();
        fs::write(file_path, text)?
    }

    let a_root = dir.path().join("a");
    let b_root = dir.path().join("a/b");

    let (mut vfs, _) = Vfs::new(vec![a_root, b_root]);
    process_tasks(&mut vfs, 2);
    {
        let files = vfs
            .commit_changes()
            .into_iter()
            .flat_map(|change| {
                let files = match change {
                    VfsChange::AddRoot { files, .. } => files,
                    _ => panic!("unexpected change"),
                };
                files.into_iter().map(|(_id, path, text)| {
                    let text: String = (&*text).clone();
                    (format!("{}", path.display()), text)
                })
            })
            .collect::<HashSet<_>>();

        let expected_files = [("foo.rs", "hello"), ("bar.rs", "world"), ("baz.rs", "nested hello")]
            .iter()
            .map(|(path, text)| (path.to_string(), text.to_string()))
            .collect::<HashSet<_>>();

        assert_eq!(files, expected_files);
    }

    // rust-analyzer#734: fsevents has a bunch of events still sitting around.
    process_tasks_in_range(&mut vfs, 0, 7);
    match vfs.commit_changes().as_slice() {
        [] => {}

        // This arises on fsevents (unless we wait 30 seconds before
        // calling `Vfs::new` above). We need to churn through these
        // events so that we can focus on the event that arises from
        // the `fs::write` below.
        [VfsChange::ChangeFile { .. }, // hello
         VfsChange::ChangeFile { .. }, // world
         VfsChange::AddFile { .. }, // b/baz.rs, nested hello
         VfsChange::ChangeFile { .. }, // hello
         VfsChange::ChangeFile { .. }, // world
         VfsChange::ChangeFile { .. }, // nested hello
         VfsChange::ChangeFile { .. }, // nested hello
        ] => {}

        changes => panic!("Expected events for setting up initial files, got: {GOT:?}",
                          GOT=changes),
    }

    fs::write(&dir.path().join("a/b/baz.rs"), "quux").unwrap();
    process_tasks(&mut vfs, 1);
    assert_match!(
        vfs.commit_changes().as_slice(),
        [VfsChange::ChangeFile { text, .. }],
        assert_eq!(text.as_str(), "quux")
    );

    vfs.add_file_overlay(&dir.path().join("a/b/baz.rs"), "m".to_string());
    assert_match!(
        vfs.commit_changes().as_slice(),
        [VfsChange::ChangeFile { text, .. }],
        assert_eq!(text.as_str(), "m")
    );

    // changing file on disk while overlayed doesn't generate a VfsChange
    fs::write(&dir.path().join("a/b/baz.rs"), "corge").unwrap();
    process_tasks(&mut vfs, 1);
    assert_match!(vfs.commit_changes().as_slice(), []);

    // removing overlay restores data on disk
    vfs.remove_file_overlay(&dir.path().join("a/b/baz.rs"));
    assert_match!(
        vfs.commit_changes().as_slice(),
        [VfsChange::ChangeFile { text, .. }],
        assert_eq!(text.as_str(), "corge")
    );

    vfs.add_file_overlay(&dir.path().join("a/b/spam.rs"), "spam".to_string());
    assert_match!(vfs.commit_changes().as_slice(), [VfsChange::AddFile { text, path, .. }], {
        assert_eq!(text.as_str(), "spam");
        assert_eq!(path, "spam.rs");
    });

    vfs.remove_file_overlay(&dir.path().join("a/b/spam.rs"));
    assert_match!(
        vfs.commit_changes().as_slice(),
        [VfsChange::RemoveFile { path, .. }],
        assert_eq!(path, "spam.rs")
    );

    fs::create_dir_all(dir.path().join("a/sub1/sub2")).unwrap();
    fs::write(dir.path().join("a/sub1/sub2/new.rs"), "new hello").unwrap();
    process_tasks(&mut vfs, 1);
    assert_match!(vfs.commit_changes().as_slice(), [VfsChange::AddFile { text, path, .. }], {
        assert_eq!(text.as_str(), "new hello");
        assert_eq!(path, "sub1/sub2/new.rs");
    });

    fs::rename(&dir.path().join("a/sub1/sub2/new.rs"), &dir.path().join("a/sub1/sub2/new1.rs"))
        .unwrap();

    // rust-analyzer#734: For testing purposes, work-around
    // passcod/notify#181 by processing either 1 or 2 events. (In
    // particular, Mac can hand back either 1 or 2 events in a
    // timing-dependent fashion.)
    //
    // rust-analyzer#827: Windows generates extra `Write` events when
    // renaming? meaning we have extra tasks to process.
    process_tasks_in_range(&mut vfs, 1, if cfg!(windows) { 4 } else { 2 });
    match vfs.commit_changes().as_slice() {
        [VfsChange::RemoveFile { path: removed_path, .. }, VfsChange::AddFile { text, path: added_path, .. }] =>
        {
            assert_eq!(removed_path, "sub1/sub2/new.rs");
            assert_eq!(added_path, "sub1/sub2/new1.rs");
            assert_eq!(text.as_str(), "new hello");
        }

        // Hopefully passcod/notify#181 will be addressed in some
        // manner that will reliably emit an event mentioning
        // `sub1/sub2/new.rs`. But until then, must accept that
        // debouncing loses information unrecoverably.
        [VfsChange::AddFile { text, path: added_path, .. }] => {
            assert_eq!(added_path, "sub1/sub2/new1.rs");
            assert_eq!(text.as_str(), "new hello");
        }

        changes => panic!(
            "Expected events for rename of {OLD} to {NEW}, got: {GOT:?}",
            OLD = "sub1/sub2/new.rs",
            NEW = "sub1/sub2/new1.rs",
            GOT = changes
        ),
    }

    fs::remove_file(&dir.path().join("a/sub1/sub2/new1.rs")).unwrap();
    process_tasks(&mut vfs, 1);
    assert_match!(
        vfs.commit_changes().as_slice(),
        [VfsChange::RemoveFile { path, .. }],
        assert_eq!(path, "sub1/sub2/new1.rs")
    );

    {
        vfs.add_file_overlay(&dir.path().join("a/memfile.rs"), "memfile".to_string());
        assert_match!(
            vfs.commit_changes().as_slice(),
            [VfsChange::AddFile { text, .. }],
            assert_eq!(text.as_str(), "memfile")
        );
        fs::write(&dir.path().join("a/memfile.rs"), "ignore me").unwrap();
        process_tasks(&mut vfs, 1);
        assert_match!(vfs.commit_changes().as_slice(), []);
    }

    // should be ignored
    fs::create_dir_all(dir.path().join("a/target")).unwrap();
    fs::write(&dir.path().join("a/target/new.rs"), "ignore me").unwrap();

    assert_match!(
        vfs.task_receiver().recv_timeout(Duration::from_millis(300)), // slightly more than watcher debounce delay
        Err(RecvTimeoutError::Timeout)
    );

    Ok(())
}
<|endoftext|>