<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 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 YUV410: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 2, 2, 1),
                    chromaton!(yuv8; 2, 2, 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 {
    use super::*;

    #[test]
    fn fmt() {
        println!("formaton yuv- {}", formats::YUV420);
        println!("formaton pal- {}", formats::PAL8);
        println!("formaton rgb565- {}", formats::RGB565);
    }
}
<commit_msg>pixel: Add a comparison test<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)
    });
    (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 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 YUV410: &Formaton = &Formaton {
        model: Trichromatic(YUV(YCbCr(Limited))),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 2, 2, 1),
                    chromaton!(yuv8; 2, 2, 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::rc::Rc;
            let rcf = Rc::new(*formats::YUV420);
            let ref cf = formats::YUV420.clone();

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

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


<commit_before>// use std::slice;
use std::path::{Path, PathBuf};
use std::io;
use std::io::{Cursor, Read, Write};
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, Mutex, MutexGuard};
use std::cmp;
use std::marker::PhantomData;
use typenum::uint::Unsigned;
use typenum::consts::U0;

use rex::filesystem::Filesystem;

use super::bytes;

lazy_static! {
    pub static ref FILES: Mutex<HashMap<PathBuf, Arc<Mutex<Cursor<Vec<u8>>>>>> = Mutex::new(HashMap::new());
}

pub struct MockFile(Arc<Mutex<Cursor<Vec<u8>>>>);

impl MockFile {
    fn new(vec: Arc<Mutex<Cursor<Vec<u8>>>>) -> MockFile {
        MockFile(vec)
    }
}

impl Read for MockFile {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut vec = self.0.lock().unwrap();
        vec.read(buf)
    }
}

impl Write for MockFile {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let mut vec = self.0.lock().unwrap();
        vec.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        let mut vec = self.0.lock().unwrap();
        vec.flush()
    }
}

pub type DefMockFilesystem = MockFilesystem<U0>;

pub struct MockFilesystem<N: Unsigned = U0> (
    PhantomData<N>
);

impl<N: Unsigned> Filesystem for MockFilesystem<N> {
    type FSRead = MockFile;
    type FSWrite = MockFile;

    fn get_config_home() -> PathBuf {
        PathBuf::from("/config/")
    }

    fn make_absolute<P: AsRef<Path>>(p: P) -> io::Result<PathBuf> {
        Ok(p.as_ref().into())
    }

    fn open<P: AsRef<Path>>(path: P) -> io::Result<Self::FSRead> {
        FILES.lock().unwrap().get(path.as_ref()).ok_or(io::Error::new(io::ErrorKind::NotFound, "File not found!")).map(|file|
            MockFile::new(file.clone())
        )
    }

    fn can_open<P: AsRef<Path>>(p: P) -> io::Result<()> {
        Ok(())
    }

    fn save<P: AsRef<Path>>(path: P) -> io::Result<Self::FSWrite> {
        let file = Arc::new(Mutex::new(Cursor::new(Vec::new())));
        if let Entry::Vacant(entry) = FILES.lock().unwrap().entry(path.as_ref().into()) {
            entry.insert(file.clone());
            Ok(MockFile::new(file))
        } else {
            Err(io::Error::new(io::ErrorKind::AlreadyExists, "File alredy exists!"))
        }
    }

    fn can_save<P: AsRef<Path>>(p: P) -> io::Result<()> {
        Ok(())
    }
}

impl<N: Unsigned> MockFilesystem<N> {
    pub fn reset() {
        FILES.lock().unwrap().clear();
    }

    pub fn get_inner<'a, P: AsRef<Path>>(path: P) -> Vec<u8> {
        // This function is very ugly, in general we would like to "unwrap" the file from the
        // mock filesystem. Sadly, there doesn't seem to be a better way.
        let f = FILES.lock().unwrap().remove(path.as_ref()).unwrap();
        let a = Arc::try_unwrap(f).unwrap();
        let m = a.lock().unwrap();
        let v = m.clone();
        v.into_inner()
    }

    pub fn put<'a, P: AsRef<Path>>(path: P, v: Vec<u8>) {
        FILES.lock().unwrap().insert(path.as_ref().into(), Arc::new(Mutex::new(Cursor::new(v))));
    }
}
<commit_msg>Tests can now take a different config file<commit_after>// use std::slice;
use std::path::{Path, PathBuf};
use std::io;
use std::io::{Cursor, Read, Write};
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, Mutex, MutexGuard};
use std::cmp;
use std::marker::PhantomData;
use typenum::uint::Unsigned;
use typenum::consts;

use rex::filesystem::Filesystem;

use super::bytes;

pub type DefaultConfig = consts::U0;
pub type ConfigTest1 = consts::U1;
const NumConfigTests: usize = 2;

const CONFIG_PATH: &'static str = "/config/rex/rex.conf";

lazy_static! {
    static ref FILES: Mutex<HashMap<PathBuf, Arc<Mutex<Cursor<Vec<u8>>>>>> = Mutex::new(HashMap::new());
    static ref CONFIG_FILES: Mutex<[Option<Arc<Mutex<Cursor<Vec<u8>>>>>; NumConfigTests]> = {
        let mut tmp: [Option<Arc<Mutex<Cursor<Vec<u8>>>>>; NumConfigTests] = [
            None,
            None
        ];
        Mutex::new(tmp)
    };
}

pub struct MockFile(Arc<Mutex<Cursor<Vec<u8>>>>);

impl MockFile {
    fn new(vec: Arc<Mutex<Cursor<Vec<u8>>>>) -> MockFile {
        MockFile(vec)
    }
}

impl Read for MockFile {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut vec = self.0.lock().unwrap();
        vec.read(buf)
    }
}

impl Write for MockFile {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let mut vec = self.0.lock().unwrap();
        vec.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        let mut vec = self.0.lock().unwrap();
        vec.flush()
    }
}

pub type DefMockFilesystem = MockFilesystem<consts::U0>;

pub struct MockFilesystem<N: Unsigned = consts::U0> (
    PhantomData<N>
);

impl<N: Unsigned> Filesystem for MockFilesystem<N> {
    type FSRead = MockFile;
    type FSWrite = MockFile;

    fn get_config_home() -> PathBuf {
        PathBuf::from("/config/")
    }

    fn make_absolute<P: AsRef<Path>>(p: P) -> io::Result<PathBuf> {
        Ok(p.as_ref().into())
    }

    fn open<P: AsRef<Path>>(path: P) -> io::Result<Self::FSRead> {
        if path.as_ref() == Path::new(CONFIG_PATH) {
            return Self::open_config()
        }
        FILES.lock().unwrap().get(path.as_ref()).ok_or(io::Error::new(io::ErrorKind::NotFound, "File not found!")).map(|file|
            MockFile::new(file.clone())
        )
    }

    fn can_open<P: AsRef<Path>>(p: P) -> io::Result<()> {
        Ok(())
    }

    fn save<P: AsRef<Path>>(path: P) -> io::Result<Self::FSWrite> {
        if path.as_ref() == Path::new(CONFIG_PATH) {
            return Self::save_config()
        }
        let file = Arc::new(Mutex::new(Cursor::new(Vec::new())));
        if let Entry::Vacant(entry) = FILES.lock().unwrap().entry(path.as_ref().into()) {
            entry.insert(file.clone());
            Ok(MockFile::new(file))
        } else {
            Err(io::Error::new(io::ErrorKind::AlreadyExists, "File alredy exists!"))
        }
    }

    fn can_save<P: AsRef<Path>>(p: P) -> io::Result<()> {
        Ok(())
    }
}

impl<N: Unsigned> MockFilesystem<N> {
    pub fn open_config() -> io::Result<<MockFilesystem<N> as Filesystem>::FSRead> {
        if let Some(ref file) = CONFIG_FILES.lock().unwrap()[N::to_usize()] {
            Ok(MockFile::new(file.clone()))
        } else {
            Err(io::Error::new(io::ErrorKind::NotFound, "File not found!"))
        }
    }

    pub fn save_config() -> io::Result<<MockFilesystem<N> as Filesystem>::FSWrite> {
        let mut configs = CONFIG_FILES.lock().unwrap();
        if let Some(ref file) = configs[N::to_usize()] {
            return Ok(MockFile::new(file.clone()));
        }

        let file = Arc::new(Mutex::new(Cursor::new(Vec::new())));
        configs[N::to_usize()] = Some(file.clone());
        Ok(MockFile::new(file))
    }

    pub fn reset() {
        FILES.lock().unwrap().clear();
    }

