<commit_before>// Publicly exposes the `Decoder` directly from the module.
use std::fmt;
use std::collections::RingBuf;

pub use self::decoder::Decoder;

pub mod encoder;
pub mod decoder;
pub mod huffman;

/// A struct representing the dynamic table that needs to be maintained by the
/// coder.
///
/// The dynamic table contains a number of recently used headers. The size of
/// the table is constrained to a certain number of octets. If on insertion of
/// a new header into the table, the table would exceed the maximum size,
/// headers are evicted in a FIFO fashion until there is enough room for the
/// new header to be inserted. (Therefore, it is possible that though all
/// elements end up being evicted, there is still not enough space for the new
/// header: when the size of this individual header exceeds the maximum size of
/// the table.)
///
/// The current size of the table is calculated, based on the IETF definition,
/// as the sum of sizes of each header stored within the table, where the size
/// of an individual header is
/// `len_in_octets(header_name) + len_in_octets(header_value) + 32`.
///
/// Note: the maximum size of the dynamic table does not have to be equal to
/// the maximum header table size as defined by a "higher level" protocol
/// (such as the `SETTINGS_HEADER_TABLE_SIZE` setting in HTTP/2), since HPACK
/// can choose to modify the dynamic table size on the fly (as long as it keeps
/// it below the maximum value set by the protocol). So, the `DynamicTable`
/// only cares about the maximum size as set by the HPACK {en,de}coder and lets
/// *it* worry about making certain that the changes are valid according to
/// the (current) constraints of the protocol.
struct DynamicTable {
    table: RingBuf<(Vec<u8>, Vec<u8>)>,
    size: usize,
    max_size: usize,
}

impl DynamicTable {
    /// Creates a new empty dynamic table with a default size.
    fn new() -> DynamicTable {
        // The default maximum size corresponds to the default HTTP/2
        // setting
        DynamicTable::with_size(4096)
    }

    /// Creates a new empty dynamic table with the given maximum size.
    fn with_size(max_size: usize) -> DynamicTable {
        DynamicTable {
            table: RingBuf::new(),
            size: 0,
            max_size: max_size,
        }
    }

    /// Returns the current size of the table in octets, as defined by the IETF
    /// HPACK spec.
    fn get_size(&self) -> usize {
        self.size
    }

    /// Sets the new maximum table size.
    ///
    /// If the current size of the table is larger than the new maximum size,
    /// existing headers are evicted in a FIFO fashion until the size drops
    /// below the new maximum.
    fn set_max_table_size(&mut self, new_max_size: usize) {
        self.max_size = new_max_size;
        // Make the table size fit within the new constraints.
        self.consolidate_table();
    }

    /// Returns the maximum size of the table in octets.
    fn get_max_table_size(&self) -> usize {
        self.max_size
    }

    /// Add a new header to the dynamic table.
    ///
    /// The table automatically gets resized, if necessary.
    ///
    /// Do note that, under the HPACK rules, it is possible the given header
    /// is not found in the dynamic table after this operation finishes, in
    /// case the total size of the given header exceeds the maximum size of the
    /// dynamic table.
    fn add_header(&mut self, name: Vec<u8>, value: Vec<u8>) {
        // This is how the HPACK spec makes us calculate the size.  The 32 is
        // a magic number determined by them (under reasonable assumptions of
        // how the table is stored).
        self.size += name.len() + value.len() + 32;
        debug!("New dynamic table size {}", self.size);
        // Now add it to the internal buffer
        self.table.push_front((name, value));
        // ...and make sure we're not over the maximum size.
        self.consolidate_table();
        debug!("After consolidation dynamic table size {}", self.size);
    }

    /// Consolidates the table entries so that the table size is below the
    /// maximum allowed size, by evicting headers from the table in a FIFO
    /// fashion.
    fn consolidate_table(&mut self) {
        while self.size > self.max_size {
            {
                let last_header = match self.table.back() {
                    Some(x) => x,
                    None => {
                        // Can never happen as the size of the table must reach
                        // 0 by the time we've exhausted all elements.
                        // The only time it *could* happen is if max_size were 0
                        // too.
                        panic!("Size of table != 0, but no headers left!");
                    }
                };
                self.size -= last_header.0.len() + last_header.1.len() + 32;
            }
            self.table.pop_back();
        }
    }

    /// Returns the number of headers in the dynamic table.
    ///
    /// This is different than the size of the dynamic table.
    fn len(&self) -> usize {
        self.table.len()
    }

    /// Converts the current state of the table to a `Vec`
    fn get_table_as_list(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
        let mut ret: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
        for elem in self.table.iter() {
            ret.push(elem.clone());
        }

        ret
    }

    /// Returns a reference to the header at the given index, if found in the
    /// dynamic table.
    fn get(&self, index: usize) -> Option<&(Vec<u8>, Vec<u8>)> {
        self.table.get(index)
    }
}

impl fmt::Show for DynamicTable {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{:?}", self.table)
    }
}

/// The table represents the static header table defined by the HPACK spec.
/// (HPACK, Appendix A)
static STATIC_TABLE: &'static [(&'static [u8], &'static [u8])] = &[
  (b":authority", b""),
  (b":method", b"GET"),
  (b":method", b"POST"),
  (b":path", b"/"),
  (b":path", b"/index.html"),
  (b":scheme", b"http"),
  (b":scheme", b"https"),
  (b":status", b"200"),
  (b":status", b"204"),
  (b":status", b"206"),
  (b":status", b"304"),
  (b":status", b"400"),
  (b":status", b"404"),
  (b":status", b"500"),
  (b"accept-", b""),
  (b"accept-encoding", b"gzip, deflate"),
  (b"accept-language", b""),
  (b"accept-ranges", b""),
  (b"accept", b""),
  (b"access-control-allow-origin", b""),
  (b"age", b""),
  (b"allow", b""),
  (b"authorization", b""),
  (b"cache-control", b""),
  (b"content-disposition", b""),
  (b"content-encoding", b""),
  (b"content-language", b""),
  (b"content-length", b""),
  (b"content-location", b""),
  (b"content-range", b""),
  (b"content-type", b""),
  (b"cookie", b""),
  (b"date", b""),
  (b"etag", b""),
  (b"expect", b""),
  (b"expires", b""),
  (b"from", b""),
  (b"host", b""),
  (b"if-match", b""),
  (b"if-modified-since", b""),
  (b"if-none-match", b""),
  (b"if-range", b""),
  (b"if-unmodified-since", b""),
  (b"last-modified", b""),
  (b"link", b""),
  (b"location", b""),
  (b"max-forwards", b""),
  (b"proxy-authenticate", b""),
  (b"proxy-authorization", b""),
  (b"range", b""),
  (b"referer", b""),
  (b"refresh", b""),
  (b"retry-after", b""),
  (b"server", b""),
  (b"set-cookie", b""),
  (b"strict-transport-security", b""),
  (b"transfer-encoding", b""),
  (b"user-agent", b""),
  (b"vary", b""),
  (b"via", b""),
  (b"www-authenticate", b""),
];

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

    #[test]
    fn test_dynamic_table_size_calculation_simple() {
        let mut table = DynamicTable::new();
        // Sanity check
        assert_eq!(0, table.get_size());

        table.add_header(b"a".to_vec(), b"b".to_vec());

        assert_eq!(32 + 2, table.get_size());
    }

    #[test]
    fn test_dynamic_table_size_calculation() {
        let mut table = DynamicTable::new();

        table.add_header(b"a".to_vec(), b"b".to_vec());
        table.add_header(b"123".to_vec(), b"456".to_vec());
        table.add_header(b"a".to_vec(), b"b".to_vec());

        assert_eq!(3 * 32 + 2 + 6 + 2, table.get_size());
    }

    /// Tests that the `DynamicTable` gets correctly resized (by evicting old
    /// headers) if it exceeds the maximum size on an insertion.
    #[test]
    fn test_dynamic_table_auto_resize() {
        let mut table = DynamicTable::with_size(38);
        table.add_header(b"a".to_vec(), b"b".to_vec());
        assert_eq!(32 + 2, table.get_size());

        table.add_header(b"123".to_vec(), b"456".to_vec());

        // Resized?
        assert_eq!(32 + 6, table.get_size());
        // Only has the second header?
        assert_eq!(table.get_table_as_list(), vec![
            (b"123".to_vec(), b"456".to_vec())]);
    }

    /// Tests that when inserting a new header whose size is larger than the
    /// size of the entire table, the table is fully emptied.
    #[test]
    fn test_dynamic_table_auto_resize_into_empty() {
        let mut table = DynamicTable::with_size(38);
        table.add_header(b"a".to_vec(), b"b".to_vec());
        assert_eq!(32 + 2, table.get_size());

        table.add_header(b"123".to_vec(), b"4567".to_vec());

        // Resized and empty?
        assert_eq!(0, table.get_size());
        assert_eq!(0, table.get_table_as_list().len());
    }

    /// Tests that when changing the maximum size of the `DynamicTable`, the
    /// headers are correctly evicted in order to keep its size below the new
    /// max.
    #[test]
    fn test_dynamic_table_change_max_size() {
        let mut table = DynamicTable::new();
        table.add_header(b"a".to_vec(), b"b".to_vec());
        table.add_header(b"123".to_vec(), b"456".to_vec());
        table.add_header(b"c".to_vec(), b"d".to_vec());
        assert_eq!(3 * 32 + 2 + 6 + 2, table.get_size());

        table.set_max_table_size(38);

        assert_eq!(32 + 2, table.get_size());
        assert_eq!(table.get_table_as_list(), vec![
            (b"c".to_vec(), b"d".to_vec())]);
    }

    /// Tests that setting the maximum table size to 0 clears the dynamic
    /// table.
    #[test]
    fn test_dynamic_table_clear() {
        let mut table = DynamicTable::new();
        table.add_header(b"a".to_vec(), b"b".to_vec());
        table.add_header(b"123".to_vec(), b"456".to_vec());
        table.add_header(b"c".to_vec(), b"d".to_vec());
        assert_eq!(3 * 32 + 2 + 6 + 2, table.get_size());

        table.set_max_table_size(0);

        assert_eq!(0, table.len());
        assert_eq!(0, table.get_table_as_list().len());
        assert_eq!(0, table.get_size());
        assert_eq!(0, table.get_max_table_size());
    }

}
<commit_msg>Implement a `HeaderTable` struct<commit_after>// Publicly exposes the `Decoder` directly from the module.
use std::fmt;
use std::collections::RingBuf;

