<commit_before>use std::{result, io, fmt};
use std::error;
use std::convert;

use byteorder::{ByteOrder, BigEndian};
use protobuf;

pub const MSG_HEADER_LEN: usize = 16;
pub const MSG_MAGIC: u16 = 0xdaf4;
pub const MSG_VERSION_V1: u16 = 1;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Protobuf(protobuf::ProtobufError),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Io(ref e) => fmt::Debug::fmt(e, f),
            &Error::Protobuf(ref e) => fmt::Debug::fmt(e, f),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            // not sure that cause should be included in message
            &Error::Io(ref e) => e.description(),
            &Error::Protobuf(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &Error::Io(ref e) => Some(e),
            &Error::Protobuf(ref e) => Some(e),
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<protobuf::ProtobufError> for Error {
    fn from(err: protobuf::ProtobufError) -> Error {
        Error::Protobuf(err)
    }
}

fn other_err(msg: String) -> Error {
    let err = io::Error::new(io::ErrorKind::Other, msg);
    convert::From::from(err)
}

pub type Result<T> = result::Result<T, Error>;

// Encodes message with message ID and protobuf body.
// Message contains header + payload.
// Header is 16 bytes, format:
//  | 0xdaf4 (2 bytes)| 0x01 (version 2 bytes)| msg_len (4 bytes) | msg_id (8 bytes)|, all use bigendian.
// Payload is a protobuf message.
pub fn encode_msg<T: io::Write, M: protobuf::Message>(w: &mut T,
                                                      msg_id: u64,
                                                      msg: &M)
                                                      -> Result<()> {
    // Create a 16 bytes header and write it.
    let mut buf = vec!(0; MSG_HEADER_LEN);
    BigEndian::write_u16(&mut buf[0..2], MSG_MAGIC);
    BigEndian::write_u16(&mut buf[2..4], MSG_VERSION_V1);
    BigEndian::write_u64(&mut buf[8..16], msg_id);

    try!(msg.write_to_vec(&mut buf));

    // Set payload length here
    let payload_len = (buf.len() - MSG_HEADER_LEN) as u32;
    BigEndian::write_u32(&mut buf[4..8], payload_len);

    try!(w.write(&buf));

    Ok(())
}

// Decode message header, return a tuple (message id, payload length);
pub fn decode_msg_header<T: io::Read>(r: &mut T) -> Result<(u64, usize)> {
    // First read 16 bytes header
    let mut header = [0; MSG_HEADER_LEN];
    // TODO: check exact read bytes number.
    try!(r.read(&mut header));

    let magic = BigEndian::read_u16(&header[0..2]);
    if MSG_MAGIC != magic {
        return Err(other_err(format!("invalid magic {}, not {}", magic, MSG_MAGIC)));
    }

    let version = BigEndian::read_u16(&header[2..4]);
    if MSG_VERSION_V1 != version {
        return Err(other_err(format!("unsupported version {}, we need {} now",
                                     version,
                                     MSG_VERSION_V1)));
    }

    let payload_len = BigEndian::read_u32(&header[4..8]) as usize;
    // TODO: check max payload

    let message_id = BigEndian::read_u64(&header[8..16]);

    Ok((message_id, payload_len))
}

// Decode message body with its payload length;
pub fn decode_msg_body<T: io::Read, M: protobuf::Message>(r: &mut T,
                                                          payload_len: usize,
                                                          m: &mut M)
                                                          -> Result<()> {
    let mut payload = vec![0;payload_len];

    try!(r.read(&mut payload));
    try!(m.merge_from_bytes(&payload));

    Ok(())
}

// Decodes message with above encoded format, returns message ID.
pub fn decode_msg<T: io::Read, M: protobuf::Message>(r: &mut T, m: &mut M) -> Result<u64> {
    let (message_id, payload_len) = try!(decode_msg_header(r));

    try!(decode_msg_body(r, payload_len, m));

    Ok(message_id)
}

#[cfg(test)]
mod tests {
    use bytes::ByteBuf;

    use super::*;
    use proto::raftpb::{Message, MessageType};

    #[test]
    fn test_codec() {
        let mut m1 = Message::new();
        m1.set_field_type(MessageType::MsgBeat);

        let mut w = ByteBuf::mut_with_capacity(64);
        assert_eq!(encode_msg(&mut w, 1, &m1).is_ok(), true);

        let mut m2 = Message::new();
        assert_eq!(decode_msg(&mut w.flip(), &mut m2).unwrap(), 1);
        assert_eq!(m1, m2);
    }
}
<commit_msg>codec: refactor and simplify it.<commit_after>// This package handles RPC message data encoding/decoding.
// Every RPC message data contains two parts: header + payload.
// Header is 16 bytes, format:
//  | 0xdaf4 (2 bytes)| 0x01 (version 2 bytes)| msg_len (4 bytes) | msg_id (8 bytes)|, all use bigendian.
// Now the version is always 1.
// Payload can be any arbitrary data, but we use Protobuf in our problem default.
use std::{result, io, fmt};
use std::error;
use std::convert;
use std::vec::Vec;
use std::io::Write;

use byteorder::{ByteOrder, BigEndian};
use protobuf;

pub const MSG_HEADER_LEN: usize = 16;
pub const MSG_MAGIC: u16 = 0xdaf4;
pub const MSG_VERSION_V1: u16 = 1;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Protobuf(protobuf::ProtobufError),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Io(ref e) => fmt::Debug::fmt(e, f),
            &Error::Protobuf(ref e) => fmt::Debug::fmt(e, f),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            // not sure that cause should be included in message
            &Error::Io(ref e) => e.description(),
            &Error::Protobuf(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &Error::Io(ref e) => Some(e),
            &Error::Protobuf(ref e) => Some(e),
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<protobuf::ProtobufError> for Error {
    fn from(err: protobuf::ProtobufError) -> Error {
        Error::Protobuf(err)
    }
}

fn other_err(msg: String) -> Error {
    let err = io::Error::new(io::ErrorKind::Other, msg);
    convert::From::from(err)
}

pub type Result<T> = result::Result<T, Error>;

// Encodes message with message ID and protobuf body.
pub fn encode_msg<T: io::Write, M: protobuf::Message>(w: &mut T,
                                                      msg_id: u64,
                                                      msg: &M)
                                                      -> Result<()> {
    let payload_len = msg.compute_size();
    let header = encode_msg_header(msg_id, payload_len as usize);
    try!(w.write(&header));
    try!(msg.write_to_writer(w));

    Ok(())
}

// Decodes encode message, returns message ID.
pub fn decode_msg<T: io::Read, M: protobuf::Message>(r: &mut T, m: &mut M) -> Result<u64> {
    let (message_id, payload) = try!(decode_data(r));
    try!(m.merge_from_bytes(&payload));

    Ok(message_id)
}

// Encodes data with message ID and any arbitrary body.
pub fn encode_data<T: io::Write>(w: &mut T, msg_id: u64, data: &[u8]) -> Result<()> {
    let header = encode_msg_header(msg_id, data.len());

    try!(w.write(&header));
    try!(w.write(data));

    Ok(())
}

// Decodes encoded data, returns message ID.
pub fn decode_data<T: io::Read>(r: &mut T) -> Result<(u64, Vec<u8>)> {
    let mut header = vec![0;MSG_HEADER_LEN];
    try!(r.read_exact(&mut header));

    let (msg_id, payload_len) = try!(decode_msg_header(&mut header));
    let mut payload = vec![0;payload_len];
    try!(r.read_exact(&mut payload));

    Ok((msg_id, payload))
}

// Encode msg header to a 16 bytes header buffer.
pub fn encode_msg_header(msg_id: u64, payload_len: usize) -> Vec<u8> {
    let mut buf = vec![0;MSG_HEADER_LEN];

    BigEndian::write_u16(&mut buf[0..2], MSG_MAGIC);
    BigEndian::write_u16(&mut buf[2..4], MSG_VERSION_V1);
    BigEndian::write_u32(&mut buf[4..8], payload_len as u32);
    BigEndian::write_u64(&mut buf[8..16], msg_id);

    return buf;
}

// Decode msg header in header buffer, the buffer length must be equal MSG_HEADER_LEN;
pub fn decode_msg_header(header: &[u8]) -> Result<(u64, usize)> {
    let magic = BigEndian::read_u16(&header[0..2]);
    if MSG_MAGIC != magic {
        return Err(other_err(format!("invalid magic {}, not {}", magic, MSG_MAGIC)));
    }

    let version = BigEndian::read_u16(&header[2..4]);
    if MSG_VERSION_V1 != version {
        return Err(other_err(format!("unsupported version {}, we need {} now",
                                     version,
                                     MSG_VERSION_V1)));
    }

    let payload_len = BigEndian::read_u32(&header[4..8]) as usize;
    // TODO: check max payload

    let message_id = BigEndian::read_u64(&header[8..16]);

    Ok((message_id, payload_len))
}

#[cfg(test)]
mod tests {
    use bytes::ByteBuf;
    use std::io::Cursor;

    use super::*;
    use proto::raftpb::{Message, MessageType};

    #[test]
    fn test_pbmsg_codec() {
        let mut m1 = Message::new();
        m1.set_field_type(MessageType::MsgBeat);

        let mut w = ByteBuf::mut_with_capacity(64);
        assert_eq!(encode_msg(&mut w, 1, &m1).is_ok(), true);

        let mut m2 = Message::new();
        assert_eq!(decode_msg(&mut w.flip(), &mut m2).unwrap(), 1);
        assert_eq!(m1, m2);
    }

    #[test]
    fn test_data_codec() {
        let body = vec![10;10];
        let mut m1 = vec![];
        encode_data(&mut m1, 1, &body).unwrap();

        let mut r = Cursor::new(m1.clone());
        let (msg_id, data) = decode_data(&mut r).unwrap();
        assert_eq!(msg_id, 1);
        assert_eq!(&data, &body);
    }

    #[test]
    fn test_header_codec() {
        let m1 = encode_msg_header(1, 1);
        let (msg_id, payload_len) = decode_msg_header(&m1).unwrap();
        assert_eq!(msg_id, 1);
        assert_eq!(payload_len, 1);
    }
}
<|endoftext|>


<commit_before>/// π <https://oeis.org/A000796>
pub const PI: f64 =
    3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214;

/// sqrt(2) <https://oeis.org/A002193>
pub const SQRT_2: f64 =
    1.41421356237309504880168872420969807856967187537694807317667973799073247846210703885038753432764157f64;

/// sqrt(3) <https://oeis.org/A002194>
pub const SQRT_3: f64 = 1.7320508075688772935274463415058723669428052538103806280558069794519330169088000370811461867572485756756261414154f64;

/// sqrt(6) <https://oeis.org/A010464>
pub const SQRT_6: f64 =
    2.44948974278317809819728407470589139196594748065667012843269256725096037745731502653985943310464023f64;

/// sqrt(2/3) <https://oeis.org/A157697>
pub const SQRT_2_BY_3: f64 =
    0.816496580927726032732428024901963797321982493552223376144230855750320125819105008846619811034880078272864f64;

/// sqt(3/2) <https://oeis.org/A115754>
pub const SQRT_3_BY_2: f64 =
    1.22474487139158904909864203735294569598297374032833506421634628362548018872865751326992971655232011f64;

/// 1/3
pub const ONE_BY_3: f64 =
    0.33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333f64;

/// 2/3
pub const TWO_BY_3: f64 =
    0.66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666f64;

/// 1/sqrt(2) = cos(pi/4) <https://oeis.org/A010503>
pub const ONE_BY_SQRT_2: f64 =
    0.707106781186547524400844362104849039284835937688474036588339868995366239231053519425193767163820786367506f64;

// cos(π/8) = cos(22.5°) <https://oeis.org/A144981>
pub const COS_PI_BY_8: f64 =
    0.923879532511286756128183189396788286822416625863642486115097731280535007501102358714839934850344596097963f64;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{COS_PI_BY_8, ONE_BY_3, ONE_BY_SQRT_2, PI, SQRT_2, SQRT_2_BY_3, SQRT_3, SQRT_3_BY_2, SQRT_6, TWO_BY_3};

    #[test]
    fn constants_are_correct() {
        assert_eq!(PI, std::f64::consts::PI);
        assert_eq!(SQRT_2, std::f64::consts::SQRT_2);
        assert_eq!(SQRT_3, f64::sqrt(3.0));
        assert_eq!(SQRT_6, f64::sqrt(6.0));
        assert_eq!(SQRT_2_BY_3, f64::sqrt(2.0 / 3.0));
        assert_eq!(SQRT_3_BY_2, f64::sqrt(3.0 / 2.0));
        assert_eq!(ONE_BY_3, 1.0 / 3.0);
        assert_eq!(TWO_BY_3, 2.0 / 3.0);
        assert_eq!(ONE_BY_SQRT_2, std::f64::consts::FRAC_1_SQRT_2);
        assert_eq!(COS_PI_BY_8, f64::cos(std::f64::consts::PI / 8.0));
    }
}
<commit_msg>Add numeric constant<commit_after>/// π <https://oeis.org/A000796>
pub const PI: f64 =
    3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214;

/// sqrt(2) <https://oeis.org/A002193>
pub const SQRT_2: f64 =
    1.41421356237309504880168872420969807856967187537694807317667973799073247846210703885038753432764157f64;

/// sqrt(3) <https://oeis.org/A002194>
pub const SQRT_3: f64 = 1.7320508075688772935274463415058723669428052538103806280558069794519330169088000370811461867572485756756261414154f64;

/// sqrt(6) <https://oeis.org/A010464>
pub const SQRT_6: f64 =
    2.44948974278317809819728407470589139196594748065667012843269256725096037745731502653985943310464023f64;

/// sqrt(2/3) <https://oeis.org/A157697>
pub const SQRT_2_BY_3: f64 =
    0.816496580927726032732428024901963797321982493552223376144230855750320125819105008846619811034880078272864f64;

/// sqt(3/2) <https://oeis.org/A115754>
pub const SQRT_3_BY_2: f64 =
    1.22474487139158904909864203735294569598297374032833506421634628362548018872865751326992971655232011f64;

/// 1/3
pub const ONE_BY_3: f64 =
    0.33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333f64;

/// 2/3
pub const TWO_BY_3: f64 =
    0.66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666f64;

/// 1/sqrt(2) = cos(pi/4) <https://oeis.org/A010503>
pub const ONE_BY_SQRT_2: f64 =
    0.707106781186547524400844362104849039284835937688474036588339868995366239231053519425193767163820786367506f64;

// cos(π/8) = cos(22.5°) <https://oeis.org/A144981>
pub const COS_PI_BY_8: f64 =
    0.923879532511286756128183189396788286822416625863642486115097731280535007501102358714839934850344596097963f64;

// sin(π/8) = sin(22.5°) <https://oeis.org/A182168>
pub const SIN_PI_BY_8: f64 =
    0.382683432365089771728459984030398866761344562485627041433800635627546033960089692237013785342283547148424f64;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{
        COS_PI_BY_8, ONE_BY_3, ONE_BY_SQRT_2, PI, SIN_PI_BY_8, SQRT_2, SQRT_2_BY_3, SQRT_3, SQRT_3_BY_2, SQRT_6,
        TWO_BY_3,
    };

    #[test]
    fn constants_are_correct() {
        assert_eq!(PI, std::f64::consts::PI);
        assert_eq!(SQRT_2, std::f64::consts::SQRT_2);
        assert_eq!(SQRT_3, f64::sqrt(3.0));
        assert_eq!(SQRT_6, f64::sqrt(6.0));
        assert_eq!(SQRT_2_BY_3, f64::sqrt(2.0 / 3.0));
        assert_eq!(SQRT_3_BY_2, f64::sqrt(3.0 / 2.0));
        assert_eq!(ONE_BY_3, 1.0 / 3.0);
        assert_eq!(TWO_BY_3, 2.0 / 3.0);
        assert_eq!(ONE_BY_SQRT_2, std::f64::consts::FRAC_1_SQRT_2);
        assert_eq!(COS_PI_BY_8, f64::cos(std::f64::consts::PI / 8.0));
        assert_eq!(SIN_PI_BY_8, f64::sin(std::f64::consts::PI / 8.0));
    }
}
<|endoftext|>