    pub fn get_inner<'a, P: AsRef<Path>>(path: P) -> Vec<u8> {
        // This function is very ugly, in general we would like to "unwrap" the file from the
        // mock filesystem. Sadly, there doesn't seem to be a better way.
        let f = FILES.lock().unwrap().remove(path.as_ref()).unwrap();
        let a = Arc::try_unwrap(f).unwrap();
        let m = a.lock().unwrap();
        let v = m.clone();
        v.into_inner()
    }

    pub fn put<'a, P: AsRef<Path>>(path: P, v: Vec<u8>) {
        FILES.lock().unwrap().insert(path.as_ref().into(), Arc::new(Mutex::new(Cursor::new(v))));
    }
}
<|endoftext|>


<commit_before>use crate::memory::io::FifoChannel;

use super::Command;

pub struct GbaAudioSampler {
    native_frequency: u32,
    frequency: u32,
    fifo_a: f32,
    fifo_b: f32,
    wait_frames: u32,
}

impl GbaAudioSampler {
    pub fn new(native_frequency: u32) -> Self {
        assert!(native_frequency.is_power_of_two());
        GbaAudioSampler {
            native_frequency,
            frequency: 32768,
            fifo_a: 0.0,
            fifo_b: 0.0,
            wait_frames: 0,
        }
    }

    pub fn frame(&mut self) -> (f32, f32) {
        self.wait_frames = self.wait_frames.saturating_sub(1);
        (self.fifo_a, self.fifo_a)
    }

    fn wait_cycles(&mut self, cycles: u32) {
        const GBA_FREQ: u64 = 16 * 1024 * 1024;
        let wait_frames = (cycles as u64 * self.frequency as u64) / GBA_FREQ;
        self.wait_frames =
            ((wait_frames * self.native_frequency as u64) / self.frequency as u64) as u32;
    }

    pub fn command(&mut self, command: Command) {
        match command {
            Command::Wait(cycles) if cycles != 0 => self.wait_cycles(cycles),
            Command::Wait(_) => { /* 0 cycles = NOP */ }
            Command::PlaySample(fifo, sample) => {
                const CONVERT: f32 = 1.0 / 128.0;
                let sample: f32 = (sample as f32 * CONVERT).clamp(-1.0, 1.0);
                if fifo == FifoChannel::A {
                    self.fifo_a = sample;
                } else {
                    self.fifo_b = sample;
                }
            }
            Command::SetResolution(resolution) => {
                self.frequency = resolution.frequency();
                log::debug!("sampler frequency changed to {}", self.frequency);
            }
        }
    }

    pub fn needs_commands(&self) -> bool {
        self.wait_frames == 0
    }
}
<commit_msg>More accurate timing for sample output.<commit_after>use crate::memory::io::FifoChannel;

use super::Command;

pub struct GbaAudioSampler {
    native_frequency: f64,
    fifo_a: f32,
    fifo_b: f32,
    wait_frames: f64,
}

impl GbaAudioSampler {
    pub fn new(native_frequency: u32) -> Self {
        // assert!(native_frequency.is_power_of_two());
        GbaAudioSampler {
            native_frequency: native_frequency as f64,
            fifo_a: 0.0,
            fifo_b: 0.0,
            wait_frames: 0.0,
        }
    }

    pub fn frame(&mut self) -> (f32, f32) {
        if self.wait_frames >= 0.0 {
            self.wait_frames -= 1.0;
        }
        (self.fifo_a, self.fifo_a)
    }

    fn wait_cycles(&mut self, cycles: u32) {
        const GBA_FREQ: f64 = 1.0 / (16.0 * 1024.0 * 1024.0);
        self.wait_frames += (cycles as f64 * self.native_frequency) * GBA_FREQ;
    }

    pub fn command(&mut self, command: Command) {
        match command {
            Command::Wait(cycles) if cycles != 0 => self.wait_cycles(cycles),
            Command::Wait(_) => { /* 0 cycles = NOP */ }
            Command::PlaySample(fifo, sample) => {
                const CONVERT: f32 = 1.0 / 128.0;
                let sample: f32 = (sample as f32 * CONVERT).clamp(-1.0, 1.0);
                if fifo == FifoChannel::A {
                    self.fifo_a = sample;
                } else {
                    self.fifo_b = sample;
                }
            }
            Command::SetResolution(resolution) => {
                // FIXME: This is currently ignored. Should it continue to be this way?
                log::debug!("GBA frequency changed to {}", resolution.frequency());
            }
        }
    }

    pub fn needs_commands(&self) -> bool {
        self.wait_frames <= 1.0
    }
}
<|endoftext|>


<commit_before>use spin::{Mutex, MutexGuard};
use super::{Address, Allocator, AllocErr, Layout};

extern crate params;

use self::params::InitParams;

use core::ops::{Deref, DerefMut};
use core::ptr::Unique;
#[cfg(feature = "bump_ptr")]
use bump_ptr::BumpPtr;

#[cfg(feature = "buddy")]
use buddy::Heap as BuddyHeap;
#[cfg(all(feature = "bump_ptr", feature="buddy"))]
pub enum Tier<'a> {
    Uninitialized
    , Bump(BumpPtr)
    , Buddy(BuddyHeap<'a>)
}
#[cfg(all(feature = "bump_ptr", feature="buddy"))]
impl Deref for Tier<'static> {
    type Target = Allocator + 'static ;
    fn deref(&self) -> &Self::Target{
        match self {
            &Tier::Bump(ref alloc) => alloc
          , &Tier::Buddy(ref alloc) => alloc
          , _ => panic!("no allocator!")
        }
    }
}

#[cfg(all(feature = "bump_ptr", feature="buddy"))]
unsafe impl<'a> Allocator for Tier<'a> {
    #[inline(always)]
    unsafe fn alloc(&mut self, layout: Layout) -> Result<Address, AllocErr> {
        match *self {
            Tier::Bump(ref mut alloc) => alloc.alloc(layout)
          , Tier::Buddy(ref mut alloc) => alloc.alloc(layout)
          , _ => Err(AllocErr::Unsupported {
                    details: "System allocator uninitialized!"
                })
        }
    }

    #[inline(always)]
    unsafe fn dealloc(&mut self, ptr: Address, layout: Layout) {
        match *self {
            Tier::Bump(ref mut alloc) => alloc.dealloc(ptr, layout)
          , Tier::Buddy(ref mut alloc) => alloc.dealloc(ptr, layout)
          , _ =>  {
              // just leak it? not sure if we should panic here...
          }
        }
    }

}

pub type SystemAllocator = Mutex<Tier<'static>>;

/// A borrowed handle on a heap allocation with a specified lifetime.
///
/// This automatically deallocates the allocated object when the borrow's
/// lifetime ends. It also ensures that the borrow only lives as long as the
/// allocator that provided it, and that the borrow is dropped if the allocator
/// is dropped.
// TODO: can this allocate pointers to _objects_ rather than `*mut u8`s?
//       - eliza, 1/23/2017
pub struct BorrowedPtr<'a, A>
where A: Allocator
    , A: 'a {
    ptr: Unique<u8>
  , layout: Layout
  , allocator: &'a Mutex
}

impl<'a, A> Deref for BorrowedPtr<'a, A>
where A: Allocator
    , A: 'a {
    type Target = *mut u8;
    fn deref(&self) ->  &Self::Target { &(*self.ptr) }
}
//
// impl<'a, A> ops::DerefMut for BorrowedPtr<'a, A>
// where A: Allocator
//     , A: 'a {
//     fn deref_mut(&mut self) ->  &mut Self::Target { &mut self.frame }
// }

impl<'a, A> Drop for BorrowedPtr<'a, A>
where A: Allocator
    , A: 'a {
    fn drop(&mut self) {
        unsafe {
            self.allocator.lock().dealloc(*self.ptr, self.layout.clone())
        }
    }
}

/// A borrowed handle on a heap allocation with a specified lifetime.
///
/// This automatically deallocates the allocated object when the borrow's
/// lifetime ends. It also ensures that the borrow only lives as long as the
/// allocator that provided it, and that the borrow is dropped if the allocator
/// is dropped.
pub struct Borrowed<'a, A, T>
where A: Allocator
    , A: 'a {
    value: Unique<T>
  , allocator: &'a Mutex
}

impl<'a, A, T> Deref for Borrowed<'a, A, T>
where A: Allocator
    , A: 'a {
    type Target = T;
    fn deref(&self) ->  &Self::Target { unsafe { self.value.get() } }
}

impl<'a, A, T> DerefMut for Borrowed<'a, A, T>
where A: Allocator
    , A: 'a {
    fn deref_mut(&mut self) ->  &mut Self::Target {
        unsafe { self.value.get_mut() }
    }
}