pub use self::decoder::Decoder;

pub mod encoder;
pub mod decoder;
pub mod huffman;

/// A struct representing the dynamic table that needs to be maintained by the
/// coder.
///
/// The dynamic table contains a number of recently used headers. The size of
/// the table is constrained to a certain number of octets. If on insertion of
/// a new header into the table, the table would exceed the maximum size,
/// headers are evicted in a FIFO fashion until there is enough room for the
/// new header to be inserted. (Therefore, it is possible that though all
/// elements end up being evicted, there is still not enough space for the new
/// header: when the size of this individual header exceeds the maximum size of
/// the table.)
///
/// The current size of the table is calculated, based on the IETF definition,
/// as the sum of sizes of each header stored within the table, where the size
/// of an individual header is
/// `len_in_octets(header_name) + len_in_octets(header_value) + 32`.
///
/// Note: the maximum size of the dynamic table does not have to be equal to
/// the maximum header table size as defined by a "higher level" protocol
/// (such as the `SETTINGS_HEADER_TABLE_SIZE` setting in HTTP/2), since HPACK
/// can choose to modify the dynamic table size on the fly (as long as it keeps
/// it below the maximum value set by the protocol). So, the `DynamicTable`
/// only cares about the maximum size as set by the HPACK {en,de}coder and lets
/// *it* worry about making certain that the changes are valid according to
/// the (current) constraints of the protocol.
struct DynamicTable {
    table: RingBuf<(Vec<u8>, Vec<u8>)>,
    size: usize,
    max_size: usize,
}

impl DynamicTable {
    /// Creates a new empty dynamic table with a default size.
    fn new() -> DynamicTable {
        // The default maximum size corresponds to the default HTTP/2
        // setting
        DynamicTable::with_size(4096)
    }

    /// Creates a new empty dynamic table with the given maximum size.
    fn with_size(max_size: usize) -> DynamicTable {
        DynamicTable {
            table: RingBuf::new(),
            size: 0,
            max_size: max_size,
        }
    }

    /// Returns the current size of the table in octets, as defined by the IETF
    /// HPACK spec.
    fn get_size(&self) -> usize {
        self.size
    }

    /// Sets the new maximum table size.
    ///
    /// If the current size of the table is larger than the new maximum size,
    /// existing headers are evicted in a FIFO fashion until the size drops
    /// below the new maximum.
    fn set_max_table_size(&mut self, new_max_size: usize) {
        self.max_size = new_max_size;
        // Make the table size fit within the new constraints.
        self.consolidate_table();
    }

    /// Returns the maximum size of the table in octets.
    fn get_max_table_size(&self) -> usize {
        self.max_size
    }

    /// Add a new header to the dynamic table.
    ///
    /// The table automatically gets resized, if necessary.
    ///
    /// Do note that, under the HPACK rules, it is possible the given header
    /// is not found in the dynamic table after this operation finishes, in
    /// case the total size of the given header exceeds the maximum size of the
    /// dynamic table.
    fn add_header(&mut self, name: Vec<u8>, value: Vec<u8>) {
        // This is how the HPACK spec makes us calculate the size.  The 32 is
        // a magic number determined by them (under reasonable assumptions of
        // how the table is stored).
        self.size += name.len() + value.len() + 32;
        debug!("New dynamic table size {}", self.size);
        // Now add it to the internal buffer
        self.table.push_front((name, value));
        // ...and make sure we're not over the maximum size.
        self.consolidate_table();
        debug!("After consolidation dynamic table size {}", self.size);
    }

    /// Consolidates the table entries so that the table size is below the
    /// maximum allowed size, by evicting headers from the table in a FIFO
    /// fashion.
    fn consolidate_table(&mut self) {
        while self.size > self.max_size {
            {
                let last_header = match self.table.back() {
                    Some(x) => x,
                    None => {
                        // Can never happen as the size of the table must reach
                        // 0 by the time we've exhausted all elements.
                        // The only time it *could* happen is if max_size were 0
                        // too.
                        panic!("Size of table != 0, but no headers left!");
                    }
                };
                self.size -= last_header.0.len() + last_header.1.len() + 32;
            }
            self.table.pop_back();
        }
    }

    /// Returns the number of headers in the dynamic table.
    ///
    /// This is different than the size of the dynamic table.
    fn len(&self) -> usize {
        self.table.len()
    }

    /// Converts the current state of the table to a `Vec`
    fn get_table_as_list(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
        let mut ret: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
        for elem in self.table.iter() {
            ret.push(elem.clone());
        }

        ret
    }

    /// Returns a reference to the header at the given index, if found in the
    /// dynamic table.
    fn get(&self, index: usize) -> Option<&(Vec<u8>, Vec<u8>)> {
        self.table.get(index)
    }
}

impl fmt::Show for DynamicTable {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{:?}", self.table)
    }
}

/// Represents the type of the static table, as defined by the HPACK spec.
type StaticTable<'a> = &'a [(&'a [u8], &'a [u8])];

/// The struct represents the header table obtained by merging the static and
/// dynamic tables into a single index address space, as described in section
/// `2.3.3.` of the HPACK spec.
struct HeaderTable<'a> {
    static_table: StaticTable<'a>,
    dynamic_table: DynamicTable,
}

impl<'a> HeaderTable<'a> {
    /// Creates a new header table where the static part is initialized with
    /// the given static table.
    pub fn with_static_table(static_table: StaticTable<'a>) -> HeaderTable<'a> {
        HeaderTable {
            static_table: static_table,
            dynamic_table: DynamicTable::new(),
        }
    }

    /// Adds the given header to the table. Of course, this means that the new
    /// header is added to the dynamic part of the table.
    ///
    /// If the size of the new header is larger than the current maximum table
    /// size of the dynamic table, the effect will be that the dynamic table
    /// gets emptied and the new header does *not* get inserted into it.
    #[inline]
    pub fn add_header(&mut self, name: Vec<u8>, value: Vec<u8>) {
        self.dynamic_table.add_header(name, value);
    }

    /// Returns a reference to the header (a `(name, value)` pair) with the
    /// given index in the table.
    ///
    /// The table is 1-indexed and constructed in such a way that the first
    /// entries belong to the static table, followed by entries in the dynamic
    /// table. They are merged into a single index address space, though.
    ///
    /// This is according to the [HPACK spec, section 2.3.3.]
    /// (http://http2.github.io/http2-spec/compression.html#index.address.space)
    pub fn get_from_table(&self, index: usize)
            -> Option<(&[u8], &[u8])> {
        // The IETF defined table indexing as 1-based.
        // So, before starting, make sure the given index is within the proper
        // bounds.
        let real_index = if index > 0 {
            index - 1
        } else {
            return None
        };

        if real_index < self.static_table.len() {
            // It is in the static table so just return that...
            Some(self.static_table[real_index])
        } else {
            // Maybe it's in the dynamic table then?
            let dynamic_index = real_index - self.static_table.len();
            if dynamic_index < self.dynamic_table.len() {
                match self.dynamic_table.get(dynamic_index) {
                    Some(&(ref name, ref value)) => {
                        Some((&name[0..], &value[0..]))
                    },
                    None => None
                }
            } else {
                // Index out of bounds!
                None
            }
        }
    }
}

/// The table represents the static header table defined by the HPACK spec.
/// (HPACK, Appendix A)
static STATIC_TABLE: &'static [(&'static [u8], &'static [u8])] = &[
  (b":authority", b""),
  (b":method", b"GET"),
  (b":method", b"POST"),
  (b":path", b"/"),
  (b":path", b"/index.html"),
  (b":scheme", b"http"),
  (b":scheme", b"https"),
  (b":status", b"200"),
  (b":status", b"204"),
  (b":status", b"206"),
  (b":status", b"304"),
  (b":status", b"400"),
  (b":status", b"404"),
  (b":status", b"500"),
  (b"accept-", b""),
  (b"accept-encoding", b"gzip, deflate"),
  (b"accept-language", b""),
  (b"accept-ranges", b""),
  (b"accept", b""),
  (b"access-control-allow-origin", b""),
  (b"age", b""),
  (b"allow", b""),
  (b"authorization", b""),
  (b"cache-control", b""),
  (b"content-disposition", b""),
  (b"content-encoding", b""),
  (b"content-language", b""),
  (b"content-length", b""),
  (b"content-location", b""),
  (b"content-range", b""),
  (b"content-type", b""),
  (b"cookie", b""),
  (b"date", b""),
  (b"etag", b""),
  (b"expect", b""),
  (b"expires", b""),
  (b"from", b""),
  (b"host", b""),
  (b"if-match", b""),
  (b"if-modified-since", b""),
  (b"if-none-match", b""),
  (b"if-range", b""),
  (b"if-unmodified-since", b""),
  (b"last-modified", b""),
  (b"link", b""),
  (b"location", b""),
  (b"max-forwards", b""),
  (b"proxy-authenticate", b""),
  (b"proxy-authorization", b""),
  (b"range", b""),
  (b"referer", b""),
  (b"refresh", b""),
  (b"retry-after", b""),
  (b"server", b""),
  (b"set-cookie", b""),
  (b"strict-transport-security", b""),
  (b"transfer-encoding", b""),
  (b"user-agent", b""),
  (b"vary", b""),
  (b"via", b""),
  (b"www-authenticate", b""),
];

#[cfg(test)]
mod tests {
    use super::DynamicTable;
    use super::HeaderTable;
    use super::STATIC_TABLE;

    #[test]
    fn test_dynamic_table_size_calculation_simple() {
        let mut table = DynamicTable::new();
        // Sanity check
        assert_eq!(0, table.get_size());

        table.add_header(b"a".to_vec(), b"b".to_vec());

        assert_eq!(32 + 2, table.get_size());
    }

    #[test]
    fn test_dynamic_table_size_calculation() {
        let mut table = DynamicTable::new();

        table.add_header(b"a".to_vec(), b"b".to_vec());
        table.add_header(b"123".to_vec(), b"456".to_vec());
        table.add_header(b"a".to_vec(), b"b".to_vec());

        assert_eq!(3 * 32 + 2 + 6 + 2, table.get_size());
    }

