<commit_before>use sodiumoxide::randombytes::randombytes;

use capnp;
use root_capnp;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Kind {
    TreeBranch = 1,
    TreeLeaf = 2,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ChunkRef {
    pub blob_id: Vec<u8>,
    pub offset: usize,
    pub length: usize,
    pub kind: Kind,
}

impl ChunkRef {
    pub fn from_bytes(bytes: &mut &[u8]) -> Result<ChunkRef, capnp::Error> {
        let reader = try!(capnp::serialize_packed::read_message(bytes,
                                                       capnp::message::ReaderOptions::new()));
        let root = try!(reader.get_root::<root_capnp::chunk_ref::Reader>());

        Ok(try!(ChunkRef::read_msg(&root)))
    }

    pub fn as_bytes(&self) -> Vec<u8> {
        let mut message = ::capnp::message::Builder::new_default();
        {
            let mut root = message.init_root::<root_capnp::chunk_ref::Builder>();
            self.populate_msg(root.borrow());
        }

        let mut out = Vec::new();
        capnp::serialize_packed::write_message(&mut out, &message).unwrap();

        out
    }

    pub fn populate_msg(&self, msg: root_capnp::chunk_ref::Builder) {
        let mut msg = msg;
        msg.set_blob_id(&self.blob_id[..]);
        msg.set_offset(self.offset as i64);
        msg.set_length(self.length as i64);
        match self.kind {
            Kind::TreeLeaf => msg.init_kind().set_tree_leaf(()),
            Kind::TreeBranch => msg.init_kind().set_tree_branch(()),
        }
    }

    pub fn read_msg(msg: &root_capnp::chunk_ref::Reader) -> Result<ChunkRef, capnp::Error> {
        Ok(ChunkRef {
            blob_id: try!(msg.get_blob_id()).to_owned(),
            offset: msg.get_offset() as usize,
            length: msg.get_length() as usize,
            kind: match try!(msg.get_kind().which()) {
                root_capnp::chunk_ref::kind::TreeBranch(()) => Kind::TreeBranch,
                root_capnp::chunk_ref::kind::TreeLeaf(()) => Kind::TreeLeaf,
            },
        })
    }
}

pub struct Blob {
    chunks: Vec<u8>,
    footer: Vec<u8>,
    overhead: usize,
    max_size: usize,
}

impl Blob {
    pub fn new(max_size: usize) -> Blob {
        Blob {
            chunks: Vec::with_capacity(max_size),
            footer: Vec::with_capacity(max_size / 2),
            overhead: 3 * Blob::len_into(max_size - 1, &mut Vec::new()),
            max_size: max_size,
        }
    }

    pub fn upperbound_len(&self) -> usize {
        if self.chunks.len() == 0 {
            0
        } else {
            self.chunks.len() + self.footer.len() + self.overhead
        }
    }

    pub fn chunk_len(&self) -> usize {
        self.chunks.len()
    }

    pub fn try_append(&mut self, mut chunk: Vec<u8>, cref: &ChunkRef) -> Result<(), Vec<u8>> {
        assert!(self.max_size > chunk.len());

        let mut entry = cref.as_bytes();

        if self.upperbound_len() + entry.len() + chunk.len() >= self.max_size {
            return Err(chunk);
        }

        self.chunks.append(&mut chunk);

        // Generate footer entry.
        let size = entry.len();
        assert!(size < 255);
        self.footer.push(size as u8);
        self.footer.append(&mut entry);

        Ok(())
    }

    pub fn into_bytes(&mut self, mut out: &mut Vec<u8>) {
        if self.chunks.len() == 0 {
            return;
        }

        out.append(&mut self.chunks);

        let mut footer = Vec::new();
        footer.append(&mut self.footer);

        let meta_len = Self::len_into(footer.len(), &mut footer);
        let meta_meta_len = Self::len_into(meta_len, &mut footer);

        assert!(meta_meta_len < 255);
        footer.push(meta_meta_len as u8);

        assert!(out.len() + footer.len() <= self.max_size);
        let left = self.max_size - out.len() - footer.len();
        if left > 0 {
            out.append(&mut randombytes(left));
        }
        out.append(&mut footer);

        // Everything has been reset. We are ready to go again.
        assert_eq!(0, self.chunks.len());
        assert_eq!(0, self.footer.len());
    }

    fn len_into(len: usize, mut out: &mut Vec<u8>) -> usize {
        let mut message = ::capnp::message::Builder::new_default();
        {
            let mut root = message.init_root::<::root_capnp::meta_footer_entry::Builder>();
            root.set_length(len as i64);
        }

        let before_len = out.len();
        capnp::serialize_packed::write_message(&mut out, &message).unwrap();

        out.len() - before_len
    }

    fn len_from(bytes: &mut &[u8]) -> Result<i64, capnp::Error> {
        let reader = try!(
            capnp::serialize_packed::read_message(bytes, capnp::message::ReaderOptions::new()));
        let root = try!(reader.get_root::<root_capnp::meta_footer_entry::Reader>());
        Ok(root.get_length())
    }

    pub fn chunk_refs_from_bytes(bytes: &[u8]) -> Result<Vec<ChunkRef>, capnp::Error> {
        if bytes.len() == 0 {
            return Ok(Vec::new());
        }

        let meta_meta_len = *bytes.last().unwrap() as usize;
        let mut pos = bytes.len() - 1;
        assert!(pos >= meta_meta_len);
        pos -= meta_meta_len;

        let meta_len = try!(Blob::len_from(&mut &bytes[pos..pos + meta_meta_len])) as usize;
        assert!(pos >= meta_len);
        pos -= meta_len;

        let footer_len = try!(Blob::len_from(&mut &bytes[pos..pos + meta_len])) as usize;
        assert!(pos >= footer_len);
        pos -= footer_len;

        let mut footer = &bytes[pos..pos + footer_len];
        let mut crefs = Vec::new();
        while footer.len() > 0 {
            let len = footer[0] as usize;
            assert!(footer.len() > len);

            crefs.push(try!(ChunkRef::from_bytes(&mut &footer[1..1 + len])));
            footer = &footer[len + 1..];
        }

        Ok(crefs)
    }
}
<commit_msg>Avoid randombytes for now as it is slow.<commit_after>use sodiumoxide::randombytes::randombytes;

use capnp;
use root_capnp;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Kind {
    TreeBranch = 1,
    TreeLeaf = 2,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ChunkRef {
    pub blob_id: Vec<u8>,
    pub offset: usize,
    pub length: usize,
    pub kind: Kind,
}

impl ChunkRef {
    pub fn from_bytes(bytes: &mut &[u8]) -> Result<ChunkRef, capnp::Error> {
        let reader = try!(capnp::serialize_packed::read_message(bytes,
                                                       capnp::message::ReaderOptions::new()));
        let root = try!(reader.get_root::<root_capnp::chunk_ref::Reader>());

        Ok(try!(ChunkRef::read_msg(&root)))
    }

    pub fn as_bytes(&self) -> Vec<u8> {
        let mut message = ::capnp::message::Builder::new_default();
        {
            let mut root = message.init_root::<root_capnp::chunk_ref::Builder>();
            self.populate_msg(root.borrow());
        }

        let mut out = Vec::new();
        capnp::serialize_packed::write_message(&mut out, &message).unwrap();

        out
    }

    pub fn populate_msg(&self, msg: root_capnp::chunk_ref::Builder) {
        let mut msg = msg;
        msg.set_blob_id(&self.blob_id[..]);
        msg.set_offset(self.offset as i64);
        msg.set_length(self.length as i64);
        match self.kind {
            Kind::TreeLeaf => msg.init_kind().set_tree_leaf(()),
            Kind::TreeBranch => msg.init_kind().set_tree_branch(()),
        }
    }

    pub fn read_msg(msg: &root_capnp::chunk_ref::Reader) -> Result<ChunkRef, capnp::Error> {
        Ok(ChunkRef {
            blob_id: try!(msg.get_blob_id()).to_owned(),
            offset: msg.get_offset() as usize,
            length: msg.get_length() as usize,
            kind: match try!(msg.get_kind().which()) {
                root_capnp::chunk_ref::kind::TreeBranch(()) => Kind::TreeBranch,
                root_capnp::chunk_ref::kind::TreeLeaf(()) => Kind::TreeLeaf,
            },
        })
    }
}

pub struct Blob {
    chunks: Vec<u8>,
    footer: Vec<u8>,
    overhead: usize,
    max_size: usize,
}

impl Blob {
    pub fn new(max_size: usize) -> Blob {
        Blob {
            chunks: Vec::with_capacity(max_size),
            footer: Vec::with_capacity(max_size / 2),
            overhead: 3 * Blob::len_into(max_size - 1, &mut Vec::new()),
            max_size: max_size,
        }
    }

    pub fn upperbound_len(&self) -> usize {
        if self.chunks.len() == 0 {
            0
        } else {
            self.chunks.len() + self.footer.len() + self.overhead
        }
    }

    pub fn chunk_len(&self) -> usize {
        self.chunks.len()
    }

    pub fn try_append(&mut self, mut chunk: Vec<u8>, cref: &ChunkRef) -> Result<(), Vec<u8>> {
        assert!(self.max_size > chunk.len());

        let mut entry = cref.as_bytes();

        if self.upperbound_len() + entry.len() + chunk.len() >= self.max_size {
            return Err(chunk);
        }

        self.chunks.append(&mut chunk);

        // Generate footer entry.
        let size = entry.len();
        assert!(size < 255);
        self.footer.push(size as u8);
        self.footer.append(&mut entry);

        Ok(())
    }

    pub fn into_bytes(&mut self, mut out: &mut Vec<u8>) {
        if self.chunks.len() == 0 {
            return;
        }

        out.append(&mut self.chunks);

        let mut footer = Vec::new();
        footer.append(&mut self.footer);

        let meta_len = Self::len_into(footer.len(), &mut footer);
        let meta_meta_len = Self::len_into(meta_len, &mut footer);

        assert!(meta_meta_len < 255);
        footer.push(meta_meta_len as u8);

        assert!(out.len() + footer.len() <= self.max_size);
        let left = self.max_size - out.len() - footer.len();
        if left > 0 {
            out.append(&mut vec![0; left]);
        }
        out.append(&mut footer);

        // Everything has been reset. We are ready to go again.
        assert_eq!(0, self.chunks.len());
        assert_eq!(0, self.footer.len());
    }

    fn len_into(len: usize, mut out: &mut Vec<u8>) -> usize {
        let mut message = ::capnp::message::Builder::new_default();
        {
            let mut root = message.init_root::<::root_capnp::meta_footer_entry::Builder>();
            root.set_length(len as i64);
        }

        let before_len = out.len();
        capnp::serialize_packed::write_message(&mut out, &message).unwrap();

        out.len() - before_len
    }

    fn len_from(bytes: &mut &[u8]) -> Result<i64, capnp::Error> {
        let reader = try!(
            capnp::serialize_packed::read_message(bytes, capnp::message::ReaderOptions::new()));
        let root = try!(reader.get_root::<root_capnp::meta_footer_entry::Reader>());
        Ok(root.get_length())
    }

    pub fn chunk_refs_from_bytes(bytes: &[u8]) -> Result<Vec<ChunkRef>, capnp::Error> {
        if bytes.len() == 0 {
            return Ok(Vec::new());
        }

        let meta_meta_len = *bytes.last().unwrap() as usize;
        let mut pos = bytes.len() - 1;
        assert!(pos >= meta_meta_len);
        pos -= meta_meta_len;

        let meta_len = try!(Blob::len_from(&mut &bytes[pos..pos + meta_meta_len])) as usize;
        assert!(pos >= meta_len);
        pos -= meta_len;

        let footer_len = try!(Blob::len_from(&mut &bytes[pos..pos + meta_len])) as usize;
        assert!(pos >= footer_len);
        pos -= footer_len;

        let mut footer = &bytes[pos..pos + footer_len];
        let mut crefs = Vec::new();
        while footer.len() > 0 {
            let len = footer[0] as usize;
            assert!(footer.len() > len);

            crefs.push(try!(ChunkRef::from_bytes(&mut &footer[1..1 + len])));
            footer = &footer[len + 1..];
        }

        Ok(crefs)
    }
}
<|endoftext|>


<commit_before>extern crate cairo;
extern crate gtk;

use std::f64::consts::PI;

use gtk::Widget;
use gtk::traits::*;
use gtk::signal::Inhibit;
use gtk::DrawingArea;

use cairo::enums::FontSlant::Normal;
use cairo::enums::FontWeight::Normal;
use cairo::Context;

fn main() {
    gtk::init();

    drawable(500, 500, |_, cr: Context| {
        cr.set_dash(&[3., 2., 1.], 1.);
        assert_eq!(cr.get_dash(), (vec![3., 2., 1.], 1.));

        cr.scale(500f64, 500f64);

        cr.set_source_rgb(250.0/255.0, 224.0/255.0, 55.0/255.0);
        cr.paint();

        cr.set_line_width(0.05);

        // border
        cr.set_source_rgb(0.3, 0.3, 0.3);
        cr.rectangle(0.0, 0.0, 1.0, 1.0);
        cr.stroke();

        cr.set_line_width(0.03);

        // draw circle
        cr.arc(0.5, 0.5, 0.4, 0.0, PI * 2.);
        cr.stroke();

        // mouth
        let mouth_top = 0.68;
        let mouth_width = 0.38;

        let mouth_dx = 0.10;
        let mouth_dy = 0.10;

        cr.move_to( 0.50 - mouth_width/2.0, mouth_top);
        cr.curve_to(0.50 - mouth_dx,        mouth_top + mouth_dy,
                     0.50 + mouth_dx,        mouth_top + mouth_dy,
                     0.50 + mouth_width/2.0, mouth_top);

        println!("Extents: {:?}", cr.fill_extents());

        cr.stroke();

        let eye_y = 0.38;
        let eye_dx = 0.15;
        cr.arc(0.5 - eye_dx, eye_y, 0.05, 0.0, PI * 2.);
        cr.fill();

        cr.arc(0.5 + eye_dx, eye_y, 0.05, 0.0, PI * 2.);
        cr.fill();

        Inhibit(false)
    });

    drawable(500, 500, |_, cr: Context| {
        cr.scale(500f64, 500f64);

        cr.select_font_face("Sans", FontSlantNormal, FontWeightNormal);
        cr.set_font_size(0.35);

        cr.move_to(0.04, 0.53);
        cr.show_text("Hello");

        cr.move_to(0.27, 0.65);
        cr.text_path("void");
        cr.set_source_rgb(0.5, 0.5, 1.0);
        cr.fill_preserve();
        cr.set_source_rgb(0.0, 0.0, 0.0);
        cr.set_line_width(0.01);
        cr.stroke();

        cr.set_source_rgba(1.0, 0.2, 0.2, 0.6);
        cr.arc(0.04, 0.53, 0.02, 0.0, PI * 2.);
        cr.arc(0.27, 0.65, 0.02, 0.0, PI * 2.);
        cr.fill();

        Inhibit(false)
    });

    gtk::main();
}

pub fn drawable<F>(width: i32, height: i32, draw_fn: F)
where F: Fn(Widget, Context) -> Inhibit + 'static {
    let window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let drawing_area = Box::new(DrawingArea::new)().unwrap();

    drawing_area.connect_draw(draw_fn);

    window.set_default_size(width, height);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });
    window.add(&drawing_area);
    window.show_all();
}
<commit_msg>Fix issue<commit_after>extern crate cairo;
extern crate gtk;