impl<'a, A, T> Drop for Borrowed<'a, A, T>
where A: Allocator
    , A: 'a {
    fn drop(&mut self) {
        unsafe {
            self.allocator.lock()
                .dealloc( *self.value as *mut u8
                        , Layout::for_value(self.value.get()))
        }
    }
}
<commit_msg>[alloc] refactor alloc::system module<commit_after>use spin::Mutex;
use super::{Address, Allocator, AllocErr, Layout};

extern crate params;

use self::params::InitParams;

use core::ops::{Deref, DerefMut};
use core::ptr::Unique;
#[cfg(feature = "bump_ptr")]
use bump_ptr::BumpPtr;

#[cfg(feature = "buddy")]
use buddy::Heap as BuddyHeap;

pub enum Tier<'a> {
    Uninitialized
    , #[cfg(feature = "bump_ptr")]
      Bump(BumpPtr)
    , #[cfg(feature = "buddy")]
      Buddy(BuddyHeap<'a>)
}
#[cfg(all(feature = "bump_ptr", feature="buddy"))]
impl Deref for Tier<'static> {
    type Target = Allocator + 'static ;
    fn deref(&self) -> &Self::Target{
        match self {
            &Tier::Bump(ref alloc) => alloc
          , &Tier::Buddy(ref alloc) => alloc
          , _ => panic!("no allocator!")
        }
    }
}

#[cfg(all(feature = "bump_ptr", feature = "buddy"))]
unsafe impl<'a> Allocator for Tier<'a> {
    #[inline(always)]
    unsafe fn alloc(&mut self, layout: Layout) -> Result<Address, AllocErr> {
        match *self {
            Tier::Bump(ref mut alloc) => alloc.alloc(layout)
          , Tier::Buddy(ref mut alloc) => alloc.alloc(layout)
          , _ => Err(AllocErr::Unsupported {
                    details: "System allocator uninitialized!"
                })
        }
    }

    #[inline(always)]
    unsafe fn dealloc(&mut self, ptr: Address, layout: Layout) {
        match *self {
            Tier::Bump(ref mut alloc) => alloc.dealloc(ptr, layout)
          , Tier::Buddy(ref mut alloc) => alloc.dealloc(ptr, layout)
          , _ =>  {
              // just leak it? not sure if we should panic here...
          }
        }
    }

}

pub type SystemAllocator = Mutex<Tier<'static>>;

/// A borrowed handle on a heap allocation with a specified lifetime.
///
/// This automatically deallocates the allocated object when the borrow's
/// lifetime ends. It also ensures that the borrow only lives as long as the
/// allocator that provided it, and that the borrow is dropped if the allocator
/// is dropped.
// TODO: can this allocate pointers to _objects_ rather than `*mut u8`s?
//       - eliza, 1/23/2017
pub struct BorrowedPtr<'a, A>
where A: Allocator
    , A: 'a {
    ptr: Unique<u8>
  , layout: Layout
  , allocator: &'a Mutex
}

impl<'a, A> Deref for BorrowedPtr<'a, A>
where A: Allocator
    , A: 'a {
    type Target = *mut u8;
    fn deref(&self) ->  &Self::Target { &(*self.ptr) }
}
//
// impl<'a, A> ops::DerefMut for BorrowedPtr<'a, A>
// where A: Allocator
//     , A: 'a {
//     fn deref_mut(&mut self) ->  &mut Self::Target { &mut self.frame }
// }

impl<'a, A> Drop for BorrowedPtr<'a, A>
where A: Allocator
    , A: 'a {
    fn drop(&mut self) {
        unsafe {
            self.allocator.lock().dealloc(*self.ptr, self.layout.clone())
        }
    }
}

/// A borrowed handle on a heap allocation with a specified lifetime.
///
/// This automatically deallocates the allocated object when the borrow's
/// lifetime ends. It also ensures that the borrow only lives as long as the
/// allocator that provided it, and that the borrow is dropped if the allocator
/// is dropped.
pub struct Borrowed<'a, A, T>
where A: Allocator
    , A: 'a {
    value: Unique<T>
  , allocator: &'a Mutex
}

impl<'a, A, T> Deref for Borrowed<'a, A, T>
where A: Allocator
    , A: 'a {
    type Target = T;
    fn deref(&self) ->  &Self::Target { unsafe { self.value.get() } }
}

impl<'a, A, T> DerefMut for Borrowed<'a, A, T>
where A: Allocator
    , A: 'a {
    fn deref_mut(&mut self) ->  &mut Self::Target {
        unsafe { self.value.get_mut() }
    }
}

impl<'a, A, T> Drop for Borrowed<'a, A, T>
where A: Allocator
    , A: 'a {
    fn drop(&mut self) {
        unsafe {
            self.allocator.lock()
                .dealloc( *self.value as *mut u8
                        , Layout::for_value(self.value.get()))
        }
    }
}
<|endoftext|>


<commit_before>use std::{
    sync::{
        atomic::{AtomicBool, AtomicUsize, Ordering},
        Arc,
    },
    thread,
};

use rand::{thread_rng, Rng};

#[cfg_attr(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        feature = "jemalloc",
    ),
    global_allocator
)]
#[cfg(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        feature = "jemalloc",
    ),
)]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

static TOTAL: AtomicUsize = AtomicUsize::new(0);
static SEQ: AtomicUsize = AtomicUsize::new(0);

const USAGE: &str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] \
    [--key-len=<l>] [--val-len=<l>] \
    [--get-prop=<p>] \
    [--set-prop=<p>] \
    [--del-prop=<p>] \
    [--cas-prop=<p>] \
    [--scan-prop=<p>] \
    [--merge-prop=<p>] \
    [--entries=<n>] \
    [--sequential] \
    [--total-ops=<n>] \
    [--flush-every=<ms>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --key-len=<l>      The length of keys [default: 10].
    --val-len=<l>      The length of values [default: 100].
    --get-prop=<p>     The relative proportion of get requests [default: 94].
    --set-prop=<p>     The relative proportion of set requests [default: 2].
    --del-prop=<p>     The relative proportion of del requests [default: 1].
    --cas-prop=<p>     The relative proportion of cas requests [default: 1].
    --scan-prop=<p>    The relative proportion of scan requests [default: 1].
    --merge-prop=<p>   The relative proportion of merge requests [default: 1].
    --entries=<n>      The total keyspace [default: 100000].
    --sequential       Run the test in sequential mode instead of random.
    --total-ops=<n>    Stop test after executing a total number of operations.
    --flush-every=<m>  Flush and sync the database every ms [default: 200].
";

#[derive(Clone, Copy)]
struct Args {
    threads: usize,
    burn_in: bool,
    duration: u64,
    key_len: usize,
    val_len: usize,
    get_prop: usize,
    set_prop: usize,
    del_prop: usize,
    cas_prop: usize,
    scan_prop: usize,
    merge_prop: usize,
    entries: usize,
    sequential: bool,
    total_ops: Option<usize>,
    flush_every: u64,
}

impl Default for Args {
    fn default() -> Args {
        Args {
            threads: 4,
            burn_in: false,
            duration: 10,
            key_len: 10,
            val_len: 100,
            get_prop: 94,
            set_prop: 2,
            del_prop: 1,
            cas_prop: 1,
            scan_prop: 1,
            merge_prop: 1,
            entries: 100000,
            sequential: false,
            total_ops: None,
            flush_every: 200,
        }
    }
}

fn parse<'a, I, T>(mut iter: I) -> T
where
    I: Iterator<Item = &'a str>,
    T: std::str::FromStr,
    <T as std::str::FromStr>::Err: std::fmt::Debug,
{
    iter.next().expect(USAGE).parse().expect(USAGE)
}

impl Args {
    fn parse() -> Args {
        let mut args = Args::default();
        for raw_arg in std::env::args().skip(1) {
            let mut splits = raw_arg[2..].split('=');
            match splits.next().unwrap() {
                "threads" => args.threads = parse(&mut splits),
                "burn-in" => args.burn_in = true,
                "duration" => args.duration = parse(&mut splits),
                "key-len" => args.key_len = parse(&mut splits),
                "val-len" => args.val_len = parse(&mut splits),
                "get-prop" => args.get_prop = parse(&mut splits),
                "set-prop" => args.set_prop = parse(&mut splits),
                "del-prop" => args.del_prop = parse(&mut splits),
                "cas-prop" => args.cas_prop = parse(&mut splits),
                "scan-prop" => args.scan_prop = parse(&mut splits),
                "merge-prop" => args.merge_prop = parse(&mut splits),
                "entries" => args.entries = parse(&mut splits),
                "sequential" => args.sequential = true,
                "total-ops" => args.total_ops = Some(parse(&mut splits)),
                "flush-every" => args.flush_every = parse(&mut splits),
                other => panic!("unknown option: {}, {}", other, USAGE),
            }
        }
        args
    }
}

fn report(shutdown: Arc<AtomicBool>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = TOTAL.load(Ordering::Acquire);

        println!("did {} ops, {}mb RSS", total - last, rss() / (1024 * 1024));

        last = total;
    }
}