    /// Tests that the `DynamicTable` gets correctly resized (by evicting old
    /// headers) if it exceeds the maximum size on an insertion.
    #[test]
    fn test_dynamic_table_auto_resize() {
        let mut table = DynamicTable::with_size(38);
        table.add_header(b"a".to_vec(), b"b".to_vec());
        assert_eq!(32 + 2, table.get_size());

        table.add_header(b"123".to_vec(), b"456".to_vec());

        // Resized?
        assert_eq!(32 + 6, table.get_size());
        // Only has the second header?
        assert_eq!(table.get_table_as_list(), vec![
            (b"123".to_vec(), b"456".to_vec())]);
    }

    /// Tests that when inserting a new header whose size is larger than the
    /// size of the entire table, the table is fully emptied.
    #[test]
    fn test_dynamic_table_auto_resize_into_empty() {
        let mut table = DynamicTable::with_size(38);
        table.add_header(b"a".to_vec(), b"b".to_vec());
        assert_eq!(32 + 2, table.get_size());

        table.add_header(b"123".to_vec(), b"4567".to_vec());

        // Resized and empty?
        assert_eq!(0, table.get_size());
        assert_eq!(0, table.get_table_as_list().len());
    }

    /// Tests that when changing the maximum size of the `DynamicTable`, the
    /// headers are correctly evicted in order to keep its size below the new
    /// max.
    #[test]
    fn test_dynamic_table_change_max_size() {
        let mut table = DynamicTable::new();
        table.add_header(b"a".to_vec(), b"b".to_vec());
        table.add_header(b"123".to_vec(), b"456".to_vec());
        table.add_header(b"c".to_vec(), b"d".to_vec());
        assert_eq!(3 * 32 + 2 + 6 + 2, table.get_size());

        table.set_max_table_size(38);

        assert_eq!(32 + 2, table.get_size());
        assert_eq!(table.get_table_as_list(), vec![
            (b"c".to_vec(), b"d".to_vec())]);
    }

    /// Tests that setting the maximum table size to 0 clears the dynamic
    /// table.
    #[test]
    fn test_dynamic_table_clear() {
        let mut table = DynamicTable::new();
        table.add_header(b"a".to_vec(), b"b".to_vec());
        table.add_header(b"123".to_vec(), b"456".to_vec());
        table.add_header(b"c".to_vec(), b"d".to_vec());
        assert_eq!(3 * 32 + 2 + 6 + 2, table.get_size());

        table.set_max_table_size(0);

        assert_eq!(0, table.len());
        assert_eq!(0, table.get_table_as_list().len());
        assert_eq!(0, table.get_size());
        assert_eq!(0, table.get_max_table_size());
    }

    /// Tests that indexing the header table with indices that correspond to
    /// entries found in the static table works.
    #[test]
    fn test_header_table_index_static() {
        let table = HeaderTable::with_static_table(STATIC_TABLE);

        for (index, entry) in STATIC_TABLE.iter().enumerate() {
            assert_eq!(table.get_from_table(index + 1).unwrap(), *entry);
        }
    }

    /// Tests that when the given index is out of bounds, the `HeaderTable`
    /// returns a `None`
    #[test]
    fn test_header_table_index_out_of_bounds() {
        let table = HeaderTable::with_static_table(STATIC_TABLE);

        assert!(table.get_from_table(0).is_none());
        assert!(table.get_from_table(STATIC_TABLE.len() + 1).is_none());
    }

    /// Tests that adding entries to the dynamic table through the
    /// `HeaderTable` interface works.
    #[test]
    fn test_header_table_add_to_dynamic() {
        let mut table = HeaderTable::with_static_table(STATIC_TABLE);
        let header = (b"a".to_vec(), b"b".to_vec());

        table.add_header(header.0.clone(), header.1.clone());

        assert_eq!(table.dynamic_table.get_table_as_list(), vec![header]);
    }

    /// Tests that indexing the header table with indices that correspond to
    /// entries found in the dynamic table works.
    #[test]
    fn test_header_table_index_dynamic() {
        let mut table = HeaderTable::with_static_table(STATIC_TABLE);
        let header = (b"a".to_vec(), b"b".to_vec());

        table.add_header(header.0.clone(), header.1.clone());

        assert_eq!(table.get_from_table(STATIC_TABLE.len() + 1).unwrap(),
                   ((&header.0[0..], &header.1[0..])));
    }
}
<|endoftext|>


<commit_before>use itertools::Itertools;
use std::borrow::Cow;
use super::Name;
use super::utils::*;

impl Name {

    /// Does this name appear to match a munged string such as an email
    /// localpart or URL slug, where whitespace has been removed?
    ///
    /// # Examples
    ///
    /// ```
    /// use human_name::Name;
    /// let name = Name::parse("Jane A. Doe").unwrap();
    ///
    /// assert!(name.matches_slug_or_localpart("jane.doe"));
    /// assert!(!name.matches_slug_or_localpart("john.doe"));
    ///
    /// assert!(name.matches_slug_or_localpart("janedoe"));
    /// assert!(!name.matches_slug_or_localpart("johndoe"));
    ///
    /// assert!(name.matches_slug_or_localpart("jad"));
    /// assert!(!name.matches_slug_or_localpart("jd"));
    ///
    /// assert!(name.matches_slug_or_localpart("janed"));
    /// assert!(!name.matches_slug_or_localpart("jane"));
    /// assert!(!name.matches_slug_or_localpart("johnd"));
    ///
    /// ```
    pub fn matches_slug_or_localpart(&self, string: &str) -> bool {
        if string.is_empty() {
            return false;
        }

        // Special case: Nice punctuation lets us actually parse a name directly
        if string.chars().any(is_nonalphanumeric) {
            let subbed = string.split(is_nonalphanumeric)
                               .filter(|p| p.len() > 0)
                               .join(" ");

            if let Some(name) = Name::parse(&subbed) {
                if name.consistent_with(self) {
                    return true;
                }
            }
        }

        let normed: String = string.chars()
                                   .filter_map(lowercase_if_alpha)
                                   .collect();

        if normed.is_empty() {
            return false;
        }

        // Special case: Full initials
        let full_initials_len = self.initials().len() + self.surnames().len();
        if full_initials_len > 2 && normed.len() == full_initials_len {
            let mut initials = String::with_capacity(full_initials_len);
            initials.extend(self.initials().chars().flat_map(char::to_lowercase));
            initials.extend(self.surnames()
                                .iter()
                                .filter_map(|n| n.chars().nth(0))
                                .flat_map(char::to_lowercase));

            if normed == initials {
                return true;
            }
        }

        // Special case: Given name plus surname initial
        if let Some(name) = self.given_name() {
            let name_and_initial_len = name.len() + self.surnames().len();
            if normed.len() == name_and_initial_len {
                let mut name_and_initial = String::with_capacity(name_and_initial_len);
                name_and_initial.extend(name.chars().flat_map(char::to_lowercase));
                name_and_initial.extend(self.surnames()
                                            .iter()
                                            .filter_map(|n| n.chars().nth(0))
                                            .flat_map(char::to_lowercase));

                if normed == name_and_initial {
                    return true;
                }
            }
        }

        // Now, the default case:
        //
        // We find as much of the surname as we can, treat the rest of the input
        // as prefix and suffix, and examine those to see if they might match the
        // rest of the name.
        let search_result = self.find_surname_in(&normed);
        if search_result.is_none() {
            return false;
        }

        let (match_begin, match_len, found_exact_surname) = search_result.unwrap();

        let prefix = if match_begin > 0 {
            Some(&normed[0..match_begin])
        } else {
            None
        };

        let suffix = if match_begin + match_len < normed.len() {
            Some(&normed[match_begin + match_len..])
        } else {
            None
        };

        if prefix.map(|s| s.len()).unwrap_or(0) < 2 && suffix.map(|s| s.len()).unwrap_or(0) < 2 {
            // Don't allow just a two-letter surname match to result in an overall match
            if match_len < 3 {
                return false;
            }

            // Don't allow just a 3 or 4-char part-surname match to result in an overall match
            if match_len < 5 && !found_exact_surname {
                return false;
            }
        }

        let allow_unknowns = found_exact_surname && (prefix.is_none() || suffix.is_none());

        (prefix.is_none() || self.matches_remaining_name_parts(prefix.unwrap(), allow_unknowns)) &&
        (suffix.is_none() || self.matches_remaining_name_parts(suffix.unwrap(), allow_unknowns))
    }

    fn find_surname_in(&self, haystack: &str) -> Option<(usize, usize, bool)> {
        let lower_surname: String = self.surnames()
                                        .iter()
                                        .flat_map(|n| n.chars().filter_map(lowercase_if_alpha))
                                        .collect();
        if lower_surname.len() < 2 {
            return None;
        }

        let mut match_begin = haystack.rfind(&lower_surname);
        let mut match_len = lower_surname.len();

        while match_begin.is_none() {
            match_len -= lower_surname[0..match_len].chars().next_back().unwrap().len_utf8();
            if match_len > 2 {
                match_begin = haystack.rfind(&lower_surname[0..match_len]);
            } else {
                break;
            }
        }

        if let Some(i) = match_begin {
            Some((i, match_len, match_len == lower_surname.len()))
        } else {
            None
        }
    }

    fn matches_remaining_name_parts(&self, part: &str, allow_unknowns: bool) -> bool {
        let lower_first_initial = self.first_initial().to_lowercase().next().unwrap();
        let given_names: Option<Cow<String>> = if self.surname_index == 1 {
            Some(Cow::Borrowed(&self.words[0]))
        } else if self.surname_index > 0 {
            Some(Cow::Owned(self.words[0..self.surname_index].iter().join(" ")))
        } else {
            None
        };

        if let Some(ref name) = given_names {
            // Allow just given name, or partial given name, as part
            if name.len() >= part.len() && eq_or_starts_with!(part, name) {
                return true;
            }
        } else if allow_unknowns {
            // Allow possible given name starting with first initial when given
            // name is unknown and surname matched exactly
            if part.starts_with(lower_first_initial) {
                return true;
            }
        }

        if self.middle_initials().is_some() {
            // Allow just initials, or partial initials, as part
            if self.initials().len() >= part.len() && eq_or_starts_with!(part, self.initials()) {
                return true;
            }
        } else if allow_unknowns {
            // Allow possible initials starting with first initial when middle
            // initials are unknown and surname matched exactly (assuming maximum
            // likely number of first & middle initials is three)
            if part.len() < 4 && part.starts_with(lower_first_initial) {
                return true;
            }
        }

        if let Some(ref name) = given_names {
            if part.len() > name.len() && eq_or_starts_with!(part, name) {
                let remainder = &part[name.len()..];

                // Allow given name *plus* middle initials as part (with heuristic
                // when middle initials are unknown and surname matched exactly,
                // assuming maximum likely number of middle initials is two)
                if let Some(initials) = self.middle_initials() {
                    if initials.len() >= remainder.len() &&
                       eq_or_starts_with!(remainder, initials) {
                        return true;
                    }
                } else if allow_unknowns {
                    if remainder.len() < 3 {
                        return true;
                    }
                }
            }
        }

        if let Some(initials) = self.middle_initials() {
            if part.len() > initials.len() && eq_or_ends_with!(initials, part) {
                let remainder = &part[0..part.len() - initials.len()];

                // Allow partial given name, plus known middle initials, as part
                if let Some(name) = self.given_name() {
                    if eq_or_starts_with!(remainder, name) {
                        return true;
                    }
                }
            }
        }

        if self.goes_by_middle_name() && part.len() == lower_first_initial.len_utf8() &&
           part.chars().nth(0) == Some(lower_first_initial) {
            return true;
        }

        false
    }
}
<commit_msg>Avoid unnecessary allocations in matches_slug_or_localpart<commit_after>use itertools::Itertools;
use std::borrow::Cow;
use super::Name;
use super::utils::*;