use std::f64::consts::PI;

use gtk::Widget;
use gtk::traits::*;
use gtk::signal::Inhibit;
use gtk::DrawingArea;

use cairo::enums::{FontSlant, FontWeight};
use cairo::Context;

fn main() {
    gtk::init();

    drawable(500, 500, |_, cr: Context| {
        cr.set_dash(&[3., 2., 1.], 1.);
        assert_eq!(cr.get_dash(), (vec![3., 2., 1.], 1.));

        cr.scale(500f64, 500f64);

        cr.set_source_rgb(250.0/255.0, 224.0/255.0, 55.0/255.0);
        cr.paint();

        cr.set_line_width(0.05);

        // border
        cr.set_source_rgb(0.3, 0.3, 0.3);
        cr.rectangle(0.0, 0.0, 1.0, 1.0);
        cr.stroke();

        cr.set_line_width(0.03);

        // draw circle
        cr.arc(0.5, 0.5, 0.4, 0.0, PI * 2.);
        cr.stroke();

        // mouth
        let mouth_top = 0.68;
        let mouth_width = 0.38;

        let mouth_dx = 0.10;
        let mouth_dy = 0.10;

        cr.move_to( 0.50 - mouth_width/2.0, mouth_top);
        cr.curve_to(0.50 - mouth_dx,        mouth_top + mouth_dy,
                     0.50 + mouth_dx,        mouth_top + mouth_dy,
                     0.50 + mouth_width/2.0, mouth_top);

        println!("Extents: {:?}", cr.fill_extents());

        cr.stroke();

        let eye_y = 0.38;
        let eye_dx = 0.15;
        cr.arc(0.5 - eye_dx, eye_y, 0.05, 0.0, PI * 2.);
        cr.fill();

        cr.arc(0.5 + eye_dx, eye_y, 0.05, 0.0, PI * 2.);
        cr.fill();

        Inhibit(false)
    });

    drawable(500, 500, |_, cr: Context| {
        cr.scale(500f64, 500f64);

        cr.select_font_face("Sans", FontSlant::Normal, FontWeight::Normal);
        cr.set_font_size(0.35);

        cr.move_to(0.04, 0.53);
        cr.show_text("Hello");

        cr.move_to(0.27, 0.65);
        cr.text_path("void");
        cr.set_source_rgb(0.5, 0.5, 1.0);
        cr.fill_preserve();
        cr.set_source_rgb(0.0, 0.0, 0.0);
        cr.set_line_width(0.01);
        cr.stroke();

        cr.set_source_rgba(1.0, 0.2, 0.2, 0.6);
        cr.arc(0.04, 0.53, 0.02, 0.0, PI * 2.);
        cr.arc(0.27, 0.65, 0.02, 0.0, PI * 2.);
        cr.fill();

        Inhibit(false)
    });

    gtk::main();
}

pub fn drawable<F>(width: i32, height: i32, draw_fn: F)
where F: Fn(Widget, Context) -> Inhibit + 'static {
    let window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let drawing_area = Box::new(DrawingArea::new)().unwrap();

    drawing_area.connect_draw(draw_fn);

    window.set_default_size(width, height);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });
    window.add(&drawing_area);
    window.show_all();
}
<|endoftext|>


<commit_before>//! FLIC encoding and decoding subroutines.

macro_rules! module {
    ($e:ident) => {
        pub use self::$e::*;
        mod $e;
    };
}

use std::iter::Zip;

use ::{FlicError,FlicResult,RasterMut};

module!(codec001);
module!(codec004);
module!(codec007);
module!(codec010);
module!(codec011);
module!(codec012);
module!(codec013);
module!(codec014);
module!(codec015);
module!(codec016);
module!(codec018);

/*--------------------------------------------------------------*/

/// Result of a GroupByX operation: a grouping type, start index, and
/// length.
#[derive(Clone,Copy,Debug,Eq,PartialEq)]
enum Group {
    Same(usize, usize),
    Diff(usize, usize),
}

/// An iterator that groups the two input streams based on whether
/// corresponding items are equal.  It returns whether they are equal
/// and the length until that comparison changes value.
///
/// This is suitable for compressing skip/memcpy type codecs,
/// e.g. FLI_COLOR64, FLI_COLOR256.
struct GroupByEq<I: Iterator> where I::Item: PartialEq {
    iter: Zip<I, I>,
    peek: Option<bool>,
    idx: usize,
    prepend_same_run: bool,
    ignore_final_same_run: bool,
}

/// An iterator that groups the two buffers into packets by "runs".
/// A run is a length of the buffer where the corresponding elements
/// of the "old" and "new" buffers are the same, or a stretch of the
/// "new" buffer where all of the elements have the same value.
///
/// This is suitable for compressing skip/memset/memcpy type codes,
/// e.g. FLI_LC, FLI_SS2.
struct GroupByRuns<'a> {
    old: &'a [u8],
    new: &'a [u8],
    idx: usize,
    prepend_same_run: bool,
    ignore_final_same_run: bool,
}

type GroupByLC<'a> = GroupByRuns<'a>;

/// An iterator that groups the buffer into packets of the same value.
///
/// This is suitable for compressing memset/memcpy type codecs,
/// e.g. FLI_BRUN.
struct GroupByValue<'a> {
    buf: &'a [u8],
    idx: usize,
}

/*--------------------------------------------------------------*/

/// Returns true if the chunk type modifies the palette.
pub fn chunk_modifies_palette(magic: u16)
        -> bool {
    (magic == FLI_COLOR256) || (magic == FLI_COLOR64) || (magic == FLI_ICOLORS)
}

/// Decode a chunk, based on the chunk type.
pub fn decode_chunk(magic: u16, buf: &[u8], dst: &mut RasterMut)
        -> FlicResult<()> {
    match magic {
        FLI_WRUN => try!(decode_fli_wrun(&buf, dst)),
        FLI_COLOR256 => try!(decode_fli_color256(&buf, dst)),
        FLI_SS2 => try!(decode_fli_ss2(&buf, dst)),
        FLI_SBSRSC => try!(decode_fli_sbsrsc(&buf, dst)),
        FLI_COLOR64 => try!(decode_fli_color64(&buf, dst)),
        FLI_LC => try!(decode_fli_lc(&buf, dst)),
        FLI_BLACK => decode_fli_black(dst),
        FLI_ICOLORS => decode_fli_icolors(dst),
        FLI_BRUN => try!(decode_fli_brun(&buf, dst)),
        FLI_COPY => try!(decode_fli_copy(&buf, dst)),

        // Postage stamps should not be decoded in the same loop as
        // the main animation; they have different sizes and work on
        // different buffers and palettes.
        FLI_PSTAMP => (),

        _ => return Err(FlicError::BadMagic),
    }

    Ok(())
}

/*--------------------------------------------------------------*/

impl<I: Iterator> GroupByEq<I>
        where I::Item: PartialEq {
    /// Create a new GroupByEq iterator.
    fn new(old: I, new: I) -> Self {
        GroupByEq {
            iter: old.zip(new),
            peek: None,
            idx: 0,
            prepend_same_run: false,
            ignore_final_same_run: false,
        }
    }

    /// If set, and if the two buffers start on a "Diff" sequence,
    /// then a "Same" group of length 0 will be added at the start.
    fn set_prepend_same_run(mut self) -> Self {
        assert!(self.peek.is_none());
        self.prepend_same_run = true;
        self
    }

    /// If set, and if the two buffers end on a "Same" sequence,
    /// then this final "same" type group will be ignored.
    fn set_ignore_final_same_run(mut self) -> Self {
        self.ignore_final_same_run = true;
        self
    }
}