fn concatenate_merge(
    _key: &[u8],              // the key being merged
    old_value: Option<&[u8]>, // the previous value, if one existed
    merged_bytes: &[u8],      // the new bytes being merged in
) -> Option<Vec<u8>> {
    // set the new value, return None to delete
    let mut ret = old_value.map(|ov| ov.to_vec()).unwrap_or_else(|| vec![]);

    ret.extend_from_slice(merged_bytes);

    Some(ret)
}

fn run(args: Args, tree: Arc<sled::Db>, shutdown: Arc<AtomicBool>) {
    let get_max = args.get_prop;
    let set_max = get_max + args.set_prop;
    let del_max = set_max + args.del_prop;
    let cas_max = del_max + args.cas_prop;
    let merge_max = cas_max + args.merge_prop;
    let scan_max = merge_max + args.scan_prop;

    let keygen = |len| -> sled::IVec {
        let i = if args.sequential {
            SEQ.fetch_add(1, Ordering::Relaxed)
        } else {
            thread_rng().gen::<usize>()
        } % args.entries;

        let i_keygen = i.to_be_bytes();

        i_keygen
            .iter()
            .skip_while(|v| **v == 0)
            .cycle()
            .take(len)
            .copied()
            .collect()
    };

    let valgen = |len| -> sled::IVec {
        let i: usize = thread_rng().gen::<usize>() % len;

        let i_keygen = i.to_be_bytes();

        i_keygen
            .iter()
            .skip_while(|v| **v == 0)
            .cycle()
            .take(len)
            .copied()
            .collect()
    };

    let mut rng = thread_rng();

    while !shutdown.load(Ordering::Relaxed) {
        let op = TOTAL.fetch_add(1, Ordering::Release);
        let key = keygen(args.key_len);
        let choice = rng.gen_range(0, scan_max + 1);

        match choice {
            v if v <= get_max => {
                tree.get(&key).unwrap();
            }
            v if v > get_max && v <= set_max => {
                let value = valgen(args.val_len);
                tree.insert(&key, value).unwrap();
            }
            v if v > set_max && v <= del_max => {
                tree.remove(&key).unwrap();
            }
            v if v > del_max && v <= cas_max => {
                let old = if rng.gen::<bool>() {
                    let value = valgen(args.val_len);
                    Some(value)
                } else {
                    None
                };

                let new = if rng.gen::<bool>() {
                    let value = valgen(args.val_len);
                    Some(value)
                } else {
                    None
                };

                if let Err(e) = tree.compare_and_swap(&key, old, new) {
                    panic!("operational error: {:?}", e);
                }
            }
            v if v > cas_max && v <= merge_max => {
                let value = valgen(args.val_len);
                tree.merge(&key, value).unwrap();
            }
            _ => {
                let iter = tree.range(key..).map(|res| res.unwrap());

                if op % 2 == 0 {
                    let _ = iter.take(rng.gen_range(0, 15)).collect::<Vec<_>>();
                } else {
                    let _ = iter
                        .rev()
                        .take(rng.gen_range(0, 15))
                        .collect::<Vec<_>>();
                }
            }
        }
    }
}

fn rss() -> usize {
    #[cfg(target_os = "linux")]
    {
        use std::io::prelude::*;
        use std::io::BufReader;

        let mut buf = String::new();
        let mut f =
            BufReader::new(std::fs::File::open("/proc/self/statm").unwrap());
        f.read_line(&mut buf).unwrap();
        let mut parts = buf.split_whitespace();
        let rss_pages = parts.nth(1).unwrap().parse::<usize>().unwrap();
        rss_pages * 4096
    }
    #[cfg(not(target_os = "linux"))]
    {
        0
    }
}

fn main() {
    #[cfg(feature = "logging")]
    setup_logger();

    let args = Args::parse();

    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::Config::new()
        .cache_capacity(256 * 1024 * 1024)
        .flush_every_ms(Some(args.flush_every))
        .print_profile_on_drop(true);

    let tree = Arc::new(config.open().unwrap());
    tree.set_merge_operator(concatenate_merge);

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.threads;

    for i in 0..=n_threads {
        let tree = tree.clone();
        let shutdown = shutdown.clone();

        let t = if i == 0 {
            thread::Builder::new()
                .name("reporter".into())
                .spawn(move || report(shutdown))
                .unwrap()
        } else {
            let args = args.clone();
            thread::spawn(move || run(args, tree, shutdown))
        };

        threads.push(t);
    }

    if let Some(ops) = args.total_ops {
        assert!(!args.burn_in, "don't set both --burn-in and --total-ops");
        while TOTAL.load(Ordering::Relaxed) < ops {
            thread::sleep(std::time::Duration::from_millis(50));
        }
        shutdown.store(true, Ordering::SeqCst);
    } else if !args.burn_in {
        thread::sleep(std::time::Duration::from_secs(args.duration));
        shutdown.store(true, Ordering::SeqCst);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = TOTAL.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}

#[cfg(feature = "logging")]
pub fn setup_logger() {
    use std::io::Write;

    color_backtrace::install();

    fn tn() -> String {
        std::thread::current().name().unwrap_or("unknown").to_owned()
    }

    let mut builder = env_logger::Builder::new();
    builder
        .format(|buf, record| {
            writeln!(
                buf,
                "{:05} {:25} {:10} {}",
                record.level(),
                tn(),
                record.module_path().unwrap().split("::").last().unwrap(),
                record.args()
            )
        })
        .filter(None, log::LevelFilter::Info);

    if let Ok(env_var) = std::env::var("RUST_LOG") {
        builder.parse(env_var);
    }

    let _r = builder.try_init();
}
<commit_msg>Fix stress2 issue with small values<commit_after>use std::{
    sync::{
        atomic::{AtomicBool, AtomicUsize, Ordering},
        Arc,
    },
    thread,
};

use rand::{thread_rng, Rng};

#[cfg_attr(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        feature = "jemalloc",
    ),
    global_allocator
)]
#[cfg(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        feature = "jemalloc",
    ),
)]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

static TOTAL: AtomicUsize = AtomicUsize::new(0);
static SEQ: AtomicUsize = AtomicUsize::new(0);

const USAGE: &str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] \
    [--key-len=<l>] [--val-len=<l>] \
    [--get-prop=<p>] \
    [--set-prop=<p>] \
    [--del-prop=<p>] \
    [--cas-prop=<p>] \
    [--scan-prop=<p>] \
    [--merge-prop=<p>] \
    [--entries=<n>] \
    [--sequential] \
    [--total-ops=<n>] \
    [--flush-every=<ms>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --key-len=<l>      The length of keys [default: 10].
    --val-len=<l>      The length of values [default: 100].
    --get-prop=<p>     The relative proportion of get requests [default: 94].
    --set-prop=<p>     The relative proportion of set requests [default: 2].
    --del-prop=<p>     The relative proportion of del requests [default: 1].
    --cas-prop=<p>     The relative proportion of cas requests [default: 1].
    --scan-prop=<p>    The relative proportion of scan requests [default: 1].
    --merge-prop=<p>   The relative proportion of merge requests [default: 1].
    --entries=<n>      The total keyspace [default: 100000].
    --sequential       Run the test in sequential mode instead of random.
    --total-ops=<n>    Stop test after executing a total number of operations.
    --flush-every=<m>  Flush and sync the database every ms [default: 200].
";

#[derive(Clone, Copy)]
struct Args {
    threads: usize,
    burn_in: bool,
    duration: u64,
    key_len: usize,
    val_len: usize,
    get_prop: usize,
    set_prop: usize,
    del_prop: usize,
    cas_prop: usize,
    scan_prop: usize,
    merge_prop: usize,
    entries: usize,
    sequential: bool,
    total_ops: Option<usize>,
    flush_every: u64,
}

impl Default for Args {
    fn default() -> Args {
        Args {
            threads: 4,
            burn_in: false,
            duration: 10,
            key_len: 10,
            val_len: 100,
            get_prop: 94,
            set_prop: 2,
            del_prop: 1,
            cas_prop: 1,
            scan_prop: 1,
            merge_prop: 1,
            entries: 100000,
            sequential: false,
            total_ops: None,
            flush_every: 200,
        }
    }
}

fn parse<'a, I, T>(mut iter: I) -> T
where
    I: Iterator<Item = &'a str>,
    T: std::str::FromStr,
    <T as std::str::FromStr>::Err: std::fmt::Debug,
{
    iter.next().expect(USAGE).parse().expect(USAGE)
}

impl Args {
    fn parse() -> Args {
        let mut args = Args::default();
        for raw_arg in std::env::args().skip(1) {
            let mut splits = raw_arg[2..].split('=');
            match splits.next().unwrap() {
                "threads" => args.threads = parse(&mut splits),
                "burn-in" => args.burn_in = true,
                "duration" => args.duration = parse(&mut splits),
                "key-len" => args.key_len = parse(&mut splits),
                "val-len" => args.val_len = parse(&mut splits),
                "get-prop" => args.get_prop = parse(&mut splits),
                "set-prop" => args.set_prop = parse(&mut splits),
                "del-prop" => args.del_prop = parse(&mut splits),
                "cas-prop" => args.cas_prop = parse(&mut splits),
                "scan-prop" => args.scan_prop = parse(&mut splits),
                "merge-prop" => args.merge_prop = parse(&mut splits),
                "entries" => args.entries = parse(&mut splits),
                "sequential" => args.sequential = true,
                "total-ops" => args.total_ops = Some(parse(&mut splits)),
                "flush-every" => args.flush_every = parse(&mut splits),
                other => panic!("unknown option: {}, {}", other, USAGE),
            }
        }
        args
    }
}

fn report(shutdown: Arc<AtomicBool>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = TOTAL.load(Ordering::Acquire);

        println!("did {} ops, {}mb RSS", total - last, rss() / (1024 * 1024));

        last = total;
    }
}