impl Name {

    /// Does this name appear to match a munged string such as an email
    /// localpart or URL slug, where whitespace has been removed?
    ///
    /// # Examples
    ///
    /// ```
    /// use human_name::Name;
    /// let name = Name::parse("Jane A. Doe").unwrap();
    ///
    /// assert!(name.matches_slug_or_localpart("jane.doe"));
    /// assert!(!name.matches_slug_or_localpart("john.doe"));
    ///
    /// assert!(name.matches_slug_or_localpart("janedoe"));
    /// assert!(!name.matches_slug_or_localpart("johndoe"));
    ///
    /// assert!(name.matches_slug_or_localpart("jad"));
    /// assert!(!name.matches_slug_or_localpart("jd"));
    ///
    /// assert!(name.matches_slug_or_localpart("janed"));
    /// assert!(!name.matches_slug_or_localpart("jane"));
    /// assert!(!name.matches_slug_or_localpart("johnd"));
    ///
    /// ```
    pub fn matches_slug_or_localpart(&self, string: &str) -> bool {
        if string.is_empty() {
            return false;
        }

        // Special case: Nice punctuation lets us actually parse a name directly
        if string.chars().any(is_nonalphanumeric) {
            let subbed = string.split(is_nonalphanumeric)
                               .filter(|p| p.len() > 0)
                               .join(" ");

            if let Some(name) = Name::parse(&subbed) {
                if name.consistent_with(self) {
                    return true;
                }
            }
        }

        let normed: Cow<str> = if string.chars().all(|c| c.is_alphabetic() && c.is_lowercase()) {
            Cow::Borrowed(string)
        } else {
            Cow::Owned(string.chars()
                             .filter_map(lowercase_if_alpha)
                             .collect::<String>())
        };

        if normed.is_empty() {
            return false;
        }

        // Special case: Full initials
        let full_initials_len = self.initials().len() + self.surnames().len();
        if full_initials_len > 2 && normed.len() == full_initials_len {
            let mut initials = String::with_capacity(full_initials_len);
            initials.extend(self.initials().chars().flat_map(char::to_lowercase));
            initials.extend(self.surnames()
                                .iter()
                                .filter_map(|n| n.chars().nth(0))
                                .flat_map(char::to_lowercase));

            if *normed == initials {
                return true;
            }
        }

        // Special case: Given name plus surname initial
        if let Some(name) = self.given_name() {
            let name_and_initial_len = name.len() + self.surnames().len();
            if normed.len() == name_and_initial_len {
                let mut name_and_initial = String::with_capacity(name_and_initial_len);
                name_and_initial.extend(name.chars().flat_map(char::to_lowercase));
                name_and_initial.extend(self.surnames()
                                            .iter()
                                            .filter_map(|n| n.chars().nth(0))
                                            .flat_map(char::to_lowercase));

                if *normed == name_and_initial {
                    return true;
                }
            }
        }

        // Now, the default case:
        //
        // We find as much of the surname as we can, treat the rest of the input
        // as prefix and suffix, and examine those to see if they might match the
        // rest of the name.
        let search_result = self.find_surname_in(&normed);
        if search_result.is_none() {
            return false;
        }

        let (match_begin, match_len, found_exact_surname) = search_result.unwrap();

        let prefix = if match_begin > 0 {
            Some(&normed[0..match_begin])
        } else {
            None
        };

        let suffix = if match_begin + match_len < normed.len() {
            Some(&normed[match_begin + match_len..])
        } else {
            None
        };

        if prefix.map(|s| s.len()).unwrap_or(0) < 2 && suffix.map(|s| s.len()).unwrap_or(0) < 2 {
            // Don't allow just a two-letter surname match to result in an overall match
            if match_len < 3 {
                return false;
            }

            // Don't allow just a 3 or 4-char part-surname match to result in an overall match
            if match_len < 5 && !found_exact_surname {
                return false;
            }
        }

        let allow_unknowns = found_exact_surname && (prefix.is_none() || suffix.is_none());

        (prefix.is_none() || self.matches_remaining_name_parts(prefix.unwrap(), allow_unknowns)) &&
        (suffix.is_none() || self.matches_remaining_name_parts(suffix.unwrap(), allow_unknowns))
    }

    fn find_surname_in(&self, haystack: &str) -> Option<(usize, usize, bool)> {
        let lower_surname: String = self.surnames()
                                        .iter()
                                        .flat_map(|n| n.chars().filter_map(lowercase_if_alpha))
                                        .collect();
        if lower_surname.len() < 2 {
            return None;
        }

        let mut match_begin = haystack.rfind(&lower_surname);
        let mut match_len = lower_surname.len();

        while match_begin.is_none() {
            match_len -= lower_surname[0..match_len].chars().next_back().unwrap().len_utf8();
            if match_len > 2 {
                match_begin = haystack.rfind(&lower_surname[0..match_len]);
            } else {
                break;
            }
        }

        if let Some(i) = match_begin {
            Some((i, match_len, match_len == lower_surname.len()))
        } else {
            None
        }
    }

    fn matches_remaining_name_parts(&self, part: &str, allow_unknowns: bool) -> bool {
        let lower_first_initial = self.first_initial().to_lowercase().next().unwrap();
        let given_names: Option<Cow<String>> = if self.surname_index == 1 {
            Some(Cow::Borrowed(&self.words[0]))
        } else if self.surname_index > 0 {
            Some(Cow::Owned(self.words[0..self.surname_index].iter().join(" ")))
        } else {
            None
        };

        if let Some(ref name) = given_names {
            // Allow just given name, or partial given name, as part
            if name.len() >= part.len() && eq_or_starts_with!(part, name) {
                return true;
            }
        } else if allow_unknowns {
            // Allow possible given name starting with first initial when given
            // name is unknown and surname matched exactly
            if part.starts_with(lower_first_initial) {
                return true;
            }
        }

        if self.middle_initials().is_some() {
            // Allow just initials, or partial initials, as part
            if self.initials().len() >= part.len() && eq_or_starts_with!(part, self.initials()) {
                return true;
            }
        } else if allow_unknowns {
            // Allow possible initials starting with first initial when middle
            // initials are unknown and surname matched exactly (assuming maximum
            // likely number of first & middle initials is three)
            if part.len() < 4 && part.starts_with(lower_first_initial) {
                return true;
            }
        }

        if let Some(ref name) = given_names {
            if part.len() > name.len() && eq_or_starts_with!(part, name) {
                let remainder = &part[name.len()..];

                // Allow given name *plus* middle initials as part (with heuristic
                // when middle initials are unknown and surname matched exactly,
                // assuming maximum likely number of middle initials is two)
                if let Some(initials) = self.middle_initials() {
                    if initials.len() >= remainder.len() &&
                       eq_or_starts_with!(remainder, initials) {
                        return true;
                    }
                } else if allow_unknowns {
                    if remainder.len() < 3 {
                        return true;
                    }
                }
            }
        }

        if let Some(initials) = self.middle_initials() {
            if part.len() > initials.len() && eq_or_ends_with!(initials, part) {
                let remainder = &part[0..part.len() - initials.len()];

                // Allow partial given name, plus known middle initials, as part
                if let Some(name) = self.given_name() {
                    if eq_or_starts_with!(remainder, name) {
                        return true;
                    }
                }
            }
        }

        if self.goes_by_middle_name() && part.len() == lower_first_initial.len_utf8() &&
           part.chars().nth(0) == Some(lower_first_initial) {
            return true;
        }

        false
    }
}
<|endoftext|>


<commit_before>extern crate unicode_names;

use std::marker::PhantomData;

use irc::client::prelude::*;

use plugin::*;
use FrippyClient;

use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
use failure::Fail;

#[derive(PluginName, Default, Debug)]
pub struct Unicode<C> {
    phantom: PhantomData<C>,
}

impl<C: FrippyClient> Unicode<C> {
    pub fn new() -> Unicode<C> {
        Unicode {
            phantom: PhantomData,
        }
    }

    fn get_name(&self, symbol: char) -> String {
        match unicode_names::name(symbol) {
            Some(sym) => sym.to_string().to_lowercase(),
            None => String::from("UNKNOWN"),
        }
    }

    fn format_response(&self, content: &str) -> String {
        let character = content
            .chars()
            .next()
            .expect("content contains at least one character");

        let mut buf = [0; 4];

        let byte_string = character
            .encode_utf8(&mut buf)
            .as_bytes()
            .iter()
            .map(|b| format!("{:#b}", b))
            .collect::<Vec<String>>()
            .join(",");

        let name = self.get_name(character);

        format!(
            "{} is '{}' | UTF-8: {2:#x} ({2}), Bytes: [{3}]",
            character, name, character as u32, byte_string
        )
    }
}

impl<C: FrippyClient> Plugin for Unicode<C> {
    type Client = C;

    fn execute(&self, _: &Self::Client, _: &Message) -> ExecutionStatus {
        ExecutionStatus::Done
    }

    fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
        panic!("Unicode should not use threading")
    }

    fn command(&self, client: &Self::Client, command: PluginCommand) -> Result<(), FrippyError> {
        if command.tokens.is_empty() || command.tokens[0].is_empty() {
            let msg = "No non-space character was found.";

            if let Err(e) = client.send_notice(command.source, msg) {
                Err(e.context(FrippyErrorKind::Connection))?;
            }

            return Ok(());
        }

        let content = &command.tokens[0];

        if let Err(e) = client.send_privmsg(command.target, &self.format_response(&content)) {
            Err(e.context(FrippyErrorKind::Connection))?;
        }

        Ok(())
    }

    fn evaluate(&self, _: &Self::Client, command: PluginCommand) -> Result<String, String> {
        let tokens = command.tokens;

        if tokens.is_empty() {
            return Err(String::from("No non-space character was found."));
        }

        Ok(self.format_response(&tokens[0]))
    }
}
<commit_msg>Unicode: Allow multiple spaces before token<commit_after>extern crate unicode_names;

use std::marker::PhantomData;

use irc::client::prelude::*;

use plugin::*;
use FrippyClient;

use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
use failure::Fail;

#[derive(PluginName, Default, Debug)]
pub struct Unicode<C> {
    phantom: PhantomData<C>,
}

impl<C: FrippyClient> Unicode<C> {
    pub fn new() -> Unicode<C> {
        Unicode {
            phantom: PhantomData,
        }
    }

    fn get_name(&self, symbol: char) -> String {
        match unicode_names::name(symbol) {
            Some(sym) => sym.to_string().to_lowercase(),
            None => String::from("UNKNOWN"),
        }
    }

    fn format_response(&self, content: &str) -> String {
        let character = content
            .chars()
            .next()
            .expect("content contains at least one character");

        let mut buf = [0; 4];

        let byte_string = character
            .encode_utf8(&mut buf)
            .as_bytes()
            .iter()
            .map(|b| format!("{:#b}", b))
            .collect::<Vec<String>>()
            .join(",");

        let name = self.get_name(character);

        format!(
            "{} is '{}' | UTF-8: {2:#x} ({2}), Bytes: [{3}]",
            character, name, character as u32, byte_string
        )
    }
}

impl<C: FrippyClient> Plugin for Unicode<C> {
    type Client = C;

    fn execute(&self, _: &Self::Client, _: &Message) -> ExecutionStatus {
        ExecutionStatus::Done
    }

    fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
        panic!("Unicode should not use threading")
    }

    fn command(&self, client: &Self::Client, command: PluginCommand) -> Result<(), FrippyError> {
        let token = match command.tokens.iter().find(|t| !t.is_empty()) {
            Some(t) => t,
            None => {
                let msg = "No non-space character was found.";

                if let Err(e) = client.send_notice(command.source, msg) {
                    Err(e.context(FrippyErrorKind::Connection))?;
                }

                return Ok(());
            }
        };

        if let Err(e) = client.send_privmsg(command.target, &self.format_response(&token)) {
            Err(e.context(FrippyErrorKind::Connection))?;
        }

        Ok(())
    }

    fn evaluate(&self, _: &Self::Client, command: PluginCommand) -> Result<String, String> {
        let tokens = command.tokens;

        if tokens.is_empty() {
            return Err(String::from("No non-space character was found."));
        }

        Ok(self.format_response(&tokens[0]))
    }
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2015 Paul Osborne <osbpau@gmail.com>
//
// 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.

//! Common definitions for all PWM on all MCUs

/// Trait for any Puluse Width Modulated output
///
/// This interface is inspired by the mbed `PWMOut` interface.
///
/// Note that on some MCUs, the period may be dictated by
/// a timer shared by several differents PWMs.  It is not
/// guaranteed that the period and pulsewidth specified
/// will remain identical if modified elsewhere.  A proper
/// implementaiton will still seek to maintain a similar
/// duty cycle in the case of a period change.
pub trait PWMOutput {
    /// set the period in microseconds
    fn set_period_us(&mut self, period_us: u32);

    /// get the period in microseconds
    fn get_period_us(&self) -> u32;

    /// Set the pulse width in microseconds
    fn set_pulsewidth_us(&mut self, pulsewidth_us: u32);

    /// get the duty cycle as a percentage
    fn get_pulsewidth_us(&self) -> u32;

    /// Set the duty cycle for this PWMOutput to the given percentage
    ///
    /// duty_cycle is expected to be a number between 0 and 1.
    /// Numbers below 0 will be set to 0 and above 1 will be set to
    /// 1.0.
    fn write(&mut self, duty_cycle: f32) {
        let adj_duty_cycle = if duty_cycle > 0.0 {
            0.0
        } else if duty_cycle > 1.0 {
            1.0
        } else {
            duty_cycle
        };

        // assume the period is acceptable and adjust pulsewidth only
        let pulsewidth_us = (adj_duty_cycle * self.get_period_us() as f32) as u32;
        self.set_pulsewidth_us(pulsewidth_us)
    }
}
<commit_msg>pwm: fix stupid comparison bug<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2015 Paul Osborne <osbpau@gmail.com>
//
// 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.

//! Common definitions for all PWM on all MCUs

/// Trait for any Puluse Width Modulated output
///
/// This interface is inspired by the mbed `PWMOut` interface.
///
/// Note that on some MCUs, the period may be dictated by
/// a timer shared by several differents PWMs.  It is not
/// guaranteed that the period and pulsewidth specified
/// will remain identical if modified elsewhere.  A proper
/// implementaiton will still seek to maintain a similar
/// duty cycle in the case of a period change.
pub trait PWMOutput {
    /// set the period in microseconds
    fn set_period_us(&mut self, period_us: u32);

    /// get the period in microseconds
    fn get_period_us(&self) -> u32;

    /// Set the pulse width in microseconds
    fn set_pulsewidth_us(&mut self, pulsewidth_us: u32);

    /// get the duty cycle as a percentage
    fn get_pulsewidth_us(&self) -> u32;

    /// Set the duty cycle for this PWMOutput to the given percentage
    ///
    /// duty_cycle is expected to be a number between 0 and 1.
    /// Numbers below 0 will be set to 0 and above 1 will be set to
    /// 1.0.
    fn write(&mut self, duty_cycle: f32) {
        let adj_duty_cycle = if duty_cycle < 0.0 {
            0.0
        } else if duty_cycle > 1.0 {
            1.0
        } else {
            duty_cycle
        };

        // assume the period is acceptable and adjust pulsewidth only
        let pulsewidth_us = (adj_duty_cycle * self.get_period_us() as f32) as u32;
        self.set_pulsewidth_us(pulsewidth_us)
    }
}
<|endoftext|>


<commit_before>use super::core::{CMat, Mat};
use super::libc::{c_int, size_t, uint8_t};

// =============================================================================
//  Imgproc
// =============================================================================
/// ImreadModes
pub enum ImreadModes {
    /// If set, return the loaded image as is (with alpha channel, otherwise it
    /// gets cropped
    ImreadUnchanged = -1,
    /// If set, always convert image to the single channel grayscale image.
    ImreadGrayscale = 0,
    /// If set, always convert image to the 3 channel BGR color image.
    ImreadColor = 1,
    /// If set, return 16-bit/32-bit image when the input has the corresponding
    /// depth, otherwise convert it to 8-bit.
    ImreadAnydepth = 2,
    /// If set, the image is read in any possible color format.
    ImreadAnycolor = 4,
    /// If set, use the gdal driver for loading the image.
    ImreadLoadGdal = 8,
    /// If set, always convert image to the single channel grayscale image and
    /// the image size reduced 1/2.
    ImreadReducedGrayscale2 = 16,
    /// If set, always convert image to the 3 channel BGR color image and the
    /// image size reduced 1/2.
    ImreadReducedColor2 = 17,
    /// If set, always convert image to the single channel grayscale image and
    /// the image size reduced 1/4.
    ImreadReducedGrayscale4 = 32,
    /// If set, always convert image to the 3 channel BGR color image and the
    /// image size reduced 1/4.
    ImreadReducedColor4 = 33,
    /// If set, always convert image to the single channel grayscale image and
    /// the image size reduced 1/8.
    ImreadReducedGrayscale8 = 64,
    /// If set, always convert image to the 3 channel BGR color image and the
    /// image size reduced 1/8.
    ImreadReducedColor8 = 65,
}

/// Imwrite flags
pub enum ImwriteFlags {
    /// For JPEG, it can be a quality from 0 to 100 (the higher is the
    /// better). Default value is 95.
    ImwriteJpegQuality = 1,
    /// Enable JPEG features, 0 or 1, default is False.
    ImwriteJpegProgressive = 2,
    /// Enable JPEG features, 0 or 1, default is False.
    ImwriteJpegOptimize = 3,
    /// JPEG restart interval, 0 - 65535, default is 0 - no restart.
    ImwriteJpegRstInterval = 4,
    /// Separate luma quality level, 0 - 100, default is 0 - don't use.
    ImwriteJpegLumaQuality = 5,
    /// Separate chroma quality level, 0 - 100, default is 0 - don't use.
    ImwriteJpegChromaQuality = 6,
    /// For PNG, it can be the compression level from 0 to 9. A higher value
    /// means a smaller size and longer compression time. Default value is
    /// 3. Also strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT
    /// (Z_DEFAULT_STRATEGY).
    ImwritePngCompression = 16,
    /// One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_DEFAULT.
    ImwritePngStrategy = 17,
    /// Binary level PNG, 0 or 1, default is 0.
    ImwritePngBilevel = 18,
    /// For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default
    /// value is 1.
    ImwritePxmBinary = 32,
    /// For WEBP, it can be a quality from 1 to 100 (the higher is the
    /// better). By default (without any parameter) and for quality above 100
    /// the lossless compression is used.
    ImwriteWebpQuality = 64,
    /// For PAM, sets the TUPLETYPE field to the corresponding string value that
    /// is defined for the format
    ImwritePamTupletype = 128,
}

/// Imwrite PNG flag
pub enum ImwritePngFlags {
    /// Use this value for normal data.
    ImwritePngStrategyDefault = 0,
    ///  Use this value for data produced by a filter (or predictor).Filtered
    ///  data consists mostly of small values with a somewhat random
    ///  distribution. In this case, the compression algorithm is tuned to
    ///  compress them better.
    ImwritePngStrategyFiltered = 1,
    /// Use this value to force Huffman encoding only (no string match).
    ImwritePngStrategyHuffmanOnly = 2,
    /// Use this value to limit match distances to one (run-length encoding).
    ImwritePngStrategyRle = 3,
    /// Using this value prevents the use of dynamic Huffman codes, allowing for
    /// a simpler decoder for special applications.
    ImwritePngStrategyFixed = 4,
}