impl<I: Iterator> Iterator for GroupByEq<I>
        where I::Item: PartialEq {
    type Item = Group;

    /// Advances the iterator and returns the next value.
    fn next(&mut self) -> Option<Group> {
        let expected: bool;
        let start = self.idx;
        let mut n = 0;

        if self.prepend_same_run {
            self.prepend_same_run = false;
            expected = true;
        } else if let Some(x) = self.peek {
            self.peek = None;
            expected = x;
            n = n + 1;
        } else if let Some((a, b)) = self.iter.next() {
            expected = a == b;
            n = n + 1;
        } else {
            return None;
        }

        for x in self.iter.by_ref().map(|(a, b)| a == b) {
            if x == expected {
                n = n + 1;
            } else {
                self.peek = Some(x);
                break;
            }
        }

        self.idx = self.idx + n;
        if expected {
            if self.ignore_final_same_run && self.peek.is_none() {
                return None;
            }
            return Some(Group::Same(start, n));
        } else {
            return Some(Group::Diff(start, n));
        }
    }
}

impl<'a> GroupByRuns<'a> {
    /// Create a new GroupByLC iterator.
    fn new_lc(old: &'a [u8], new: &'a [u8]) -> Self {
        assert_eq!(old.len(), new.len());
        GroupByLC {
            old: old,
            new: new,
            idx: 0,
            prepend_same_run: false,
            ignore_final_same_run: false,
        }
    }

    /// If set, and if the two buffers start on a "Diff" sequence,
    /// then a "Same" group of length 0 will be added at the start.
    fn set_prepend_same_run(mut self) -> Self {
        self.prepend_same_run = true;
        self
    }

    /// If set, and if the two buffers end on a "Same" sequence,
    /// then this final "same" type group will be ignored.
    fn set_ignore_final_same_run(mut self) -> Self {
        self.ignore_final_same_run = true;
        self
    }
}

impl<'a> Iterator for GroupByRuns<'a> {
    type Item = Group;

    /// Advances the iterator and returns the next value.
    fn next(&mut self) -> Option<Group> {
        let len = self.new.len();
        let start = self.idx;
        let mut i = self.idx;

        if i >= len {
            return None;
        } else if self.old[i] == self.new[i]
                || self.prepend_same_run {
            while (i < len) && (self.old[i] == self.new[i]) {
                i = i + 1;
            }

            let n = i - self.idx;
            self.idx = i;
            self.prepend_same_run = false;

            if i >= len && self.ignore_final_same_run {
                return None;
            } else {
                return Some(Group::Same(start, n));
            }
        } else {
            let c = self.new[self.idx];
            while (i < len) && (self.old[i] != self.new[i]) && (self.new[i] == c) {
                i = i + 1;
            }

            let n = i - self.idx;
            self.idx = i;
            return Some(Group::Diff(start, n));
        }
    }
}

impl<'a> GroupByValue<'a> {
    /// Create a new GroupByValue iterator.
    fn new(buf: &'a [u8]) -> Self {
        GroupByValue {
            buf: buf,
            idx: 0,
        }
    }
}

impl<'a> Iterator for GroupByValue<'a> {
    type Item = Group;

    /// Advances the iterator and returns the next value.
    fn next(&mut self) -> Option<Group> {
        let len = self.buf.len();
        let start = self.idx;
        let mut i = self.idx;

        if i >= len {
            return None;
        } else {
            let c = self.buf[self.idx];
            while (i < len) && (self.buf[i] == c) {
                i = i + 1;
            }

            let n = i - self.idx;
            self.idx = i;
            return Some(Group::Same(start, n));
        }
    }
}

/// A little routine to help with linear scaling functions.
fn linscale(sw: usize, dw: usize, dx: usize)
        -> usize {
    assert!(sw > 0 && dw > 0);
    assert!(dx < dw);

    match dx {
        0 => 0,
        _ => (dx * sw + sw / 2) / dw,
    }
}

#[cfg(test)]
mod tests {
    use super::{Group,GroupByEq,GroupByLC};

    #[test]
    fn test_group_by_eq() {
        let xs = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
        let ys = [ 0, 0, 3, 4, 5, 0, 7, 8, 9 ];
        let expected = [
            Group::Same(0, 0), // prepend
            Group::Diff(0, 2), Group::Same(2, 3), Group::Diff(5, 1) ];

        let gs: Vec<Group>
            = GroupByEq::new(xs.iter(), ys.iter())
            .set_prepend_same_run()
            .set_ignore_final_same_run()
            .collect();

        assert_eq!(&gs[..], expected);
    }

    #[test]
    fn test_group_by_lc() {
        let xs = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
        let ys = [ 2, 1, 3, 4, 5, 0, 0, 0, 9 ];
        //         ^  ^  ^^^^^^^  ^^^^^^^  ^
        let expected = [
            Group::Same(0, 0), // prepend
            Group::Diff(0, 1), Group::Diff(1, 1), Group::Same(2, 3), Group::Diff(5, 3) ];

        let gs: Vec<Group>
            = GroupByLC::new_lc(&xs, &ys)
            .set_prepend_same_run()
            .set_ignore_final_same_run()
            .collect();

        assert_eq!(&gs[..], expected);
    }

    #[test]
    fn test_group_by_value() {
        use super::{Group,GroupByValue};

        let xs = [ 1, 1, 3, 4, 4, 4, 4, 7, 7 ];
        let expected = [
            Group::Same(0, 2), Group::Same(2, 1), Group::Same(3, 4), Group::Same(7, 2) ];

        let gs: Vec<Group>
            = GroupByValue::new(&xs).collect();

        assert_eq!(&gs[..], expected);
    }
}
<commit_msg>Add GroupBySS2 iterator.<commit_after>//! FLIC encoding and decoding subroutines.

macro_rules! module {
    ($e:ident) => {
        pub use self::$e::*;
        mod $e;
    };
}

use std::iter::Zip;

use ::{FlicError,FlicResult,RasterMut};

module!(codec001);
module!(codec004);
module!(codec007);
module!(codec010);
module!(codec011);
module!(codec012);
module!(codec013);
module!(codec014);
module!(codec015);
module!(codec016);
module!(codec018);

/*--------------------------------------------------------------*/

/// Result of a GroupByX operation: a grouping type, start index, and
/// length.
#[derive(Clone,Copy,Debug,Eq,PartialEq)]
enum Group {
    Same(usize, usize),
    Diff(usize, usize),
}

/// An iterator that groups the two input streams based on whether
/// corresponding items are equal.  It returns whether they are equal
/// and the length until that comparison changes value.
///
/// This is suitable for compressing skip/memcpy type codecs,
/// e.g. FLI_COLOR64, FLI_COLOR256.
struct GroupByEq<I: Iterator> where I::Item: PartialEq {
    iter: Zip<I, I>,
    peek: Option<bool>,
    idx: usize,
    prepend_same_run: bool,
    ignore_final_same_run: bool,
}

/// An iterator that groups the two buffers into packets by "runs".
/// A run is a length of the buffer where the corresponding elements
/// of the "old" and "new" buffers are the same, or a stretch of the
/// "new" buffer where all of the elements have the same value.
///
/// This is suitable for compressing skip/memset/memcpy type codes,
/// e.g. FLI_LC, FLI_SS2.
struct GroupByRuns<'a> {
    old: &'a [u8],
    new: &'a [u8],
    idx: usize,
    prepend_same_run: bool,
    ignore_final_same_run: bool,
    group_by_lc: bool,
}

type GroupByLC<'a> = GroupByRuns<'a>;
type GroupBySS2<'a> = GroupByRuns<'a>;

/// An iterator that groups the buffer into packets of the same value.
///
/// This is suitable for compressing memset/memcpy type codecs,
/// e.g. FLI_BRUN.
struct GroupByValue<'a> {
    buf: &'a [u8],
    idx: usize,
}

/*--------------------------------------------------------------*/

/// Returns true if the chunk type modifies the palette.
pub fn chunk_modifies_palette(magic: u16)
        -> bool {
    (magic == FLI_COLOR256) || (magic == FLI_COLOR64) || (magic == FLI_ICOLORS)
}

/// Decode a chunk, based on the chunk type.
pub fn decode_chunk(magic: u16, buf: &[u8], dst: &mut RasterMut)
        -> FlicResult<()> {
    match magic {
        FLI_WRUN => try!(decode_fli_wrun(&buf, dst)),
        FLI_COLOR256 => try!(decode_fli_color256(&buf, dst)),
        FLI_SS2 => try!(decode_fli_ss2(&buf, dst)),
        FLI_SBSRSC => try!(decode_fli_sbsrsc(&buf, dst)),
        FLI_COLOR64 => try!(decode_fli_color64(&buf, dst)),
        FLI_LC => try!(decode_fli_lc(&buf, dst)),
        FLI_BLACK => decode_fli_black(dst),
        FLI_ICOLORS => decode_fli_icolors(dst),
        FLI_BRUN => try!(decode_fli_brun(&buf, dst)),
        FLI_COPY => try!(decode_fli_copy(&buf, dst)),

        // Postage stamps should not be decoded in the same loop as
        // the main animation; they have different sizes and work on
        // different buffers and palettes.
        FLI_PSTAMP => (),

        _ => return Err(FlicError::BadMagic),
    }

    Ok(())
}

/*--------------------------------------------------------------*/

impl<I: Iterator> GroupByEq<I>
        where I::Item: PartialEq {
    /// Create a new GroupByEq iterator.
    fn new(old: I, new: I) -> Self {
        GroupByEq {
            iter: old.zip(new),
            peek: None,
            idx: 0,
            prepend_same_run: false,
            ignore_final_same_run: false,
        }
    }

    /// If set, and if the two buffers start on a "Diff" sequence,
    /// then a "Same" group of length 0 will be added at the start.
    fn set_prepend_same_run(mut self) -> Self {
        assert!(self.peek.is_none());
        self.prepend_same_run = true;
        self
    }

    /// If set, and if the two buffers end on a "Same" sequence,
    /// then this final "same" type group will be ignored.
    fn set_ignore_final_same_run(mut self) -> Self {
        self.ignore_final_same_run = true;
        self
    }
}

impl<I: Iterator> Iterator for GroupByEq<I>
        where I::Item: PartialEq {
    type Item = Group;

    /// Advances the iterator and returns the next value.
    fn next(&mut self) -> Option<Group> {
        let expected: bool;
        let start = self.idx;
        let mut n = 0;

        if self.prepend_same_run {
            self.prepend_same_run = false;
            expected = true;
        } else if let Some(x) = self.peek {
            self.peek = None;
            expected = x;
            n = n + 1;
        } else if let Some((a, b)) = self.iter.next() {
            expected = a == b;
            n = n + 1;
        } else {
            return None;
        }

        for x in self.iter.by_ref().map(|(a, b)| a == b) {
            if x == expected {
                n = n + 1;
            } else {
                self.peek = Some(x);
                break;
            }
        }

        self.idx = self.idx + n;
        if expected {
            if self.ignore_final_same_run && self.peek.is_none() {
                return None;
            }
            return Some(Group::Same(start, n));
        } else {
            return Some(Group::Diff(start, n));
        }
    }
}

impl<'a> GroupByRuns<'a> {
    /// Create a new GroupByLC iterator.
    fn new_lc(old: &'a [u8], new: &'a [u8]) -> Self {
        assert_eq!(old.len(), new.len());
        GroupByLC {
            old: old,
            new: new,
            idx: 0,
            prepend_same_run: false,
            ignore_final_same_run: false,
            group_by_lc: true,
        }
    }

    /// Create a new GroupBySS2 iterator.
    #[allow(dead_code)]
    fn new_ss2(old: &'a [u8], new: &'a [u8]) -> Self {
        assert_eq!(old.len(), new.len());
        GroupBySS2 {
            old: old,
            new: new,
            idx: 0,
            prepend_same_run: false,
            ignore_final_same_run: false,
            group_by_lc: false,
        }
    }

    /// If set, and if the two buffers start on a "Diff" sequence,
    /// then a "Same" group of length 0 will be added at the start.
    fn set_prepend_same_run(mut self) -> Self {
        self.prepend_same_run = true;
        self
    }