fn concatenate_merge(
    _key: &[u8],              // the key being merged
    old_value: Option<&[u8]>, // the previous value, if one existed
    merged_bytes: &[u8],      // the new bytes being merged in
) -> Option<Vec<u8>> {
    // set the new value, return None to delete
    let mut ret = old_value.map(|ov| ov.to_vec()).unwrap_or_else(|| vec![]);

    ret.extend_from_slice(merged_bytes);

    Some(ret)
}

fn run(args: Args, tree: Arc<sled::Db>, shutdown: Arc<AtomicBool>) {
    let get_max = args.get_prop;
    let set_max = get_max + args.set_prop;
    let del_max = set_max + args.del_prop;
    let cas_max = del_max + args.cas_prop;
    let merge_max = cas_max + args.merge_prop;
    let scan_max = merge_max + args.scan_prop;

    let keygen = |len| -> sled::IVec {
        let i = if args.sequential {
            SEQ.fetch_add(1, Ordering::Relaxed)
        } else {
            thread_rng().gen::<usize>()
        } % args.entries;

        let i_keygen = i.to_be_bytes();

        i_keygen
            .iter()
            .skip_while(|v| **v == 0)
            .cycle()
            .take(len)
            .copied()
            .collect()
    };

    let valgen = |len| -> sled::IVec {
        if len == 0 {
            return vec![].into();
        }

        let i: usize = thread_rng().gen::<usize>() % (len * 8);

        let i_keygen = i.to_be_bytes();

        i_keygen
            .iter()
            .skip_while(|v| **v == 0)
            .cycle()
            .take(len)
            .copied()
            .collect()
    };

    let mut rng = thread_rng();

    while !shutdown.load(Ordering::Relaxed) {
        let op = TOTAL.fetch_add(1, Ordering::Release);
        let key = keygen(args.key_len);
        let choice = rng.gen_range(0, scan_max + 1);

        match choice {
            v if v <= get_max => {
                tree.get(&key).unwrap();
            }
            v if v > get_max && v <= set_max => {
                let value = valgen(args.val_len);
                tree.insert(&key, value).unwrap();
            }
            v if v > set_max && v <= del_max => {
                tree.remove(&key).unwrap();
            }
            v if v > del_max && v <= cas_max => {
                let old = if rng.gen::<bool>() {
                    let value = valgen(args.val_len);
                    Some(value)
                } else {
                    None
                };

                let new = if rng.gen::<bool>() {
                    let value = valgen(args.val_len);
                    Some(value)
                } else {
                    None
                };

                if let Err(e) = tree.compare_and_swap(&key, old, new) {
                    panic!("operational error: {:?}", e);
                }
            }
            v if v > cas_max && v <= merge_max => {
                let value = valgen(args.val_len);
                tree.merge(&key, value).unwrap();
            }
            _ => {
                let iter = tree.range(key..).map(|res| res.unwrap());

                if op % 2 == 0 {
                    let _ = iter.take(rng.gen_range(0, 15)).collect::<Vec<_>>();
                } else {
                    let _ = iter
                        .rev()
                        .take(rng.gen_range(0, 15))
                        .collect::<Vec<_>>();
                }
            }
        }
    }
}

fn rss() -> usize {
    #[cfg(target_os = "linux")]
    {
        use std::io::prelude::*;
        use std::io::BufReader;

        let mut buf = String::new();
        let mut f =
            BufReader::new(std::fs::File::open("/proc/self/statm").unwrap());
        f.read_line(&mut buf).unwrap();
        let mut parts = buf.split_whitespace();
        let rss_pages = parts.nth(1).unwrap().parse::<usize>().unwrap();
        rss_pages * 4096
    }
    #[cfg(not(target_os = "linux"))]
    {
        0
    }
}