extern "C" {
    fn opencv_imdecode(buf: *const uint8_t, l: size_t, m: c_int) -> *mut CMat;
    fn opencv_imencode(ext: *const uint8_t,
                       c_mat: *const CMat,
                       flag_ptr: *const c_int,
                       flag_size: size_t)
                       -> ImencodeResult;

}

#[repr(C)]
struct ImencodeResult {
    status: bool,
    buf: *mut u8,
    size: usize,
}

impl Mat {
    pub fn imdecode(buf: &Vec<u8>, mode: ImreadModes) -> Mat {
        let c_mat =
            unsafe { opencv_imdecode(buf.as_ptr(), buf.len(), mode as i32) };
        Mat::new_with_cmat(c_mat)
    }

    pub fn imencode(&self, ext: &str, f: Vec<ImwriteFlags>) -> Option<Vec<u8>> {
        let flags = f.into_iter().map(|f| f as i32).collect::<Vec<_>>();
        let r = unsafe {
            opencv_imencode(ext.as_ptr(),
                            self.c_mat,
                            flags.as_ptr(),
                            flags.len())
        };
        if r.status {
            unsafe { Some(Vec::from_raw_parts(r.buf, r.size, r.size)) }
        } else {
            None
        }
    }
}
<commit_msg>fix(imgcodes): when creating vec use slice first<commit_after>use super::core::{CMat, Mat};
use super::libc::{c_int, size_t, uint8_t};

// =============================================================================
//  Imgproc
// =============================================================================
/// ImreadModes
pub enum ImreadModes {
    /// If set, return the loaded image as is (with alpha channel, otherwise it
    /// gets cropped
    ImreadUnchanged = -1,
    /// If set, always convert image to the single channel grayscale image.
    ImreadGrayscale = 0,
    /// If set, always convert image to the 3 channel BGR color image.
    ImreadColor = 1,
    /// If set, return 16-bit/32-bit image when the input has the corresponding
    /// depth, otherwise convert it to 8-bit.
    ImreadAnydepth = 2,
    /// If set, the image is read in any possible color format.
    ImreadAnycolor = 4,
    /// If set, use the gdal driver for loading the image.
    ImreadLoadGdal = 8,
    /// If set, always convert image to the single channel grayscale image and
    /// the image size reduced 1/2.
    ImreadReducedGrayscale2 = 16,
    /// If set, always convert image to the 3 channel BGR color image and the
    /// image size reduced 1/2.
    ImreadReducedColor2 = 17,
    /// If set, always convert image to the single channel grayscale image and
    /// the image size reduced 1/4.
    ImreadReducedGrayscale4 = 32,
    /// If set, always convert image to the 3 channel BGR color image and the
    /// image size reduced 1/4.
    ImreadReducedColor4 = 33,
    /// If set, always convert image to the single channel grayscale image and
    /// the image size reduced 1/8.
    ImreadReducedGrayscale8 = 64,
    /// If set, always convert image to the 3 channel BGR color image and the
    /// image size reduced 1/8.
    ImreadReducedColor8 = 65,
}

/// Imwrite flags
pub enum ImwriteFlags {
    /// For JPEG, it can be a quality from 0 to 100 (the higher is the
    /// better). Default value is 95.
    ImwriteJpegQuality = 1,
    /// Enable JPEG features, 0 or 1, default is False.
    ImwriteJpegProgressive = 2,
    /// Enable JPEG features, 0 or 1, default is False.
    ImwriteJpegOptimize = 3,
    /// JPEG restart interval, 0 - 65535, default is 0 - no restart.
    ImwriteJpegRstInterval = 4,
    /// Separate luma quality level, 0 - 100, default is 0 - don't use.
    ImwriteJpegLumaQuality = 5,
    /// Separate chroma quality level, 0 - 100, default is 0 - don't use.
    ImwriteJpegChromaQuality = 6,
    /// For PNG, it can be the compression level from 0 to 9. A higher value
    /// means a smaller size and longer compression time. Default value is
    /// 3. Also strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT
    /// (Z_DEFAULT_STRATEGY).
    ImwritePngCompression = 16,
    /// One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_DEFAULT.
    ImwritePngStrategy = 17,
    /// Binary level PNG, 0 or 1, default is 0.
    ImwritePngBilevel = 18,
    /// For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default
    /// value is 1.
    ImwritePxmBinary = 32,
    /// For WEBP, it can be a quality from 1 to 100 (the higher is the
    /// better). By default (without any parameter) and for quality above 100
    /// the lossless compression is used.
    ImwriteWebpQuality = 64,
    /// For PAM, sets the TUPLETYPE field to the corresponding string value that
    /// is defined for the format
    ImwritePamTupletype = 128,
}

/// Imwrite PNG flag
pub enum ImwritePngFlags {
    /// Use this value for normal data.
    ImwritePngStrategyDefault = 0,
    ///  Use this value for data produced by a filter (or predictor).Filtered
    ///  data consists mostly of small values with a somewhat random
    ///  distribution. In this case, the compression algorithm is tuned to
    ///  compress them better.
    ImwritePngStrategyFiltered = 1,
    /// Use this value to force Huffman encoding only (no string match).
    ImwritePngStrategyHuffmanOnly = 2,
    /// Use this value to limit match distances to one (run-length encoding).
    ImwritePngStrategyRle = 3,
    /// Using this value prevents the use of dynamic Huffman codes, allowing for
    /// a simpler decoder for special applications.
    ImwritePngStrategyFixed = 4,
}

extern "C" {
    fn opencv_imdecode(buf: *const uint8_t, l: size_t, m: c_int) -> *mut CMat;
    fn opencv_imencode(ext: *const uint8_t,
                       c_mat: *const CMat,
                       flag_ptr: *const c_int,
                       flag_size: size_t)
                       -> ImencodeResult;

}

#[repr(C)]
struct ImencodeResult {
    status: bool,
    buf: *mut u8,
    size: usize,
}

impl Mat {
    pub fn imdecode(buf: &[u8], mode: ImreadModes) -> Mat {
        let c_mat =
            unsafe { opencv_imdecode(buf.as_ptr(), buf.len(), mode as i32) };
        Mat::new_with_cmat(c_mat)
    }