<commit_before>use libc::{c_uint, c_int, size_t};

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn GetFixedTree(ll_lengths: *mut c_uint, d_lengths: *mut c_uint) {
    unsafe {
        for i in 0..144 {
            *ll_lengths.offset(i) = 8;
        }
        for i in 144..256 {
            *ll_lengths.offset(i) = 9;
        }
        for i in 256..280 {
            *ll_lengths.offset(i) = 7;
        }
        for i in 280..288 {
            *ll_lengths.offset(i) = 8;
        }
        for i in 0..32 {
            *d_lengths.offset(i) = 5;
        }
    }
}

/// Change the population counts in a way that the consequent Huffman tree
/// compression, especially its rle-part will be more likely to compress this data
/// more efficiently. length containts the size of the histogram.
#[no_mangle]
#[allow(non_snake_case)]
pub extern fn OptimizeHuffmanForRle(length: c_int, counts: *mut size_t) {
    let mut length = length;

    // 1) We don't want to touch the trailing zeros. We may break the
    // rules of the format by adding more data in the distance codes.
    while length >= 0 {
        if length == 0 {
            return;
        }
        if unsafe { *counts.offset((length - 1) as isize) } != 0 {
            // Now counts[0..length - 1] does not have trailing zeros.
            break;
        }
        length -= 1;
    }

    // 2) Let's mark all population counts that already can be encoded
    // with an rle code.
    let mut good_for_rle = vec![0; length as size_t];

    // Let's not spoil any of the existing good rle codes.
    // Mark any seq of 0's that is longer than 5 as a good_for_rle.
    // Mark any seq of non-0's that is longer than 7 as a good_for_rle.
    let mut symbol = unsafe { *counts.offset(0) };
    let mut stride = 0;
    for i in 0..(length + 1) {
        let ci = unsafe { *counts.offset(i as isize) };
        if i == length || ci != symbol {
            if (symbol == 0 && stride >= 5) || (symbol != 0 && stride >= 7) {
                for k in 0..stride {
                    good_for_rle[(i - k - 1) as usize] = 1;
                }
            }
            stride = 1;
            if i != length {
                symbol = ci;
            }
        } else {
            stride += 1;
        }
    }

    // 3) Let's replace those population counts that lead to more rle codes.
    stride = 0;
    let mut limit = unsafe { *counts.offset(0) };
    let mut sum = 0;
    for i in 0..(length + 1) {
        let ci = unsafe { *counts.offset(i as isize) };

        // Heuristic for selecting the stride ranges to collapse.
        if i == length || good_for_rle[i as usize] != 0 || (ci as i32 - limit as i32).abs() >= 4 {
            if stride >= 4 || (stride >= 3 && sum == 0) {
                // The stride must end, collapse what we have, if we have enough (4).
                let mut count = (sum + stride / 2) / stride;
                if count < 1 {
                    count = 1;
                }
                if sum == 0 {
                    // Don't make an all zeros stride to be upgraded to ones.
                    count = 0;
                }
                for k in 0..stride {
                    // We don't want to change value at counts[i],
                    // that is already belonging to the next stride. Thus - 1.
                    unsafe { *counts.offset((i - k - 1) as isize) = count as size_t };
                }
            }
            stride = 0;
            sum = 0;
            if i < length - 3 {
                // All interesting strides have a count of at least 4,
                // at least when non-zeros.
                unsafe {
                    limit = (
                        ci +
                        *counts.offset((i + 1) as isize) +
                        *counts.offset((i + 2) as isize) +
                        *counts.offset((i + 3) as isize) +
                        2
                    ) / 4;
                }
            } else if i < length {
                limit = ci;
            } else {
                limit = 0;
            }
        }
        stride += 1;
        if i != length {
            sum += ci as i32;
        }
    }
}
<commit_msg>Make OptimizeHuffmanForRle a bit rustier<commit_after>use std::slice;

use libc::{c_uint, c_int, size_t};

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn GetFixedTree(ll_lengths: *mut c_uint, d_lengths: *mut c_uint) {
    unsafe {
        for i in 0..144 {
            *ll_lengths.offset(i) = 8;
        }
        for i in 144..256 {
            *ll_lengths.offset(i) = 9;
        }
        for i in 256..280 {
            *ll_lengths.offset(i) = 7;
        }
        for i in 280..288 {
            *ll_lengths.offset(i) = 8;
        }
        for i in 0..32 {
            *d_lengths.offset(i) = 5;
        }
    }
}

/// Change the population counts in a way that the consequent Huffman tree
/// compression, especially its rle-part will be more likely to compress this data
/// more efficiently. length containts the size of the histogram.
#[no_mangle]
#[allow(non_snake_case)]
pub extern fn OptimizeHuffmanForRle(length: c_int, counts: *mut size_t) {
    let mut length = length as usize;
    let c = unsafe { slice::from_raw_parts(counts, length) };

    // 1) We don't want to touch the trailing zeros. We may break the
    // rules of the format by adding more data in the distance codes.
    loop {
        if length == 0 {
            return;
        }
        if c[length - 1] != 0 {
            // Now counts[0..length - 1] does not have trailing zeros.
            break;
        }
        length -= 1;
    }

    // 2) Let's mark all population counts that already can be encoded
    // with an rle code.
    let mut good_for_rle = vec![0; length as size_t];

    // Let's not spoil any of the existing good rle codes.
    // Mark any seq of 0's that is longer than 5 as a good_for_rle.
    // Mark any seq of non-0's that is longer than 7 as a good_for_rle.
    let mut symbol = c[0];
    let mut stride = 0;
    for i in 0..(length + 1) {
        if i == length || c[i] != symbol {
            if (symbol == 0 && stride >= 5) || (symbol != 0 && stride >= 7) {
                for k in 0..stride {
                    good_for_rle[(i - k - 1) as usize] = 1;
                }
            }
            stride = 1;
            if i != length {
                symbol = c[i];
            }
        } else {
            stride += 1;
        }
    }

    // 3) Let's replace those population counts that lead to more rle codes.
    stride = 0;
    let mut limit = c[0];
    let mut sum = 0;
    for i in 0..(length + 1) {
        // Heuristic for selecting the stride ranges to collapse.
        if i == length || good_for_rle[i as usize] != 0 || (c[i] as i32 - limit as i32).abs() >= 4 {
            if stride >= 4 || (stride >= 3 && sum == 0) {
                // The stride must end, collapse what we have, if we have enough (4).
                let mut count = (sum + stride / 2) / stride;
                if count < 1 {
                    count = 1;
                }
                if sum == 0 {
                    // Don't make an all zeros stride to be upgraded to ones.
                    count = 0;
                }
                for k in 0..stride {
                    // We don't want to change value at counts[i],
                    // that is already belonging to the next stride. Thus - 1.
                    unsafe { *counts.offset((i - k - 1) as isize) = count as size_t };
                }
            }
            stride = 0;
            sum = 0;
            if length > 2 && i < length - 3 {
                // All interesting strides have a count of at least 4,
                // at least when non-zeros.
                limit = (c[i] + c[i + 1] + c[i + 2] + c[i + 3] + 2) / 4;
            } else if i < length {
                limit = c[i];
            } else {
                limit = 0;
            }
        }
        stride += 1;
        if i != length {
            sum += c[i];
        }
    }
}
<|endoftext|>


<commit_before>use traits::translation::{Translation, Translatable};

/// Trait of object which represent a rotation, and to wich new rotations can
/// be appended. A rotation is assumed to be an isomitry without translation
/// and without reflexion.
pub trait Rotation<V>
{
  /// Gets the rotation associated with this object.
  fn rotation(&self) -> V;