fn main() {
    #[cfg(feature = "logging")]
    setup_logger();

    let args = Args::parse();

    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::Config::new()
        .cache_capacity(256 * 1024 * 1024)
        .flush_every_ms(Some(args.flush_every))
        .print_profile_on_drop(true);

    let tree = Arc::new(config.open().unwrap());
    tree.set_merge_operator(concatenate_merge);

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.threads;

    for i in 0..=n_threads {
        let tree = tree.clone();
        let shutdown = shutdown.clone();

        let t = if i == 0 {
            thread::Builder::new()
                .name("reporter".into())
                .spawn(move || report(shutdown))
                .unwrap()
        } else {
            let args = args.clone();
            thread::spawn(move || run(args, tree, shutdown))
        };

        threads.push(t);
    }

    if let Some(ops) = args.total_ops {
        assert!(!args.burn_in, "don't set both --burn-in and --total-ops");
        while TOTAL.load(Ordering::Relaxed) < ops {
            thread::sleep(std::time::Duration::from_millis(50));
        }
        shutdown.store(true, Ordering::SeqCst);
    } else if !args.burn_in {
        thread::sleep(std::time::Duration::from_secs(args.duration));
        shutdown.store(true, Ordering::SeqCst);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = TOTAL.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}

#[cfg(feature = "logging")]
pub fn setup_logger() {
    use std::io::Write;

    color_backtrace::install();

    fn tn() -> String {
        std::thread::current().name().unwrap_or("unknown").to_owned()
    }

    let mut builder = env_logger::Builder::new();
    builder
        .format(|buf, record| {
            writeln!(
                buf,
                "{:05} {:25} {:10} {}",
                record.level(),
                tn(),
                record.module_path().unwrap().split("::").last().unwrap(),
                record.args()
            )
        })
        .filter(None, log::LevelFilter::Info);

    if let Ok(env_var) = std::env::var("RUST_LOG") {
        builder.parse(env_var);
    }

    let _r = builder.try_init();
}
<|endoftext|>


<commit_before><commit_msg>Redefine so that into_pattern works on vecs<commit_after><|endoftext|>


<commit_before><commit_msg>ref: Allow upload-dif to follow symlinks to make it inline with difutil behavior (#948)<commit_after><|endoftext|>


<commit_before>
//! This temporary module generates types that wrap around the old API (winit v5 and below) and
//! expose the new API (winit v6 and above).
//!
//! This is temporary so that existing backends can smoothly transition. After all implementations
//! have finished transitionning, this module should disappear.

macro_rules! gen_api_transition {
    () => {
        pub struct EventsLoop {
            windows: ::std::sync::Arc<::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>>,
            awakened: ::std::sync::Arc<::std::sync::atomic::AtomicBool>,
        }

        pub struct EventsLoopProxy {
            awakened: ::std::sync::Weak<::std::sync::atomic::AtomicBool>,
        }

        impl EventsLoop {
            pub fn new() -> EventsLoop {
                EventsLoop {
                    windows: ::std::sync::Arc::new(::std::sync::Mutex::new(vec![])),
                    awakened: ::std::sync::Arc::new(::std::sync::atomic::AtomicBool::new(false)),
                }
            }

            pub fn poll_events<F>(&mut self, mut callback: F)
                where F: FnMut(::Event)
            {
                if self.awakened.load(::std::sync::atomic::Ordering::Relaxed) {
                    self.awakened.store(false, ::std::sync::atomic::Ordering::Relaxed);
                    callback(::Event::Awakened);
                }

                let mut windows = self.windows.lock().unwrap();
                for window in windows.iter() {
                    for event in window.poll_events() {
                        callback(::Event::WindowEvent {
                            window_id: ::WindowId(WindowId(&**window as *const Window as usize)),
                            event: event,
                        })
                    }
                }
            }

            pub fn run_forever<F>(&mut self, mut callback: F)
                where F: FnMut(::Event) -> ControlFlow,
            {
                self.awakened.store(false, ::std::sync::atomic::Ordering::Relaxed);

                // Yeah that's a very bad implementation.
                loop {
                    let mut control_flow = ::ControlFlow::Continue;
                    self.poll_events(|e| {
                        if let ::ControlFlow::Complete = callback(e) {
                            control_flow = ::ControlFlow::Complete;
                        }
                    });
                    if let ::ControlFlow::Complete = control_flow {
                        break;
                    }
                    ::std::thread::sleep_ms(5);
                }
            }

            pub fn create_proxy(&self) -> EventsLoopProxy {
                EventsLoopProxy {
                    awakened: ::std::sync::Arc::downgrade(&self.awakened),
                }
            }
        }

        impl EventsLoopProxy {
            pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> {
                match self.awakened.upgrade() {
                    None => Err(::EventsLoopClosed),
                    Some(awakened) => {
                        awakened.store(true, ::std::sync::atomic::Ordering::Relaxed);
                        Ok(())
                    },
                }
            }
        }

        #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct WindowId(usize);

        #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct DeviceId;

        pub struct Window2 {
            pub window: ::std::sync::Arc<Window>,
            windows: ::std::sync::Weak<::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>>
        }

        impl ::std::ops::Deref for Window2 {
            type Target = Window;
            #[inline]
            fn deref(&self) -> &Window {
                &*self.window
            }
        }

        impl Window2 {
            pub fn new(events_loop: &EventsLoop,
                       window: &::WindowAttributes,
                       pl_attribs: &PlatformSpecificWindowBuilderAttributes)
                       -> Result<Window2, CreationError>
            {
                let win = ::std::sync::Arc::new(try!(Window::new(window, pl_attribs)));
                events_loop.windows.lock().unwrap().push(win.clone());
                Ok(Window2 {
                    window: win,
                    events_loop: ::std::sync::Arc::downgrade(&events_loop.windows),
                })
            }

            #[inline]
            pub fn id(&self) -> WindowId {
                WindowId(&*self.window as *const Window as usize)
            }
        }

        impl Drop for Window2 {
            fn drop(&mut self) {
                if let Some(windows) = self.windows.upgrade() {
                    let mut windows = windows.lock().unwrap();
                    windows.retain(|w| &**w as *const Window != &*self.window as *const _);
                }
            }
        }
    };
}
<commit_msg>Fix api_transition ControlFlow update compile errors<commit_after>
//! This temporary module generates types that wrap around the old API (winit v5 and below) and
//! expose the new API (winit v6 and above).
//!
//! This is temporary so that existing backends can smoothly transition. After all implementations
//! have finished transitionning, this module should disappear.

macro_rules! gen_api_transition {
    () => {
        pub struct EventsLoop {
            windows: ::std::sync::Arc<::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>>,
            awakened: ::std::sync::Arc<::std::sync::atomic::AtomicBool>,
        }

        pub struct EventsLoopProxy {
            awakened: ::std::sync::Weak<::std::sync::atomic::AtomicBool>,
        }

        impl EventsLoop {
            pub fn new() -> EventsLoop {
                EventsLoop {
                    windows: ::std::sync::Arc::new(::std::sync::Mutex::new(vec![])),
                    awakened: ::std::sync::Arc::new(::std::sync::atomic::AtomicBool::new(false)),
                }
            }

            pub fn poll_events<F>(&mut self, mut callback: F)
                where F: FnMut(::Event)
            {
                if self.awakened.load(::std::sync::atomic::Ordering::Relaxed) {
                    self.awakened.store(false, ::std::sync::atomic::Ordering::Relaxed);
                    callback(::Event::Awakened);
                }

                let windows = self.windows.lock().unwrap();
                for window in windows.iter() {
                    for event in window.poll_events() {
                        callback(::Event::WindowEvent {
                            window_id: ::WindowId(WindowId(&**window as *const Window as usize)),
                            event: event,
                        })
                    }
                }
            }

            pub fn run_forever<F>(&mut self, mut callback: F)
                where F: FnMut(::Event) -> ::ControlFlow,
            {
                self.awakened.store(false, ::std::sync::atomic::Ordering::Relaxed);

                // Yeah that's a very bad implementation.
                loop {
                    let mut control_flow = ::ControlFlow::Continue;
                    self.poll_events(|e| {
                        if let ::ControlFlow::Complete = callback(e) {
                            control_flow = ::ControlFlow::Complete;
                        }
                    });
                    if let ::ControlFlow::Complete = control_flow {
                        break;
                    }
                    ::std::thread::sleep(::std::time::Duration::from_millis(5));
                }
            }

            pub fn create_proxy(&self) -> EventsLoopProxy {
                EventsLoopProxy {
                    awakened: ::std::sync::Arc::downgrade(&self.awakened),
                }
            }
        }

        impl EventsLoopProxy {
            pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> {
                match self.awakened.upgrade() {
                    None => Err(::EventsLoopClosed),
                    Some(awakened) => {
                        awakened.store(true, ::std::sync::atomic::Ordering::Relaxed);
                        Ok(())
                    },
                }
            }
        }

        #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct WindowId(usize);

        #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct DeviceId;

        pub struct Window2 {
            pub window: ::std::sync::Arc<Window>,
            windows: ::std::sync::Weak<::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>>
        }

        impl ::std::ops::Deref for Window2 {
            type Target = Window;
            #[inline]
            fn deref(&self) -> &Window {
                &*self.window
            }
        }

        impl Window2 {
            pub fn new(events_loop: &EventsLoop,
                       window: &::WindowAttributes,
                       pl_attribs: &PlatformSpecificWindowBuilderAttributes)
                       -> Result<Window2, CreationError>
            {
                let win = ::std::sync::Arc::new(try!(Window::new(window, pl_attribs)));
                events_loop.windows.lock().unwrap().push(win.clone());
                Ok(Window2 {
                    window: win,
                    windows: ::std::sync::Arc::downgrade(&events_loop.windows),
                })
            }

            #[inline]
            pub fn id(&self) -> WindowId {
                WindowId(&*self.window as *const Window as usize)
            }
        }

        impl Drop for Window2 {
            fn drop(&mut self) {
                if let Some(windows) = self.windows.upgrade() {
                    let mut windows = windows.lock().unwrap();
                    windows.retain(|w| &**w as *const Window != &*self.window as *const _);
                }
            }
        }
    };
}
<|endoftext|>


<commit_before>use std::io::{self,ErrorKind,Read,Write};
use std::net::SocketAddr;
use mio::tcp::{TcpListener,TcpStream};
use rustls::{ServerSession, Session, ProtocolVersion};
use net2::TcpBuilder;
use net2::unix::UnixTcpBuilderExt;
#[cfg(feature = "use-openssl")]
use openssl::ssl::{ErrorCode, SslStream, SslVersion};

#[derive(Debug,PartialEq,Copy,Clone)]
pub enum SocketResult {
  Continue,
  Closed,
  WouldBlock,
  Error
}

#[derive(Debug,PartialEq,Copy,Clone)]
pub enum TransportProtocol {
  Tcp,
  Ssl2,
  Ssl3,
  Tls1_0,
  Tls1_1,
  Tls1_2,
  Tls1_3,
}

pub trait SocketHandler {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult);
  fn socket_write(&mut self, buf: &[u8])    -> (usize, SocketResult);
  fn socket_write_vectored(&mut self,  buf: &[&iovec::IoVec]) -> (usize, SocketResult) {
    unimplemented!()
  }
  fn has_vectored_writes(&self) -> bool { false }
  fn socket_ref(&self) -> &TcpStream;
  fn protocol(&self) -> TransportProtocol;
}

impl SocketHandler for TcpStream {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.read(&mut buf[size..]) {
        Ok(0)  => return (size, SocketResult::Closed),
        Ok(sz) => size +=sz,
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => return (size, SocketResult::WouldBlock),
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("tcp.read.error");
            return (size, SocketResult::Closed)
          },
          _ => {
            error!("SOCKET\tsocket_read error={:?}", e);
            incr!("tcp.read.error");
            return (size, SocketResult::Error)
          },
        }
      }
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.write(&buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size += sz,
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => return (size, SocketResult::WouldBlock),
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("tcp.write.error");
            return (size, SocketResult::Closed)
          },
          _ => {
            //FIXME: timeout and other common errors should be sent up
            error!("SOCKET\tsocket_write error={:?}", e);
            incr!("tcp.write.error");
            return (size, SocketResult::Error)
          },
        }
      }
    }
  }

  fn socket_write_vectored(&mut self,  bufs: &[&iovec::IoVec]) -> (usize, SocketResult) {
    match self.write_bufs(bufs) {
      Ok(0)  => return (0, SocketResult::Continue),
      Ok(sz) => return (sz, SocketResult::Continue),
      Err(e) => match e.kind() {
        ErrorKind::WouldBlock => return (0, SocketResult::WouldBlock),
        ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
          incr!("tcp.write.error");
          return (0, SocketResult::Closed)
        },
        _ => {
          //FIXME: timeout and other common errors should be sent up
          error!("SOCKET\tsocket_write error={:?}", e);
          incr!("tcp.write.error");
          return (0, SocketResult::Error)
        },
      }
    }
  }

  fn has_vectored_writes(&self) -> bool { true }

  fn socket_ref(&self) -> &TcpStream { self }

  fn protocol(&self) -> TransportProtocol {
    TransportProtocol::Tcp
  }
}