    /// If set, and if the two buffers end on a "Same" sequence,
    /// then this final "same" type group will be ignored.
    fn set_ignore_final_same_run(mut self) -> Self {
        self.ignore_final_same_run = true;
        self
    }
}

impl<'a> Iterator for GroupByRuns<'a> {
    type Item = Group;

    /// Advances the iterator and returns the next value.
    fn next(&mut self) -> Option<Group> {
        let len = self.new.len();
        let start = self.idx;
        let mut i = self.idx;

        if i >= len {
            return None;
        } else if self.old[i] == self.new[i]
                || self.prepend_same_run {
            while (i < len) && (self.old[i] == self.new[i]) {
                i = i + 1;
            }

            let n = i - self.idx;
            self.idx = i;
            self.prepend_same_run = false;

            if i >= len && self.ignore_final_same_run {
                return None;
            } else {
                return Some(Group::Same(start, n));
            }
        }

        // GroupByLC.
        if self.group_by_lc {
            let c = self.new[self.idx];
            while (i < len) && (self.old[i] != self.new[i]) && (self.new[i] == c) {
                i = i + 1;
            }

            let n = i - self.idx;
            self.idx = i;
            return Some(Group::Diff(start, n));
        }

        // GroupBySS2.
        if i + 1 >= len {
            self.idx = i + 1;
            return Some(Group::Diff(start, 1));
        } else {
            let c0 = self.new[self.idx + 0];
            let c1 = self.new[self.idx + 1];
            while i + 1 < len {
                if (self.old[i + 0] != self.new[i + 0] || self.old[i + 1] != self.new[i + 1])
                        && (self.new[i + 0] == c0 && self.new[i + 1] == c1) {
                    i = i + 2;
                } else {
                    break;
                }
            }

            let n = i - self.idx;
            self.idx = i;
            return Some(Group::Diff(start, n));
        }
    }
}

impl<'a> GroupByValue<'a> {
    /// Create a new GroupByValue iterator.
    fn new(buf: &'a [u8]) -> Self {
        GroupByValue {
            buf: buf,
            idx: 0,
        }
    }
}

impl<'a> Iterator for GroupByValue<'a> {
    type Item = Group;

    /// Advances the iterator and returns the next value.
    fn next(&mut self) -> Option<Group> {
        let len = self.buf.len();
        let start = self.idx;
        let mut i = self.idx;

        if i >= len {
            return None;
        } else {
            let c = self.buf[self.idx];
            while (i < len) && (self.buf[i] == c) {
                i = i + 1;
            }

            let n = i - self.idx;
            self.idx = i;
            return Some(Group::Same(start, n));
        }
    }
}

/// A little routine to help with linear scaling functions.
fn linscale(sw: usize, dw: usize, dx: usize)
        -> usize {
    assert!(sw > 0 && dw > 0);
    assert!(dx < dw);

    match dx {
        0 => 0,
        _ => (dx * sw + sw / 2) / dw,
    }
}

#[cfg(test)]
mod tests {
    use super::{Group,GroupByEq,GroupByLC,GroupBySS2};

    #[test]
    fn test_group_by_eq() {
        let xs = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
        let ys = [ 0, 0, 3, 4, 5, 0, 7, 8, 9 ];
        let expected = [
            Group::Same(0, 0), // prepend
            Group::Diff(0, 2), Group::Same(2, 3), Group::Diff(5, 1) ];

        let gs: Vec<Group>
            = GroupByEq::new(xs.iter(), ys.iter())
            .set_prepend_same_run()
            .set_ignore_final_same_run()
            .collect();

        assert_eq!(&gs[..], expected);
    }

    #[test]
    fn test_group_by_lc() {
        let xs = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
        let ys = [ 2, 1, 3, 4, 5, 0, 0, 0, 9 ];
        //         ^  ^  ^^^^^^^  ^^^^^^^  ^
        let expected = [
            Group::Same(0, 0), // prepend
            Group::Diff(0, 1), Group::Diff(1, 1), Group::Same(2, 3), Group::Diff(5, 3) ];

        let gs: Vec<Group>
            = GroupByLC::new_lc(&xs, &ys)
            .set_prepend_same_run()
            .set_ignore_final_same_run()
            .collect();

        assert_eq!(&gs[..], expected);
    }

    #[test]
    fn test_group_by_ss2() {
        let xs = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
        let ys = [ 2, 2, 3, 4, 5, 0, 1, 0, 1,  0 ];
        //         ^^^^  ^^^^^^^  ^^^^^^^^^^  ^^
        let expected = [
            Group::Same(0, 0), // prepend
            Group::Diff(0, 2), Group::Same(2, 3), Group::Diff(5, 4), Group::Diff(9, 1) ];

        let gs: Vec<Group>
            = GroupBySS2::new_ss2(&xs, &ys)
            .set_prepend_same_run()
            .set_ignore_final_same_run()
            .collect();

        assert_eq!(&gs[..], expected);
    }

    #[test]
    fn test_group_by_value() {
        use super::{Group,GroupByValue};

        let xs = [ 1, 1, 3, 4, 4, 4, 4, 7, 7 ];
        let expected = [
            Group::Same(0, 2), Group::Same(2, 1), Group::Same(3, 4), Group::Same(7, 2) ];

        let gs: Vec<Group>
            = GroupByValue::new(&xs).collect();

        assert_eq!(&gs[..], expected);
    }
}
<|endoftext|>


<commit_before>use Error;

use std::io::prelude::*;
use std::io::Cursor;
use std::fmt;

/// A packet enum.
pub trait PacketKind : Clone + fmt::Debug
{
    fn read(read: &mut Read) -> Result<Self, Error>;
    fn write(&self, write: &mut Write) -> Result<(), Error>;

    fn bytes(&self) -> Result<Vec<u8>, Error> {
        let mut buffer = Cursor::new(Vec::new());
        self.write(&mut buffer)?;
        Ok(buffer.into_inner())
    }
}

/// A specific packet type.
pub trait Packet : Clone + fmt::Debug
{
    fn read(read: &mut Read) -> Result<Self, Error>;
    fn write(&self, write: &mut Write) -> Result<(), Error>;
}

#[cfg(test)]
mod test {
    define_packet!(Handshake);
    define_packet!(Kick);

    define_packet!(Hello {
        id: i64,
        data: Vec<u8>
    });

    define_packet!(Goodbye {
        id: i64,
        reason: String
    });

    define_packet!(Properties {
        properties: ::std::collections::HashMap<String, bool>
    });

    define_packet_kind!(Packet: u32 {
        0x00 => Handshake,
        0x01 => Kick,
        0x02 => Hello,
        0x03 => Goodbye,
        0x04 => Properties
    });

    describe! packets {
        before_each {
            let hello = Hello { id: 5678, data: vec![1, 2, 3] };
            let goodbye = Goodbye { id: 8765, reason: "um".to_string() };
        }

        describe! packet_ids {
            describe! numerical {
                it "gets the corrrect ids" {
                    assert_eq!(Packet::Handshake(Handshake).packet_id(), 0x00);
                    assert_eq!(Packet::Kick(Kick).packet_id(), 0x01);

                    assert_eq!(Packet::Hello(hello).packet_id(), 0x02);
                    assert_eq!(Packet::Goodbye(goodbye).packet_id(), 0x03);
                }
            }
        }
    }
}

<commit_msg>Add more packet tests<commit_after>use Error;

use std::io::prelude::*;
use std::io::Cursor;
use std::fmt;

/// A packet enum.
pub trait PacketKind : Clone + fmt::Debug
{
    fn read(read: &mut Read) -> Result<Self, Error>;
    fn write(&self, write: &mut Write) -> Result<(), Error>;

    fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
        let mut buffer = Cursor::new(bytes);
        Self::read(&mut buffer)
    }

    fn bytes(&self) -> Result<Vec<u8>, Error> {
        let mut buffer = Cursor::new(Vec::new());
        self.write(&mut buffer)?;
        Ok(buffer.into_inner())
    }
}

/// A specific packet type.
pub trait Packet : Clone + fmt::Debug
{
    fn read(read: &mut Read) -> Result<Self, Error>;
    fn write(&self, write: &mut Write) -> Result<(), Error>;
}

#[cfg(test)]
#[allow(unused_variables)]
mod test {
    pub use PacketKind;

    define_packet!(Handshake);
    define_packet!(Kick);

    define_packet!(Hello {
        id: i64,
        data: Vec<u8>
    });

    define_packet!(Goodbye {
        id: i64,
        reason: String
    });

    define_packet!(Properties {
        properties: ::std::collections::HashMap<String, bool>
    });

    define_packet_kind!(Packet: u32 {
        0x00 => Handshake,
        0x01 => Kick,
        0x02 => Hello,
        0x03 => Goodbye,
        0x04 => Properties
    });