  fn inv_rotation(&self) -> V;

  /// In-place version of `rotated`.
  fn rotate_by(&mut self, &V);
}

pub trait Rotatable<V, Res: Rotation<V>>
{
  /// Appends a rotation from an alternative representation. Such
  /// representation has the same format as the one returned by `rotation`.
  fn rotated(&self, &V) -> Res;
}

pub trait Rotate<V>
{
  fn rotate(&self, &V)     -> V;
  fn inv_rotate(&self, &V) -> V;
}

/**
 * Applies a rotation centered on a specific point.
 *
 *   - `m`:       the object to be rotated.
 *   - `ammount`: the rotation to apply.
 *   - `point`:   the center of rotation.
 */
#[inline]
pub fn rotate_wrt_point<M: Translatable<LV, M2>,
                        M2: Rotation<AV> + Translation<LV>,
                        LV: Neg<LV>,
                        AV>
       (m: &M, ammount: &AV, center: &LV) -> M2
{
  let mut res = m.translated(&-center);

  res.rotate_by(ammount);
  res.translate_by(center);

  res
}
<commit_msg>Add rotation wrt center of a matrix.<commit_after>use traits::translation::{Translation, Translatable};

/// Trait of object which represent a rotation, and to wich new rotations can
/// be appended. A rotation is assumed to be an isomitry without translation
/// and without reflexion.
pub trait Rotation<V>
{
  /// Gets the rotation associated with this object.
  fn rotation(&self) -> V;

  fn inv_rotation(&self) -> V;

  /// In-place version of `rotated`.
  fn rotate_by(&mut self, &V);
}

pub trait Rotatable<V, Res: Rotation<V>>
{
  /// Appends a rotation from an alternative representation. Such
  /// representation has the same format as the one returned by `rotation`.
  fn rotated(&self, &V) -> Res;
}

pub trait Rotate<V>
{
  fn rotate(&self, &V)     -> V;
  fn inv_rotate(&self, &V) -> V;
}

/**
 * Applies a rotation centered on a specific point.
 *
 *   - `m`:       the object to be rotated.
 *   - `ammount`: the rotation to apply.
 *   - `point`:   the center of rotation.
 */
#[inline]
pub fn rotate_wrt_point<M: Translatable<LV, M2>,
                        M2: Rotation<AV> + Translation<LV>,
                        LV: Neg<LV>,
                        AV>
       (m: &M, ammount: &AV, center: &LV) -> M2
{
  let mut res = m.translated(&-center);

  res.rotate_by(ammount);
  res.translate_by(center);

  res
}

/**
 * Applies a rotation centered on the input translation.
 *
 *   - `m`:       the object to be rotated.
 *   - `ammount`: the rotation to apply.
 */
#[inline]
pub fn rotate_wrt_center<M: Translatable<LV, M2> + Translation<LV>,
                         M2: Rotation<AV> + Translation<LV>,
                         LV: Neg<LV>,
                         AV>
       (m: &M, ammount: &AV) -> M2
{ rotate_wrt_point(m, ammount, &m.translation()) }
<|endoftext|>


<commit_before>//
extern crate termion;

//
use self::termion::screen::AlternateScreen;
use self::termion::event::{Event, Key, MouseEvent};
use self::termion::input::{TermRead, MouseTerminal};
use self::termion::raw::IntoRawMode;
use self::termion::terminal_size;

use std::io::{self, Write, stdin, Stdout};

//
use core::view::View;
use core::screen::Screen;
use core::codepointinfo::CodepointInfo;

use core::editor::Editor;

fn fill_screen(view: &mut View) {

    match view.document {

        Some(ref buf) => {

            let data = &buf.buffer.data;

            view.screen.clear();

            let mut offset = 0;
            for c in data {

                let mut displayed_cp: char = *c as char;
                if *c as char == '\n' as char {
                    displayed_cp = ' ';
                }

                let cpi = CodepointInfo {
                    cp: *c as char,
                    displayed_cp: displayed_cp,
                    offset: offset,
                    is_selected: false,
                };

                let (ok, _) = view.screen.push(cpi);
                offset += 1;
                if ok == false {
                    break;
                }
            }

            for m in &buf.moving_marks {

                if m.offset >= view.start_offset && m.offset >= view.start_offset {}
            }
        }
        None => {}
    }
}

fn draw_screen(screen: &mut Screen, mut stdout: &mut Stdout) {

    write!(stdout, "{}", termion::cursor::Goto(1, 1)).unwrap();

    for l in 0..screen.height {

        terminal_cursor_to(&mut stdout, 1, (l + 1) as u16);

        let line = screen.get_line(l).unwrap();

        for c in 0..line.used {

            let cpi = line.get_cpi(c).unwrap();

            if cpi.is_selected == true {
                write!(stdout, "{}", termion::style::Invert).unwrap();
            }

            write!(stdout, "{}", cpi.displayed_cp).unwrap();
            write!(stdout, "{}", termion::style::Reset).unwrap();
        }

        for _ in line.used..line.width {
            write!(stdout, " ").unwrap();
        }
    }

    stdout.flush().unwrap();
}

/*
    TODO:
    1 : be explicit
    2 : create editor internal result type Result<>
    3 : use idomatic    func()? style
*/
fn draw_view(mut view: &mut View, mut stdout: &mut Stdout) {

    fill_screen(&mut view);
    draw_screen(&mut view.screen, &mut stdout);
}

fn terminal_clear_current_line(mut stdout: &mut Stdout, line_width: u16) {
    for _ in 0..line_width {
        write!(stdout, " ").unwrap();
    }
}

fn terminal_cursor_to(mut stdout: &mut Stdout, x: u16, y: u16) {
    write!(stdout, "{}", termion::cursor::Goto(x, y)).unwrap();
}

/*
 TODO: create a view per buffer
*/
fn setup_views(editor: &mut Editor, width: usize, height: usize) {

    let mut views = Vec::new();

    let mut vid = 0;

    for (_, b) in &editor.document_map {

        let view = View::new(vid,
                             0 as u64,
                             width as usize,
                             height as usize,
                             Some(b.clone()));
        views.push(view);
        vid += 1;
    }

    for view in views {
        &editor.view_map.insert(view.id, Box::new(view));
    }
}