#[cfg(feature = "use-openssl")]
impl SocketHandler for SslStream<TcpStream> {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.ssl_read(&mut buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size += sz,
        Err(e) => {
          match e.code() {
            ErrorCode::WANT_READ  => return (size, SocketResult::WouldBlock),
            ErrorCode::WANT_WRITE => return (size, SocketResult::WouldBlock),
            ErrorCode::SSL        => {
              debug!("SOCKET-TLS\treadable TLS socket SSL error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::SYSCALL    => {
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::ZERO_RETURN => {
              incr!("openssl.read.error");
              return (size, SocketResult::Closed)
            },
            _ => {
              debug!("SOCKET-TLS\treadable TLS socket error={:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            }
          }
        }
      }
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.ssl_write(&buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size +=sz,
        Err(e) => {
          match e.code() {
            ErrorCode::WANT_READ  => return (size, SocketResult::WouldBlock),
            ErrorCode::WANT_WRITE => return (size, SocketResult::WouldBlock),
            ErrorCode::SSL        => {
              debug!("SOCKET-TLS\twritable TLS socket SSL error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::SYSCALL        => {
              debug!("SOCKET-TLS\twritable TLS socket syscall error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::ZERO_RETURN => {
              incr!("openssl.write.error");
              return (size, SocketResult::Closed)
            },
            _ => {
              debug!("SOCKET-TLS\twritable TLS socket error={:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            }
          }
        }
      }
    }
  }

  fn socket_ref(&self) -> &TcpStream { self.get_ref() }

  fn protocol(&self) -> TransportProtocol {
    self.ssl().version2().map(|version| match version {
      SslVersion::SSL3 => TransportProtocol::Ssl3,
      SslVersion::TLS1 => TransportProtocol::Tls1_0,
      SslVersion::TLS1_1 => TransportProtocol::Tls1_1,
      SslVersion::TLS1_2 => TransportProtocol::Tls1_2,
      _ => TransportProtocol::Tls1_3,
    }).unwrap_or(TransportProtocol::Tcp)
  }
}

pub struct FrontRustls {
  pub stream:  TcpStream,
  pub session: ServerSession,
}

impl SocketHandler for FrontRustls {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size      = 0usize;
    let mut can_read  = true;
    let mut is_error  = false;
    let mut is_closed = false;

    loop {
      if size == buf.len() {
        break;
      }

      if !can_read | is_error | is_closed {
        break;
      }

      match self.session.read_tls(&mut self.stream) {
        Ok(0)  => {
          can_read  = false;
          is_closed = true;
        },
        Ok(sz) => {},
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => {
            can_read = false;
          },
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("rustls.read.error");
            is_closed = true;
          },
          _ => {
            error!("could not read TLS stream from socket: {:?}", e);
            incr!("rustls.read.error");
            is_error = true;
            break;
           }
        }
      }

      if let Err(e) = self.session.process_new_packets() {
        error!("could not process read TLS packets: {:?}", e);
        is_error = true;
        break;
      }

      while !self.session.wants_read() {
        match self.session.read(&mut buf[size..]) {
          Ok(sz) => size += sz,
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => {
              break;
            },
            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
              incr!("rustls.read.error");
              is_closed = true;
              break;
            },
            _ => {
              error!("could not read data from TLS stream: {:?}", e);
              incr!("rustls.read.error");
              is_error = true;
              break;
            }
          }
        }
      }
    }

    if is_error {
      (size, SocketResult::Error)
    } else if is_closed {
      (size, SocketResult::Closed)
    } else if !can_read {
      (size, SocketResult::WouldBlock)
    } else {
      (size, SocketResult::Continue)
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut buffered_size = 0usize;
    let mut sent_size     = 0usize;
    let mut can_write     = true;
    let mut is_error      = false;
    let mut is_closed     = false;

    loop {
      if buffered_size == buf.len() {
        break;
      }

      if !can_write | is_error | is_closed {
        break;
      }

      match self.session.write(&buf[buffered_size..]) {
        Ok(0)  => {
          break;
        },
        Ok(sz) => {
          buffered_size += sz;
        },
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => {
            // we don't need to do anything, the session will return false in wants_write?
            //error!("rustls socket_write wouldblock");
          },
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            //FIXME: this should probably not happen here
            incr!("rustls.write.error");
            is_closed = true;
            break;
          },
          _ => {
            error!("could not write data to TLS stream: {:?}", e);
            incr!("rustls.write.error");
            is_error = true;
            break;
          }
        }
      }

      loop {
        match self.session.write_tls(&mut self.stream) {
          Ok(0)  => {
            //can_write = false;
            break;
          },
          Ok(sz) => {
            sent_size += sz;
          },
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => can_write = false,
            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
              incr!("rustls.write.error");
              is_closed = true;
              break;
            },
            _ => {
              error!("could not write TLS stream to socket: {:?}", e);
              incr!("rustls.write.error");
              is_error = true;
              break;
            }
          }
        }
      }
    }

    if is_error {
      (buffered_size, SocketResult::Error)
    } else if is_closed {
      (buffered_size, SocketResult::Closed)
    } else if !can_write {
      (buffered_size, SocketResult::WouldBlock)
    } else {
      (buffered_size, SocketResult::Continue)
    }
  }

  fn socket_ref(&self) -> &TcpStream { &self.stream }

  fn protocol(&self) -> TransportProtocol {
    self.session.get_protocol_version().map(|version| match version {
      ProtocolVersion::SSLv2 => TransportProtocol::Ssl2,
      ProtocolVersion::SSLv3 => TransportProtocol::Ssl3,
      ProtocolVersion::TLSv1_0 => TransportProtocol::Tls1_0,
      ProtocolVersion::TLSv1_1 => TransportProtocol::Tls1_1,
      ProtocolVersion::TLSv1_2 => TransportProtocol::Tls1_2,
      ProtocolVersion::TLSv1_3 => TransportProtocol::Tls1_3,
      _ => TransportProtocol::Tls1_3,
    }).unwrap_or(TransportProtocol::Tcp)
  }
}

pub fn server_bind(addr: &SocketAddr) -> io::Result<TcpListener> {
  let sock = match *addr {
    SocketAddr::V4(..) => TcpBuilder::new_v4()?,
    SocketAddr::V6(..) => TcpBuilder::new_v6()?,
  };

  // set so_reuseaddr, but only on unix (mirrors what libstd does)
  if cfg!(unix) {
    sock.reuse_address(true)?;
  }

  sock.reuse_port(true)?;

  // bind the socket
  sock.bind(addr)?;

  // listen
  // FIXME: make the backlog configurable?
  let listener = sock.listen(1024)?;
  TcpListener::from_std(listener)
}

<commit_msg>Rustls Socket: break loop when we read 0 from stream<commit_after>use std::io::{self,ErrorKind,Read,Write};
use std::net::SocketAddr;
use mio::tcp::{TcpListener,TcpStream};
use rustls::{ServerSession, Session, ProtocolVersion};
use net2::TcpBuilder;
use net2::unix::UnixTcpBuilderExt;
#[cfg(feature = "use-openssl")]
use openssl::ssl::{ErrorCode, SslStream, SslVersion};

#[derive(Debug,PartialEq,Copy,Clone)]
pub enum SocketResult {
  Continue,
  Closed,
  WouldBlock,
  Error
}

#[derive(Debug,PartialEq,Copy,Clone)]
pub enum TransportProtocol {
  Tcp,
  Ssl2,
  Ssl3,
  Tls1_0,
  Tls1_1,
  Tls1_2,
  Tls1_3,
}

pub trait SocketHandler {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult);
  fn socket_write(&mut self, buf: &[u8])    -> (usize, SocketResult);
  fn socket_write_vectored(&mut self,  buf: &[&iovec::IoVec]) -> (usize, SocketResult) {
    unimplemented!()
  }
  fn has_vectored_writes(&self) -> bool { false }
  fn socket_ref(&self) -> &TcpStream;
  fn protocol(&self) -> TransportProtocol;
}