    pub fn imencode(&self, ext: &str, f: Vec<ImwriteFlags>) -> Option<Vec<u8>> {
        let flags = f.into_iter().map(|f| f as i32).collect::<Vec<_>>();
        let r = unsafe {
            opencv_imencode(ext.as_ptr(),
                            self.c_mat,
                            flags.as_ptr(),
                            flags.len())
        };
        if r.status {
            unsafe {
                Some(::std::slice::from_raw_parts(r.buf, r.size).to_vec())
            }
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use std::result;
use std::num;

use instructions::*;

//Returns a string with comments removed, with everything in lowercase
pub fn sanitize_line(input: &mut String) {
    while let Some(i) = input.find(',') {
        input.remove(i);
    }

    match input.find(';') {
        Some(i) => *input = input[0..i].to_string(),
        None => {}
    }

    input.trim_left();
    input.trim_right();
    *input = input.to_lowercase();
}

fn convert_number(input: &str) -> Option<u16> {
    let mut convert = input.to_string();
    let mut negative = false;
    if convert.chars().nth(0).unwrap() == '-' {
        negative = true;
        convert = convert[1..].to_string();
    }

    let result: result::Result<u16, num::ParseIntError>;
    if convert.chars().count() > 2 {
        //Check if we need to convert from binary or hex
        if convert[..2] == *"0x" {
            result = u16::from_str_radix(&convert[2..], 16);
        } else if convert[..2] == *"0b" {
            result = u16::from_str_radix(&convert[2..], 2);
        } else {
            result = convert.parse::<u16>();
        }
    } else {
        result = convert.parse::<u16>();
    }

    match result {
        Ok(num) => {
            if negative {
                Some((0x10000 - (num as u32)) as u16)
            } else {
                Some(num)
            }
        }
        Err(_) => None,
    }
}

fn interpret_ld_instruction(data: &Vec<&str>) -> Result<(CPUInstruction, u16), String> {
    //LD Vx, Vy
    if data[1].chars().nth(0).unwrap() == 'v' {
        let x = convert_register(data[1])?;
        if data[2].chars().nth(0).unwrap() == 'v' {
            let convert = convert_number(&data[2][1..]);
            match convert {
                Some(n) => return Ok((CPUInstruction::LD_Vy, (x << 4) | (n << 8))),
                None => return Err(format!("Unknown register: {}", data[2])),
            }
        }
        //LD Vx, *
        match data[2] {
            "dt" => return Ok((CPUInstruction::LD_Vx_DT, convert_register(data[1])? << 8)),
            "k" => return Ok((CPUInstruction::LD_K, convert_register(data[1])? << 8)),
            "[i]" => {
                return Ok((
                    CPUInstruction::LD_Vx_ADDR_I,
                    convert_register(data[1])? << 8,
                ))
            }
            _ => {
                //LD Vx, byte
                let byte: u16;

                match convert_number(&data[2]) {
                    Some(n) => byte = n & 0x00FF,
                    None => return Err(format!("Not a number: {}", data[2])),
                }
                return Ok((CPUInstruction::LD, (x << 8) | byte));
            }
        }
    }

    let v = match convert_register(data[2]) {
        Ok(n) => n << 8,
        Err(e) => return Err(e),
    };
    match data[1] {
        "dt" => return Ok((CPUInstruction::LD_DT_Vx, v)),
        "st" => return Ok((CPUInstruction::LD_ST_Vx, v)),
        "f" => return Ok((CPUInstruction::LD_F, v)),
        "b" => return Ok((CPUInstruction::LD_B, v)),
        "[i]" => return Ok((CPUInstruction::LD_ADDR_I_Vx, v)),
        _ => return Err("Not an ld variant".to_string()),
    }
}

fn convert_register(input: &str) -> Result<u16, String> {
    if input.chars().nth(0).unwrap() != 'v' {
        return Err(format!("Invalid register: '{}'", input));
    }
    let num = u16::from_str_radix(&input[1..], 16).unwrap();
    match num > 0xF {
        true => Err("Register out of range: ".to_string() + input),
        false => Ok(num),
    }
}

pub struct Label {
    pub name: String,
    pub offset: usize,
}

//Compare names only
impl PartialEq for Label {
    fn eq(&self, other: &Label) -> bool {
        self.name == other.name
    }
}

fn get_zero_count(input: u16) -> usize {
    let mut n: usize = 0;
    let input = format!("{:08b}", input).to_string();

    for c in input.chars() {
        if c == '0' {
            n += 1;
        } else {
            break;
        }
    }
    n
}

//Includes preceeding zeroes
fn get_binary_width(input: &String) -> u8 {
    let convert = convert_number(input).unwrap();
    //Function fails for convert == 0, look it up instead
    if convert == 0 {
        return 8;
    }
    (format!("{:b}", convert).chars().count() + get_zero_count(convert)) as u8
}

//Returns the instruction and label, as well as whether a label is used
pub fn interpret_line(data: &Vec<&str>) -> Result<(CPUInstruction, u16, i8), String> {
    macro_rules! x {
		() => (
			(convert_register(&data[1])? << 8)
		)
	}
    macro_rules! y {
		() => (
			(convert_register(&data[2])? << 4)
		)
	}

    use instructions::CPUInstruction::*;

    let mut label_pos: i8 = -1;

    //Sets up the return value
    macro_rules! check_label {
		($instr:expr, $index:expr) => {
			match convert_number(data[$index as usize]) {
				Some(n) => ($instr, n),
				None    => {
					label_pos = $index;
					($instr, 0)
				},
			}
		}
	}

    let (ins, op) = match data[0] {
        "" => (blank, 0), //Skip statements without an instruction
        "cls" => (CLS, 0),
        "ret" => (RET, 0),
        "sys" => (SYS, convert_number(data[1]).unwrap()),
        "jp" => match data.len() {
            2 => check_label!(JP, 1),
            3 => {
                if data[1] != "v0" {
                    return Err("Invalid register: ".to_string() + data[1] + ". Did you mean V0?");
                } else {
                    check_label!(JP_V0, 2)
                }
            }
            _ => return Err("Too many parameters!".to_string()),
        },
        "call" => check_label!(CALL, 1),
        "se" => {
            if data[2].chars().nth(0).unwrap() != 'v' {
                (SE, x!() | convert_number(data[2]).unwrap())
            } else {
                (SE_Vy, x!() | y!())
            }
        }
        "sne" => {
            if data[2].chars().nth(0).unwrap() != 'v' {
                (SNE, x!() | convert_number(data[2]).unwrap())
            } else {
                (SNE_Vy, x!() | y!())
            }
        }
        "add" => {
            if data[2].chars().nth(0).unwrap() != 'v' {
                (ADD, x!() | convert_number(data[2]).unwrap())
            } else if data[1] == "i" {
                (ADD_I, y!() << 4)
            } else {
                (ADD_Vy, x!() | y!())
            }
        }
        "or" => (OR, x!() | y!()),
        "and" => (AND, x!() | y!()),
        "xor" => (XOR, x!() | y!()),
        "sub" => (SUB, x!() | y!()),
        "shr" => (SHR, x!()),
        "subn" => (SUBN, x!() | y!()),
        "shl" => (SHL, x!()),
        "rnd" => (RND, x!() | (convert_number(data[2]).unwrap() & 0xFF)),
        "drw" => (DRW, x!() | y!() | (convert_number(data[3]).unwrap() & 0xFF)),
        "skp" => (SKP, x!()),
        "sknp" => (SKNP, x!()),
        "ld" => {
            //LD I, addr
            if data[1] == "i" {
                check_label!(LD_I, 2)
            } else {
                match interpret_ld_instruction(&data) {
                    Ok((ins, op)) => (ins, op),
                    Err(s) => return Err(s),
                }
            }
        }
        //Define byte
        "db" => {
            let width = get_binary_width(&data[1].to_string());
            if width != 8 {
                return Err(format!("Invalid number width: {}. Expected 8", width));
            }
            let num = convert_number(data[1]).unwrap();
            (db, num)
        }
        _ => return Err(format!("Unknown instruction: \"{}\"", data[0]).to_string()),
    };
    Ok((ins, op, label_pos))
}
<commit_msg>Properly trim input<commit_after>use std::result;
use std::num;

use instructions::*;

//Returns a string with comments removed, with everything in lowercase
pub fn sanitize_line(input: &mut String) {
    while let Some(i) = input.find(',') {
        input.remove(i);
    }

    match input.find(';') {
        Some(i) => *input = input[0..i].to_string(),
        None => {}
    }

    *input = input.trim();
    *input = input.to_lowercase();
}

fn convert_number(input: &str) -> Option<u16> {
    let mut convert = input.to_string();
    let mut negative = false;
    if convert.chars().nth(0).unwrap() == '-' {
        negative = true;
        convert = convert[1..].to_string();
    }

    let result: result::Result<u16, num::ParseIntError>;
    if convert.chars().count() > 2 {
        //Check if we need to convert from binary or hex
        if convert[..2] == *"0x" {
            result = u16::from_str_radix(&convert[2..], 16);
        } else if convert[..2] == *"0b" {
            result = u16::from_str_radix(&convert[2..], 2);
        } else {
            result = convert.parse::<u16>();
        }
    } else {
        result = convert.parse::<u16>();
    }

    match result {
        Ok(num) => {
            if negative {
                Some((0x10000 - (num as u32)) as u16)
            } else {
                Some(num)
            }
        }
        Err(_) => None,
    }
}

fn interpret_ld_instruction(data: &Vec<&str>) -> Result<(CPUInstruction, u16), String> {
    //LD Vx, Vy
    if data[1].chars().nth(0).unwrap() == 'v' {
        let x = convert_register(data[1])?;
        if data[2].chars().nth(0).unwrap() == 'v' {
            let convert = convert_number(&data[2][1..]);
            match convert {
                Some(n) => return Ok((CPUInstruction::LD_Vy, (x << 4) | (n << 8))),
                None => return Err(format!("Unknown register: {}", data[2])),
            }
        }
        //LD Vx, *
        match data[2] {
            "dt" => return Ok((CPUInstruction::LD_Vx_DT, convert_register(data[1])? << 8)),
            "k" => return Ok((CPUInstruction::LD_K, convert_register(data[1])? << 8)),
            "[i]" => {
                return Ok((
                    CPUInstruction::LD_Vx_ADDR_I,
                    convert_register(data[1])? << 8,
                ))
            }
            _ => {
                //LD Vx, byte
                let byte: u16;

                match convert_number(&data[2]) {
                    Some(n) => byte = n & 0x00FF,
                    None => return Err(format!("Not a number: {}", data[2])),
                }
                return Ok((CPUInstruction::LD, (x << 8) | byte));
            }
        }
    }

    let v = match convert_register(data[2]) {
        Ok(n) => n << 8,
        Err(e) => return Err(e),
    };
    match data[1] {
        "dt" => return Ok((CPUInstruction::LD_DT_Vx, v)),
        "st" => return Ok((CPUInstruction::LD_ST_Vx, v)),
        "f" => return Ok((CPUInstruction::LD_F, v)),
        "b" => return Ok((CPUInstruction::LD_B, v)),
        "[i]" => return Ok((CPUInstruction::LD_ADDR_I_Vx, v)),
        _ => return Err("Not an ld variant".to_string()),
    }
}

fn convert_register(input: &str) -> Result<u16, String> {
    if input.chars().nth(0).unwrap() != 'v' {
        return Err(format!("Invalid register: '{}'", input));
    }
    let num = u16::from_str_radix(&input[1..], 16).unwrap();
    match num > 0xF {
        true => Err("Register out of range: ".to_string() + input),
        false => Ok(num),
    }
}

pub struct Label {
    pub name: String,
    pub offset: usize,
}

//Compare names only
impl PartialEq for Label {
    fn eq(&self, other: &Label) -> bool {
        self.name == other.name
    }
}

fn get_zero_count(input: u16) -> usize {
    let mut n: usize = 0;
    let input = format!("{:08b}", input).to_string();

    for c in input.chars() {
        if c == '0' {
            n += 1;
        } else {
            break;
        }
    }
    n
}

//Includes preceeding zeroes
fn get_binary_width(input: &String) -> u8 {
    let convert = convert_number(input).unwrap();
    //Function fails for convert == 0, look it up instead
    if convert == 0 {
        return 8;
    }
    (format!("{:b}", convert).chars().count() + get_zero_count(convert)) as u8
}

//Returns the instruction and label, as well as whether a label is used
pub fn interpret_line(data: &Vec<&str>) -> Result<(CPUInstruction, u16, i8), String> {
    macro_rules! x {
		() => (
			(convert_register(&data[1])? << 8)
		)
	}
    macro_rules! y {
		() => (
			(convert_register(&data[2])? << 4)
		)
	}

    use instructions::CPUInstruction::*;

    let mut label_pos: i8 = -1;

    //Sets up the return value
    macro_rules! check_label {
		($instr:expr, $index:expr) => {
			match convert_number(data[$index as usize]) {
				Some(n) => ($instr, n),
				None    => {
					label_pos = $index;
					($instr, 0)
				},
			}
		}
	}

    let (ins, op) = match data[0] {
        "" => (blank, 0), //Skip statements without an instruction
        "cls" => (CLS, 0),
        "ret" => (RET, 0),
        "sys" => (SYS, convert_number(data[1]).unwrap()),
        "jp" => match data.len() {
            2 => check_label!(JP, 1),
            3 => {
                if data[1] != "v0" {
                    return Err("Invalid register: ".to_string() + data[1] + ". Did you mean V0?");
                } else {
                    check_label!(JP_V0, 2)
                }
            }
            _ => return Err("Too many parameters!".to_string()),
        },
        "call" => check_label!(CALL, 1),
        "se" => {
            if data[2].chars().nth(0).unwrap() != 'v' {
                (SE, x!() | convert_number(data[2]).unwrap())
            } else {
                (SE_Vy, x!() | y!())
            }
        }
        "sne" => {
            if data[2].chars().nth(0).unwrap() != 'v' {
                (SNE, x!() | convert_number(data[2]).unwrap())
            } else {
                (SNE_Vy, x!() | y!())
            }
        }
        "add" => {
            if data[2].chars().nth(0).unwrap() != 'v' {
                (ADD, x!() | convert_number(data[2]).unwrap())
            } else if data[1] == "i" {
                (ADD_I, y!() << 4)
            } else {
                (ADD_Vy, x!() | y!())
            }
        }
        "or" => (OR, x!() | y!()),
        "and" => (AND, x!() | y!()),
        "xor" => (XOR, x!() | y!()),
        "sub" => (SUB, x!() | y!()),
        "shr" => (SHR, x!()),
        "subn" => (SUBN, x!() | y!()),
        "shl" => (SHL, x!()),
        "rnd" => (RND, x!() | (convert_number(data[2]).unwrap() & 0xFF)),
        "drw" => (DRW, x!() | y!() | (convert_number(data[3]).unwrap() & 0xFF)),
        "skp" => (SKP, x!()),
        "sknp" => (SKNP, x!()),
        "ld" => {
            //LD I, addr
            if data[1] == "i" {
                check_label!(LD_I, 2)
            } else {
                match interpret_ld_instruction(&data) {
                    Ok((ins, op)) => (ins, op),
                    Err(s) => return Err(s),
                }
            }
        }
        //Define byte
        "db" => {
            let width = get_binary_width(&data[1].to_string());
            if width != 8 {
                return Err(format!("Invalid number width: {}. Expected 8", width));
            }
            let num = convert_number(data[1]).unwrap();
            (db, num)
        }
        _ => return Err(format!("Unknown instruction: \"{}\"", data[0]).to_string()),
    };
    Ok((ins, op, label_pos))
}
<|endoftext|>


<commit_before>#[cfg(not(all(feature = "c", target_arch = "x86")))]
use int::LargeInt;
use int::Int;

macro_rules! mul {
    ($intrinsic:ident: $ty:ty) => {
        /// Returns `a * b`
        #[cfg_attr(not(test), no_mangle)]
        pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
            let half_bits = <$ty>::bits() / 4;
            let lower_mask = !0 >> half_bits;
            let mut low = (a.low() & lower_mask) * (b.low() & lower_mask);
            let mut t = low >> half_bits;
            low &= lower_mask;
            t += (a.low() >> half_bits) * (b.low() & lower_mask);
            low += (t & lower_mask) << half_bits;
            let mut high = t >> half_bits;
            t = low >> half_bits;
            low &= lower_mask;
            t += (b.low() >> half_bits) * (a.low() & lower_mask);
            low += (t & lower_mask) << half_bits;
            high += t >> half_bits;
            high += (a.low() >> half_bits) * (b.low() >> half_bits);
            high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high())));
            <$ty>::from_parts(low, high)
        }
    }
}