pub fn main_loop(mut editor: &mut Editor) {

    let (width, height) = terminal_size().unwrap();

    setup_views(editor, width as usize, height as usize);

    //
    let stdout = MouseTerminal::from(io::stdout().into_raw_mode().unwrap());
    let mut stdout = AlternateScreen::from(stdout);

    write!(stdout, "{}{}", termion::cursor::Hide, termion::clear::All).unwrap();
    stdout.flush().unwrap();

    let mut keys: Vec<Event> = Vec::new();
    let mut quit = false;

    //
    let mut status = String::new();
    let display_status = true;

    let display_view = true;

    // select view
    let mut vid = 0;

    while !quit {

        let nb_view = editor.view_map.len();
        let mut view = editor.view_map.get_mut(&vid);

        let status_line_y = height;

        if display_view == true {
            draw_view(&mut view.as_mut().unwrap(), &mut stdout);
        }

        if display_status == true {
            display_status_line(&mut view.as_mut().unwrap(), &status, status_line_y, width, &mut stdout);
        }

        for evt in stdin().events() {

            keys.push(evt.unwrap());
            let evt = keys[keys.len() - 1].clone();

            // Print recieved Events...
            match evt {

                Event::Key(k) => {
                    match k {
                        // Exit.
                        Key::Ctrl('r') => {
                            keys.clear();
                        }

                        Key::Ctrl('c') => {
                            if keys.len() > 1 {
                                if let Event::Key(prev_event) = keys[keys.len() - 2] {
                                    if let Key::Ctrl(prev_char) = prev_event {
                                        if prev_char == 'x' {
                                            quit = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }

                        Key::Char(c) => {
                            if c == '\n' {
                                status = format!("'{}'", "<newline>");
                            } else {
                                status = format!("'{}'", c);
                            }
                        }
                        Key::Alt(c) => status = format!("Alt-{}", c),
                        Key::Ctrl(c) => status = format!("Ctrl-{}", c),

                        Key::F(1) => {
                            if vid > 0 {
                                vid -= 1;
                            }
                            break;
                        }

                        Key::F(2) => {
                            vid = ::std::cmp::min(vid + 1, (nb_view - 1) as u64);
                            break;
                        }

                        Key::F(f) => status = format!("F{:?}", f),
                        Key::Left => status = format!("<left>"),
                        Key::Right => status = format!("<right>"),
                        Key::Up => status = format!("<up>"),
                        Key::Down => status = format!("<down>"),
                        Key::Backspace => status = format!("<backspace>"),
                        Key::Home => status = format!("<Home>"),
                        Key::End => status = format!("<End>"),
                        Key::PageUp => status = format!("<PageUp>"),
                        Key::PageDown => status = format!("<PageDown>"),
                        Key::Delete => status = format!("<Delete>"),
                        Key::Insert => status = format!("<Insert>"),
                        Key::Esc => status = format!("<Esc>"),
                        _ => status = format!("Other"),
                    }
                }

                Event::Mouse(m) => {
                    match m {
                        MouseEvent::Press(mb, x, y) => {
                            status = format!("MouseEvent::Press => MouseButton {:?} @ ({}, {})",
                                             mb,
                                             x,
                                             y);
                        }

                        MouseEvent::Release(x, y) => {
                            status = format!("MouseEvent::Release => @ ({}, {})", x, y);
                        }

                        MouseEvent::Hold(x, y) => {
                            status = format!("MouseEvent::Hold => @ ({}, {})", x, y);
                        }
                    };
                }

                Event::Unsupported(e) => {
                    status = format!("Event::Unsupported {:?}", e);
                }

            }

/*
            if display_status == true {
                //display_status_line(&buf, &status, status_line_y, width, &mut stdout);
            }
*/
            break;
        }
    }

    // quit
    // clear, restore cursor
    write!(stdout, "{}{}", termion::clear::All, termion::cursor::Show).unwrap();
    stdout.flush().unwrap();
}

fn display_status_line(view: &View,
                       status: &str,
                       line: u16,
                       width: u16,
                       mut stdout: &mut Stdout) {
    // select/clear last line
    let name = match view.document {
        Some(ref b) => b.name.as_str(),
        None => "",
    };

    let file_name = match view.document {
        Some(ref b) => b.buffer.file_name.as_str(),
        None => "",
    };

    terminal_cursor_to(&mut stdout, 1, line);
    terminal_clear_current_line(&mut stdout, width);
    terminal_cursor_to(&mut stdout, 1, line);

    let status_str = format!("line {} document_name '{}', file: '{}', event '{}'",
                             line,
                             name,
                             file_name,
                             status);

    print!("{}", status_str);
    stdout.flush().unwrap();
}
<commit_msg>split ui main loop<commit_after>//
extern crate termion;

//
use self::termion::screen::AlternateScreen;
use self::termion::event::{Event, Key, MouseEvent};
use self::termion::input::{TermRead, MouseTerminal};
use self::termion::raw::IntoRawMode;
use self::termion::terminal_size;

use std::io::{self, Write, stdin, Stdout};

//
use core::view::View;
use core::screen::Screen;
use core::codepointinfo::CodepointInfo;

use core::editor::Editor;

//
struct ViewState {
    keys: Vec<Event>,
    quit: bool,
    status: String,
    display_status: bool,
    display_view: bool,
    vid: u64,
    nb_view: usize,
}

impl ViewState {
    fn new() -> ViewState {
        ViewState {
            keys: Vec::new(),
            quit: false,
            status: String::new(),
            display_status: true,
            display_view: true,
            vid: 0,
            nb_view: 0,
        }
    }
}

pub fn main_loop(mut editor: &mut Editor) {

    let mut view_state = ViewState::new();

    let (width, height) = terminal_size().unwrap();

    setup_views(editor, width as usize, height as usize);

    //
    let stdout = MouseTerminal::from(io::stdout().into_raw_mode().unwrap());
    let mut stdout = AlternateScreen::from(stdout);

    write!(stdout, "{}{}", termion::cursor::Hide, termion::clear::All).unwrap();
    stdout.flush().unwrap();

    while !view_state.quit {

        view_state.nb_view = editor.view_map.len();
        let mut view = editor.view_map.get_mut(&view_state.vid);

        let status_line_y = height;

        if view_state.display_view == true {
            draw_view(&mut view.as_mut().unwrap(), &mut stdout);
        }

        if view_state.display_status == true {
            display_status_line(&mut view.as_mut().unwrap(),
                                &view_state.status,
                                status_line_y,
                                width,
                                &mut stdout);
        }

        process_input_events(&mut view_state);
    }

    // quit
    // clear, restore cursor
    write!(stdout, "{}{}", termion::clear::All, termion::cursor::Show).unwrap();
    stdout.flush().unwrap();
}

fn setup_views(editor: &mut Editor, width: usize, height: usize) {

    let mut views = Vec::new();

    let mut vid = 0;

    for (_, b) in &editor.document_map {

        let view = View::new(vid,
                             0 as u64,
                             width as usize,
                             height as usize,
                             Some(b.clone()));
        views.push(view);
        vid += 1;
    }

    for view in views {
        &editor.view_map.insert(view.id, Box::new(view));
    }
}

fn fill_screen(view: &mut View) {

    match view.document {

        Some(ref buf) => {

            let data = &buf.buffer.data;

            view.screen.clear();

            let mut offset = 0;
            for c in data {

                let mut displayed_cp: char = *c as char;
                if *c as char == '\n' as char {
                    displayed_cp = ' ';
                }

                let cpi = CodepointInfo {
                    cp: *c as char,
                    displayed_cp: displayed_cp,
                    offset: offset,
                    is_selected: false,
                };

                let (ok, _) = view.screen.push(cpi);
                offset += 1;
                if ok == false {
                    break;
                }
            }

            for m in &buf.moving_marks {

                if m.offset >= view.start_offset && m.offset >= view.start_offset {}
            }
        }
        None => {}
    }
}

fn draw_screen(screen: &mut Screen, mut stdout: &mut Stdout) {

    write!(stdout, "{}", termion::cursor::Goto(1, 1)).unwrap();

    for l in 0..screen.height {

        terminal_cursor_to(&mut stdout, 1, (l + 1) as u16);

        let line = screen.get_line(l).unwrap();

        for c in 0..line.used {

            let cpi = line.get_cpi(c).unwrap();

            if cpi.is_selected == true {
                write!(stdout, "{}", termion::style::Invert).unwrap();
            }

            write!(stdout, "{}", cpi.displayed_cp).unwrap();
            write!(stdout, "{}", termion::style::Reset).unwrap();
        }

        for _ in line.used..line.width {
            write!(stdout, " ").unwrap();
        }
    }

    stdout.flush().unwrap();
}

/*
    TODO:
    1 : be explicit
    2 : create editor internal result type Result<>
    3 : use idomatic    func()? style
*/
fn draw_view(mut view: &mut View, mut stdout: &mut Stdout) {

    fill_screen(&mut view);
    draw_screen(&mut view.screen, &mut stdout);
}

fn terminal_clear_current_line(mut stdout: &mut Stdout, line_width: u16) {
    for _ in 0..line_width {
        write!(stdout, " ").unwrap();
    }
}

fn terminal_cursor_to(mut stdout: &mut Stdout, x: u16, y: u16) {
    write!(stdout, "{}", termion::cursor::Goto(x, y)).unwrap();
}

fn process_input_events(view_state: &mut ViewState) {
    for evt in stdin().events() {

        view_state.keys.push(evt.unwrap());
        let evt = view_state.keys[view_state.keys.len() - 1].clone();

        // Print recieved Events...
        match evt {

            Event::Key(k) => {
                match k {
                    // Exit.
                    Key::Ctrl('r') => {
                        view_state.keys.clear();
                    }

                    Key::Ctrl('c') => {
                        if view_state.keys.len() > 1 {
                            if let Event::Key(prev_event) =
                                view_state.keys[view_state.keys.len() - 2] {
                                if let Key::Ctrl(prev_char) = prev_event {
                                    if prev_char == 'x' {
                                        view_state.quit = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    Key::Char(c) => {
                        if c == '\n' {
                            view_state.status = format!("'{}'", "<newline>");
                        } else {
                            view_state.status = format!("'{}'", c);
                        }
                    }
                    Key::Alt(c) => view_state.status = format!("Alt-{}", c),
                    Key::Ctrl(c) => view_state.status = format!("Ctrl-{}", c),

                    Key::F(1) => {
                        if view_state.vid > 0 {
                            view_state.vid -= 1;
                        }
                        break;
                    }

                    Key::F(2) => {
                        view_state.vid = ::std::cmp::min(view_state.vid + 1,
                                                         (view_state.nb_view - 1) as u64);
                        break;
                    }

                    Key::F(f) => view_state.status = format!("F{:?}", f),
                    Key::Left => view_state.status = format!("<left>"),
                    Key::Right => view_state.status = format!("<right>"),
                    Key::Up => view_state.status = format!("<up>"),
                    Key::Down => view_state.status = format!("<down>"),
                    Key::Backspace => view_state.status = format!("<backspace>"),
                    Key::Home => view_state.status = format!("<Home>"),
                    Key::End => view_state.status = format!("<End>"),
                    Key::PageUp => view_state.status = format!("<PageUp>"),
                    Key::PageDown => view_state.status = format!("<PageDown>"),
                    Key::Delete => view_state.status = format!("<Delete>"),
                    Key::Insert => view_state.status = format!("<Insert>"),
                    Key::Esc => view_state.status = format!("<Esc>"),
                    _ => view_state.status = format!("Other"),
                }
            }

            Event::Mouse(m) => {
                match m {
                    MouseEvent::Press(mb, x, y) => {
                        view_state.status =
                            format!("MouseEvent::Press => MouseButton {:?} @ ({}, {})", mb, x, y);
                    }

                    MouseEvent::Release(x, y) => {
                        view_state.status = format!("MouseEvent::Release => @ ({}, {})", x, y);
                    }

                    MouseEvent::Hold(x, y) => {
                        view_state.status = format!("MouseEvent::Hold => @ ({}, {})", x, y);
                    }
                };
            }

            Event::Unsupported(e) => {
                view_state.status = format!("Event::Unsupported {:?}", e);
            }
        }

        break;
    }
}

fn display_status_line(view: &View, status: &str, line: u16, width: u16, mut stdout: &mut Stdout) {
    // select/clear last line
    let name = match view.document {
        Some(ref b) => b.name.as_str(),
        None => "",
    };

    let file_name = match view.document {
        Some(ref b) => b.buffer.file_name.as_str(),
        None => "",
    };

    terminal_cursor_to(&mut stdout, 1, line);
    terminal_clear_current_line(&mut stdout, width);
    terminal_cursor_to(&mut stdout, 1, line);

    let status_str = format!("line {} document_name '{}', file: '{}', event '{}'",
                             line,
                             name,
                             file_name,
                             status);

    print!("{}", status_str);
    stdout.flush().unwrap();
}
<|endoftext|>


<commit_before>use CHIP8_HEIGHT;
use CHIP8_WIDTH;
use CHIP8_RAM;

pub struct OutputState<'a> {
    pub vram: &'a [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    pub vram_changed: bool,
    pub beep: bool,
}

pub struct Processor {
    vram: [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    vram_changed: bool,
    ram: [u8; CHIP8_RAM],
    stack: [usize; 16],
    v: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    delay_timer: u8,
    sound_timer: u8,
}

impl Processor {
    pub fn new() -> Self {
        Processor {
            vram: [[0; CHIP8_WIDTH]; CHIP8_HEIGHT],
            vram_changed: false,
            ram: [0; CHIP8_RAM],
            stack: [0; 16],
            v: [0; 16],
            i: 0,
            pc: 0x200,
            sp: 0,
            delay_timer: 0,
            sound_timer: 0,
        }
    }

    pub fn tick(&mut self, keypad: &[bool; 16]) -> OutputState {
        println!("tick: {:?}", keypad);
        self.vram_changed = false;
        self.run_opcode(self.get_opcode());
        OutputState {
            vram: &self.vram,
            vram_changed: self.vram_changed,
            beep: self.sound_timer > 0,
        }
    }

    fn get_opcode(&self) -> u16 {
        (self.ram[self.pc] as u16) << 8 | (self.ram[self.pc + 1] as u16)
    }

    fn run_opcode(&self, opcode: u16) {

        let nibbles = (
            (opcode & 0x000F) as u8,
            (opcode & 0x00F0) >> 4 as u8,
            (opcode & 0x0F00) >> 8 as u8,
            (opcode & 0xF000) >> 12 as u8,
        );

        let nnn = (opcode & 0x0FFF);
        let kk = (opcode & 0x00FF) as u8;
        let x = nibbles.2 as usize;
        let y = nibbles.1 as usize;
        let n = nibbles.0 as u8;

        match nibbles {
            (0x00, 0x00, 0x0e, 0x00) => self.op_00e0(),
            (0x00, 0x00, 0x0e, 0x0e) => self.op_00ee(),
            (0x00, _, _, _) => self.op_0nnn(nnn),
            (0x01, _, _, _) => self.op_1nnn(nnn),
            (0x02, _, _, _) => self.op_2nnn(nnn),
            (0x03, _, _, _) => self.op_3xkk(x, kk),
            (0x04, _, _, _) => self.op_4xkk(x, kk),
            (0x05, _, _, 0x00) => self.op_5xy0(x, y),
            (0x06, _, _, _) => self.op_6xkk(x, kk),
            (0x07, _, _, _) => self.op_7xkk(x, kk),
            (0x08, _, _, 0x00) => self.op_8xy0(x, y),
            (0x08, _, _, 0x01) => self.op_8xy1(x, y),
            (0x08, _, _, 0x02) => self.op_8xy2(x, y),
            (0x08, _, _, 0x03) => self.op_8xy3(x, y),
            (0x08, _, _, 0x04) => self.op_8xy4(x, y),
            (0x08, _, _, 0x05) => self.op_8xy5(x, y),
            (0x08, _, _, 0x06) => self.op_8xy6(x, y),
            (0x08, _, _, 0x07) => self.op_8xy7(x, y),
            (0x08, _, _, 0x0e) => self.op_8xye(x, y),
            (0x09, _, _, 0x00) => self.op_9xy0(x, y),
            (0x0a, _, _, _) => self.op_annn(nnn),
            (0x0b, _, _, _) => self.op_annn(nnn),
            (0x0c, _, _, _) => self.op_cxkk(x, kk),
            (0x0d, _, _, _) => self.op_dxyn(x, y, n),
            (0x0e, _, 0x09, 0x0e) => self.op_ex9e(x),
            (0x0e, _, 0x0a, 0x01) => self.op_exa1(x),
            (0x0f, _, 0x00, 0x07) => self.op_fx07(x),
            (0x0f, _, 0x00, 0x0a) => self.op_fx0a(x),
            (0x0f, _, 0x01, 0x05) => self.op_fx15(x),
            (0x0f, _, 0x01, 0x08) => self.op_fx18(x),
            (0x0f, _, 0x01, 0x0e) => self.op_fx1e(x),
            (0x0f, _, 0x02, 0x09) => self.op_fx29(x),
            (0x0f, _, 0x03, 0x03) => self.op_fx33(x),
            (0x0f, _, 0x05, 0x05) => self.op_fx55(x),
            (0x0f, _, 0x06, 0x05) => self.op_fx65(x),
            _ => return,
        }

    }
    // CLS
    fn op_00e0(&self) {}
    // RET
    fn op_00ee(&self) {}
    // SYS addr
    fn op_0nnn(&self, nnn: u16) {}
    // JP addr
    fn op_1nnn(&self, nnn: u16) {}
    // CALL addr
    fn op_2nnn(&self, nnn: u16) {}
    // SE Vx, byte
    fn op_3xkk(&self, x: usize, kk: u8) {}
    // SNE Vx, byte
    fn op_4xkk(&self, x: usize, kk: u8) {}
    // SE Vx, Vy
    fn op_5xy0(&self, x: usize, y: usize) {}
    // LD Vx, byte
    fn op_6xkk(&self, x: usize, kk: u8) {}
    // ADD Vx, byte
    fn op_7xkk(&self, x: usize, kk: u8) {}
    // LD Vx, Vy
    fn op_8xy0(&self, x: usize, y: usize) {}
    // OR Vx, Vy
    fn op_8xy1(&self, x: usize, y: usize) {}
    // AND Vx, Vy
    fn op_8xy2(&self, x: usize, y: usize) {}
    // XOR Vx, Vy
    fn op_8xy3(&self, x: usize, y: usize) {}
    // ADD Vx, Vy
    fn op_8xy4(&self, x: usize, y: usize) {}
    // SUB Vx, Vy
    fn op_8xy5(&self, x: usize, y: usize) {}
    // SHR Vx {, Vy}
    fn op_8xy6(&self, x: usize, y: usize) {}
    // SUBN Vx, Vy
    fn op_8xy7(&self, x: usize, y: usize) {}
    // SHL Vx {, Vy}
    fn op_8xye(&self, x: usize, y: usize) {}
    // SNE Vx, Vy
    fn op_9xy0(&self, x: usize, y: usize) {}
    // LD I, addr
    fn op_annn(&self, nnn: u16) {}
    // JP V0, addr
    fn op_bnnn(&self, nnn: u16) {}
    // RND Vx, byte
    fn op_cxkk(&self, x: usize, kk: u8) {}
    // DRW Vx, Vy, nibble
    fn op_dxyn(&self, x: usize, y: usize, n: u8) {}
    // SKP Vx
    fn op_ex9e(&self, x: usize) {}
    // SKNP Vx
    fn op_exa1(&self, x: usize) {}
    // LD Vx, DT
    fn op_fx07(&self, x: usize) {}
    // LD Vx, K
    fn op_fx0a(&self, x: usize) {}
    // LD DT, Vx
    fn op_fx15(&self, x: usize) {}
    // LD ST, Vx
    fn op_fx18(&self, x: usize) {}
    // ADD I, Vx
    fn op_fx1e(&self, x: usize) {}
    // LD F, Vx
    fn op_fx29(&self, x: usize) {}
    // LD B, Vx
    fn op_fx33(&self, x: usize) {}
    // LD [I], Vx
    fn op_fx55(&self, x: usize) {}
    // LD Vx, [I]
    fn op_fx65(&self, x: usize) {}
}
<commit_msg>fix typos<commit_after>use CHIP8_HEIGHT;
use CHIP8_WIDTH;
use CHIP8_RAM;

pub struct OutputState<'a> {
    pub vram: &'a [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    pub vram_changed: bool,
    pub beep: bool,
}

pub struct Processor {
    vram: [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    vram_changed: bool,
    ram: [u8; CHIP8_RAM],
    stack: [usize; 16],
    v: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    delay_timer: u8,
    sound_timer: u8,
}

impl Processor {
    pub fn new() -> Self {
        Processor {
            vram: [[0; CHIP8_WIDTH]; CHIP8_HEIGHT],
            vram_changed: false,
            ram: [0; CHIP8_RAM],
            stack: [0; 16],
            v: [0; 16],
            i: 0,
            pc: 0x200,
            sp: 0,
            delay_timer: 0,
            sound_timer: 0,
        }
    }

    pub fn tick(&mut self, keypad: &[bool; 16]) -> OutputState {
        println!("tick: {:?}", keypad);
        self.vram_changed = false;
        self.run_opcode(self.get_opcode());
        OutputState {
            vram: &self.vram,
            vram_changed: self.vram_changed,
            beep: self.sound_timer > 0,
        }
    }

    fn get_opcode(&self) -> u16 {
        (self.ram[self.pc] as u16) << 8 | (self.ram[self.pc + 1] as u16)
    }

    fn run_opcode(&self, opcode: u16) {

        let nibbles = (
            (opcode & 0x000F) as u8,
            (opcode & 0x00F0) >> 4 as u8,
            (opcode & 0x0F00) >> 8 as u8,
            (opcode & 0xF000) >> 12 as u8,
        );

        let nnn = opcode & 0x0FFF;
        let kk = (opcode & 0x00FF) as u8;
        let x = nibbles.2 as usize;
        let y = nibbles.1 as usize;
        let n = nibbles.0 as u8;

        match nibbles {
            (0x00, 0x00, 0x0e, 0x00) => self.op_00e0(),
            (0x00, 0x00, 0x0e, 0x0e) => self.op_00ee(),
            (0x00, _, _, _) => self.op_0nnn(nnn),
            (0x01, _, _, _) => self.op_1nnn(nnn),
            (0x02, _, _, _) => self.op_2nnn(nnn),
            (0x03, _, _, _) => self.op_3xkk(x, kk),
            (0x04, _, _, _) => self.op_4xkk(x, kk),
            (0x05, _, _, 0x00) => self.op_5xy0(x, y),
            (0x06, _, _, _) => self.op_6xkk(x, kk),
            (0x07, _, _, _) => self.op_7xkk(x, kk),
            (0x08, _, _, 0x00) => self.op_8xy0(x, y),
            (0x08, _, _, 0x01) => self.op_8xy1(x, y),
            (0x08, _, _, 0x02) => self.op_8xy2(x, y),
            (0x08, _, _, 0x03) => self.op_8xy3(x, y),
            (0x08, _, _, 0x04) => self.op_8xy4(x, y),
            (0x08, _, _, 0x05) => self.op_8xy5(x, y),
            (0x08, _, _, 0x06) => self.op_8xy6(x, y),
            (0x08, _, _, 0x07) => self.op_8xy7(x, y),
            (0x08, _, _, 0x0e) => self.op_8xye(x, y),
            (0x09, _, _, 0x00) => self.op_9xy0(x, y),
            (0x0a, _, _, _) => self.op_annn(nnn),
            (0x0b, _, _, _) => self.op_bnnn(nnn),
            (0x0c, _, _, _) => self.op_cxkk(x, kk),
            (0x0d, _, _, _) => self.op_dxyn(x, y, n),
            (0x0e, _, 0x09, 0x0e) => self.op_ex9e(x),
            (0x0e, _, 0x0a, 0x01) => self.op_exa1(x),
            (0x0f, _, 0x00, 0x07) => self.op_fx07(x),
            (0x0f, _, 0x00, 0x0a) => self.op_fx0a(x),
            (0x0f, _, 0x01, 0x05) => self.op_fx15(x),
            (0x0f, _, 0x01, 0x08) => self.op_fx18(x),
            (0x0f, _, 0x01, 0x0e) => self.op_fx1e(x),
            (0x0f, _, 0x02, 0x09) => self.op_fx29(x),
            (0x0f, _, 0x03, 0x03) => self.op_fx33(x),
            (0x0f, _, 0x05, 0x05) => self.op_fx55(x),
            (0x0f, _, 0x06, 0x05) => self.op_fx65(x),
            _ => return,
        }

    }
    // CLS
    fn op_00e0(&self) {}
    // RET
    fn op_00ee(&self) {}
    // SYS addr
    fn op_0nnn(&self, nnn: u16) {}
    // JP addr
    fn op_1nnn(&self, nnn: u16) {}
    // CALL addr
    fn op_2nnn(&self, nnn: u16) {}
    // SE Vx, byte
    fn op_3xkk(&self, x: usize, kk: u8) {}
    // SNE Vx, byte
    fn op_4xkk(&self, x: usize, kk: u8) {}
    // SE Vx, Vy
    fn op_5xy0(&self, x: usize, y: usize) {}
    // LD Vx, byte
    fn op_6xkk(&self, x: usize, kk: u8) {}
    // ADD Vx, byte
    fn op_7xkk(&self, x: usize, kk: u8) {}
    // LD Vx, Vy
    fn op_8xy0(&self, x: usize, y: usize) {}
    // OR Vx, Vy
    fn op_8xy1(&self, x: usize, y: usize) {}
    // AND Vx, Vy
    fn op_8xy2(&self, x: usize, y: usize) {}
    // XOR Vx, Vy
    fn op_8xy3(&self, x: usize, y: usize) {}
    // ADD Vx, Vy
    fn op_8xy4(&self, x: usize, y: usize) {}
    // SUB Vx, Vy
    fn op_8xy5(&self, x: usize, y: usize) {}
    // SHR Vx {, Vy}
    fn op_8xy6(&self, x: usize, y: usize) {}
    // SUBN Vx, Vy
    fn op_8xy7(&self, x: usize, y: usize) {}
    // SHL Vx {, Vy}
    fn op_8xye(&self, x: usize, y: usize) {}
    // SNE Vx, Vy
    fn op_9xy0(&self, x: usize, y: usize) {}
    // LD I, addr
    fn op_annn(&self, nnn: u16) {}
    // JP V0, addr
    fn op_bnnn(&self, nnn: u16) {}
    // RND Vx, byte
    fn op_cxkk(&self, x: usize, kk: u8) {}
    // DRW Vx, Vy, nibble
    fn op_dxyn(&self, x: usize, y: usize, n: u8) {}
    // SKP Vx
    fn op_ex9e(&self, x: usize) {}
    // SKNP Vx
    fn op_exa1(&self, x: usize) {}
    // LD Vx, DT
    fn op_fx07(&self, x: usize) {}
    // LD Vx, K
    fn op_fx0a(&self, x: usize) {}
    // LD DT, Vx
    fn op_fx15(&self, x: usize) {}
    // LD ST, Vx
    fn op_fx18(&self, x: usize) {}
    // ADD I, Vx
    fn op_fx1e(&self, x: usize) {}
    // LD F, Vx
    fn op_fx29(&self, x: usize) {}
    // LD B, Vx
    fn op_fx33(&self, x: usize) {}
    // LD [I], Vx
    fn op_fx55(&self, x: usize) {}
    // LD Vx, [I]
    fn op_fx65(&self, x: usize) {}
}
<|endoftext|>


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

use std::{borrow::Cow, cell::RefCell, mem};

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use enum_primitive_derive::Primitive;
use failure::{self, ensure, format_err};
use num_traits::FromPrimitive;
use serde_derive::{Deserialize, Serialize};

use crate::{BinaryKey, BinaryValue};

use super::{IndexAccess, IndexAddress, View};

/// TODO Add documentation. [ECR-2820]
const INDEXES_POOL_NAME: &str = "__INDEXES_POOL__";
/// TODO Add documentation. [ECR-2820]
const INDEXES_POOL_LEN_NAME: &str = "INDEXES_POOL_LEN";

/// TODO Add documentation. [ECR-2820]
#[derive(Debug, Copy, Clone, PartialEq, Primitive, Serialize, Deserialize)]
#[repr(u32)]
pub enum IndexType {
    Map = 1,
    List = 2,
    Entry = 3,
    ValueSet = 4,
    KeySet = 5,
    SparseList = 6,
    ProofList = 7,
    ProofMap = 8,
    Unknown = 255,
}

/// TODO Add documentation. [ECR-2820]
pub trait BinaryAttribute {
    /// TODO Add documentation. [ECR-2820]
    fn size(&self) -> usize;
    /// TODO Add documentation. [ECR-2820]
    fn write<W: std::io::Write>(&self, buffer: &mut W);
    /// TODO Add documentation. [ECR-2820]
    fn read<R: std::io::Read>(buffer: &mut R) -> Self;
}

/// No-op implementation.
impl BinaryAttribute for () {
    fn size(&self) -> usize {
        0
    }

    fn write<W: std::io::Write>(&self, _buffer: &mut W) {}

    fn read<R: std::io::Read>(_buffer: &mut R) -> Self {}
}

impl BinaryAttribute for u64 {
    fn size(&self) -> usize {
        mem::size_of_val(self)
    }

    fn write<W: std::io::Write>(&self, buffer: &mut W) {
        buffer.write_u64::<LittleEndian>(*self).unwrap()
    }

    fn read<R: std::io::Read>(buffer: &mut R) -> Self {
        buffer.read_u64::<LittleEndian>().unwrap()
    }
}

impl Default for IndexType {
    fn default() -> Self {
        IndexType::Unknown
    }
}

/// TODO Add documentation. [ECR-2820]
#[derive(Debug, Clone, PartialEq)]
pub struct IndexMetadata<V> {
    identifier: u64,
    index_type: IndexType,
    state: V,
}

impl<V> BinaryValue for IndexMetadata<V>
where
    V: BinaryAttribute,
{
    fn to_bytes(&self) -> Vec<u8> {
        let state_len = self.state.size();
        let mut buf = Vec::with_capacity(
            mem::size_of_val(&self.identifier)
                + mem::size_of_val(&self.index_type)
                + mem::size_of::<u32>()
                + state_len,
        );

        buf.write_u64::<LittleEndian>(self.identifier).unwrap();
        buf.write_u32::<LittleEndian>(self.index_type as u32)
            .unwrap();
        buf.write_u32::<LittleEndian>(state_len as u32).unwrap();
        self.state.write(&mut buf);
        buf
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let mut bytes = bytes.as_ref();

        let identifier = bytes.read_u64::<LittleEndian>()?;
        let index_type = bytes.read_u32::<LittleEndian>()?;
        let state_len = bytes.read_u32::<LittleEndian>()? as usize;

        ensure!(bytes.len() >= state_len, "Index state is too short");

        let mut state_bytes = &bytes[0..state_len];
        let state = V::read(&mut state_bytes);

        Ok(Self {
            identifier,
            index_type: IndexType::from_u32(index_type)
                .ok_or_else(|| format_err!("Unknown index type: {}", index_type))?,
            state,
        })
    }
}

impl<V> IndexMetadata<V> {
    fn index_address(&self) -> IndexAddress {
        IndexAddress::new().append_bytes(&self.identifier)
    }
}

impl IndexAddress {
    fn index_name(&self) -> Vec<u8> {
        if let Some(bytes) = self.bytes() {
            concat_keys!(self.name(), bytes)
        } else {
            concat_keys!(self.name())
        }
    }
}

/// TODO Add documentation. [ECR-2820]
pub fn index_metadata<T, V>(
    index_access: T,
    index_address: &IndexAddress,
    index_type: IndexType,
) -> (IndexAddress, IndexState<T, V>)
where
    T: IndexAccess,
    V: BinaryAttribute + Copy + Default,
{
    let index_name = index_address.index_name();

    let mut pool = IndexesPool::new(index_access);
    let metadata = if let Some(metadata) = pool.index_metadata(&index_name) {
        assert_eq!(
            metadata.index_type, index_type,
            "Index type doesn't match specified"
        );
        metadata
    } else {
        pool.set_index_metadata(&index_name, index_type)
    };

    let index_address = metadata.index_address();
    let index_state = IndexState::new(index_access, index_name, metadata);
    (index_address, index_state)
}

/// TODO Add documentation. [ECR-2820]
struct IndexesPool<T: IndexAccess>(View<T>);

impl<T: IndexAccess> IndexesPool<T> {
    fn new(index_access: T) -> Self {
        let pool_address = IndexAddress::from(INDEXES_POOL_NAME);
        Self(View::new(index_access, pool_address))
    }

    fn index_metadata<V>(&self, index_name: &[u8]) -> Option<IndexMetadata<V>>
    where
        V: BinaryAttribute + Default + Copy,
    {
        self.0.get(index_name)
    }

    fn set_index_metadata<V>(
        &mut self,
        index_name: &[u8],
        index_type: IndexType,
    ) -> IndexMetadata<V>
    where
        V: BinaryAttribute + Default + Copy,
    {
        let mut pool_len = View::new(
            self.0.index_access,
            IndexAddress::from(INDEXES_POOL_LEN_NAME),
        );
        let len: u64 = pool_len.get(&()).unwrap_or_default();

        let metadata = IndexMetadata {
            index_type,
            identifier: len,
            state: V::default(),
        };

        self.0.put(index_name, metadata.to_bytes());
        pool_len.put(&(), len + 1);
        metadata
    }
}

/// TODO Add documentation. [ECR-2820]
pub struct IndexState<T, V>
where
    V: BinaryAttribute + Default + Copy,
    T: IndexAccess,
{
    index_access: T,
    index_name: Vec<u8>,
    cache: RefCell<IndexMetadata<V>>,
}

impl<T, V> IndexState<T, V>
where
    V: BinaryAttribute + Default + Copy,
    T: IndexAccess,
{
    pub fn new(index_access: T, index_name: Vec<u8>, metadata: IndexMetadata<V>) -> Self {
        Self {
            index_access,
            index_name,
            cache: RefCell::new(metadata),
        }
    }

    /// TODO Add documentation. [ECR-2820]
    pub fn get(&self) -> V {
        self.cache.borrow().state
    }

    /// TODO Add documentation. [ECR-2820]
    pub fn set(&mut self, state: V) {
        let mut cache = self.cache.get_mut();
        cache.state = state;
        View::new(self.index_access, IndexAddress::from(INDEXES_POOL_NAME))
            .put(&self.index_name, cache.to_bytes());
    }
}

impl<T, V> std::fmt::Debug for IndexState<T, V>
where
    T: IndexAccess,
    V: BinaryAttribute + Default + Copy,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("IndexState").finish()
    }
}

#[cfg(test)]
mod tests {
    use crate::BinaryValue;

    use super::{IndexMetadata, IndexType};

    #[test]
    fn test_index_metadata_binary_value() {
        let metadata = IndexMetadata {
            identifier: 12,
            index_type: IndexType::ProofList,
            state: 16_u64,
        };

        let bytes = metadata.to_bytes();
        assert_eq!(IndexMetadata::from_bytes(bytes.into()).unwrap(), metadata);
    }
}
<commit_msg>Add test for binary value<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{borrow::Cow, cell::RefCell, mem};

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use enum_primitive_derive::Primitive;
use failure::{self, ensure, format_err};
use num_traits::FromPrimitive;
use serde_derive::{Deserialize, Serialize};

use crate::{BinaryKey, BinaryValue};

use super::{IndexAccess, IndexAddress, View};

/// TODO Add documentation. [ECR-2820]
const INDEXES_POOL_NAME: &str = "__INDEXES_POOL__";
/// TODO Add documentation. [ECR-2820]
const INDEXES_POOL_LEN_NAME: &str = "INDEXES_POOL_LEN";

/// TODO Add documentation. [ECR-2820]
#[derive(Debug, Copy, Clone, PartialEq, Primitive, Serialize, Deserialize)]
#[repr(u32)]
pub enum IndexType {
    Map = 1,
    List = 2,
    Entry = 3,
    ValueSet = 4,
    KeySet = 5,
    SparseList = 6,
    ProofList = 7,
    ProofMap = 8,
    Unknown = 255,
}

/// TODO Add documentation. [ECR-2820]
pub trait BinaryAttribute {
    /// TODO Add documentation. [ECR-2820]
    fn size(&self) -> usize;
    /// TODO Add documentation. [ECR-2820]
    fn write<W: std::io::Write>(&self, buffer: &mut W);
    /// TODO Add documentation. [ECR-2820]
    fn read<R: std::io::Read>(buffer: &mut R) -> Self;
}

/// No-op implementation.
impl BinaryAttribute for () {
    fn size(&self) -> usize {
        0
    }

    fn write<W: std::io::Write>(&self, _buffer: &mut W) {}

    fn read<R: std::io::Read>(_buffer: &mut R) -> Self {}
}

impl BinaryAttribute for u64 {
    fn size(&self) -> usize {
        mem::size_of_val(self)
    }

    fn write<W: std::io::Write>(&self, buffer: &mut W) {
        buffer.write_u64::<LittleEndian>(*self).unwrap()
    }

    fn read<R: std::io::Read>(buffer: &mut R) -> Self {
        buffer.read_u64::<LittleEndian>().unwrap()
    }
}

impl Default for IndexType {
    fn default() -> Self {
        IndexType::Unknown
    }
}

/// TODO Add documentation. [ECR-2820]
#[derive(Debug, Clone, PartialEq)]
pub struct IndexMetadata<V> {
    identifier: u64,
    index_type: IndexType,
    state: V,
}

impl<V> BinaryValue for IndexMetadata<V>
where
    V: BinaryAttribute,
{
    fn to_bytes(&self) -> Vec<u8> {
        let state_len = self.state.size();
        let mut buf = Vec::with_capacity(
            mem::size_of_val(&self.identifier)
                + mem::size_of_val(&self.index_type)
                + mem::size_of::<u32>()
                + state_len,
        );

        buf.write_u64::<LittleEndian>(self.identifier).unwrap();
        buf.write_u32::<LittleEndian>(self.index_type as u32)
            .unwrap();
        buf.write_u32::<LittleEndian>(state_len as u32).unwrap();
        self.state.write(&mut buf);
        buf
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let mut bytes = bytes.as_ref();

        let identifier = bytes.read_u64::<LittleEndian>()?;
        let index_type = bytes.read_u32::<LittleEndian>()?;
        let state_len = bytes.read_u32::<LittleEndian>()? as usize;

        ensure!(bytes.len() >= state_len, "Index state is too short");

        let mut state_bytes = &bytes[0..state_len];
        let state = V::read(&mut state_bytes);

        Ok(Self {
            identifier,
            index_type: IndexType::from_u32(index_type)
                .ok_or_else(|| format_err!("Unknown index type: {}", index_type))?,
            state,
        })
    }
}

impl<V> IndexMetadata<V> {
    fn index_address(&self) -> IndexAddress {
        IndexAddress::new().append_bytes(&self.identifier)
    }
}

impl IndexAddress {
    fn index_name(&self) -> Vec<u8> {
        if let Some(bytes) = self.bytes() {
            concat_keys!(self.name(), bytes)
        } else {
            concat_keys!(self.name())
        }
    }
}

/// TODO Add documentation. [ECR-2820]
pub fn index_metadata<T, V>(
    index_access: T,
    index_address: &IndexAddress,
    index_type: IndexType,
) -> (IndexAddress, IndexState<T, V>)
where
    T: IndexAccess,
    V: BinaryAttribute + Copy + Default,
{
    let index_name = index_address.index_name();

    let mut pool = IndexesPool::new(index_access);
    let metadata = if let Some(metadata) = pool.index_metadata(&index_name) {
        assert_eq!(
            metadata.index_type, index_type,
            "Index type doesn't match specified"
        );
        metadata
    } else {
        pool.set_index_metadata(&index_name, index_type)
    };

    let index_address = metadata.index_address();
    let index_state = IndexState::new(index_access, index_name, metadata);
    (index_address, index_state)
}

/// TODO Add documentation. [ECR-2820]
struct IndexesPool<T: IndexAccess>(View<T>);

impl<T: IndexAccess> IndexesPool<T> {
    fn new(index_access: T) -> Self {
        let pool_address = IndexAddress::from(INDEXES_POOL_NAME);
        Self(View::new(index_access, pool_address))
    }

    fn index_metadata<V>(&self, index_name: &[u8]) -> Option<IndexMetadata<V>>
    where
        V: BinaryAttribute + Default + Copy,
    {
        self.0.get(index_name)
    }

    fn set_index_metadata<V>(
        &mut self,
        index_name: &[u8],
        index_type: IndexType,
    ) -> IndexMetadata<V>
    where
        V: BinaryAttribute + Default + Copy,
    {
        let mut pool_len = View::new(
            self.0.index_access,
            IndexAddress::from(INDEXES_POOL_LEN_NAME),
        );
        let len: u64 = pool_len.get(&()).unwrap_or_default();

        let metadata = IndexMetadata {
            index_type,
            identifier: len,
            state: V::default(),
        };

        self.0.put(index_name, metadata.to_bytes());
        pool_len.put(&(), len + 1);
        metadata
    }
}

/// TODO Add documentation. [ECR-2820]
pub struct IndexState<T, V>
where
    V: BinaryAttribute + Default + Copy,
    T: IndexAccess,
{
    index_access: T,
    index_name: Vec<u8>,
    cache: RefCell<IndexMetadata<V>>,
}

impl<T, V> IndexState<T, V>
where
    V: BinaryAttribute + Default + Copy,
    T: IndexAccess,
{
    pub fn new(index_access: T, index_name: Vec<u8>, metadata: IndexMetadata<V>) -> Self {
        Self {
            index_access,
            index_name,
            cache: RefCell::new(metadata),
        }
    }

    /// TODO Add documentation. [ECR-2820]
    pub fn get(&self) -> V {
        self.cache.borrow().state
    }

    /// TODO Add documentation. [ECR-2820]
    pub fn set(&mut self, state: V) {
        let mut cache = self.cache.get_mut();
        cache.state = state;
        View::new(self.index_access, IndexAddress::from(INDEXES_POOL_NAME))
            .put(&self.index_name, cache.to_bytes());
    }
}

impl<T, V> std::fmt::Debug for IndexState<T, V>
where
    T: IndexAccess,
    V: BinaryAttribute + Default + Copy,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("IndexState").finish()
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use crate::BinaryValue;

    use super::{IndexMetadata, IndexType, BinaryAttribute};

    #[test]
    fn test_binary_attribute_read_write() {
        let mut buf = Vec::new();
        11_u64.write(&mut buf);
        12_u64.write(&mut buf);
        assert_eq!(buf.len(), 16);

        let mut reader = Cursor::new(buf);
        let a = u64::read(&mut reader);
        let b = u64::read(&mut reader);
        assert_eq!(a, 11);
        assert_eq!(b, 12);
    }

    #[test]
    fn test_index_metadata_binary_value() {
        let metadata = IndexMetadata {
            identifier: 12,
            index_type: IndexType::ProofList,
            state: 16_u64,
        };

        let bytes = metadata.to_bytes();
        assert_eq!(IndexMetadata::from_bytes(bytes.into()).unwrap(), metadata);
    }
}
<|endoftext|>


<commit_before>
<commit_msg>try that crate can be imported<commit_after>extern crate rusty_wolf_common;

<|endoftext|>


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

use binaryninjacore_sys::{
    BNBeginUndoActions,
    BNCloseFile,
    BNCommitUndoActions,
    BNCreateFileMetadata,
    BNFileMetadata,
    BNFreeFileMetadata,
    BNGetCurrentOffset,
    BNGetCurrentView,
    BNGetFileViewOfType,
    BNGetFilename,
    BNIsAnalysisChanged,
    BNIsBackedByDatabase,
    //BNSetFileMetadataNavigationHandler,
    BNIsFileModified,
    BNMarkFileModified,
    BNMarkFileSaved,
    BNNavigate,
    BNNewFileReference,
    BNRedo,
    BNSetFilename,
    BNUndo,
};

use crate::binaryview::BinaryView;

use crate::rc::*;
use crate::string::*;

#[derive(PartialEq, Eq, Hash)]
pub struct FileMetadata {
    pub(crate) handle: *mut BNFileMetadata,
}

unsafe impl Send for FileMetadata {}
unsafe impl Sync for FileMetadata {}

impl FileMetadata {
    pub(crate) fn from_raw(handle: *mut BNFileMetadata) -> Self {
        Self { handle }
    }

    pub fn new() -> Ref<Self> {
        unsafe {
            Ref::new(Self {
                handle: BNCreateFileMetadata(),
            })
        }
    }

    pub fn with_filename<S: BnStrCompatible>(name: S) -> Ref<Self> {
        let ret = FileMetadata::new();
        ret.set_filename(name);
        ret
    }

    pub fn close(&self) {
        unsafe {
            BNCloseFile(self.handle);
        }
    }

    pub fn filename(&self) -> BnString {
        unsafe {
            let raw = BNGetFilename(self.handle);
            BnString::from_raw(raw)
        }
    }

    pub fn set_filename<S: BnStrCompatible>(&self, name: S) {
        let name = name.as_bytes_with_nul();

        unsafe {
            BNSetFilename(self.handle, name.as_ref().as_ptr() as *mut _);
        }
    }

    pub fn is_modified(&self) -> bool {
        unsafe { BNIsFileModified(self.handle) }
    }

    pub fn mark_modified(&self) {
        unsafe {
            BNMarkFileModified(self.handle);
        }
    }

    pub fn is_analysis_changed(&self) -> bool {
        unsafe { BNIsAnalysisChanged(self.handle) }
    }

    pub fn mark_saved(&self) {
        unsafe {
            BNMarkFileSaved(self.handle);
        }
    }

    pub fn is_database_backed(&self) -> bool {
        unsafe { BNIsBackedByDatabase(self.handle) }
    }

    pub fn begin_undo_actions(&self) {
        unsafe {
            BNBeginUndoActions(self.handle);
        }
    }

    pub fn commit_undo_actions(&self) {
        unsafe {
            BNCommitUndoActions(self.handle);
        }
    }

    pub fn undo(&self) {
        unsafe {
            BNUndo(self.handle);
        }
    }

    pub fn redo(&self) {
        unsafe {
            BNRedo(self.handle);
        }
    }

    pub fn current_view(&self) -> BnString {
        unsafe { BnString::from_raw(BNGetCurrentView(self.handle)) }
    }

    pub fn current_offset(&self) -> u64 {
        unsafe { BNGetCurrentOffset(self.handle) }
    }

    pub fn navigate_to<S: BnStrCompatible>(&self, view: S, offset: u64) -> Result<(), ()> {
        let view = view.as_bytes_with_nul();

        unsafe {
            if BNNavigate(self.handle, view.as_ref().as_ptr() as *const _, offset) {
                Ok(())
            } else {
                Err(())
            }
        }
    }

    pub fn get_view_of_type<S: BnStrCompatible>(&self, view: S) -> Result<Ref<BinaryView>, ()> {
        let view = view.as_bytes_with_nul();

        unsafe {
            let res = BNGetFileViewOfType(self.handle, view.as_ref().as_ptr() as *const _);

            if res.is_null() {
                Err(())
            } else {
                Ok(Ref::new(BinaryView::from_raw(res)))
            }
        }
    }
}

impl ToOwned for FileMetadata {
    type Owned = Ref<Self>;

    fn to_owned(&self) -> Self::Owned {
        unsafe { RefCountable::inc_ref(self) }
    }
}

unsafe impl RefCountable for FileMetadata {
    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
        Ref::new(Self {
            handle: BNNewFileReference(handle.handle),
        })
    }

    unsafe fn dec_ref(handle: &Self) {
        BNFreeFileMetadata(handle.handle);
    }
}

/*
BNCreateDatabase,
BNCreateDatabaseWithProgress,
BNOpenExistingDatabase,
BNOpenExistingDatabaseWithProgress,
*/
<commit_msg>Add View Type to BNIsBackedByDatabase<commit_after>// Copyright 2021 Vector 35 Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use binaryninjacore_sys::{
    BNBeginUndoActions,
    BNCloseFile,
    BNCommitUndoActions,
    BNCreateFileMetadata,
    BNFileMetadata,
    BNFreeFileMetadata,
    BNGetCurrentOffset,
    BNGetCurrentView,
    BNGetFileViewOfType,
    BNGetFilename,
    BNIsAnalysisChanged,
    BNIsBackedByDatabase,
    //BNSetFileMetadataNavigationHandler,
    BNIsFileModified,
    BNMarkFileModified,
    BNMarkFileSaved,
    BNNavigate,
    BNNewFileReference,
    BNRedo,
    BNSetFilename,
    BNUndo,
};

use crate::binaryview::BinaryView;

use crate::rc::*;
use crate::string::*;

#[derive(PartialEq, Eq, Hash)]
pub struct FileMetadata {
    pub(crate) handle: *mut BNFileMetadata,
}

unsafe impl Send for FileMetadata {}
unsafe impl Sync for FileMetadata {}

impl FileMetadata {
    pub(crate) fn from_raw(handle: *mut BNFileMetadata) -> Self {
        Self { handle }
    }

    pub fn new() -> Ref<Self> {
        unsafe {
            Ref::new(Self {
                handle: BNCreateFileMetadata(),
            })
        }
    }

    pub fn with_filename<S: BnStrCompatible>(name: S) -> Ref<Self> {
        let ret = FileMetadata::new();
        ret.set_filename(name);
        ret
    }

    pub fn close(&self) {
        unsafe {
            BNCloseFile(self.handle);
        }
    }

    pub fn filename(&self) -> BnString {
        unsafe {
            let raw = BNGetFilename(self.handle);
            BnString::from_raw(raw)
        }
    }

    pub fn set_filename<S: BnStrCompatible>(&self, name: S) {
        let name = name.as_bytes_with_nul();

        unsafe {
            BNSetFilename(self.handle, name.as_ref().as_ptr() as *mut _);
        }
    }

    pub fn is_modified(&self) -> bool {
        unsafe { BNIsFileModified(self.handle) }
    }

    pub fn mark_modified(&self) {
        unsafe {
            BNMarkFileModified(self.handle);
        }
    }

    pub fn is_analysis_changed(&self) -> bool {
        unsafe { BNIsAnalysisChanged(self.handle) }
    }

    pub fn mark_saved(&self) {
        unsafe {
            BNMarkFileSaved(self.handle);
        }
    }

    pub fn is_database_backed<S: BnStrCompatible>(&self, view_type: S) -> bool {
        let view_type = view_type.as_bytes_with_nul();

        unsafe {
            BNIsBackedByDatabase(
                self.handle,
                view_type.as_ref().as_ptr() as *const _
            )
        }
    }

    pub fn begin_undo_actions(&self) {
        unsafe {
            BNBeginUndoActions(self.handle);
        }
    }

    pub fn commit_undo_actions(&self) {
        unsafe {
            BNCommitUndoActions(self.handle);
        }
    }

    pub fn undo(&self) {
        unsafe {
            BNUndo(self.handle);
        }
    }

    pub fn redo(&self) {
        unsafe {
            BNRedo(self.handle);
        }
    }

    pub fn current_view(&self) -> BnString {
        unsafe { BnString::from_raw(BNGetCurrentView(self.handle)) }
    }

    pub fn current_offset(&self) -> u64 {
        unsafe { BNGetCurrentOffset(self.handle) }
    }

    pub fn navigate_to<S: BnStrCompatible>(&self, view: S, offset: u64) -> Result<(), ()> {
        let view = view.as_bytes_with_nul();

        unsafe {
            if BNNavigate(self.handle, view.as_ref().as_ptr() as *const _, offset) {
                Ok(())
            } else {
                Err(())
            }
        }
    }

    pub fn get_view_of_type<S: BnStrCompatible>(&self, view: S) -> Result<Ref<BinaryView>, ()> {
        let view = view.as_bytes_with_nul();

        unsafe {
            let res = BNGetFileViewOfType(self.handle, view.as_ref().as_ptr() as *const _);

            if res.is_null() {
                Err(())
            } else {
                Ok(Ref::new(BinaryView::from_raw(res)))
            }
        }
    }
}

impl ToOwned for FileMetadata {
    type Owned = Ref<Self>;

    fn to_owned(&self) -> Self::Owned {
        unsafe { RefCountable::inc_ref(self) }
    }
}

unsafe impl RefCountable for FileMetadata {
    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
        Ref::new(Self {
            handle: BNNewFileReference(handle.handle),
        })
    }

    unsafe fn dec_ref(handle: &Self) {
        BNFreeFileMetadata(handle.handle);
    }
}

/*
BNCreateDatabase,
BNCreateDatabaseWithProgress,
BNOpenExistingDatabase,
BNOpenExistingDatabaseWithProgress,
*/
<|endoftext|>


<commit_before>
#![allow(dead_code)]

use std::cmp;
use raft::storage::Storage;
use proto::raftpb::{HardState, ConfState, Entry, Snapshot, Message};
use raft::progress::{Progress, Inflights};
use raft::errors::{Result, Error, other};
use std::collections::HashMap;
use raft::raft_log::RaftLog;

#[derive(Debug, PartialEq)]
enum StateRole {
    Follower,
    Candidate,
    Leader,
    Invalid,
}

impl Default for StateRole {
    fn default() -> StateRole {
        StateRole::Invalid
    }
}

const INVALID_ID: u64 = 0;

// Config contains the parameters to start a raft.
#[derive(Debug, Default)]
pub struct Config<T>
    where T: Storage
{
    // id is the identity of the local raft. ID cannot be 0.
    id: u64,

    // peers contains the IDs of all nodes (including self) in
    // the raft cluster. It should only be set when starting a new
    // raft cluster.
    // Restarting raft from previous configuration will panic if
    // peers is set.
    // peer is private and only used for testing right now.
    peers: Vec<u64>,

    // ElectionTick is the election timeout. If a follower does not
    // receive any message from the leader of current term during
    // ElectionTick, it will become candidate and start an election.
    // ElectionTick must be greater than HeartbeatTick. We suggest
    // to use ElectionTick = 10 * HeartbeatTick to avoid unnecessary
    // leader switching.
    election_tick: usize,
    // HeartbeatTick is the heartbeat usizeerval. A leader sends heartbeat
    // message to mausizeain the leadership every heartbeat usizeerval.
    heartbeat_tick: usize,

    // Storage is the storage for raft. raft generates entires and
    // states to be stored in storage. raft reads the persisted entires
    // and states out of Storage when it needs. raft reads out the previous
    // state and configuration out of storage when restarting.
    storage: T,
    // Applied is the last applied index. It should only be set when restarting
    // raft. raft will not return entries to the application smaller or equal to Applied.
    // If Applied is unset when restarting, raft might return previous applied entries.
    // This is a very application dependent configuration.
    applied: u64,

    // MaxSizePerMsg limits the max size of each append message. Smaller value lowers
    // the raft recovery cost(initial probing and message lost during normal operation).
    // On the other side, it might affect the throughput during normal replication.
    // Note: math.MaxUusize64 for unlimited, 0 for at most one entry per message.
    max_size_per_msg: u64,
    // max_inflights_msgs limits the max number of in-flight append messages during optimistic
    // replication phase. The application transportation layer usually has its own sending
    // buffer over TCP/UDP. Setting MaxInflightMsgs to avoid overflowing that sending buffer.
    // TODO (xiangli): feedback to application to limit the proposal rate?
    max_inflights_msgs: usize,

    // check_quorum specifies if the leader should check quorum activity. Leader steps down when
    // quorum is not active for an electionTimeout.
    check_quorum: bool,
}

impl<T> Config<T> where T: Storage
{
    pub fn validate(&self) -> Result<()> {
        if self.id == INVALID_ID {
            return Err(other("invalid node id"));
        }

        if self.heartbeat_tick <= 0 {
            return Err(other("heartbeat tick must greater than 0"));
        }

        if self.election_tick <= self.heartbeat_tick {
            return Err(other("election tick must be greater than heartbeat tick"));
        }

        if self.max_inflights_msgs <= 0 {
            return Err(other("max inflight messages must be greater than 0"));
        }

        Ok(())
    }
}

#[derive(Default)]
struct Raft {
    hs: HardState,

    id: u64,

    max_inflight: usize,
    max_msg_size: u64,
    prs: HashMap<u64, Progress>,

    state: StateRole,

    votes: HashMap<u64, bool>,

    msgs: Vec<Message>,

    // the leader id
    lead: u64,

    // New configuration is ignored if there exists unapplied configuration.
    pending_conf: bool,

    // number of ticks since it reached last electionTimeout when it is leader
    // or candidate.
    // number of ticks since it reached last electionTimeout or received a
    // valid message from current leader when it is a follower.
    election_elapsed: usize,

    // number of ticks since it reached last heartbeatTimeout.
    // only leader keeps heartbeatElapsed.
    heartbeat_elapsed: usize,

    check_quorum: bool,

    heartbeat_timeout: usize,
    election_timeout: usize,
    tick: Vec<Box<FnMut()>>,
    step: Vec<Box<FnMut(&Message)>>,
}

impl Raft {
    fn newRaft<T>(c: &Config<T>) -> Raft
        where T: Storage
    {
        c.validate().map_err(|e| panic!(e));
        let mut raftlog = RaftLog::new(c.storage);
        let state = &c.storage.initial_state();
        state.map_err(|e| panic!(e));
        let hs = &state.unwrap().hard_state;
        let cs = &state.unwrap().conf_state;
        let mut peers = c.peers.into_iter().collect::<Vec<u64>>();
        if cs.get_nodes().len() > 0 {
            if peers.len() > 0 {
                panic!("cannot specify both newRaft(peers) and conf_state.nodes")
            }
            peers = cs.get_nodes().into_iter().map(|&x| x).collect::<Vec<u64>>();
        }

        let mut tmp: HashMap<u64, Progress> = HashMap::new();
        for id in peers {
            tmp.insert(id,
                       Progress {
                           next_idx: 1,
                           ins: Inflights::new(c.max_inflights_msgs),
                           ..Default::default()
                       });
        }
        // empty state
        if hs == &HardState::new() {

        }
        Raft {
            id: c.id,
            lead: INVALID_ID,
            max_msg_size: c.max_size_per_msg,
            max_inflight: c.max_inflights_msgs,
            election_timeout: c.election_tick,
            heartbeat_timeout: c.heartbeat_tick,
            check_quorum: c.check_quorum,
            prs: tmp,
            tick: Vec::new(),
            step: Vec::new(),
            ..Default::default()
        }
    }

    pub fn do_nothing(&self) {}
}
<commit_msg>Using dyanmic dispatch<commit_after>
#![allow(dead_code)]

use std::cmp;
use raft::storage::Storage;
use proto::raftpb::{HardState, ConfState, Entry, Snapshot, Message};
use raft::progress::{Progress, Inflights};
use raft::errors::{Result, Error, other};
use std::collections::HashMap;
use raft::raft_log::RaftLog;

#[derive(Debug, PartialEq)]
enum StateRole {
    Follower,
    Candidate,
    Leader,
    Invalid,
}

impl Default for StateRole {
    fn default() -> StateRole {
        StateRole::Invalid
    }
}

const INVALID_ID: u64 = 0;

// Config contains the parameters to start a raft.
#[derive( Default)]
pub struct Config {
    // id is the identity of the local raft. ID cannot be 0.
    id: u64,

    // peers contains the IDs of all nodes (including self) in
    // the raft cluster. It should only be set when starting a new
    // raft cluster.
    // Restarting raft from previous configuration will panic if
    // peers is set.
    // peer is private and only used for testing right now.
    peers: Vec<u64>,

    // ElectionTick is the election timeout. If a follower does not
    // receive any message from the leader of current term during
    // ElectionTick, it will become candidate and start an election.
    // ElectionTick must be greater than HeartbeatTick. We suggest
    // to use ElectionTick = 10 * HeartbeatTick to avoid unnecessary
    // leader switching.
    election_tick: usize,
    // HeartbeatTick is the heartbeat usizeerval. A leader sends heartbeat
    // message to mausizeain the leadership every heartbeat usizeerval.
    heartbeat_tick: usize,

    // Storage is the storage for raft. raft generates entires and
    // states to be stored in storage. raft reads the persisted entires
    // and states out of Storage when it needs. raft reads out the previous
    // state and configuration out of storage when restarting.
    storage: Option<Box<Storage>>,
    // Applied is the last applied index. It should only be set when restarting
    // raft. raft will not return entries to the application smaller or equal to Applied.
    // If Applied is unset when restarting, raft might return previous applied entries.
    // This is a very application dependent configuration.
    applied: u64,

    // MaxSizePerMsg limits the max size of each append message. Smaller value lowers
    // the raft recovery cost(initial probing and message lost during normal operation).
    // On the other side, it might affect the throughput during normal replication.
    // Note: math.MaxUusize64 for unlimited, 0 for at most one entry per message.
    max_size_per_msg: u64,
    // max_inflights_msgs limits the max number of in-flight append messages during optimistic
    // replication phase. The application transportation layer usually has its own sending
    // buffer over TCP/UDP. Setting MaxInflightMsgs to avoid overflowing that sending buffer.
    // TODO (xiangli): feedback to application to limit the proposal rate?
    max_inflights_msgs: usize,

    // check_quorum specifies if the leader should check quorum activity. Leader steps down when
    // quorum is not active for an electionTimeout.
    check_quorum: bool,
}

impl Config {
    pub fn validate(&self) -> Result<()> {
        if self.id == INVALID_ID {
            return Err(other("invalid node id"));
        }

        if self.heartbeat_tick <= 0 {
            return Err(other("heartbeat tick must greater than 0"));
        }

        if self.election_tick <= self.heartbeat_tick {
            return Err(other("election tick must be greater than heartbeat tick"));
        }

        if self.max_inflights_msgs <= 0 {
            return Err(other("max inflight messages must be greater than 0"));
        }

        Ok(())
    }
}

#[derive(Default)]
struct Raft {
    hs: HardState,

    id: u64,

    max_inflight: usize,
    max_msg_size: u64,
    prs: HashMap<u64, Progress>,

    state: StateRole,

    votes: HashMap<u64, bool>,

    msgs: Vec<Message>,

    // the leader id
    lead: u64,

    // New configuration is ignored if there exists unapplied configuration.
    pending_conf: bool,

    // number of ticks since it reached last electionTimeout when it is leader
    // or candidate.
    // number of ticks since it reached last electionTimeout or received a
    // valid message from current leader when it is a follower.
    election_elapsed: usize,

    // number of ticks since it reached last heartbeatTimeout.
    // only leader keeps heartbeatElapsed.
    heartbeat_elapsed: usize,

    check_quorum: bool,

    heartbeat_timeout: usize,
    election_timeout: usize,
    tick: Vec<Box<FnMut()>>,
    step: Vec<Box<FnMut(&Message)>>,
}

impl Raft {
    fn newRaft<T>(c: &Config) -> Raft
        where T: Storage
    {
        c.validate().map_err(|e| panic!(e));
        let mut raftlog = RaftLog::new(c.storage);
        let state = &c.storage.initial_state();
        state.map_err(|e| panic!(e));
        let hs = &state.unwrap().hard_state;
        let cs = &state.unwrap().conf_state;
        let mut peers = c.peers.into_iter().collect::<Vec<u64>>();
        if cs.get_nodes().len() > 0 {
            if peers.len() > 0 {
                panic!("cannot specify both newRaft(peers) and conf_state.nodes")
            }
            peers = cs.get_nodes().into_iter().map(|&x| x).collect::<Vec<u64>>();
        }

        let mut tmp: HashMap<u64, Progress> = HashMap::new();
        for id in peers {
            tmp.insert(id,
                       Progress {
                           next_idx: 1,
                           ins: Inflights::new(c.max_inflights_msgs),
                           ..Default::default()
                       });
        }
        // empty state
        if hs == &HardState::new() {

        }
        Raft {
            id: c.id,
            lead: INVALID_ID,
            max_msg_size: c.max_size_per_msg,
            max_inflight: c.max_inflights_msgs,
            election_timeout: c.election_tick,
            heartbeat_timeout: c.heartbeat_tick,
            check_quorum: c.check_quorum,
            prs: tmp,
            tick: Vec::new(),
            step: Vec::new(),
            ..Default::default()
        }
    }

    pub fn do_nothing(&self) {}
}
<|endoftext|>