impl SocketHandler for TcpStream {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.read(&mut buf[size..]) {
        Ok(0)  => return (size, SocketResult::Closed),
        Ok(sz) => size +=sz,
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => return (size, SocketResult::WouldBlock),
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("tcp.read.error");
            return (size, SocketResult::Closed)
          },
          _ => {
            error!("SOCKET\tsocket_read error={:?}", e);
            incr!("tcp.read.error");
            return (size, SocketResult::Error)
          },
        }
      }
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.write(&buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size += sz,
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => return (size, SocketResult::WouldBlock),
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("tcp.write.error");
            return (size, SocketResult::Closed)
          },
          _ => {
            //FIXME: timeout and other common errors should be sent up
            error!("SOCKET\tsocket_write error={:?}", e);
            incr!("tcp.write.error");
            return (size, SocketResult::Error)
          },
        }
      }
    }
  }

  fn socket_write_vectored(&mut self,  bufs: &[&iovec::IoVec]) -> (usize, SocketResult) {
    match self.write_bufs(bufs) {
      Ok(0)  => return (0, SocketResult::Continue),
      Ok(sz) => return (sz, SocketResult::Continue),
      Err(e) => match e.kind() {
        ErrorKind::WouldBlock => return (0, SocketResult::WouldBlock),
        ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
          incr!("tcp.write.error");
          return (0, SocketResult::Closed)
        },
        _ => {
          //FIXME: timeout and other common errors should be sent up
          error!("SOCKET\tsocket_write error={:?}", e);
          incr!("tcp.write.error");
          return (0, SocketResult::Error)
        },
      }
    }
  }

  fn has_vectored_writes(&self) -> bool { true }

  fn socket_ref(&self) -> &TcpStream { self }

  fn protocol(&self) -> TransportProtocol {
    TransportProtocol::Tcp
  }
}

#[cfg(feature = "use-openssl")]
impl SocketHandler for SslStream<TcpStream> {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.ssl_read(&mut buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size += sz,
        Err(e) => {
          match e.code() {
            ErrorCode::WANT_READ  => return (size, SocketResult::WouldBlock),
            ErrorCode::WANT_WRITE => return (size, SocketResult::WouldBlock),
            ErrorCode::SSL        => {
              debug!("SOCKET-TLS\treadable TLS socket SSL error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::SYSCALL    => {
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::ZERO_RETURN => {
              incr!("openssl.read.error");
              return (size, SocketResult::Closed)
            },
            _ => {
              debug!("SOCKET-TLS\treadable TLS socket error={:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            }
          }
        }
      }
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.ssl_write(&buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size +=sz,
        Err(e) => {
          match e.code() {
            ErrorCode::WANT_READ  => return (size, SocketResult::WouldBlock),
            ErrorCode::WANT_WRITE => return (size, SocketResult::WouldBlock),
            ErrorCode::SSL        => {
              debug!("SOCKET-TLS\twritable TLS socket SSL error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::SYSCALL        => {
              debug!("SOCKET-TLS\twritable TLS socket syscall error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::ZERO_RETURN => {
              incr!("openssl.write.error");
              return (size, SocketResult::Closed)
            },
            _ => {
              debug!("SOCKET-TLS\twritable TLS socket error={:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            }
          }
        }
      }
    }
  }

  fn socket_ref(&self) -> &TcpStream { self.get_ref() }

  fn protocol(&self) -> TransportProtocol {
    self.ssl().version2().map(|version| match version {
      SslVersion::SSL3 => TransportProtocol::Ssl3,
      SslVersion::TLS1 => TransportProtocol::Tls1_0,
      SslVersion::TLS1_1 => TransportProtocol::Tls1_1,
      SslVersion::TLS1_2 => TransportProtocol::Tls1_2,
      _ => TransportProtocol::Tls1_3,
    }).unwrap_or(TransportProtocol::Tcp)
  }
}

pub struct FrontRustls {
  pub stream:  TcpStream,
  pub session: ServerSession,
}

impl SocketHandler for FrontRustls {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size      = 0usize;
    let mut can_read  = true;
    let mut is_error  = false;
    let mut is_closed = false;

    loop {
      if size == buf.len() {
        break;
      }

      if !can_read | is_error | is_closed {
        break;
      }

      match self.session.read_tls(&mut self.stream) {
        Ok(0)  => {
          can_read  = false;
          is_closed = true;
        },
        Ok(sz) => {},
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => {
            can_read = false;
          },
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("rustls.read.error");
            is_closed = true;
          },
          _ => {
            error!("could not read TLS stream from socket: {:?}", e);
            incr!("rustls.read.error");
            is_error = true;
            break;
           }
        }
      }

      if let Err(e) = self.session.process_new_packets() {
        error!("could not process read TLS packets: {:?}", e);
        is_error = true;
        break;
      }

      while !self.session.wants_read() {
        match self.session.read(&mut buf[size..]) {
          Ok(0) => break,
          Ok(sz) => size += sz,
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => {
              break;
            },
            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
              incr!("rustls.read.error");
              is_closed = true;
              break;
            },
            _ => {
              error!("could not read data from TLS stream: {:?}", e);
              incr!("rustls.read.error");
              is_error = true;
              break;
            }
          }
        }
      }
    }

    if is_error {
      (size, SocketResult::Error)
    } else if is_closed {
      (size, SocketResult::Closed)
    } else if !can_read {
      (size, SocketResult::WouldBlock)
    } else {
      (size, SocketResult::Continue)
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut buffered_size = 0usize;
    let mut sent_size     = 0usize;
    let mut can_write     = true;
    let mut is_error      = false;
    let mut is_closed     = false;

    loop {
      if buffered_size == buf.len() {
        break;
      }

      if !can_write | is_error | is_closed {
        break;
      }

      match self.session.write(&buf[buffered_size..]) {
        Ok(0)  => {
          break;
        },
        Ok(sz) => {
          buffered_size += sz;
        },
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => {
            // we don't need to do anything, the session will return false in wants_write?
            //error!("rustls socket_write wouldblock");
          },
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            //FIXME: this should probably not happen here
            incr!("rustls.write.error");
            is_closed = true;
            break;
          },
          _ => {
            error!("could not write data to TLS stream: {:?}", e);
            incr!("rustls.write.error");
            is_error = true;
            break;
          }
        }
      }

      loop {
        match self.session.write_tls(&mut self.stream) {
          Ok(0)  => {
            //can_write = false;
            break;
          },
          Ok(sz) => {
            sent_size += sz;
          },
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => can_write = false,
            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
              incr!("rustls.write.error");
              is_closed = true;
              break;
            },
            _ => {
              error!("could not write TLS stream to socket: {:?}", e);
              incr!("rustls.write.error");
              is_error = true;
              break;
            }
          }
        }
      }
    }

    if is_error {
      (buffered_size, SocketResult::Error)
    } else if is_closed {
      (buffered_size, SocketResult::Closed)
    } else if !can_write {
      (buffered_size, SocketResult::WouldBlock)
    } else {
      (buffered_size, SocketResult::Continue)
    }
  }

  fn socket_ref(&self) -> &TcpStream { &self.stream }

  fn protocol(&self) -> TransportProtocol {
    self.session.get_protocol_version().map(|version| match version {
      ProtocolVersion::SSLv2 => TransportProtocol::Ssl2,
      ProtocolVersion::SSLv3 => TransportProtocol::Ssl3,
      ProtocolVersion::TLSv1_0 => TransportProtocol::Tls1_0,
      ProtocolVersion::TLSv1_1 => TransportProtocol::Tls1_1,
      ProtocolVersion::TLSv1_2 => TransportProtocol::Tls1_2,
      ProtocolVersion::TLSv1_3 => TransportProtocol::Tls1_3,
      _ => TransportProtocol::Tls1_3,
    }).unwrap_or(TransportProtocol::Tcp)
  }
}

pub fn server_bind(addr: &SocketAddr) -> io::Result<TcpListener> {
  let sock = match *addr {
    SocketAddr::V4(..) => TcpBuilder::new_v4()?,
    SocketAddr::V6(..) => TcpBuilder::new_v6()?,
  };

  // set so_reuseaddr, but only on unix (mirrors what libstd does)
  if cfg!(unix) {
    sock.reuse_address(true)?;
  }

  sock.reuse_port(true)?;

  // bind the socket
  sock.bind(addr)?;

  // listen
  // FIXME: make the backlog configurable?
  let listener = sock.listen(1024)?;
  TcpListener::from_std(listener)
}

<|endoftext|>