    describe! packets {
        before_each {
            let hello = Hello { id: 55, data: vec![1, 2, 3] };
            let goodbye = Goodbye { id: 8765, reason: "um".to_string() };

            let hello_expected_bytes = &[
                0x00, 0x00, 0x00, 0x02, // Packet ID
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55, // 'id' field
                0x00, 0x00, 0x00, 0x03, // 'data' length
                0x01, 0x02, 0x03, // 'data' array
            ];
        }

        describe! packet_ids {
            describe! numerical {
                it "gets the corrrect ids" {
                    assert_eq!(Packet::Handshake(Handshake).packet_id(), 0x00);
                    assert_eq!(Packet::Kick(Kick).packet_id(), 0x01);

                    assert_eq!(Packet::Hello(hello).packet_id(), 0x02);
                    assert_eq!(Packet::Goodbye(goodbye).packet_id(), 0x03);
                }
            }

            describe! writing {
                it "writes the correct values" {
                    let packet = Packet::Hello(hello);

                    assert_eq!(&packet.bytes().unwrap(), hello_expected_bytes);
                }
            }

            describe! reading {
                it "reads the correct values" {
                    let packet = Packet::from_bytes(hello_expected_bytes).unwrap();

                    assert_eq!(packet.bytes().unwrap(), hello_expected_bytes);
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>//! Abstraction of spatial partitioning schemes

pub use partition::interval::Interval;
pub use partition::boxes::{Box2, Box3};
pub use partition::ncube::Ncube;
pub use partition::unitquad::UnitQuad;

/// A type describing a partition of some space
///
/// In addition to this trait signature an implementation is required to satisfy
/// `prop_is_total`.
pub trait Partition<T>: Sized {
    // TODO: uncomment the following, as soon as this bug is fixed.
    // link: https://github.com/rust-lang/rust/issues/20551

    // The type of subsequent partitions
    // type Subpartition: Partition<T> = Self;

    /// Subdivide into smaller partitions
    fn subdivide(&self) -> Vec<Self>;

    /// Does the partition contain an element?
    fn contains(&self, elem: &T) -> bool;

    /// Dispatch an element to the correct subpartition
    ///
    /// The default implementation works, if the totality proposition is
    /// fulfilled. However, note that its performance is not optimal, as it
    /// checks for all subpartitions whether they contain the element, until one
    /// is found that does.
    fn dispatch(&self, elem: &T) -> usize {
        for (i, part) in self.subdivide().iter().enumerate() {
            if part.contains(elem) {
                return i;
            }
        }
        panic!("partition dispatch impossible");
    }
}

/// Totality proposition
///
/// A partition is required to be total, i.e. any element contained in the
/// partition will be contained in exactly one of its subdivided partitions.
/// At the same time, an element not contained in the partition can not be
/// contained by any subdivided partition.
pub fn prop_is_total<P: Partition<T>, T>(partition: P, elem: T) -> bool {
    let subs = partition.subdivide();
    if partition.contains(&elem) {
        subs.iter().filter(|sub| sub.contains(&elem)).count() == 1
    }
    else {
        subs.iter().all(|sub| !sub.contains(&elem))
    }
}

/// Consistency of dispatch mechanism
///
/// An element contained in the partition must be dispatched consistently, i.e.
/// the subpartition to which it is dispatched must contain it.
pub fn prop_consistent_dispatch<P: Partition<T>, T>(partition: P, elem: T) -> bool {
    if partition.contains(&elem) {
        partition.subdivide()[partition.dispatch(&elem)].contains(&elem)
    }
    else {
        true
    }
}

#[macro_escape]
macro_rules! partition_quickcheck (
    ($testfn: ident, $p: ty, $t: ty) => (
        mod $testfn {
            use $crate::partition::{prop_is_total, prop_consistent_dispatch};
            use quickcheck::quickcheck;
            use super::*;

            #[test]
            fn is_total() {
                quickcheck(prop_is_total as fn($p, $t) -> bool);
            }

            #[test]
            fn consistent_dispatch() {
                quickcheck(prop_consistent_dispatch as fn($p, $t) -> bool);
            }
        }
    )
);

/// The notion of a mid point between two inputs
trait Mid {
    /// Return the mid between this point and another
    fn mid(&self, other: &Self) -> Self;
}

impl Mid for f64 {
    fn mid(&self, other: &f64) -> f64 { (*self + *other) / 2.0 }
}

impl Mid for f32 {
    fn mid(&self, other: &f32) -> f32 { (*self + *other) / 2.0 }
}

mod interval;
mod boxes;
mod ncube;
mod unitquad;
<commit_msg>Split partition's totality proposition<commit_after>//! Abstraction of spatial partitioning schemes

pub use partition::interval::Interval;
pub use partition::boxes::{Box2, Box3};
pub use partition::ncube::Ncube;
pub use partition::unitquad::UnitQuad;

#[cfg(any(test, feature = "arbitrary"))]
use quickcheck::TestResult;

/// A type describing a partition of some space
///
/// In addition to this trait signature an implementation is required to satisfy
/// `prop_is_total`.
pub trait Partition<T>: Sized {
    // TODO: uncomment the following, as soon as this bug is fixed.
    // link: https://github.com/rust-lang/rust/issues/20551

    // The type of subsequent partitions
    // type Subpartition: Partition<T> = Self;

    /// Subdivide into smaller partitions
    fn subdivide(&self) -> Vec<Self>;

    /// Does the partition contain an element?
    fn contains(&self, elem: &T) -> bool;

    /// Dispatch an element to the correct subpartition
    ///
    /// The default implementation works, if the totality proposition is
    /// fulfilled. However, note that its performance is not optimal, as it
    /// checks for all subpartitions whether they contain the element, until one
    /// is found that does.
    fn dispatch(&self, elem: &T) -> usize {
        for (i, part) in self.subdivide().iter().enumerate() {
            if part.contains(elem) {
                return i;
            }
        }
        panic!("partition dispatch impossible");
    }
}

/// Totality proposition (contained)
///
/// Any element contained in the partition will be contained in exactly one of
/// its subpartitions.
#[cfg(any(test, feature = "arbitrary"))]
pub fn prop_is_total_elem<P: Partition<T>, T>(partition: P, elem: T) -> TestResult {
    if partition.contains(&elem) {
        TestResult::from_bool(
            partition.subdivide().iter()
                .filter(|sub| sub.contains(&elem)).count()
            == 1
        )
    }
    else {
        TestResult::discard()
    }
}

/// Totality proposition (not contained)
///
/// If a partition does not contain an element, none of its subpartitions
/// contain it either.
#[cfg(any(test, feature = "arbitrary"))]
pub fn prop_is_total_non_elem<P: Partition<T>, T>(partition: P, elem: T) -> TestResult {
    if partition.contains(&elem) {
        TestResult::discard()
    }
    else {
        TestResult::from_bool(
            partition.subdivide().iter()
                .all(|sub| !sub.contains(&elem))
        )
    }
}

/// Consistency of dispatch mechanism
///
/// An element contained in the partition must be dispatched consistently, i.e.
/// the subpartition to which it is dispatched must contain it.
#[cfg(any(test, feature = "arbitrary"))]
pub fn prop_consistent_dispatch<P: Partition<T>, T>(partition: P, elem: T) -> TestResult {
    if partition.contains(&elem) {
        TestResult::from_bool(partition.subdivide()[partition.dispatch(&elem)].contains(&elem))
    }
    else {
        TestResult::discard()
    }
}

#[macro_escape]
macro_rules! partition_quickcheck (
    ($testfn: ident, $p: ty, $t: ty) => (
        mod $testfn {
            use $crate::partition::{
                prop_is_total_elem, prop_is_total_non_elem,
                prop_consistent_dispatch
            };
            use quickcheck::{quickcheck, TestResult};
            use super::*;

            #[test]
            fn is_total_elem() {
                quickcheck(prop_is_total_elem as fn($p, $t) -> TestResult);
            }

            #[test]
            fn is_total_non_elem() {
                quickcheck(prop_is_total_non_elem as fn($p, $t) -> TestResult);
            }

            #[test]
            fn consistent_dispatch() {
                quickcheck(prop_consistent_dispatch as fn($p, $t) -> TestResult);
            }
        }
    )
);

/// The notion of a mid point between two inputs
trait Mid {
    /// Return the mid between this point and another
    fn mid(&self, other: &Self) -> Self;
}

impl Mid for f64 {
    fn mid(&self, other: &f64) -> f64 { (*self + *other) / 2.0 }
}

impl Mid for f32 {
    fn mid(&self, other: &f32) -> f32 { (*self + *other) / 2.0 }
}

mod interval;
mod boxes;
mod ncube;
mod unitquad;
<|endoftext|>


<commit_before>//! Implementation of the `#[simd_test]` macro
//!
//! This macro expands to a `#[test]` function which tests the local machine
//! for the appropriate cfg before calling the inner test function.

#![feature(proc_macro)]

extern crate proc_macro2;
extern crate proc_macro;
#[macro_use]
extern crate quote;

use proc_macro2::{Term, TokenNode, TokenStream, TokenTree};
use proc_macro2::Literal;

fn string(s: &str) -> TokenTree {
    TokenTree {
        kind: TokenNode::Literal(Literal::string(s)),

        span: Default::default(),
    }
}

#[proc_macro_attribute]
pub fn simd_test(
    attr: proc_macro::TokenStream, item: proc_macro::TokenStream
) -> proc_macro::TokenStream {
    let tokens = TokenStream::from(attr).into_iter().collect::<Vec<_>>();
    if tokens.len() != 2 {
        panic!("expected #[simd_test = \"feature\"]");
    }
    match tokens[0].kind {
        TokenNode::Op('=', _) => {}
        _ => panic!("expected #[simd_test = \"feature\"]"),
    }
    let target_feature = &tokens[1];
    let enable_feature = match tokens[1].kind {
        TokenNode::Literal(ref l) => l.to_string(),
        _ => panic!("expected #[simd_test = \"feature\"]"),
    };
    let enable_feature = enable_feature
        .trim_left_matches('"')
        .trim_right_matches('"');
    let enable_feature = string(&format!("+{}", enable_feature));
    let item = TokenStream::from(item);
    let name = find_name(item.clone());

    let name: TokenStream = name.as_str().parse().unwrap();

    let ret: TokenStream = quote! {
        #[allow(non_snake_case)]
        #[test]
        fn #name() {
            if cfg_feature_enabled!(#target_feature) {
                return unsafe { #name() };
            } else {
                ::stdsimd_test::assert_skip_test_ok(stringify!(#name));
            }

            #[target_feature = #enable_feature]
            #item
        }
    }.into();
    ret.into()
}

fn find_name(item: TokenStream) -> Term {
    let mut tokens = item.into_iter();
    while let Some(tok) = tokens.next() {
        if let TokenNode::Term(word) = tok.kind {
            if word.as_str() == "fn" {
                break;
            }
        }
    }

    match tokens.next().map(|t| t.kind) {
        Some(TokenNode::Term(word)) => word,
        _ => panic!("failed to find function name"),
    }
}
<commit_msg>[stdsimd-test] testing conditional on more than one feature<commit_after>//! Implementation of the `#[simd_test]` macro
//!
//! This macro expands to a `#[test]` function which tests the local machine
//! for the appropriate cfg before calling the inner test function.

#![feature(proc_macro)]

extern crate proc_macro2;
extern crate proc_macro;
#[macro_use]
extern crate quote;

use proc_macro2::{Term, TokenNode, TokenStream, TokenTree};
use proc_macro2::Literal;

fn string(s: &str) -> TokenTree {
    TokenTree {
        kind: TokenNode::Literal(Literal::string(s)),

        span: Default::default(),
    }
}

#[proc_macro_attribute]
pub fn simd_test(
    attr: proc_macro::TokenStream, item: proc_macro::TokenStream
) -> proc_macro::TokenStream {
    let tokens = TokenStream::from(attr).into_iter().collect::<Vec<_>>();
    if tokens.len() != 2 {
        panic!("expected #[simd_test = \"feature\"]");
    }
    match tokens[0].kind {
        TokenNode::Op('=', _) => {}
        _ => panic!("expected #[simd_test = \"feature\"]"),
    }
    let target_features = match tokens[1].kind {
        TokenNode::Literal(ref l) => l.to_string(),
        _ => panic!("expected #[simd_test = \"feature\"]"),
    };
    let target_features: Vec<String> = target_features
        .replace('"', "")
        .replace('+', "")
        .split(',')
        .map(|v| String::from(v))
        .collect();

    let enable_feature = match tokens[1].kind {
        TokenNode::Literal(ref l) => l.to_string(),
        _ => panic!("expected #[simd_test = \"feature\"]"),
    };
    let enable_feature = enable_feature
        .trim_left_matches('"')
        .trim_right_matches('"');
    let enable_feature =
        string(&(format!("+{}", enable_feature).replace(',', ",+")));
    let item = TokenStream::from(item);
    let name = find_name(item.clone());

    let name: TokenStream = name.as_str().parse().unwrap();

    let mut cfg_target_features = quote::Tokens::new();
    use quote::ToTokens;
    for feature in target_features {
        let q = quote! {
            cfg_feature_enabled!(#feature) &&
        };
        q.to_tokens(&mut cfg_target_features);
    }
    let q = quote!{ true };
    q.to_tokens(&mut cfg_target_features);

    let ret: TokenStream = quote! {
        #[allow(non_snake_case)]
        #[test]
        fn #name() {
            if #cfg_target_features {
                return unsafe { #name() };
            } else {
                ::stdsimd_test::assert_skip_test_ok(stringify!(#name));
            }

            #[target_feature = #enable_feature]
            #item
        }
    }.into();
    ret.into()
}

fn find_name(item: TokenStream) -> Term {
    let mut tokens = item.into_iter();
    while let Some(tok) = tokens.next() {
        if let TokenNode::Term(word) = tok.kind {
            if word.as_str() == "fn" {
                break;
            }
        }
    }

    match tokens.next().map(|t| t.kind) {
        Some(TokenNode::Term(word)) => word,
        _ => panic!("failed to find function name"),
    }
}
<|endoftext|>


<commit_before>use cranelift_entity::{entity_impl, EntityRef, PrimaryMap};

#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct RegBankIndex(u32);
entity_impl!(RegBankIndex);

pub struct RegBank {
    pub name: &'static str,
    pub first_unit: u8,
    pub units: u8,
    pub names: Vec<&'static str>,
    pub prefix: &'static str,
    pub pressure_tracking: bool,
    pub toprcs: Vec<RegClassIndex>,
    pub classes: Vec<RegClassIndex>,
}

impl RegBank {
    pub fn new(
        name: &'static str,
        first_unit: u8,
        units: u8,
        names: Vec<&'static str>,
        prefix: &'static str,
        pressure_tracking: bool,
    ) -> Self {
        RegBank {
            name,
            first_unit,
            units,
            names,
            prefix,
            pressure_tracking,
            toprcs: Vec::new(),
            classes: Vec::new(),
        }
    }

    fn unit_by_name(&self, name: &'static str) -> u8 {
        let unit = if let Some(found) = self.names.iter().position(|&reg_name| reg_name == name) {
            found
        } else {
            // Try to match without the bank prefix.
            assert!(name.starts_with(self.prefix));
            let name_without_prefix = &name[self.prefix.len()..];
            self.names
                .iter()
                .position(|&reg_name| reg_name == name_without_prefix)
                .expect(&format!("invalid register name {}", name))
        };
        self.first_unit + (unit as u8)
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct RegClassIndex(u32);
entity_impl!(RegClassIndex);

pub struct RegClass {
    pub name: &'static str,
    pub index: RegClassIndex,
    pub width: u8,
    pub bank: RegBankIndex,
    pub toprc: RegClassIndex,
    pub count: u8,
    pub start: u8,
    pub subclasses: Vec<RegClassIndex>,
}

impl RegClass {
    pub fn new(
        name: &'static str,
        index: RegClassIndex,
        width: u8,
        bank: RegBankIndex,
        toprc: RegClassIndex,
        count: u8,
        start: u8,
    ) -> Self {
        Self {
            name,
            index,
            width,
            bank,
            toprc,
            count,
            start,
            subclasses: Vec::new(),
        }
    }

    /// Compute a bit-mask of subclasses, including self.
    pub fn subclass_mask(&self) -> u64 {
        let mut m = 1 << self.index.index();
        for rc in self.subclasses.iter() {
            m |= 1 << rc.index();
        }
        m
    }

    /// Compute a bit-mask of the register units allocated by this register class.
    pub fn mask(&self, bank_first_unit: u8) -> Vec<u32> {
        let mut u = (self.start + bank_first_unit) as usize;
        let mut out_mask = vec![0, 0, 0];
        for _ in 0..self.count {
            out_mask[u / 32] |= 1 << (u % 32);
            u += self.width as usize;
        }
        out_mask
    }
}

pub enum RegClassProto {
    TopLevel(RegBankIndex),
    SubClass(RegClassIndex),
}

pub struct RegClassBuilder {
    pub name: &'static str,
    pub width: u8,
    pub count: u8,
    pub start: u8,
    pub proto: RegClassProto,
}

impl RegClassBuilder {
    pub fn new_toplevel(name: &'static str, bank: RegBankIndex) -> Self {
        Self {
            name,
            width: 1,
            count: 0,
            start: 0,
            proto: RegClassProto::TopLevel(bank),
        }
    }
    pub fn subclass_of(
        name: &'static str,
        parent_index: RegClassIndex,
        start: u8,
        stop: u8,
    ) -> Self {
        assert!(stop >= start);
        Self {
            name,
            width: 0,
            count: stop - start,
            start: start,
            proto: RegClassProto::SubClass(parent_index),
        }
    }
    pub fn count(mut self, count: u8) -> Self {
        self.count = count;
        self
    }
    pub fn width(mut self, width: u8) -> Self {
        match self.proto {
            RegClassProto::TopLevel(_) => self.width = width,
            RegClassProto::SubClass(_) => panic!("Subclasses inherit their parent's width."),
        }
        self
    }
}

pub struct RegBankBuilder {
    pub name: &'static str,
    pub units: u8,
    pub names: Vec<&'static str>,
    pub prefix: &'static str,
    pub pressure_tracking: Option<bool>,
}

impl RegBankBuilder {
    pub fn new(name: &'static str, prefix: &'static str) -> Self {
        Self {
            name,
            units: 0,
            names: vec![],
            prefix,
            pressure_tracking: None,
        }
    }
    pub fn units(mut self, units: u8) -> Self {
        self.units = units;
        self
    }
    pub fn names(mut self, names: Vec<&'static str>) -> Self {
        self.names = names;
        self
    }
    pub fn track_pressure(mut self, track: bool) -> Self {
        self.pressure_tracking = Some(track);
        self
    }
}

pub struct IsaRegsBuilder {
    pub banks: PrimaryMap<RegBankIndex, RegBank>,
    pub classes: PrimaryMap<RegClassIndex, RegClass>,
}

impl IsaRegsBuilder {
    pub fn new() -> Self {
        Self {
            banks: PrimaryMap::new(),
            classes: PrimaryMap::new(),
        }
    }

    pub fn add_bank(&mut self, builder: RegBankBuilder) -> RegBankIndex {
        let first_unit = if self.banks.len() == 0 {
            0
        } else {
            let last = &self.banks.last().unwrap();
            let first_available_unit = (last.first_unit + last.units) as i8;
            let units = builder.units;
            let align = if units.is_power_of_two() {
                units
            } else {
                units.next_power_of_two()
            } as i8;
            (first_available_unit + align - 1) & -align
        } as u8;

        self.banks.push(RegBank::new(
            builder.name,
            first_unit,
            builder.units,
            builder.names,
            builder.prefix,
            builder
                .pressure_tracking
                .expect("Pressure tracking must be explicitly set"),
        ))
    }

    pub fn add_class(&mut self, builder: RegClassBuilder) -> RegClassIndex {
        let class_index = self.classes.next_key();

        // Finish delayed construction of RegClass.
        let (bank, toprc, start, width) = match builder.proto {
            RegClassProto::TopLevel(bank_index) => {
                self.banks
                    .get_mut(bank_index)
                    .unwrap()
                    .toprcs
                    .push(class_index);
                (bank_index, class_index, builder.start, builder.width)
            }
            RegClassProto::SubClass(parent_class_index) => {
                assert!(builder.width == 0);
                let (bank, toprc, start, width) = {
                    let parent = self.classes.get(parent_class_index).unwrap();
                    (parent.bank, parent.toprc, parent.start, parent.width)
                };
                for reg_class in self.classes.values_mut() {
                    if reg_class.toprc == toprc {
                        reg_class.subclasses.push(class_index);
                    }
                }
                let subclass_start = start + builder.start * width;
                (bank, toprc, subclass_start, width)
            }
        };

        let reg_bank_units = self.banks.get(bank).unwrap().units;
        assert!(start < reg_bank_units);

        let count = if builder.count != 0 {
            builder.count
        } else {
            reg_bank_units / width
        };

        let reg_class = RegClass::new(builder.name, class_index, width, bank, toprc, count, start);
        self.classes.push(reg_class);

        let reg_bank = self.banks.get_mut(bank).unwrap();
        reg_bank.classes.push(class_index);

        class_index
    }

    /// Checks that the set of register classes satisfies:
    ///
    /// 1. Closed under intersection: The intersection of any two register
    ///    classes in the set is either empty or identical to a member of the
    ///    set.
    /// 2. There are no identical classes under different names.
    /// 3. Classes are sorted topologically such that all subclasses have a
    ///    higher index that the superclass.
    pub fn build(self) -> IsaRegs {
        for reg_bank in self.banks.values() {
            for i1 in reg_bank.classes.iter() {
                for i2 in reg_bank.classes.iter() {
                    if i1 >= i2 {
                        continue;
                    }

                    let rc1 = self.classes.get(*i1).unwrap();
                    let rc2 = self.classes.get(*i2).unwrap();

                    let rc1_mask = rc1.mask(0);
                    let rc2_mask = rc2.mask(0);

                    assert!(
                        rc1.width != rc2.width || rc1_mask != rc2_mask,
                        "no duplicates"
                    );
                    if rc1.width != rc2.width {
                        continue;
                    }

                    let mut intersect = Vec::new();
                    for (a, b) in rc1_mask.iter().zip(rc2_mask.iter()) {
                        intersect.push(a & b);
                    }
                    if intersect == vec![0; intersect.len()] {
                        continue;
                    }

                    // Classes must be topologically ordered, so the intersection can't be the
                    // superclass.
                    assert!(intersect != rc1_mask);

                    // If the intersection is the second one, then it must be a subclass.
                    if intersect == rc2_mask {
                        assert!(self
                            .classes
                            .get(*i1)
                            .unwrap()
                            .subclasses
                            .iter()
                            .find(|x| **x == *i2)
                            .is_some());
                    }
                }
            }
        }

        // This limit should be coordinated with the `RegClassMask` and `RegClassIndex` types in
        // isa/registers.rs of the non-meta code.
        assert!(self.classes.len() <= 32, "Too many register classes");

        // The maximum number of top-level register classes which have pressure tracking should be
        // kept in sync with the MAX_TRACKED_TOPRCS constant in isa/registers.rs of the non-meta
        // code.
        let num_toplevel = self
            .classes
            .values()
            .filter(|x| x.toprc == x.index && self.banks.get(x.bank).unwrap().pressure_tracking)
            .count();
        assert!(num_toplevel <= 4, "Too many top-level register classes");

        IsaRegs::new(self.banks, self.classes)
    }
}

pub struct IsaRegs {
    pub banks: PrimaryMap<RegBankIndex, RegBank>,
    pub classes: PrimaryMap<RegClassIndex, RegClass>,
}

impl IsaRegs {
    fn new(
        banks: PrimaryMap<RegBankIndex, RegBank>,
        classes: PrimaryMap<RegClassIndex, RegClass>,
    ) -> Self {
        Self { banks, classes }
    }

    pub fn class_by_name(&self, name: &str) -> RegClassIndex {
        self.classes
            .values()
            .find(|&class| class.name == name)
            .expect(&format!("register class {} not found", name))
            .index
    }

    pub fn regunit_by_name(&self, class_index: RegClassIndex, name: &'static str) -> u8 {
        let bank_index = self.classes.get(class_index).unwrap().bank;
        self.banks.get(bank_index).unwrap().unit_by_name(name)
    }
}
<commit_msg>[meta] Try to use {prefix+number} when looking up a register by name;<commit_after>use cranelift_entity::{entity_impl, EntityRef, PrimaryMap};

#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct RegBankIndex(u32);
entity_impl!(RegBankIndex);

pub struct RegBank {
    pub name: &'static str,
    pub first_unit: u8,
    pub units: u8,
    pub names: Vec<&'static str>,
    pub prefix: &'static str,
    pub pressure_tracking: bool,
    pub toprcs: Vec<RegClassIndex>,
    pub classes: Vec<RegClassIndex>,
}

impl RegBank {
    pub fn new(
        name: &'static str,
        first_unit: u8,
        units: u8,
        names: Vec<&'static str>,
        prefix: &'static str,
        pressure_tracking: bool,
    ) -> Self {
        RegBank {
            name,
            first_unit,
            units,
            names,
            prefix,
            pressure_tracking,
            toprcs: Vec::new(),
            classes: Vec::new(),
        }
    }

    fn unit_by_name(&self, name: &'static str) -> u8 {
        let unit = if let Some(found) = self.names.iter().position(|&reg_name| reg_name == name) {
            found
        } else {
            // Try to match without the bank prefix.
            assert!(name.starts_with(self.prefix));
            let name_without_prefix = &name[self.prefix.len()..];
            if let Some(found) = self
                .names
                .iter()
                .position(|&reg_name| reg_name == name_without_prefix)
            {
                found
            } else {
                // Ultimate try: try to parse a number and use this in the array, eg r15 on x86.
                if let Ok(as_num) = name_without_prefix.parse::<u8>() {
                    assert!(
                        (as_num - self.first_unit) < self.units,
                        "trying to get {}, but bank only has {} registers!",
                        name,
                        self.units
                    );
                    (as_num - self.first_unit) as usize
                } else {
                    panic!("invalid register name {}", name);
                }
            }
        };
        self.first_unit + (unit as u8)
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct RegClassIndex(u32);
entity_impl!(RegClassIndex);

pub struct RegClass {
    pub name: &'static str,
    pub index: RegClassIndex,
    pub width: u8,
    pub bank: RegBankIndex,
    pub toprc: RegClassIndex,
    pub count: u8,
    pub start: u8,
    pub subclasses: Vec<RegClassIndex>,
}

impl RegClass {
    pub fn new(
        name: &'static str,
        index: RegClassIndex,
        width: u8,
        bank: RegBankIndex,
        toprc: RegClassIndex,
        count: u8,
        start: u8,
    ) -> Self {
        Self {
            name,
            index,
            width,
            bank,
            toprc,
            count,
            start,
            subclasses: Vec::new(),
        }
    }

    /// Compute a bit-mask of subclasses, including self.
    pub fn subclass_mask(&self) -> u64 {
        let mut m = 1 << self.index.index();
        for rc in self.subclasses.iter() {
            m |= 1 << rc.index();
        }
        m
    }

    /// Compute a bit-mask of the register units allocated by this register class.
    pub fn mask(&self, bank_first_unit: u8) -> Vec<u32> {
        let mut u = (self.start + bank_first_unit) as usize;
        let mut out_mask = vec![0, 0, 0];
        for _ in 0..self.count {
            out_mask[u / 32] |= 1 << (u % 32);
            u += self.width as usize;
        }
        out_mask
    }
}

pub enum RegClassProto {
    TopLevel(RegBankIndex),
    SubClass(RegClassIndex),
}

pub struct RegClassBuilder {
    pub name: &'static str,
    pub width: u8,
    pub count: u8,
    pub start: u8,
    pub proto: RegClassProto,
}

impl RegClassBuilder {
    pub fn new_toplevel(name: &'static str, bank: RegBankIndex) -> Self {
        Self {
            name,
            width: 1,
            count: 0,
            start: 0,
            proto: RegClassProto::TopLevel(bank),
        }
    }
    pub fn subclass_of(
        name: &'static str,
        parent_index: RegClassIndex,
        start: u8,
        stop: u8,
    ) -> Self {
        assert!(stop >= start);
        Self {
            name,
            width: 0,
            count: stop - start,
            start: start,
            proto: RegClassProto::SubClass(parent_index),
        }
    }
    pub fn count(mut self, count: u8) -> Self {
        self.count = count;
        self
    }
    pub fn width(mut self, width: u8) -> Self {
        match self.proto {
            RegClassProto::TopLevel(_) => self.width = width,
            RegClassProto::SubClass(_) => panic!("Subclasses inherit their parent's width."),
        }
        self
    }
}

pub struct RegBankBuilder {
    pub name: &'static str,
    pub units: u8,
    pub names: Vec<&'static str>,
    pub prefix: &'static str,
    pub pressure_tracking: Option<bool>,
}

impl RegBankBuilder {
    pub fn new(name: &'static str, prefix: &'static str) -> Self {
        Self {
            name,
            units: 0,
            names: vec![],
            prefix,
            pressure_tracking: None,
        }
    }
    pub fn units(mut self, units: u8) -> Self {
        self.units = units;
        self
    }
    pub fn names(mut self, names: Vec<&'static str>) -> Self {
        self.names = names;
        self
    }
    pub fn track_pressure(mut self, track: bool) -> Self {
        self.pressure_tracking = Some(track);
        self
    }
}

pub struct IsaRegsBuilder {
    pub banks: PrimaryMap<RegBankIndex, RegBank>,
    pub classes: PrimaryMap<RegClassIndex, RegClass>,
}

impl IsaRegsBuilder {
    pub fn new() -> Self {
        Self {
            banks: PrimaryMap::new(),
            classes: PrimaryMap::new(),
        }
    }

    pub fn add_bank(&mut self, builder: RegBankBuilder) -> RegBankIndex {
        let first_unit = if self.banks.len() == 0 {
            0
        } else {
            let last = &self.banks.last().unwrap();
            let first_available_unit = (last.first_unit + last.units) as i8;
            let units = builder.units;
            let align = if units.is_power_of_two() {
                units
            } else {
                units.next_power_of_two()
            } as i8;
            (first_available_unit + align - 1) & -align
        } as u8;

        self.banks.push(RegBank::new(
            builder.name,
            first_unit,
            builder.units,
            builder.names,
            builder.prefix,
            builder
                .pressure_tracking
                .expect("Pressure tracking must be explicitly set"),
        ))
    }

    pub fn add_class(&mut self, builder: RegClassBuilder) -> RegClassIndex {
        let class_index = self.classes.next_key();

        // Finish delayed construction of RegClass.
        let (bank, toprc, start, width) = match builder.proto {
            RegClassProto::TopLevel(bank_index) => {
                self.banks
                    .get_mut(bank_index)
                    .unwrap()
                    .toprcs
                    .push(class_index);
                (bank_index, class_index, builder.start, builder.width)
            }
            RegClassProto::SubClass(parent_class_index) => {
                assert!(builder.width == 0);
                let (bank, toprc, start, width) = {
                    let parent = self.classes.get(parent_class_index).unwrap();
                    (parent.bank, parent.toprc, parent.start, parent.width)
                };
                for reg_class in self.classes.values_mut() {
                    if reg_class.toprc == toprc {
                        reg_class.subclasses.push(class_index);
                    }
                }
                let subclass_start = start + builder.start * width;
                (bank, toprc, subclass_start, width)
            }
        };

        let reg_bank_units = self.banks.get(bank).unwrap().units;
        assert!(start < reg_bank_units);

        let count = if builder.count != 0 {
            builder.count
        } else {
            reg_bank_units / width
        };

        let reg_class = RegClass::new(builder.name, class_index, width, bank, toprc, count, start);
        self.classes.push(reg_class);

        let reg_bank = self.banks.get_mut(bank).unwrap();
        reg_bank.classes.push(class_index);

        class_index
    }

    /// Checks that the set of register classes satisfies:
    ///
    /// 1. Closed under intersection: The intersection of any two register
    ///    classes in the set is either empty or identical to a member of the
    ///    set.
    /// 2. There are no identical classes under different names.
    /// 3. Classes are sorted topologically such that all subclasses have a
    ///    higher index that the superclass.
    pub fn build(self) -> IsaRegs {
        for reg_bank in self.banks.values() {
            for i1 in reg_bank.classes.iter() {
                for i2 in reg_bank.classes.iter() {
                    if i1 >= i2 {
                        continue;
                    }

                    let rc1 = self.classes.get(*i1).unwrap();
                    let rc2 = self.classes.get(*i2).unwrap();

                    let rc1_mask = rc1.mask(0);
                    let rc2_mask = rc2.mask(0);

                    assert!(
                        rc1.width != rc2.width || rc1_mask != rc2_mask,
                        "no duplicates"
                    );
                    if rc1.width != rc2.width {
                        continue;
                    }

                    let mut intersect = Vec::new();
                    for (a, b) in rc1_mask.iter().zip(rc2_mask.iter()) {
                        intersect.push(a & b);
                    }
                    if intersect == vec![0; intersect.len()] {
                        continue;
                    }

                    // Classes must be topologically ordered, so the intersection can't be the
                    // superclass.
                    assert!(intersect != rc1_mask);

                    // If the intersection is the second one, then it must be a subclass.
                    if intersect == rc2_mask {
                        assert!(self
                            .classes
                            .get(*i1)
                            .unwrap()
                            .subclasses
                            .iter()
                            .find(|x| **x == *i2)
                            .is_some());
                    }
                }
            }
        }

        // This limit should be coordinated with the `RegClassMask` and `RegClassIndex` types in
        // isa/registers.rs of the non-meta code.
        assert!(self.classes.len() <= 32, "Too many register classes");

        // The maximum number of top-level register classes which have pressure tracking should be
        // kept in sync with the MAX_TRACKED_TOPRCS constant in isa/registers.rs of the non-meta
        // code.
        let num_toplevel = self
            .classes
            .values()
            .filter(|x| x.toprc == x.index && self.banks.get(x.bank).unwrap().pressure_tracking)
            .count();
        assert!(num_toplevel <= 4, "Too many top-level register classes");

        IsaRegs::new(self.banks, self.classes)
    }
}

pub struct IsaRegs {
    pub banks: PrimaryMap<RegBankIndex, RegBank>,
    pub classes: PrimaryMap<RegClassIndex, RegClass>,
}

impl IsaRegs {
    fn new(
        banks: PrimaryMap<RegBankIndex, RegBank>,
        classes: PrimaryMap<RegClassIndex, RegClass>,
    ) -> Self {
        Self { banks, classes }
    }

    pub fn class_by_name(&self, name: &str) -> RegClassIndex {
        self.classes
            .values()
            .find(|&class| class.name == name)
            .expect(&format!("register class {} not found", name))
            .index
    }

    pub fn regunit_by_name(&self, class_index: RegClassIndex, name: &'static str) -> u8 {
        let bank_index = self.classes.get(class_index).unwrap().bank;
        self.banks.get(bank_index).unwrap().unit_by_name(name)
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::ffi::{CString};

#[link(name = "ncurses")]
#[allow(dead_code)]
extern "C" {
    fn getpid() -> i32;
    fn initscr() -> *mut i8;
    fn noecho() -> i32;
    fn curs_set(c: i8) -> i32;
    fn halfdelay(tenths: i8) -> i32;
    #[link_name = "box"]
    fn box_(window: *mut i8, verch: i8, horch: i8);
    fn mvprintw(y: i8, x: i8, s: *const libc::c_char);
    fn getch() -> i8;
    fn endwin() -> libc::c_int;

    fn newwin(nlines: i8, ncols: i8, begin_y: i8, begin_x: i8) -> *mut i8;
    fn wclear(window: *mut i8) -> i8;
    fn wrefresh(window: *mut i8) -> i8;
    fn mvwprintw(window: *mut i8, y: i8, x: i8, s: *const libc::c_char);
    fn wgetch(window: *mut i8) -> i8;
    fn delwin(window: *mut i8) -> i8;
}

fn main() {
    unsafe {
        initscr();
        noecho();
        curs_set(0);
        halfdelay(3);

        let mut game = Game {
            width: 20,
            height: 10,
            snake: Snake {
                cells: vec![Cell { x: 4, y: 0 }, Cell { x: 3, y: 0 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
                direction: Direction::Right,
            }
        };
        let window = newwin(game.height + 2, game.width + 2, 0, 0);

        let mut c = 0;
        while char::from(c as u8) != 'q' {

            game.draw(window);

            c = wgetch(window);
            let direction = match char::from(c as u8) {
                'i' => Some(Direction::Up),
                'j' => Some(Direction::Left),
                'k' => Some(Direction::Down),
                'l' => Some(Direction::Right),
                _ => Option::None
            };

            game = game.update(direction);
        }

        delwin(window);
        endwin();
    }
}

impl Game {
    fn draw(&self, window: *mut i8) {
        unsafe {
            wclear(window);
            box_(window, 0, 0);

            self.snake.tail().iter().for_each(|cell|
                mvwprintw(window, cell.y + 1, cell.x + 1, "o".to_c_str().as_ptr())
            );
            mvwprintw(window, self.snake.head().y + 1, self.snake.head().x + 1, "Q".to_c_str().as_ptr());

            if self.is_over() {
                mvwprintw(window, 0, 4, "Game is Over".to_c_str().as_ptr());
                mvwprintw(window, 1, 3, format!("Your score is {}", self.score()).as_str().to_c_str().as_ptr());
            }

            wrefresh(window);
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
struct Game {
    width: i8,
    height: i8,
    snake: Snake,
}

impl Game {
    fn is_over(&self) -> bool {
        self.snake.cells.iter().any(|&it| it.x < 0 || it.x >= self.width || it.y < 0 || it.y >= self.height) ||
        self.snake.tail().contains(self.snake.head())
    }

    fn score(&self) -> u8 {
        self.snake.cells.len() as u8
    }

    fn update(&self, direction: Option<Direction>) -> Game {
        if self.is_over() {
            return self.clone();
        }

        let new_snake;
        if direction.is_some() {
            new_snake = self.snake.turn_in(direction.unwrap()).slide();
        } else {
            new_snake = self.snake.slide();
        }
        return Game {
            width: self.width,
            height: self.height,
            snake: new_snake,
        };
    }
}

#[derive(Debug, PartialEq, Clone)]
struct Snake {
    cells: Vec<Cell>,
    direction: Direction,
}

impl Snake {
    fn head(&self) -> &Cell {
        &self.cells[0]
    }

    fn tail(&self) -> Vec<Cell> {
        self.cells[1..self.cells.len()].to_owned()
    }

    fn turn_in(&self, new_direction: Direction) -> Snake {
        if are_opposite(new_direction, self.direction) {
            self.clone()
        } else {
            Snake { cells: self.cells.clone(), direction: new_direction }
        }
    }

    fn slide(&self) -> Snake {
        let mut vec: Vec<Cell> = vec![self.cells.first().unwrap().move_in(&self.direction)];

        let mut new_cells = self.cells.clone();
        new_cells.pop();
        vec.append(&mut new_cells);

        Snake { cells: vec, direction: self.direction }
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
struct Cell {
    x: i8,
    y: i8,
}

impl Cell {
    fn move_in(&self, direction: &Direction) -> Cell {
        let dx = match direction {
            Direction::Up => 0,
            Direction::Down => 0,
            Direction::Left => -1,
            Direction::Right => 1,
        };
        let dy = match direction {
            Direction::Up => -1,
            Direction::Down => 1,
            Direction::Left => 0,
            Direction::Right => 0,
        };
        return Cell { x: self.x + dx, y: self.y + dy };
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

fn are_opposite(d1: Direction, d2: Direction) -> bool {
    if d1 == Direction::Up && d2 == Direction::Down { return true; }
    if d2 == Direction::Up && d1 == Direction::Down { return true; }
    if d1 == Direction::Left && d2 == Direction::Right { return true; }
    if d2 == Direction::Left && d1 == Direction::Right { return true; }
    false
}

trait ToCStr {
    fn to_c_str(&self) -> CString;
}

impl<'a> ToCStr for &'a str {
    fn to_c_str(&self) -> CString {
        CString::new(*self).unwrap()
    }
}

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

    #[test]
    fn snake_moves_right() {
        let snake = Snake {
            cells: vec![Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };

        assert_eq!(
            snake.slide(),
            Snake {
                cells: vec![Cell { x: 3, y: 0 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }],
                direction: Direction::Right,
            }
        )
    }

    #[test]
    fn snake_can_change_direction() {
        let snake = Snake {
            cells: vec![Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };

        assert_eq!(
            snake.turn_in(Direction::Down).slide(),
            Snake {
                cells: vec![Cell { x: 2, y: 1 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }],
                direction: Direction::Down,
            }
        );
        assert_eq!(
            snake.turn_in(Direction::Left).slide(),
            Snake {
                cells: vec![Cell { x: 3, y: 0 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }],
                direction: Direction::Right,
            }
        );
    }

    #[test]
    fn game_is_over_when_snake_hits_border() {
        let snake = Snake {
            cells: vec![Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };
        let game = Game { width: 3, height: 1, snake };

        assert_eq!(game.is_over(), false);
        assert_eq!(game.update(None).is_over(), true);
        assert_eq!(game.update(Some(Direction::Down)).is_over(), true);
    }

    #[test]
    fn game_is_over_when_snake_bites_itself() {
        let snake = Snake {
            cells: vec![Cell { x: 0, y: 0 }, Cell { x: 0, y: 1 }, Cell { x: 1, y: 1 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };
        let game = Game { width: 100, height: 100, snake };

        assert_eq!(game.is_over(), true);
    }
}<commit_msg>use i16 for coordinates<commit_after>extern crate libc;

use std::ffi::{CString};

#[link(name = "ncurses")]
#[allow(dead_code)]
extern "C" {
    fn getpid() -> i32;
    fn initscr() -> *mut i8;
    fn noecho() -> i32;
    fn curs_set(c: i8) -> i32;
    fn halfdelay(tenths: i8) -> i32;
    #[link_name = "box"]
    fn box_(window: *mut i8, verch: i8, horch: i8);
    fn mvprintw(y: i16, x: i16, s: *const libc::c_char);
    fn getch() -> i8;
    fn endwin() -> libc::c_int;

    fn newwin(nlines: i16, ncols: i16, begin_y: i8, begin_x: i8) -> *mut i8;
    fn wclear(window: *mut i8) -> i8;
    fn wrefresh(window: *mut i8) -> i8;
    fn mvwprintw(window: *mut i8, y: i16, x: i16, s: *const libc::c_char);
    fn wgetch(window: *mut i8) -> i8;
    fn delwin(window: *mut i8) -> i8;
}

fn main() {
    unsafe {
        initscr();
        noecho();
        curs_set(0);
        halfdelay(3);

        let mut game = Game {
            width: 20,
            height: 10,
            snake: Snake {
                cells: vec![Cell { x: 4, y: 0 }, Cell { x: 3, y: 0 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
                direction: Direction::Right,
            }
        };
        let window = newwin(game.height + 2, game.width + 2, 0, 0);

        let mut c = 0;
        while char::from(c as u8) != 'q' {

            game.draw(window);

            c = wgetch(window);
            let direction = match char::from(c as u8) {
                'i' => Some(Direction::Up),
                'j' => Some(Direction::Left),
                'k' => Some(Direction::Down),
                'l' => Some(Direction::Right),
                _ => Option::None
            };

            game = game.update(direction);
        }

        delwin(window);
        endwin();
    }
}

impl Game {
    fn draw(&self, window: *mut i8) {
        unsafe {
            wclear(window);
            box_(window, 0, 0);

            self.snake.tail().iter().for_each(|cell|
                mvwprintw(window, cell.y + 1, cell.x + 1, "o".to_c_str().as_ptr())
            );
            mvwprintw(window, self.snake.head().y + 1, self.snake.head().x + 1, "Q".to_c_str().as_ptr());

            if self.is_over() {
                mvwprintw(window, 0, 4, "Game is Over".to_c_str().as_ptr());
                mvwprintw(window, 1, 3, format!("Your score is {}", self.score()).as_str().to_c_str().as_ptr());
            }

            wrefresh(window);
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
struct Game {
    width: i16,
    height: i16,
    snake: Snake,
}

impl Game {
    fn is_over(&self) -> bool {
        self.snake.cells.iter().any(|&it| it.x < 0 || it.x >= self.width || it.y < 0 || it.y >= self.height) ||
        self.snake.tail().contains(self.snake.head())
    }

    fn score(&self) -> u8 {
        self.snake.cells.len() as u8
    }

    fn update(&self, direction: Option<Direction>) -> Game {
        if self.is_over() {
            return self.clone();
        }

        let new_snake;
        if direction.is_some() {
            new_snake = self.snake.turn_in(direction.unwrap()).slide();
        } else {
            new_snake = self.snake.slide();
        }
        return Game {
            width: self.width,
            height: self.height,
            snake: new_snake,
        };
    }
}

#[derive(Debug, PartialEq, Clone)]
struct Snake {
    cells: Vec<Cell>,
    direction: Direction,
}

impl Snake {
    fn head(&self) -> &Cell {
        &self.cells[0]
    }

    fn tail(&self) -> Vec<Cell> {
        self.cells[1..self.cells.len()].to_owned()
    }

    fn turn_in(&self, new_direction: Direction) -> Snake {
        if are_opposite(new_direction, self.direction) {
            self.clone()
        } else {
            Snake { cells: self.cells.clone(), direction: new_direction }
        }
    }

    fn slide(&self) -> Snake {
        let mut vec: Vec<Cell> = vec![self.cells.first().unwrap().move_in(&self.direction)];

        let mut new_cells = self.cells.clone();
        new_cells.pop();
        vec.append(&mut new_cells);

        Snake { cells: vec, direction: self.direction }
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
struct Cell {
    x: i16,
    y: i16,
}

impl Cell {
    fn move_in(&self, direction: &Direction) -> Cell {
        let dx = match direction {
            Direction::Up => 0,
            Direction::Down => 0,
            Direction::Left => -1,
            Direction::Right => 1,
        };
        let dy = match direction {
            Direction::Up => -1,
            Direction::Down => 1,
            Direction::Left => 0,
            Direction::Right => 0,
        };
        return Cell { x: self.x + dx, y: self.y + dy };
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

fn are_opposite(d1: Direction, d2: Direction) -> bool {
    if d1 == Direction::Up && d2 == Direction::Down { return true; }
    if d2 == Direction::Up && d1 == Direction::Down { return true; }
    if d1 == Direction::Left && d2 == Direction::Right { return true; }
    if d2 == Direction::Left && d1 == Direction::Right { return true; }
    false
}

trait ToCStr {
    fn to_c_str(&self) -> CString;
}

impl<'a> ToCStr for &'a str {
    fn to_c_str(&self) -> CString {
        CString::new(*self).unwrap()
    }
}

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

    #[test]
    fn snake_moves_right() {
        let snake = Snake {
            cells: vec![Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };

        assert_eq!(
            snake.slide(),
            Snake {
                cells: vec![Cell { x: 3, y: 0 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }],
                direction: Direction::Right,
            }
        )
    }

    #[test]
    fn snake_can_change_direction() {
        let snake = Snake {
            cells: vec![Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };

        assert_eq!(
            snake.turn_in(Direction::Down).slide(),
            Snake {
                cells: vec![Cell { x: 2, y: 1 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }],
                direction: Direction::Down,
            }
        );
        assert_eq!(
            snake.turn_in(Direction::Left).slide(),
            Snake {
                cells: vec![Cell { x: 3, y: 0 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }],
                direction: Direction::Right,
            }
        );
    }

    #[test]
    fn game_is_over_when_snake_hits_border() {
        let snake = Snake {
            cells: vec![Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };
        let game = Game { width: 3, height: 1, snake };

        assert_eq!(game.is_over(), false);
        assert_eq!(game.update(None).is_over(), true);
        assert_eq!(game.update(Some(Direction::Down)).is_over(), true);
    }

    #[test]
    fn game_is_over_when_snake_bites_itself() {
        let snake = Snake {
            cells: vec![Cell { x: 0, y: 0 }, Cell { x: 0, y: 1 }, Cell { x: 1, y: 1 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };
        let game = Game { width: 100, height: 100, snake };

        assert_eq!(game.is_over(), true);
    }
}<|endoftext|>


<commit_before>#[macro_use]
extern crate askama;

use askama::Template;

#[derive(Template)]
#[template(path = "macro.html", print = "all")]
struct MacroTemplate<'a> {
    s: &'a str,
}

#[test]
fn test_macro() {
    let t = MacroTemplate { s: "foo" };
    assert_eq!(t.render().unwrap(), "foo foo foo");
}
<commit_msg>Forgot to remove debugging cruft, again<commit_after>#[macro_use]
extern crate askama;

use askama::Template;

#[derive(Template)]
#[template(path = "macro.html")]
struct MacroTemplate<'a> {
    s: &'a str,
}

#[test]
fn test_macro() {
    let t = MacroTemplate { s: "foo" };
    assert_eq!(t.render().unwrap(), "foo foo foo");
}
<|endoftext|>