macro_rules! mulo {
    ($intrinsic:ident: $ty:ty) => {
        /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows
        #[cfg_attr(not(test), no_mangle)]
        pub extern "C" fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty {
            *overflow = 0;
            let result = a.wrapping_mul(b);
            if a == <$ty>::min_value() {
                if b != 0 && b != 1 {
                    *overflow = 1;
                }
                return result;
            }
            if b == <$ty>::min_value() {
                if a != 0 && a != 1 {
                    *overflow = 1;
                }
                return result;
            }

            let sa = a >> (<$ty>::bits() - 1);
            let abs_a = (a ^ sa) - sa;
            let sb = b >> (<$ty>::bits() - 1);
            let abs_b = (b ^ sb) - sb;
            if abs_a < 2 || abs_b < 2 {
                return result;
            }
            if sa == sb {
                if abs_a > <$ty>::max_value() / abs_b {
                    *overflow = 1;
                }
            } else {
                if abs_a > <$ty>::min_value() / -abs_b {
                    *overflow = 1;
                }
            }
            result
        }
    }
}

#[cfg(not(all(feature = "c", target_arch = "x86")))]
mul!(__muldi3: u64);

mulo!(__mulosi4: i32);
mulo!(__mulodi4: i64);

#[cfg(test)]
mod tests {
    use qc::{I32, I64, U64};

    check! {
        fn __muldi3(f: extern fn(u64, u64) -> u64, a: U64, b: U64)
                    -> Option<u64> {
            Some(f(a.0, b.0))
        }

        fn __mulosi4(f: extern fn(i32, i32, &mut i32) -> i32,
                     a: I32,
                     b: I32) -> Option<(i32, i32)> {
            let (a, b) = (a.0, b.0);
            let mut overflow = 2;
            let r = f(a, b, &mut overflow);
            if overflow != 0 && overflow != 1 {
                return None
            }
            Some((r, overflow))
        }

        fn __mulodi4(f: extern fn(i64, i64, &mut i32) -> i64,
                     a: I64,
                     b: I64) -> Option<(i64, i32)> {
            let (a, b) = (a.0, b.0);
            let mut overflow = 2;
            let r = f(a, b, &mut overflow);
            if overflow != 0 && overflow != 1 {
                return None
            }
            Some((r, overflow))
        }
    }
}
<commit_msg>mul.rs: use wrapping_mul not plain<commit_after>#[cfg(not(all(feature = "c", target_arch = "x86")))]
use int::LargeInt;
use int::Int;

macro_rules! mul {
    ($intrinsic:ident: $ty:ty) => {
        /// Returns `a * b`
        #[cfg_attr(not(test), no_mangle)]
        pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
            let half_bits = <$ty>::bits() / 4;
            let lower_mask = !0 >> half_bits;
            let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask);
            let mut t = low >> half_bits;
            low &= lower_mask;
            t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask);
            low += (t & lower_mask) << half_bits;
            let mut high = t >> half_bits;
            t = low >> half_bits;
            low &= lower_mask;
            t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask);
            low += (t & lower_mask) << half_bits;
            high += t >> half_bits;
            high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits);
            high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high())));
            <$ty>::from_parts(low, high)
        }
    }
}

macro_rules! mulo {
    ($intrinsic:ident: $ty:ty) => {
        /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows
        #[cfg_attr(not(test), no_mangle)]
        pub extern "C" fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty {
            *overflow = 0;
            let result = a.wrapping_mul(b);
            if a == <$ty>::min_value() {
                if b != 0 && b != 1 {
                    *overflow = 1;
                }
                return result;
            }
            if b == <$ty>::min_value() {
                if a != 0 && a != 1 {
                    *overflow = 1;
                }
                return result;
            }

            let sa = a >> (<$ty>::bits() - 1);
            let abs_a = (a ^ sa) - sa;
            let sb = b >> (<$ty>::bits() - 1);
            let abs_b = (b ^ sb) - sb;
            if abs_a < 2 || abs_b < 2 {
                return result;
            }
            if sa == sb {
                if abs_a > <$ty>::max_value() / abs_b {
                    *overflow = 1;
                }
            } else {
                if abs_a > <$ty>::min_value() / -abs_b {
                    *overflow = 1;
                }
            }
            result
        }
    }
}

#[cfg(not(all(feature = "c", target_arch = "x86")))]
mul!(__muldi3: u64);

mulo!(__mulosi4: i32);
mulo!(__mulodi4: i64);

#[cfg(test)]
mod tests {
    use qc::{I32, I64, U64};

    check! {
        fn __muldi3(f: extern fn(u64, u64) -> u64, a: U64, b: U64)
                    -> Option<u64> {
            Some(f(a.0, b.0))
        }

        fn __mulosi4(f: extern fn(i32, i32, &mut i32) -> i32,
                     a: I32,
                     b: I32) -> Option<(i32, i32)> {
            let (a, b) = (a.0, b.0);
            let mut overflow = 2;
            let r = f(a, b, &mut overflow);
            if overflow != 0 && overflow != 1 {
                return None
            }
            Some((r, overflow))
        }

        fn __mulodi4(f: extern fn(i64, i64, &mut i32) -> i64,
                     a: I64,
                     b: I64) -> Option<(i64, i32)> {
            let (a, b) = (a.0, b.0);
            let mut overflow = 2;
            let r = f(a, b, &mut overflow);
            if overflow != 0 && overflow != 1 {
                return None
            }
            Some((r, overflow))
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
#[macro_use] extern crate log;
#[macro_use] extern crate version;

extern crate libimagbookmark;
extern crate libimagentrylink;
extern crate libimagrt;
extern crate libimagutil;

use libimagentrytag::ui::{get_add_tags, get_remove_tags};
use libimagentrylink::internal::Link;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup("imag-bookmark",
                                    &version!()[..],
                                    "Bookmark collection tool",
                                    build_ui);

    rt.cli()
        .subcommand_name()
        .map(|name| {
            debug!("Call {}", name);
            match name {
                "add"        => add(&rt),
                "collection" => collection(&rt),
                "list"       => list(&rt),
                "remove"     => remove(&rt),
                _            => {
                    debug!("Unknown command"); // More error handling
                },
            }
        });
}

fn add(rt: &Runtime) {
    unimplemented!()
}

fn collection(rt: &Runtime) {
    unimplemented!()
}

fn list(rt: &Runtime) {
    unimplemented!()
}

fn remove(rt: &Runtime) {
    unimplemented!()
}

<commit_msg>Impl add()<commit_after>extern crate clap;
#[macro_use] extern crate log;
#[macro_use] extern crate version;

extern crate libimagbookmark;
extern crate libimagentrylink;
extern crate libimagentrytag;
extern crate libimagrt;
extern crate libimagerror;
extern crate libimagutil;

use libimagentrytag::ui::{get_add_tags, get_remove_tags};
use libimagentrylink::internal::Link;
use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagbookmark::collection::BookmarkCollection;
use libimagbookmark::link::Link as BookmarkLink;
use libimagerror::trace::trace_error;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup("imag-bookmark",
                                    &version!()[..],
                                    "Bookmark collection tool",
                                    build_ui);

    rt.cli()
        .subcommand_name()
        .map(|name| {
            debug!("Call {}", name);
            match name {
                "add"        => add(&rt),
                "collection" => collection(&rt),
                "list"       => list(&rt),
                "remove"     => remove(&rt),
                _            => {
                    debug!("Unknown command"); // More error handling
                },
            }
        });
}

fn add(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("add").unwrap();
    let coll = scmd.value_of("collection").unwrap(); // enforced by clap

    BookmarkCollection::get(rt.store(), coll)
        .map(|mut collection| {
            for url in scmd.values_of("urls").unwrap() { // enforced by clap
                collection.add_link(BookmarkLink::from(url)).map_err(|e| trace_error(&e));
            }
        });
    info!("Ready");
}

fn collection(rt: &Runtime) {
    unimplemented!()
}

fn list(rt: &Runtime) {
    unimplemented!()
}

fn remove(rt: &Runtime) {
    unimplemented!()
}

<|endoftext|>