<commit_before>//! lzf-rs is a small wrapper around [LibLZF](http://software.schmorp.de/pkg/liblzf.html),
//! a very small data compression library.
//!
//! The compression algorithm is very, very fast, yet still written in portable C.
//!
//! This Rust library is a wrapper around the library from Marc Lehmann.
//!
//! # Basic Operation
//!
//! ```rust,no_run
//! #![allow(unstable)]
//! # use lzf;
//! let data = "foobar";
//!
//! let compressed = lzf::compress(data.as_bytes()).unwrap();
//!
//! let decompressed = lzf::decompress(compressed.as_slice(), data.len()).unwrap();
//! ```

#![experimental]

extern crate libc;

use libc::{c_uint,c_void};

extern {
    fn lzf_compress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
    fn lzf_decompress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
}

#[derive(PartialEq, Eq, Clone, Show, Copy)]
pub enum LzfError {
    BufferTooSmall,
    DataCorrupted,
    NoCompressionPossible,
    UnknownError(usize)
}
pub type LzfResult<T> = Result<T, LzfError>;

/// Compress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The buffer is always set to the same size as the input buffer.
/// If that is not enough to hold the lzf-compressed data,
/// an error will be returned.
///
/// Example:
///
/// ```rust
/// let data = "foobar";
/// let compressed = lzf::compress(data.as_bytes());
/// ```
pub fn compress(data: &[u8]) -> LzfResult<Vec<u8>> {
    let data_len = data.len();
    let mut out : Vec<u8> = Vec::with_capacity(data_len);

    let result = unsafe { lzf_compress(data.as_ptr() as *const c_void, data_len as c_uint,
                                       out.as_ptr() as *const c_void, data_len as c_uint) };

    match result {
        0 => Err(LzfError::NoCompressionPossible),
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

/// Decompress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The length of the output buffer can be specified.
/// If the output buffer is not large enough to hold the decompressed data,
/// BufferTooSmall is returned.
/// Otherwise the number of decompressed bytes
/// (i.e. the original length of the data) is returned.
///
/// If an error in the compressed data is detected, DataCorrupted is returned.
///
/// Example:
///
/// ```rust,no_run
/// let data = "[your-compressed-data]";
/// let decompressed = lzf::decompress(data.as_bytes(), 10);
/// ```
pub fn decompress(data: &[u8], out_len: usize) -> LzfResult<Vec<u8>> {
    let mut out : Vec<u8> = Vec::with_capacity(out_len);

    let result = unsafe { lzf_decompress(data.as_ptr() as *const c_void, data.len() as c_uint,
                                         out.as_ptr() as *const c_void, out_len as c_uint) };
    match result {
        0 => {
            match std::os::errno() {
                7  => Err(LzfError::BufferTooSmall),
                22 => Err(LzfError::DataCorrupted),
                e  => Err(LzfError::UnknownError(e))
            }
        },
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

#[test]
fn test_compress_skips_short() {
    match compress("foo".as_bytes()) {
        Ok(_) => panic!("Compression did _something_, with is wrong for 'foo'"),
        Err(err) => assert_eq!(LzfError::NoCompressionPossible, err)
    }
}

#[test]
fn test_compress_lorem() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    match compress(lorem.as_bytes()) {
        Ok(compressed) => {
            assert_eq!(272, compressed.len())
        }
        Err(err) => panic!("Compression failed with error {:?}", err)
    }
}

#[test]
fn test_compress_decompress_lorem_round() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {:?}", err)
    };

    match decompress(compressed.as_slice(), lorem.len()) {
        Ok(decompressed) => {
            assert_eq!(lorem.len(), decompressed.len());
            assert_eq!(lorem.as_bytes(), decompressed.as_slice());
        },
        Err(err) => panic!("Decompression failed with error {:?}", err)
    };
}

#[test]
fn test_decompress_fails_with_short_buffer() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {:?}", err)
    };

    match decompress(compressed.as_slice(), 10) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::BufferTooSmall, err)
    }
}

#[test]
fn test_decompress_fails_for_corrupted_data() {
    let lorem = "Lorem ipsum dolor sit amet";

    match decompress(lorem.as_bytes(), lorem.len()) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::DataCorrupted, err)
    }
}
<commit_msg>Implement Display for LzfError to allow for unwrap of the result<commit_after>//! lzf-rs is a small wrapper around [LibLZF](http://software.schmorp.de/pkg/liblzf.html),
//! a very small data compression library.
//!
//! The compression algorithm is very, very fast, yet still written in portable C.
//!
//! This Rust library is a wrapper around the library from Marc Lehmann.
//!
//! # Basic Operation
//!
//! ```rust,no_run
//! #![allow(unstable)]
//! # use lzf;
//! let data = "foobar";
//!
//! let compressed = lzf::compress(data.as_bytes()).unwrap();
//!
//! let decompressed = lzf::decompress(compressed.as_slice(), data.len()).unwrap();
//! ```

#![experimental]

extern crate libc;

use libc::{c_uint,c_void};
use std::fmt;

extern {
    fn lzf_compress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
    fn lzf_decompress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
}

#[derive(PartialEq, Eq, Clone, Show, Copy)]
pub enum LzfError {
    BufferTooSmall,
    DataCorrupted,
    NoCompressionPossible,
    UnknownError(usize)
}

impl fmt::Display for LzfError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            LzfError::BufferTooSmall => {
                write!(f, "the given buffer is too small to handle the uncompressed data")
            }
            LzfError::DataCorrupted => {
                write!(f, "the given data is corrupted")
            }
            LzfError::NoCompressionPossible => {
                write!(f, "the input data cannot be compressed")
            }
            LzfError::UnknownError(err) => {
                write!(f, "unknown error, code {}", err)
            }
        }
    }
}

pub type LzfResult<T> = Result<T, LzfError>;

/// Compress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The buffer is always set to the same size as the input buffer.
/// If that is not enough to hold the lzf-compressed data,
/// an error will be returned.
///
/// Example:
///
/// ```rust
/// let data = "foobar";
/// let compressed = lzf::compress(data.as_bytes());
/// ```
pub fn compress(data: &[u8]) -> LzfResult<Vec<u8>> {
    let data_len = data.len();
    let mut out : Vec<u8> = Vec::with_capacity(data_len);

    let result = unsafe { lzf_compress(data.as_ptr() as *const c_void, data_len as c_uint,
                                       out.as_ptr() as *const c_void, data_len as c_uint) };

    match result {
        0 => Err(LzfError::NoCompressionPossible),
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

/// Decompress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The length of the output buffer can be specified.
/// If the output buffer is not large enough to hold the decompressed data,
/// BufferTooSmall is returned.
/// Otherwise the number of decompressed bytes
/// (i.e. the original length of the data) is returned.
///
/// If an error in the compressed data is detected, DataCorrupted is returned.
///
/// Example:
///
/// ```rust,no_run
/// let data = "[your-compressed-data]";
/// let decompressed = lzf::decompress(data.as_bytes(), 10);
/// ```
pub fn decompress(data: &[u8], out_len: usize) -> LzfResult<Vec<u8>> {
    let mut out : Vec<u8> = Vec::with_capacity(out_len);

    let result = unsafe { lzf_decompress(data.as_ptr() as *const c_void, data.len() as c_uint,
                                         out.as_ptr() as *const c_void, out_len as c_uint) };
    match result {
        0 => {
            match std::os::errno() {
                7  => Err(LzfError::BufferTooSmall),
                22 => Err(LzfError::DataCorrupted),
                e  => Err(LzfError::UnknownError(e))
            }
        },
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

#[test]
fn test_compress_skips_short() {
    match compress("foo".as_bytes()) {
        Ok(_) => panic!("Compression did _something_, with is wrong for 'foo'"),
        Err(err) => assert_eq!(LzfError::NoCompressionPossible, err)
    }
}

#[test]
fn test_compress_lorem() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    match compress(lorem.as_bytes()) {
        Ok(compressed) => {
            assert_eq!(272, compressed.len())
        }
        Err(err) => panic!("Compression failed with error {:?}", err)
    }
}

#[test]
fn test_compress_decompress_lorem_round() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {:?}", err)
    };

    match decompress(compressed.as_slice(), lorem.len()) {
        Ok(decompressed) => {
            assert_eq!(lorem.len(), decompressed.len());
            assert_eq!(lorem.as_bytes(), decompressed.as_slice());
        },
        Err(err) => panic!("Decompression failed with error {:?}", err)
    };
}

#[test]
fn test_decompress_fails_with_short_buffer() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {:?}", err)
    };

    match decompress(compressed.as_slice(), 10) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::BufferTooSmall, err)
    }
}

#[test]
fn test_decompress_fails_for_corrupted_data() {
    let lorem = "Lorem ipsum dolor sit amet";

    match decompress(lorem.as_bytes(), lorem.len()) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::DataCorrupted, err)
    }
}
<|endoftext|>


<commit_before>//! Taken from http://www.itu.int/rec/T-REC-X.680-200811-I

#![allow(dead_code)] // Until parser is complete. Too noisy otherwise

#[macro_use]
extern crate nom;

extern crate regex;

use std::str::FromStr;

/// Parse an integer.
///
/// Defined in X.680 §12.8
named!(number<&str, u64>,
    map_res!(
        re_find!(r"^(0|[1-9]\d*)"),
        FromStr::from_str
    )
);

/// Parse an `f64`.
///
/// Defined in X.680 §12.9
named!(realnumber<&str, f64>,
   map_res!(
       re_find!(r"^\d+(\.\d*)?([eE]-?(0|[1-9]\d*))?"),
       FromStr::from_str
   )
);

#[cfg(test)]
mod tests {

    use super::{number, realnumber};
    use nom::IResult;
    use nom::IResult::Done;

    /// Simple way of specifying an `IResult::Done` with no remaining input.
    macro_rules! done_result (
        ($res:expr) => (
            IResult::Done("", $res)
        )
    );

    #[test]
    fn test_newline() {
        assert_eq!(newline("\n"), done_result!("\n"));
        assert_eq!(newline("\x0B"), done_result!("\x0B"));
    }

    #[test]
    fn test_take_until_single_line_comment_end() {
        assert_eq!(take_until_single_line_comment_end(" thing\nmore"), Done("\nmore", " thing"));
        assert_eq!(take_until_single_line_comment_end(" thing\n"), Done("\n", " thing"));
        assert_eq!(take_until_single_line_comment_end(" thing--"), Done("--", " thing"));
        assert_eq!(take_until_single_line_comment_end(" dash-in-middle--"),
                   Done("--", " dash-in-middle"));
        assert_eq!(take_until_single_line_comment_end(" dash-in-middle\x0C"),
                   Done("\x0C", " dash-in-middle"));

        // Empty comments
        assert_eq!(take_until_single_line_comment_end("\n"), Done("\n", ""));
        assert_eq!(take_until_single_line_comment_end("--"), Done("--", ""));

        assert_eq!(take_until_single_line_comment_end("stuff-"), done_result!("stuff-"));
        assert_eq!(take_until_single_line_comment_end("-"), done_result!("-"));
    }

    #[test]
    fn test_single_line_comment() {
        assert_eq!(single_line_comment("-- thing\nmore"), Done("more", " thing"));
        assert_eq!(single_line_comment("-- thing--"), done_result!(" thing"));
        assert_eq!(single_line_comment("-- thing\n"), done_result!(" thing"));
        assert_eq!(single_line_comment("-- dash-in-middle--"), done_result!(" dash-in-middle"));
        assert_eq!(single_line_comment("-- dash-in-middle\x0C"), done_result!(" dash-in-middle"));
        assert_eq!(single_line_comment("--\n"), done_result!(""));
        assert_eq!(single_line_comment("----"), done_result!(""));
    }

    #[test]
    fn test_number() {
        assert_eq!(number("0"), done_result!(0));
        assert_eq!(number("1"), done_result!(1));

        // Matches the first zero, but considers the second digit to be leftover input.
        assert_eq!(number("01"), Done("1", 0));
    }

    #[test]
    fn test_realnumber() {
        assert_eq!(realnumber("1"), done_result!(1.0));
        assert_eq!(realnumber("0"), done_result!(0.0));

        // Can have a leading zero
        assert_eq!(realnumber("00"), done_result!(0.0));
        assert_eq!(realnumber("01"), done_result!(1.0));

        // Can have a trailing period without a factional part
        assert_eq!(realnumber("1."), done_result!(1.0));
        assert_eq!(realnumber("1.0"), done_result!(1.0));
        assert_eq!(realnumber("1.001"), done_result!(1.001));

        // Exponents
        assert_eq!(realnumber("1.1e3"), done_result!(1100.0));
        assert_eq!(realnumber("1.1e-3"), done_result!(0.0011));
        assert_eq!(realnumber("1.e3"), done_result!(1000.0));
        assert_eq!(realnumber("1e3"), done_result!(1000.0));
        assert_eq!(realnumber("1.1E3"), done_result!(1100.0));
        assert_eq!(realnumber("1.1E-3"), done_result!(0.0011));

        // Leading zero in exponent
        assert_eq!(realnumber("1.1E-03"), Done("3", 1.1));
        assert_eq!(realnumber("1.1E03"), Done("3", 1.1));
    }

}
<commit_msg>Support for single-line comment<commit_after>//! Taken from http://www.itu.int/rec/T-REC-X.680-200811-I

#![allow(dead_code)] // Until parser is complete. Too noisy otherwise

#[macro_use]
extern crate nom;

extern crate regex;

use std::str::FromStr;
use nom::{IResult};

/// Returns `true` if the character is a newline character according to ASN.1.
///
/// Defined in X.680 §12.1.6
fn is_newline(ch: char) -> bool {
    match ch {
        // LINE FEED
        '\n' => true,

        // VERTICAL TABULATION
        '\x0B' => true,

        // FORM FEED
        '\x0C' => true,

        // CARRIAGE RETURN
        '\x0D' => true,
        _ => false,
    }
}

named!(newline<&str, &str>,
       alt!(
           tag_s!("\n") |
           tag_s!("\x0B") |
           tag_s!("\x0C") |
           tag_s!("\x0D")
       )
);

/// Returns `true` if the character is a whitespace character according to ASN.1.
///
/// Defined in X.680 §12.1.6
fn is_whitespace(ch: char) -> bool {
    match ch {
        ' ' | '\t' => true,

        // All newline characters are also whitespace
        _ if is_newline(ch) => true,
        _ => false,
    }
}

/// Takes input until it finds the end of a single-line comment. This will not consume the ending
/// character(s) of the comment.
fn take_until_single_line_comment_end(input: &str) -> IResult<&str, &str> {
    let mut offset = input.len();
    let mut chars = input.char_indices().peekable();
    loop {
        match chars.next() {
            Some((i, c)) => {
                match c {
                    '-' => {
                        match chars.peek() {
                            Some(&(_, pc)) => {
                                if pc == '-' {
                                    offset = i;
                                    break;
                                } else {
                                    // Safe to advance because we know that the peeked char is not
                                    // a dash.
                                    chars.next();
                                    continue;
                                }
                            },
                            // Got a single "-" at the end of the string. Consider it to be part of
                            // the comment.
                            None => {
                                // Normally, adding 1 to a byte offset in a `&str` could lead to an
                                // invalid access of a non-character boundary. In this case, we
                                // know that the last character was a "-", which is a single byte.
                                offset = i + 1;
                                break
                            }
                        }
                    },
                    _ if is_newline(c) => {
                        offset = i;
                        break
                    },
                    _ => continue,
                }
            },
            None => break,
        }
    }

    if offset < input.len() {
        IResult::Done(&input[offset..], &input[..offset])
    } else {
        IResult::Done("", input)
    }
}

/// Parse a single-line comment.
///
/// Defined in X.680 §12.6a
named!(single_line_comment<&str, &str>,
    delimited!(
        tag_s!("--"),
        take_until_single_line_comment_end,
        alt!(newline | tag_s!("--"))
    )
);

/// Parse a comment.
///
/// Defined in X.680 §12.6
named!(comment<&str, &str>,
    alt!(
        single_line_comment
    )
);

/// Parse an integer.
///
/// Defined in X.680 §12.8
named!(number<&str, u64>,
    map_res!(
        re_find!(r"^(0|[1-9]\d*)"),
        FromStr::from_str
    )
);

/// Parse an `f64`.
///
/// Defined in X.680 §12.9
named!(realnumber<&str, f64>,
   map_res!(
       re_find!(r"^\d+(\.\d*)?([eE]-?(0|[1-9]\d*))?"),
       FromStr::from_str
   )
);

#[cfg(test)]
mod tests {

    use super::{number, realnumber, single_line_comment, take_until_single_line_comment_end,
                newline};
    use nom::IResult;
    use nom::IResult::Done;

    /// Simple way of specifying an `IResult::Done` with no remaining input.
    macro_rules! done_result (
        ($res:expr) => (
            IResult::Done("", $res)
        )
    );

    #[test]
    fn test_newline() {
        assert_eq!(newline("\n"), done_result!("\n"));
        assert_eq!(newline("\x0B"), done_result!("\x0B"));
    }

    #[test]
    fn test_take_until_single_line_comment_end() {
        assert_eq!(take_until_single_line_comment_end(" thing\nmore"), Done("\nmore", " thing"));
        assert_eq!(take_until_single_line_comment_end(" thing\n"), Done("\n", " thing"));
        assert_eq!(take_until_single_line_comment_end(" thing--"), Done("--", " thing"));
        assert_eq!(take_until_single_line_comment_end(" dash-in-middle--"),
                   Done("--", " dash-in-middle"));
        assert_eq!(take_until_single_line_comment_end(" dash-in-middle\x0C"),
                   Done("\x0C", " dash-in-middle"));

        // Empty comments
        assert_eq!(take_until_single_line_comment_end("\n"), Done("\n", ""));
        assert_eq!(take_until_single_line_comment_end("--"), Done("--", ""));

        assert_eq!(take_until_single_line_comment_end("stuff-"), done_result!("stuff-"));
        assert_eq!(take_until_single_line_comment_end("-"), done_result!("-"));
    }

    #[test]
    fn test_single_line_comment() {
        assert_eq!(single_line_comment("-- thing\nmore"), Done("more", " thing"));
        assert_eq!(single_line_comment("-- thing--"), done_result!(" thing"));
        assert_eq!(single_line_comment("-- thing\n"), done_result!(" thing"));
        assert_eq!(single_line_comment("-- dash-in-middle--"), done_result!(" dash-in-middle"));
        assert_eq!(single_line_comment("-- dash-in-middle\x0C"), done_result!(" dash-in-middle"));
        assert_eq!(single_line_comment("--\n"), done_result!(""));
        assert_eq!(single_line_comment("----"), done_result!(""));
    }

    #[test]
    fn test_number() {
        assert_eq!(number("0"), done_result!(0));
        assert_eq!(number("1"), done_result!(1));

        // Matches the first zero, but considers the second digit to be leftover input.
        assert_eq!(number("01"), Done("1", 0));
    }

    #[test]
    fn test_realnumber() {
        assert_eq!(realnumber("1"), done_result!(1.0));
        assert_eq!(realnumber("0"), done_result!(0.0));

        // Can have a leading zero
        assert_eq!(realnumber("00"), done_result!(0.0));
        assert_eq!(realnumber("01"), done_result!(1.0));

        // Can have a trailing period without a factional part
        assert_eq!(realnumber("1."), done_result!(1.0));
        assert_eq!(realnumber("1.0"), done_result!(1.0));
        assert_eq!(realnumber("1.001"), done_result!(1.001));

        // Exponents
        assert_eq!(realnumber("1.1e3"), done_result!(1100.0));
        assert_eq!(realnumber("1.1e-3"), done_result!(0.0011));
        assert_eq!(realnumber("1.e3"), done_result!(1000.0));
        assert_eq!(realnumber("1e3"), done_result!(1000.0));
        assert_eq!(realnumber("1.1E3"), done_result!(1100.0));
        assert_eq!(realnumber("1.1E-3"), done_result!(0.0011));

        // Leading zero in exponent
        assert_eq!(realnumber("1.1E-03"), Done("3", 1.1));
        assert_eq!(realnumber("1.1E03"), Done("3", 1.1));
    }

}
<|endoftext|>


<commit_before>#![feature(no_std)]
#![feature(core)]
#![feature(lang_items)]
#![feature(asm)]
#![feature(static_assert)]
#![feature(step_by)]
#![no_std]

#![feature(trace_macros)]

#![crate_name="titanium"]

#[macro_use]
extern crate core;

#[macro_use]
pub mod macros;

#[macro_use]
pub mod arch;

pub mod lang;
pub mod drv;
pub mod consts;
pub mod hw;

pub use hw::HW;

#[macro_use]
pub mod selftest;

mod titanium {
    pub use super::selftest;
}
<commit_msg>Update rustc.<commit_after>#![feature(no_std)]
#![feature(core)]
#![feature(lang_items)]
#![feature(asm)]
#![feature(step_by)]
#![feature(custom_attribute)]
#![feature(core_intrinsics)]
#![feature(core_str_ext)]
#![no_std]

#![feature(trace_macros)]

#![crate_name="titanium"]

#[macro_use]
extern crate core;

#[macro_use]
pub mod macros;

#[macro_use]
pub mod arch;

pub mod lang;
pub mod drv;
pub mod consts;
pub mod hw;

pub use hw::HW;

#[macro_use]
pub mod selftest;

mod titanium {
    pub use super::selftest;
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A 3D game engine with built-in editor.

#[macro_use]
extern crate bitflags;
extern crate vecmath;
extern crate piston_window;
extern crate sdl2_window;
#[macro_use]
extern crate gfx;
extern crate gfx_device_gl;
extern crate piston_meta;
extern crate camera_controllers;
extern crate gfx_debug_draw;
extern crate gfx_text;
#[macro_use]
extern crate log;

pub use math::Vec3;
pub use math::Mat4;
pub use math::AABB;
pub use math::Ray;

pub mod math;
pub mod render;
pub mod logger;

/// The maximum number of entities.
pub const ENTITY_COUNT: usize = 10000;

bitflags!(
    /// Used to turn on/off components per entity.
    flags Mask: u32 {
        /// Entity is alive.
        const ALIVE         = 0b00000001,
        /// Entity is selected.
        const SELECT        = 0b00000010,
        /// Entity has an AABB.
        const AABB          = 0b00000100,
    }
);

/// Stores physical state.
pub struct Physics {
    /// The position.
    pub position: [Vec3; ENTITY_COUNT],
}

impl Physics {
    /// Gets next linear step.
    pub fn step(&mut self, prev: &Physics, current: &Physics) {
        use math::Vector;

        for i in 0..ENTITY_COUNT {
            // current + (current - prev) = 2 * current - prev.
            self.position[i] = current.position[i]
                .scale(2.0)
                .sub(prev.position[i]);
        }
    }
}

/// Stores the world data.
pub struct World {
    /// The active components per entity.
    pub mask: [Mask; ENTITY_COUNT],
    /// The initial state of physics.
    pub init: Box<Physics>,
    /// The previous state.
    pub prev: Box<Physics>,
    /// The current state.
    pub current: Box<Physics>,
    /// The next state.
    pub next: Box<Physics>,
    /// An AABB relative to position.
    pub aabb: [AABB; ENTITY_COUNT],
}

impl World {
    /// Swaps the physical state such that previous is now next.
    pub fn swap_physics(&mut self) {
        use std::mem::swap;

        swap(&mut self.prev, &mut self.current);
        swap(&mut self.current, &mut self.next);
    }

    /// Finds the first free entity slot.
    pub fn find_free_entity_slot(&self) -> Option<usize> {
        for i in 0..ENTITY_COUNT {
            if self.mask[i].is_empty() { return Some(i); }
        }
        None
    }

    /// Sets position with no velocity.
    pub fn set_position_with_no_velocity(&mut self, id: usize, pos: Vec3) {
        self.prev.position[id] = pos;
        self.current.position[id] = pos;
        self.next.position[id] = pos;
    }

    /// Adds a new entity.
    /// Marks the entity as alive and selects it.
    pub fn add_entity(&mut self, pos: Vec3) {
        let id = match self.find_free_entity_slot() {
            Some(id) => id,
            None => {
                warn!("There are no free entity slots");
                return;
            }
        };
        self.init.position[id] = pos;
        self.set_position_with_no_velocity(id, pos);
        let mask = &mut self.mask[id];
        mask.insert(ALIVE);
        mask.insert(SELECT);
    }
}

/// Starts Turbine pointing it to a project folder.
pub fn start(_project_folder: &str) {
    use piston_window::*;
    use sdl2_window::Sdl2Window;
    use camera_controllers::*;
    use gfx_debug_draw::DebugRenderer;
    use math::{ Matrix, Vector };

    println!("
~~~~~~~~   TURBINE   ~~~~~~~~\n\
=============================\n\
Camera navigation (on/off): C\n\
Camera control: WASD\n\
");

    let mut window: PistonWindow<(), Sdl2Window> =
        WindowSettings::new("Turbine", [1024, 768])
        .exit_on_esc(true)
        .samples(4)
        .build()
        .unwrap();

    logger::init().unwrap();

    let mut capture_cursor = true;

    window.set_capture_cursor(capture_cursor);

    let fov = 90.0;
    let near = 0.1;
    let far = 1000.0;
    let get_projection = |w: &PistonWindow<(), Sdl2Window>| {
        let draw_size = w.window.borrow().draw_size();
        CameraPerspective {
            fov: 90.0, near_clip: near, far_clip: far,
            aspect_ratio: (draw_size.width as f32) / (draw_size.height as f32)
        }.projection()
    };

    let mut projection = get_projection(&window);
    let mut first_person = FirstPerson::new(
        [0.5, 0.5, 4.0],
        FirstPersonSettings::keyboard_wasd()
    );

    let mut debug_renderer = {
        let text_renderer = {
            gfx_text::new(window.factory.borrow().clone()).unwrap()
        };
        DebugRenderer::new(window.factory.borrow().clone(),
            text_renderer, 64).ok().unwrap()
    };

    let mut cursor_pos = [0.0, 0.0];
    let mut ground_pos = [0.0, 0.0, 0.0];
    let mut ortho = false;

    for mut e in window {
        if capture_cursor {
            first_person.event(&e);
        }
        e.draw_3d(|stream| {
            let args = e.render_args().unwrap();
            let mvp = model_view_projection(
                Matrix::id(),
                first_person.camera(args.ext_dt).orthogonal(),
                projection
            );
            render::clear(stream);

            render::axes(&mut debug_renderer);
            debug_renderer.draw_marker(ground_pos, 0.1, [1.0, 1.0, 0.0, 1.0]);
            debug_renderer.render(stream, mvp).unwrap();
        });
        e.resize(|_, _| {
            if !ortho {
                projection = get_projection(&e);
            }
        });
        if let Some(pos) = e.mouse_cursor_args() {
            cursor_pos = pos;
        }
        if let Some(Button::Keyboard(Key::C)) = e.press_args() {
            capture_cursor = !capture_cursor;
            e.set_capture_cursor(capture_cursor);
        }
        if let Some(Button::Keyboard(Key::O)) = e.press_args() {
            ortho = !ortho;
            if ortho {
                projection = Matrix::id();
            } else {
                projection = get_projection(&e);
            }
        }
        if let Some(Button::Mouse(MouseButton::Left)) = e.press_args() {
            if !capture_cursor {
                let draw_size = e.draw_size();
                let draw_size = [draw_size.width, draw_size.height];
                let ray = Ray::from_2d(cursor_pos, draw_size, fov, near, far);
                let view_to_world = first_person.camera(0.0).orthogonal().inv();
                match view_to_world.ray(ray).ground_plane() {
                    None => info!("Click on the ground to add entity"),
                    Some(pos) => {
                        ground_pos = pos;
                    }
                }
            }
        }
    }
}

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

    #[test]
    fn entity_syntax() {
        let _ = load_syntax_data2("assets/entity/syntax.txt",
            "assets/entity/test-cube.txt");
    }
}
<commit_msg>Use `fov` variable for CameraPerspective.<commit_after>#![deny(missing_docs)]

//! A 3D game engine with built-in editor.

#[macro_use]
extern crate bitflags;
extern crate vecmath;
extern crate piston_window;
extern crate sdl2_window;
#[macro_use]
extern crate gfx;
extern crate gfx_device_gl;
extern crate piston_meta;
extern crate camera_controllers;
extern crate gfx_debug_draw;
extern crate gfx_text;
#[macro_use]
extern crate log;

pub use math::Vec3;
pub use math::Mat4;
pub use math::AABB;
pub use math::Ray;

pub mod math;
pub mod render;
pub mod logger;

/// The maximum number of entities.
pub const ENTITY_COUNT: usize = 10000;

bitflags!(
    /// Used to turn on/off components per entity.
    flags Mask: u32 {
        /// Entity is alive.
        const ALIVE         = 0b00000001,
        /// Entity is selected.
        const SELECT        = 0b00000010,
        /// Entity has an AABB.
        const AABB          = 0b00000100,
    }
);

/// Stores physical state.
pub struct Physics {
    /// The position.
    pub position: [Vec3; ENTITY_COUNT],
}

impl Physics {
    /// Gets next linear step.
    pub fn step(&mut self, prev: &Physics, current: &Physics) {
        use math::Vector;

        for i in 0..ENTITY_COUNT {
            // current + (current - prev) = 2 * current - prev.
            self.position[i] = current.position[i]
                .scale(2.0)
                .sub(prev.position[i]);
        }
    }
}

/// Stores the world data.
pub struct World {
    /// The active components per entity.
    pub mask: [Mask; ENTITY_COUNT],
    /// The initial state of physics.
    pub init: Box<Physics>,
    /// The previous state.
    pub prev: Box<Physics>,
    /// The current state.
    pub current: Box<Physics>,
    /// The next state.
    pub next: Box<Physics>,
    /// An AABB relative to position.
    pub aabb: [AABB; ENTITY_COUNT],
}

impl World {
    /// Swaps the physical state such that previous is now next.
    pub fn swap_physics(&mut self) {
        use std::mem::swap;

        swap(&mut self.prev, &mut self.current);
        swap(&mut self.current, &mut self.next);
    }

    /// Finds the first free entity slot.
    pub fn find_free_entity_slot(&self) -> Option<usize> {
        for i in 0..ENTITY_COUNT {
            if self.mask[i].is_empty() { return Some(i); }
        }
        None
    }

    /// Sets position with no velocity.
    pub fn set_position_with_no_velocity(&mut self, id: usize, pos: Vec3) {
        self.prev.position[id] = pos;
        self.current.position[id] = pos;
        self.next.position[id] = pos;
    }

    /// Adds a new entity.
    /// Marks the entity as alive and selects it.
    pub fn add_entity(&mut self, pos: Vec3) {
        let id = match self.find_free_entity_slot() {
            Some(id) => id,
            None => {
                warn!("There are no free entity slots");
                return;
            }
        };
        self.init.position[id] = pos;
        self.set_position_with_no_velocity(id, pos);
        let mask = &mut self.mask[id];
        mask.insert(ALIVE);
        mask.insert(SELECT);
    }
}

/// Starts Turbine pointing it to a project folder.
pub fn start(_project_folder: &str) {
    use piston_window::*;
    use sdl2_window::Sdl2Window;
    use camera_controllers::*;
    use gfx_debug_draw::DebugRenderer;
    use math::{ Matrix, Vector };

    println!("
~~~~~~~~   TURBINE   ~~~~~~~~\n\
=============================\n\
Camera navigation (on/off): C\n\
Camera control: WASD\n\
");

    let mut window: PistonWindow<(), Sdl2Window> =
        WindowSettings::new("Turbine", [1024, 768])
        .exit_on_esc(true)
        .samples(4)
        .build()
        .unwrap();

    logger::init().unwrap();

    let mut capture_cursor = true;

    window.set_capture_cursor(capture_cursor);

    let fov = 90.0;
    let near = 0.1;
    let far = 1000.0;
    let get_projection = |w: &PistonWindow<(), Sdl2Window>| {
        let draw_size = w.window.borrow().draw_size();
        CameraPerspective {
            fov: fov, near_clip: near, far_clip: far,
            aspect_ratio: (draw_size.width as f32) / (draw_size.height as f32)
        }.projection()
    };

    let mut projection = get_projection(&window);
    let mut first_person = FirstPerson::new(
        [0.5, 0.5, 4.0],
        FirstPersonSettings::keyboard_wasd()
    );

    let mut debug_renderer = {
        let text_renderer = {
            gfx_text::new(window.factory.borrow().clone()).unwrap()
        };
        DebugRenderer::new(window.factory.borrow().clone(),
            text_renderer, 64).ok().unwrap()
    };

    let mut cursor_pos = [0.0, 0.0];
    let mut ground_pos = [0.0, 0.0, 0.0];
    let mut ortho = false;

    for mut e in window {
        if capture_cursor {
            first_person.event(&e);
        }
        e.draw_3d(|stream| {
            let args = e.render_args().unwrap();
            let mvp = model_view_projection(
                Matrix::id(),
                first_person.camera(args.ext_dt).orthogonal(),
                projection
            );
            render::clear(stream);

            render::axes(&mut debug_renderer);
            debug_renderer.draw_marker(ground_pos, 0.1, [1.0, 1.0, 0.0, 1.0]);
            debug_renderer.render(stream, mvp).unwrap();
        });
        e.resize(|_, _| {
            if !ortho {
                projection = get_projection(&e);
            }
        });
        if let Some(pos) = e.mouse_cursor_args() {
            cursor_pos = pos;
        }
        if let Some(Button::Keyboard(Key::C)) = e.press_args() {
            capture_cursor = !capture_cursor;
            e.set_capture_cursor(capture_cursor);
        }
        if let Some(Button::Keyboard(Key::O)) = e.press_args() {
            ortho = !ortho;
            if ortho {
                projection = Matrix::id();
            } else {
                projection = get_projection(&e);
            }
        }
        if let Some(Button::Mouse(MouseButton::Left)) = e.press_args() {
            if !capture_cursor {
                let draw_size = e.draw_size();
                let draw_size = [draw_size.width, draw_size.height];
                let ray = Ray::from_2d(cursor_pos, draw_size, fov, near, far);
                let view_to_world = first_person.camera(0.0).orthogonal().inv();
                match view_to_world.ray(ray).ground_plane() {
                    None => info!("Click on the ground to add entity"),
                    Some(pos) => {
                        ground_pos = pos;
                    }
                }
            }
        }
    }
}

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

    #[test]
    fn entity_syntax() {
        let _ = load_syntax_data2("assets/entity/syntax.txt",
            "assets/entity/test-cube.txt");
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;
extern crate libc;

use std::io;

pub trait CopyAddress {
    fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()>;
}

// This should be dropped in favor of TryInto when that stabilizes:
// https://github.com/rust-lang/rust/issues/33417
pub trait TryIntoProcessHandle {
    fn try_into_process_handle(self) -> io::Result<platform::ProcessHandle>;
}

/// Trivial implementation of `TryIntoProcessHandle`.
impl TryIntoProcessHandle for platform::ProcessHandle {
    fn try_into_process_handle(self) -> io::Result<platform::ProcessHandle> {
        Ok(self)
    }
}

pub struct Process {
    handle: platform::ProcessHandle,
}

pub use platform::Pid;

impl Process {
    pub fn new<T>(process: T) -> io::Result<Process> where T: TryIntoProcessHandle {
        Ok(Process {
            handle: try!(process.try_into_process_handle()),
        })
    }
}

#[cfg(target_os="linux")]
mod platform {
    use libc::{pid_t, c_void, iovec, process_vm_readv};
    use std::io;
    use std::process::Child;

    use super::{CopyAddress, Process, TryIntoProcessHandle};

    pub type Pid = pid_t;
    pub type ProcessHandle = pid_t;

    impl<'a> TryIntoProcessHandle for &'a Child {
        fn try_into_process_handle(self) -> io::Result<ProcessHandle> {
            Ok(self.id() as pid_t)
        }
    }

    impl CopyAddress for Process {
        fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()> {
            let local_iov = iovec {
                iov_base: buf.as_mut_ptr() as *mut c_void,
                iov_len: buf.len(),
            };
            let remote_iov = iovec {
                iov_base: addr as *mut c_void,
                iov_len: buf.len(),
            };
            let result = unsafe {
                process_vm_readv(self.handle, &local_iov, 1, &remote_iov, 1, 0)
            };
            if result == -1 {
                Err(io::Error::last_os_error())
            } else {
                Ok(())
            }
        }
    }
}

#[cfg(target_os="macos")]
mod platform {
    extern crate mach;

    use libc::{pid_t, c_int};
    use self::mach::kern_return::{kern_return_t, KERN_SUCCESS};
    use self::mach::port::{mach_port_t, mach_port_name_t, MACH_PORT_NULL};
    use self::mach::vm_types::{mach_vm_address_t, mach_vm_size_t};
    use self::mach::message::{mach_msg_type_number_t};
    use std::io;
    use std::ptr;
    use std::slice;

    use super::{CopyAddress, Process, TryIntoProcessHandle};

    #[allow(non_camel_case_types)] type vm_map_t = mach_port_t;
    #[allow(non_camel_case_types)] type vm_address_t = mach_vm_address_t;
    #[allow(non_camel_case_types)] type vm_size_t = mach_vm_size_t;

    pub type Pid = pid_t;
    pub type ProcessHandle = mach_port_name_t;

    extern "C" {
        fn vm_read(target_task: vm_map_t, address: vm_address_t, size: vm_size_t, data: &*mut u8, data_size: *mut mach_msg_type_number_t) -> kern_return_t;
    }

    fn task_for_pid(pid: pid_t) -> io::Result<mach_port_name_t> {
        let mut task: mach_port_name_t = MACH_PORT_NULL;

        unsafe {
            let result = mach::traps::task_for_pid(mach::traps::mach_task_self(), pid as c_int, &mut task);
            if result != KERN_SUCCESS {
                return Err(io::Error::last_os_error())
            }
        }

        Ok(task)
    }

    /// `pid_t` can be turned into a `mach_port_name_t` with `task_for_pid`.
    impl TryIntoProcessHandle for pid_t {
        fn try_into_process_handle(self) -> io::Result<ProcessHandle> {
            task_for_pid(self)
        }
    }

    impl CopyAddress for Process {
        fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()> {
            let page_addr      = (addr as i64 & (-4096)) as mach_vm_address_t;
	    let last_page_addr = ((addr as i64 + buf.len() as i64 + 4095) & (-4096)) as mach_vm_address_t;
            let page_size      = last_page_addr as usize - page_addr as usize;

            let read_ptr: *mut u8 = ptr::null_mut();
            let mut read_len: mach_msg_type_number_t = 0;

            let result = unsafe {
                vm_read(self.handle, page_addr as u64, page_size as vm_size_t, &read_ptr, &mut read_len)
            };

            if result != KERN_SUCCESS {
                // panic!("({}) {:?}", result, io::Error::last_os_error());
                return Err(io::Error::last_os_error())
            }

            if read_len != page_size as u32 {
                panic!("Mismatched read sizes for `vm_read` (expected {}, got {})", page_size, read_len)
            }

            let read_buf = unsafe { slice::from_raw_parts(read_ptr, read_len as usize) };

            let offset = addr - page_addr as usize;
            let len = buf.len();
            buf.copy_from_slice(&read_buf[offset..(offset + len)]);

            Ok(())
        }
    }
}

#[cfg(windows)]
mod platform {
    extern crate winapi;
    extern crate kernel32;

    use std::io;
    use std::mem;
    use std::os::windows::io::{AsRawHandle, RawHandle};
    use std::process::Child;
    use std::ptr;

    use super::{CopyAddress, Process, TryIntoProcessHandle};

    pub type Pid = winapi::DWORD;
    pub type ProcessHandle = RawHandle;

    /// `DWORD` can be turned into a `HANDLE` with `OpenProcess`.
    impl TryIntoProcessHandle for winapi::DWORD {
        fn try_into_process_handle(self) -> io::Result<ProcessHandle> {
            let handle = unsafe { kernel32::OpenProcess(winapi::winnt::PROCESS_VM_READ, winapi::FALSE, self) };
            if handle == (0 as RawHandle) {
                Err(io::Error::last_os_error())
            } else {
                Ok(handle)
            }
        }
    }

    impl<'a> TryIntoProcessHandle for &'a Child {
        fn try_into_process_handle(self) -> io::Result<ProcessHandle> {
            Ok(self.as_raw_handle())
        }
    }

    impl CopyAddress for Process {
        fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()> {
            if buf.len() == 0 {
                return Ok(());
            }

            if unsafe { kernel32::ReadProcessMemory(self.handle,
                                                    addr as winapi::LPVOID,
                                                    buf.as_mut_ptr() as winapi::LPVOID,
                                                    mem::size_of_val(buf) as winapi::SIZE_T,
                                                    ptr::null_mut()) } == winapi::FALSE
            {
                Err(io::Error::last_os_error())
            } else {
                Ok(())
            }
        }
    }
}

pub fn copy_address_raw<T>(addr: usize, length: usize, source: &T) -> io::Result<Vec<u8>>
    where T: CopyAddress
{
    debug!("copy_address_raw: addr: {:x}", addr);

    let mut copy = vec![0; length];

    source.copy_address(addr, &mut copy)
        .map_err(|e| {
            warn!("copy_address failed for {:x}: {:?}", addr, e);
            e
        })
        .and(Ok(copy))
}

#[cfg(test)]
mod test {
    use super::*;
    use std::env;
    use std::io::{self, BufRead, BufReader};
    use std::path::PathBuf;
    use std::process::{Command, Stdio};

    fn test_process_path() -> io::Result<PathBuf> {
        env::current_exe().map(|mut p| { p.set_file_name("test"); p })
    }

    #[test]
    fn read_test_process() {
        let child = Command::new(test_process_path().unwrap())
            .stdout(Stdio::piped())
            .spawn().unwrap();
        let p = Process::new(&child).unwrap();
        // The test program prints the address and size.
        let reader = BufReader::new(child.stdout.unwrap());
        let line = reader.lines().next().unwrap().unwrap();
        let bits = line.split(' ').collect::<Vec<_>>();
        let addr = usize::from_str_radix(&bits[0][2..], 16).unwrap();
        let size = bits[1].parse::<usize>().unwrap();
        let mem = copy_address_raw(addr, size, &p).unwrap();
        assert_eq!(mem, (0..32u8).collect::<Vec<u8>>());
    }
}
<commit_msg>skip tests on osx for now<commit_after>#[macro_use] extern crate log;
extern crate libc;

use std::io;

pub trait CopyAddress {
    fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()>;
}

// This should be dropped in favor of TryInto when that stabilizes:
// https://github.com/rust-lang/rust/issues/33417
pub trait TryIntoProcessHandle {
    fn try_into_process_handle(self) -> io::Result<platform::ProcessHandle>;
}

/// Trivial implementation of `TryIntoProcessHandle`.
impl TryIntoProcessHandle for platform::ProcessHandle {
    fn try_into_process_handle(self) -> io::Result<platform::ProcessHandle> {
        Ok(self)
    }
}

pub struct Process {
    handle: platform::ProcessHandle,
}

pub use platform::Pid;

impl Process {
    pub fn new<T>(process: T) -> io::Result<Process> where T: TryIntoProcessHandle {
        Ok(Process {
            handle: try!(process.try_into_process_handle()),
        })
    }
}

#[cfg(target_os="linux")]
mod platform {
    use libc::{pid_t, c_void, iovec, process_vm_readv};
    use std::io;
    use std::process::Child;

    use super::{CopyAddress, Process, TryIntoProcessHandle};

    pub type Pid = pid_t;
    pub type ProcessHandle = pid_t;

    impl<'a> TryIntoProcessHandle for &'a Child {
        fn try_into_process_handle(self) -> io::Result<ProcessHandle> {
            Ok(self.id() as pid_t)
        }
    }

    impl CopyAddress for Process {
        fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()> {
            let local_iov = iovec {
                iov_base: buf.as_mut_ptr() as *mut c_void,
                iov_len: buf.len(),
            };
            let remote_iov = iovec {
                iov_base: addr as *mut c_void,
                iov_len: buf.len(),
            };
            let result = unsafe {
                process_vm_readv(self.handle, &local_iov, 1, &remote_iov, 1, 0)
            };
            if result == -1 {
                Err(io::Error::last_os_error())
            } else {
                Ok(())
            }
        }
    }
}

#[cfg(target_os="macos")]
mod platform {
    extern crate mach;

    use libc::{pid_t, c_int};
    use self::mach::kern_return::{kern_return_t, KERN_SUCCESS};
    use self::mach::port::{mach_port_t, mach_port_name_t, MACH_PORT_NULL};
    use self::mach::vm_types::{mach_vm_address_t, mach_vm_size_t};
    use self::mach::message::{mach_msg_type_number_t};
    use std::io;
    use std::ptr;
    use std::slice;

    use super::{CopyAddress, Process, TryIntoProcessHandle};

    #[allow(non_camel_case_types)] type vm_map_t = mach_port_t;
    #[allow(non_camel_case_types)] type vm_address_t = mach_vm_address_t;
    #[allow(non_camel_case_types)] type vm_size_t = mach_vm_size_t;

    pub type Pid = pid_t;
    pub type ProcessHandle = mach_port_name_t;

    extern "C" {
        fn vm_read(target_task: vm_map_t, address: vm_address_t, size: vm_size_t, data: &*mut u8, data_size: *mut mach_msg_type_number_t) -> kern_return_t;
    }

    fn task_for_pid(pid: pid_t) -> io::Result<mach_port_name_t> {
        let mut task: mach_port_name_t = MACH_PORT_NULL;

        unsafe {
            let result = mach::traps::task_for_pid(mach::traps::mach_task_self(), pid as c_int, &mut task);
            if result != KERN_SUCCESS {
                return Err(io::Error::last_os_error())
            }
        }

        Ok(task)
    }

    /// `pid_t` can be turned into a `mach_port_name_t` with `task_for_pid`.
    impl TryIntoProcessHandle for pid_t {
        fn try_into_process_handle(self) -> io::Result<ProcessHandle> {
            task_for_pid(self)
        }
    }

    impl CopyAddress for Process {
        fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()> {
            let page_addr      = (addr as i64 & (-4096)) as mach_vm_address_t;
	    let last_page_addr = ((addr as i64 + buf.len() as i64 + 4095) & (-4096)) as mach_vm_address_t;
            let page_size      = last_page_addr as usize - page_addr as usize;

            let read_ptr: *mut u8 = ptr::null_mut();
            let mut read_len: mach_msg_type_number_t = 0;

            let result = unsafe {
                vm_read(self.handle, page_addr as u64, page_size as vm_size_t, &read_ptr, &mut read_len)
            };

            if result != KERN_SUCCESS {
                // panic!("({}) {:?}", result, io::Error::last_os_error());
                return Err(io::Error::last_os_error())
            }

            if read_len != page_size as u32 {
                panic!("Mismatched read sizes for `vm_read` (expected {}, got {})", page_size, read_len)
            }

            let read_buf = unsafe { slice::from_raw_parts(read_ptr, read_len as usize) };

            let offset = addr - page_addr as usize;
            let len = buf.len();
            buf.copy_from_slice(&read_buf[offset..(offset + len)]);

            Ok(())
        }
    }
}

#[cfg(windows)]
mod platform {
    extern crate winapi;
    extern crate kernel32;

    use std::io;
    use std::mem;
    use std::os::windows::io::{AsRawHandle, RawHandle};
    use std::process::Child;
    use std::ptr;

    use super::{CopyAddress, Process, TryIntoProcessHandle};

    pub type Pid = winapi::DWORD;
    pub type ProcessHandle = RawHandle;

    /// `DWORD` can be turned into a `HANDLE` with `OpenProcess`.
    impl TryIntoProcessHandle for winapi::DWORD {
        fn try_into_process_handle(self) -> io::Result<ProcessHandle> {
            let handle = unsafe { kernel32::OpenProcess(winapi::winnt::PROCESS_VM_READ, winapi::FALSE, self) };
            if handle == (0 as RawHandle) {
                Err(io::Error::last_os_error())
            } else {
                Ok(handle)
            }
        }
    }

    impl<'a> TryIntoProcessHandle for &'a Child {
        fn try_into_process_handle(self) -> io::Result<ProcessHandle> {
            Ok(self.as_raw_handle())
        }
    }

    impl CopyAddress for Process {
        fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()> {
            if buf.len() == 0 {
                return Ok(());
            }

            if unsafe { kernel32::ReadProcessMemory(self.handle,
                                                    addr as winapi::LPVOID,
                                                    buf.as_mut_ptr() as winapi::LPVOID,
                                                    mem::size_of_val(buf) as winapi::SIZE_T,
                                                    ptr::null_mut()) } == winapi::FALSE
            {
                Err(io::Error::last_os_error())
            } else {
                Ok(())
            }
        }
    }
}

pub fn copy_address_raw<T>(addr: usize, length: usize, source: &T) -> io::Result<Vec<u8>>
    where T: CopyAddress
{
    debug!("copy_address_raw: addr: {:x}", addr);

    let mut copy = vec![0; length];

    source.copy_address(addr, &mut copy)
        .map_err(|e| {
            warn!("copy_address failed for {:x}: {:?}", addr, e);
            e
        })
        .and(Ok(copy))
}

//TODO: make the tests work on OS X by sending task rights:
// http://www.foldr.org/~michaelw/log/computers/macosx/task-info-fun-with-mach
#[cfg(test)]
#[cfg(not(target_os="macos"))]
mod test {
    use super::*;
    use std::env;
    use std::io::{self, BufRead, BufReader};
    use std::path::PathBuf;
    use std::process::{Command, Stdio};

    fn test_process_path() -> io::Result<PathBuf> {
        env::current_exe().map(|mut p| { p.set_file_name("test"); p })
    }

    #[test]
    fn read_test_process() {
        let child = Command::new(test_process_path().unwrap())
            .stdout(Stdio::piped())
            .spawn().unwrap();
        let p = Process::new(&child).unwrap();
        // The test program prints the address and size.
        let reader = BufReader::new(child.stdout.unwrap());
        let line = reader.lines().next().unwrap().unwrap();
        let bits = line.split(' ').collect::<Vec<_>>();
        let addr = usize::from_str_radix(&bits[0][2..], 16).unwrap();
        let size = bits[1].parse::<usize>().unwrap();
        let mem = copy_address_raw(addr, size, &p).unwrap();
        assert_eq!(mem, (0..32u8).collect::<Vec<u8>>());
    }
}
<|endoftext|>


<commit_before>mod key;
mod rangeset;

use key::Key;
use rangeset::{Range, RangeSet};
use std::collections::HashMap;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct VKeyMarker;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct EKeyMarker;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct FKeyMarker;
pub type VKey = Key<VKeyMarker>;
pub type EKey = Key<EKeyMarker>;
pub type FKey = Key<FKeyMarker>;
pub type FaceLen = u32;

/// Editable mesh with persistent adjacency data. Modeled loosely
/// after Blender's BMesh:
///
/// http://wiki.blender.org/index.php/Dev:2.6/Source/Modeling/BMesh/Design
pub struct Mesh<VData, EData, FData> {
    verts: HashMap<VKey, Vert<VData>>,
    edges: HashMap<EKey, Edge<EData>>,
    faces: HashMap<FKey, Face<FData>>,

    vert_range_set: RangeSet,
    edge_range_set: RangeSet,
    face_range_set: RangeSet
}

// TODO
fn new_key_range_set() -> RangeSet {
    RangeSet::new(Range::new(0, 0xffffffff - 1))
}

impl<VData: Clone, EData: Clone, FData: Clone> Mesh<VData, EData, FData> {
    pub fn new() -> Mesh<VData, EData, FData> {
        Mesh {
            verts: HashMap::new(),
            edges: HashMap::new(),
            faces: HashMap::new(),

            vert_range_set: new_key_range_set(),
            edge_range_set: new_key_range_set(),
            face_range_set: new_key_range_set()
        }
    }

    /// Return the edge between two verts, or None if no such edge
    /// exists.
    pub fn find_edge(&self, vk0: VKey, vk1: VKey) -> Option<EKey> {
        for ek in self.verts[&vk0].edges.iter() {
            if self.edges[ek].is_vert_adjacent(vk1) {
                return Some(*ek)
            }
        }
        None
    }

    /// Get all faces adjacent to the specified vertex. The order is
    /// arbitrary.
    pub fn vert_adjacent_faces(&self, vk: VKey) -> Vec<FKey> {
        let mut adj = Vec::new();
        for ek in self.verts[&vk].edges.iter() {
            for fk in self.edges[ek].faces.iter() {
                if !adj.contains(fk) {
                    adj.push(*fk);
                }
            }
        }
        adj
    }

    /// Add a new isolated vertex and return its key. Fail and return
    /// None if there are no more vertex keys available.
    pub fn add_vert(&mut self, vdata: VData) -> Option<VKey> {
        if let Some(val) = self.vert_range_set.take_any_one() {
            let vkey = VKey::new(val);
            self.verts.insert(vkey, Vert::new(vdata));
            Some(vkey)
        } else {
            None
        }
    }

    pub fn add_edge(&mut self, vk0: VKey, vk1: VKey, edata: EData) -> Option<EKey> {
        // TODO(nicholasbishop): check that the verts are in the mesh,
        if vk0 == vk1 {
            None
        } else if let Some(ek) = self.find_edge(vk0, vk1) {
            Some(ek)
        } else {
            if let Some(val) = self.edge_range_set.take_any_one() {
                let ekey = EKey::new(val);
                self.verts.get_mut(&vk0).unwrap().push_edge(ekey);
                self.verts.get_mut(&vk1).unwrap().push_edge(ekey);
                self.edges.insert(ekey, Edge::new(vk0, vk1, edata));
                Some(ekey)
            } else {
                None
            }
        }
    }

    pub fn add_face(&mut self, vk: &[VKey], edata: EData, fdata: FData) -> Option<FKey> {
        let mut loops = Vec::with_capacity(vk.len());
        for i in 0..vk.len() {
            let vk0 = vk[i];
            let vk1 = vk[if i < (vk.len() - 1) { i + 1 } else { 0 }];
            // TODO(nicholasbishop): do more checking up front so that
            // edges don't get created on failure, or delete them after.
            if let Some(ek) = self.add_edge(vk0, vk1, edata.clone()) {
                loops.push(Loop { vert: vk0, edge: ek });
            } else {
                // Error: failed to create edge
                return None;
            }
        }
        if let Some(val) = self.face_range_set.take_any_one() {
            let fk = FKey::new(val);
            for lp in loops.iter() {
                self.edges.get_mut(&lp.edge).unwrap().push_face(fk);
            }
            self.faces.insert(fk, Face::new(loops, fdata));
            Some(fk)
        } else {
            None
        }
    }
}

pub struct Vert<VData> {
    vdata: VData,
    edges: Vec<EKey>
}

impl<VData> Vert<VData> {
    fn new(vdata: VData) -> Vert<VData> {
        Vert { vdata: vdata, edges: Vec::new() }
    }

    /// Check if the edge is in the set of edges adjacent to this vert.
    pub fn is_edge_adjacent(&self, ek: EKey) -> bool {
        self.edges.contains(&ek)
    }

    /// Add edge to set of edges adjacent to the vert. Does nothing if
    /// the edge is already in the set.
    fn push_edge(&mut self, ek: EKey) {
        if !self.is_edge_adjacent(ek) {
            self.edges.push(ek);
        }
    }
}

pub struct Edge<EData> {
    edata: EData,
    verts: [VKey; 2],
    faces: Vec<FKey>
}

impl<EData> Edge<EData> {
    fn new(vk0: VKey, vk1: VKey, edata: EData) -> Edge<EData> {
        Edge { edata: edata, verts: [vk0, vk1], faces: Vec::new() }
    }

    /// Check if the vert is one of the two verts adjacent to this edge.
    fn is_vert_adjacent(&self, vk: VKey) -> bool {
        self.verts.contains(&vk)
    }

    /// Check if the face is in the set of edges adjacent to this edge.
    pub fn is_face_adjacent(&self, fk: FKey) -> bool {
        self.faces.contains(&fk)
    }

    /// Add face to set of faces adjacent to the edge. Does nothing if
    /// the face is already in the set.
    fn push_face(&mut self, fk: FKey) {
        if !self.is_face_adjacent(fk) {
            self.faces.push(fk);
        }
    }
}

pub struct Loop {
    vert: VKey,
    edge: EKey,
}

pub struct Face<FData> {
    fdata: FData,
    loops: Vec<Loop>
}

impl<FData> Face<FData> {
    fn new(loops: Vec<Loop>, fdata: FData) -> Face<FData> {
        Face { fdata: fdata, loops: loops }
    }
}

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

    // Placeholder for vert/edge/face data
    const DAT: () = ();

    #[test]
    fn test_add_vert() {
        let mut mesh = Mesh::<_, (), ()>::new();
        assert!(mesh.add_vert(DAT).is_some());
        assert!(!mesh.verts.is_empty());
    }

    #[test]
    fn test_add_edge() {
        let mut mesh = Mesh::<_, _, ()>::new();
        let a = mesh.add_vert(DAT).unwrap();
        let b = mesh.add_vert(DAT).unwrap();

        // Add a valid edge
        let e = mesh.add_edge(a, b, DAT).unwrap();
        assert!(mesh.verts[&a].edges.contains(&e));
        assert!(mesh.verts[&b].edges.contains(&e));

        // Edge from a vertex to the same vertex is not allowed
        assert!(mesh.add_edge(a, a, DAT).is_none());

        // Duplicate edge should return the existing edge
        assert_eq!(mesh.add_edge(a, b, DAT).unwrap(), e);
        assert_eq!(mesh.add_edge(b, a, DAT).unwrap(), e);
    }

    #[test]
    fn test_add_face() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert(DAT).unwrap();
        let b = mesh.add_vert(DAT).unwrap();
        let c = mesh.add_vert(DAT).unwrap();

        // Add a valid triangle
        let fk = mesh.add_face(&[a, b, c], DAT, DAT).unwrap();
        assert_eq!(mesh.edges.len(), 3);
        for lp in mesh.faces[&fk].loops.iter() {
            assert!(mesh.edges[&lp.edge].is_face_adjacent(fk));
        }

        // Add an invalid triangle with invalid edge
        assert!(mesh.add_face(&[a, b, b], DAT, DAT).is_none());
    }

    #[test]
    fn test_vert_adjacent_faces() {
        // Create a bow-tie mesh
        let mut mesh = Mesh::new();
        let middle = mesh.add_vert(DAT).unwrap();
        let l0 = mesh.add_vert(DAT).unwrap();
        let l1 = mesh.add_vert(DAT).unwrap();
        let r0 = mesh.add_vert(DAT).unwrap();
        let r1 = mesh.add_vert(DAT).unwrap();
        let fk0 = mesh.add_face(&[middle, l0, l1], DAT, DAT).unwrap();
        let fk1 = mesh.add_face(&[middle, r0, r1], DAT, DAT).unwrap();

        let adj = mesh.vert_adjacent_faces(middle);
        assert_eq!(adj.len(), 2);
        assert!(adj.contains(&fk0));
        assert!(adj.contains(&fk1));
    }
}
<commit_msg>Add ngon test<commit_after>mod key;
mod rangeset;

use key::Key;
use rangeset::{Range, RangeSet};
use std::collections::HashMap;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct VKeyMarker;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct EKeyMarker;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct FKeyMarker;
pub type VKey = Key<VKeyMarker>;
pub type EKey = Key<EKeyMarker>;
pub type FKey = Key<FKeyMarker>;
pub type FaceLen = u32;

/// Editable mesh with persistent adjacency data. Modeled loosely
/// after Blender's BMesh:
///
/// http://wiki.blender.org/index.php/Dev:2.6/Source/Modeling/BMesh/Design
pub struct Mesh<VData, EData, FData> {
    verts: HashMap<VKey, Vert<VData>>,
    edges: HashMap<EKey, Edge<EData>>,
    faces: HashMap<FKey, Face<FData>>,

    vert_range_set: RangeSet,
    edge_range_set: RangeSet,
    face_range_set: RangeSet
}

// TODO
fn new_key_range_set() -> RangeSet {
    RangeSet::new(Range::new(0, 0xffffffff - 1))
}

impl<VData: Clone, EData: Clone, FData: Clone> Mesh<VData, EData, FData> {
    pub fn new() -> Mesh<VData, EData, FData> {
        Mesh {
            verts: HashMap::new(),
            edges: HashMap::new(),
            faces: HashMap::new(),

            vert_range_set: new_key_range_set(),
            edge_range_set: new_key_range_set(),
            face_range_set: new_key_range_set()
        }
    }

    /// Return the edge between two verts, or None if no such edge
    /// exists.
    pub fn find_edge(&self, vk0: VKey, vk1: VKey) -> Option<EKey> {
        for ek in self.verts[&vk0].edges.iter() {
            if self.edges[ek].is_vert_adjacent(vk1) {
                return Some(*ek)
            }
        }
        None
    }

    /// Get all faces adjacent to the specified vertex. The order is
    /// arbitrary.
    pub fn vert_adjacent_faces(&self, vk: VKey) -> Vec<FKey> {
        let mut adj = Vec::new();
        for ek in self.verts[&vk].edges.iter() {
            for fk in self.edges[ek].faces.iter() {
                if !adj.contains(fk) {
                    adj.push(*fk);
                }
            }
        }
        adj
    }

    /// Add a new isolated vertex and return its key. Fail and return
    /// None if there are no more vertex keys available.
    pub fn add_vert(&mut self, vdata: VData) -> Option<VKey> {
        if let Some(val) = self.vert_range_set.take_any_one() {
            let vkey = VKey::new(val);
            self.verts.insert(vkey, Vert::new(vdata));
            Some(vkey)
        } else {
            None
        }
    }

    pub fn add_edge(&mut self, vk0: VKey, vk1: VKey, edata: EData) -> Option<EKey> {
        // TODO(nicholasbishop): check that the verts are in the mesh,
        if vk0 == vk1 {
            None
        } else if let Some(ek) = self.find_edge(vk0, vk1) {
            Some(ek)
        } else {
            if let Some(val) = self.edge_range_set.take_any_one() {
                let ekey = EKey::new(val);
                self.verts.get_mut(&vk0).unwrap().push_edge(ekey);
                self.verts.get_mut(&vk1).unwrap().push_edge(ekey);
                self.edges.insert(ekey, Edge::new(vk0, vk1, edata));
                Some(ekey)
            } else {
                None
            }
        }
    }

    pub fn add_face(&mut self, vk: &[VKey], edata: EData, fdata: FData) -> Option<FKey> {
        let mut loops = Vec::with_capacity(vk.len());
        for i in 0..vk.len() {
            let vk0 = vk[i];
            let vk1 = vk[if i < (vk.len() - 1) { i + 1 } else { 0 }];
            // TODO(nicholasbishop): do more checking up front so that
            // edges don't get created on failure, or delete them after.
            if let Some(ek) = self.add_edge(vk0, vk1, edata.clone()) {
                loops.push(Loop { vert: vk0, edge: ek });
            } else {
                // Error: failed to create edge
                return None;
            }
        }
        if let Some(val) = self.face_range_set.take_any_one() {
            let fk = FKey::new(val);
            for lp in loops.iter() {
                self.edges.get_mut(&lp.edge).unwrap().push_face(fk);
            }
            self.faces.insert(fk, Face::new(loops, fdata));
            Some(fk)
        } else {
            None
        }
    }
}

pub struct Vert<VData> {
    vdata: VData,
    edges: Vec<EKey>
}

impl<VData> Vert<VData> {
    fn new(vdata: VData) -> Vert<VData> {
        Vert { vdata: vdata, edges: Vec::new() }
    }

    /// Check if the edge is in the set of edges adjacent to this vert.
    pub fn is_edge_adjacent(&self, ek: EKey) -> bool {
        self.edges.contains(&ek)
    }

    /// Add edge to set of edges adjacent to the vert. Does nothing if
    /// the edge is already in the set.
    fn push_edge(&mut self, ek: EKey) {
        if !self.is_edge_adjacent(ek) {
            self.edges.push(ek);
        }
    }
}

pub struct Edge<EData> {
    edata: EData,
    verts: [VKey; 2],
    faces: Vec<FKey>
}

impl<EData> Edge<EData> {
    fn new(vk0: VKey, vk1: VKey, edata: EData) -> Edge<EData> {
        Edge { edata: edata, verts: [vk0, vk1], faces: Vec::new() }
    }

    /// Check if the vert is one of the two verts adjacent to this edge.
    fn is_vert_adjacent(&self, vk: VKey) -> bool {
        self.verts.contains(&vk)
    }

    /// Check if the face is in the set of edges adjacent to this edge.
    pub fn is_face_adjacent(&self, fk: FKey) -> bool {
        self.faces.contains(&fk)
    }

    /// Add face to set of faces adjacent to the edge. Does nothing if
    /// the face is already in the set.
    fn push_face(&mut self, fk: FKey) {
        if !self.is_face_adjacent(fk) {
            self.faces.push(fk);
        }
    }
}

pub struct Loop {
    vert: VKey,
    edge: EKey,
}

pub struct Face<FData> {
    fdata: FData,
    loops: Vec<Loop>
}

impl<FData> Face<FData> {
    fn new(loops: Vec<Loop>, fdata: FData) -> Face<FData> {
        Face { fdata: fdata, loops: loops }
    }
}

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

    // Placeholder for vert/edge/face data
    const DAT: () = ();

    #[test]
    fn test_add_vert() {
        let mut mesh = Mesh::<_, (), ()>::new();
        assert!(mesh.add_vert(DAT).is_some());
        assert!(!mesh.verts.is_empty());
    }

    #[test]
    fn test_add_edge() {
        let mut mesh = Mesh::<_, _, ()>::new();
        let a = mesh.add_vert(DAT).unwrap();
        let b = mesh.add_vert(DAT).unwrap();

        // Add a valid edge
        let e = mesh.add_edge(a, b, DAT).unwrap();
        assert!(mesh.verts[&a].edges.contains(&e));
        assert!(mesh.verts[&b].edges.contains(&e));

        // Edge from a vertex to the same vertex is not allowed
        assert!(mesh.add_edge(a, a, DAT).is_none());

        // Duplicate edge should return the existing edge
        assert_eq!(mesh.add_edge(a, b, DAT).unwrap(), e);
        assert_eq!(mesh.add_edge(b, a, DAT).unwrap(), e);
    }

    #[test]
    fn test_add_face() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert(DAT).unwrap();
        let b = mesh.add_vert(DAT).unwrap();
        let c = mesh.add_vert(DAT).unwrap();

        // Add a valid triangle
        let fk = mesh.add_face(&[a, b, c], DAT, DAT).unwrap();
        assert_eq!(mesh.edges.len(), 3);
        for lp in mesh.faces[&fk].loops.iter() {
            assert!(mesh.edges[&lp.edge].is_face_adjacent(fk));
        }

        // Add an invalid triangle with invalid edge
        assert!(mesh.add_face(&[a, b, b], DAT, DAT).is_none());
    }

    #[test]
    fn test_vert_adjacent_faces() {
        // Create a bow-tie mesh
        let mut mesh = Mesh::new();
        let middle = mesh.add_vert(DAT).unwrap();
        let l0 = mesh.add_vert(DAT).unwrap();
        let l1 = mesh.add_vert(DAT).unwrap();
        let r0 = mesh.add_vert(DAT).unwrap();
        let r1 = mesh.add_vert(DAT).unwrap();
        let fk0 = mesh.add_face(&[middle, l0, l1], DAT, DAT).unwrap();
        let fk1 = mesh.add_face(&[middle, r0, r1], DAT, DAT).unwrap();

        let adj = mesh.vert_adjacent_faces(middle);
        assert_eq!(adj.len(), 2);
        assert!(adj.contains(&fk0));
        assert!(adj.contains(&fk1));
    }

    #[test]
    fn test_ngon() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert(DAT).unwrap();
        let b = mesh.add_vert(DAT).unwrap();
        let c = mesh.add_vert(DAT).unwrap();
        let d = mesh.add_vert(DAT).unwrap();
        let e = mesh.add_vert(DAT).unwrap();

        let fk = mesh.add_face(&[a, b, c, d, e], DAT, DAT).unwrap();
        let face = &mesh.faces[&fk];

        assert_eq!(face.loops.len(), 5);
    }
}
<|endoftext|>


<commit_before>//! Collection traits for generic programming.
//!
//! Code that uses these traits should use them as generally as possible. For example, consider the
//! following function that fills a map with default values for some keys:
//!
//! ```
//! use eclectic::map::*;
//!
//! fn fill<M, K>(keys: K) -> M
//! where
//!     M: Default + Map,
//!     K: IntoIterator<Item = M::Key>,
//!     M::Value: Default,
//! {
//!     let mut map = M::default();
//!     for key in keys { map.insert(key, M::Value::default()); }
//!     map
//! }
//! ```
//!
//! `Map` is a convenient shorthand for code that uses multiple map APIs, but this code only ever
//! calls `insert`, so it could be rewritten more generally as:
//!
//! ```
//! use eclectic::map;
//!
//! fn fill<M, K>(keys: K) -> M
//! where
//!     M: Default + map::Insert,
//!     K: IntoIterator<Item = M::Key>,
//!     M::Value: Default,
//! {
//!     let mut map = M::default();
//!     for key in keys { map.insert(key, M::Value::default()); }
//!     map
//! }
//! ```

mod std_impls;

/// A collection that contains a finite number of items.
pub trait Len {
    /// Checks if the collection is empty.
    fn is_empty(&self) -> bool { self.len() == 0 }

    /// Returns the number of items in the collection.
    fn len(&self) -> usize;
}

/// A collection that can be cleared.
pub trait Clear {
    /// Removes all items from the collection.
    fn clear(&mut self);
}

pub mod map {
    //! Maps.
    //!
    //! A map is a collection that associates keys with corresponding values, where the keys are
    //! distinguished according to some uniqueness criteria.

    use super::*;

    /// A trait that declares a map's key and value types.
    ///
    /// It is unusual to bound a type by this trait directly.
    pub trait Base {
        /// The map's key type.
        type Key;

        /// The map's value type.
        type Value;
    }

    /// A map that supports lookups using keys of type `&Q`.
    pub trait Get<Q: ?Sized>: Base {
        /// Checks if the map contains the given key.
        fn contains_key(&self, key: &Q) -> bool { self.get(key).is_some() }

        /// Returns a reference to the value in the map corresponding to the given key.
        fn get(&self, key: &Q) -> Option<&Self::Value>;
    }

    /// A map that supports mutable lookups using keys of type `&Q`.
    pub trait GetMut<Q: ?Sized>: Get<Q> {
        /// Returns a mutable reference to the value in the map corresponding to the given key.
        fn get_mut(&mut self, key: &Q) -> Option<&mut Self::Value>;
    }

    /// A map that supports removals using keys of type `&Q`.
    pub trait Remove<Q: ?Sized>: GetMut<Q> {
        /// Removes the given key from the map and returns its corresponding value, if any.
        fn remove(&mut self, key: &Q) -> Option<Self::Value>;
    }

    /// A map that supports insertion.
    pub trait Insert: Base + Extend<(<Self as Base>::Key, <Self as Base>::Value)> {
        /// Inserts the given key and value into the map and returns the previous value
        /// corresponding to the given key, if any.
        // TODO: document replacement requirements
        fn insert(&mut self, key: Self::Key, value: Self::Value) -> Option<Self::Value>;
    }

    /// A map.
    ///
    /// This trait is implemented for all types that implement `{Len, Clear, Insert, Remove}`.
    pub trait Map: Len + Clear + Insert + Remove<<Self as Base>::Key> {}

    impl<M: ?Sized> Map for M where M: Len + Clear + Insert + Remove<<M as Base>::Key> {}

    /// A map that supports efficient in-place manipulation.
    ///
    /// `'a` is the lifetime of the map.
    pub trait EntryMap<'a>: Base where
        <Self as Base>::Key: 'a,
        <Self as Base>::Value: 'a,
    {
        /// The type of the map's occupied entries.
        type OccupiedEntry: OccupiedEntry<'a, Key = Self::Key, Value = Self::Value>;

        /// The type of the map's vacant entries.
        type VacantEntry: VacantEntry<'a, Key = Self::Key, Value = Self::Value>;

        /// Returns the entry in the map corresponding to the given key.
        fn entry(&'a mut self, key: Self::Key) -> Entry<Self::OccupiedEntry, Self::VacantEntry>;
    }

    /// An occupied map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait OccupiedEntry<'a> {
        /// The type of the map's keys.
        type Key: 'a;

        /// The type of the map's values.
        type Value: 'a;

        /// Returns a reference to the entry's value.
        fn get(&self) -> &Self::Value;

        /// Returns a mutable reference to the entry's value.
        fn get_mut(&mut self) -> &mut Self::Value;

        /// Returns a mutable reference to the entry's value with the same lifetime as the map.
        fn into_mut(self) -> &'a mut Self::Value;

        /// Replaces the entry's value with the given one and returns the old value.
        fn insert(&mut self, value: Self::Value) -> Self::Value {
            ::std::mem::replace(self.get_mut(), value)
        }

        /// Removes the entry from the map and returns its value.
        fn remove(self) -> Self::Value;
    }

    /// A vacant map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait VacantEntry<'a> {
        /// The type of the map's keys.
        type Key: 'a;

        /// The type of the map's values.
        type Value: 'a;

        /// Inserts the entry into the map with the given value and returns a mutable reference to
        /// it with the same lifetime as the map.
        fn insert(self, value: Self::Value) -> &'a mut Self::Value;
    }

    /// A map entry.
    #[derive(Debug)]
    pub enum Entry<OE, VE> {
        /// An occupied map entry.
        Occupied(OE),
        /// A vacant map entry.
        Vacant(VE),
    }

    impl<'a, OE, VE> Entry<OE, VE>
    where
        OE: OccupiedEntry<'a>,
        VE: VacantEntry<'a, Value = OE::Value>,
    {
        /// Ensures the entry is occupied by inserting it with the given default value if it is
        /// vacant.
        pub fn or_insert(self, default: VE::Value) -> &'a mut OE::Value {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(default),
            }
        }

        /// Ensures the entry is occupied by inserting it with the result of the given function if
        /// it is vacant.
        pub fn or_insert_with<F>(self, f: F) -> &'a mut OE::Value where F: FnOnce() -> VE::Value {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(f()),
            }
        }
    }

    #[cfg(test)]
    pub fn count<M, I>(items: I) -> M
    where
        M: Default + for<'a> map::EntryMap<'a, Value = usize>,
        I: IntoIterator<Item = M::Key>,
    {
        let mut map = M::default();
        for item in items { *map.entry(item).or_insert(0) += 1; }
        map
    }
}

pub mod set {
    //! Sets.
    //!
    //! A set is a collection whose items are distinguished according to some uniqueness criteria.

    use super::*;

    /// A trait that declares a set's item type.
    ///
    /// It is unusual to bound a type by this trait directly.
    pub trait Base {
        type Item;
    }

    /// A set that supports lookups using items of type `&Q`.
    pub trait Contains<Q: ?Sized>: Base {
        /// Checks if the set contains the given item.
        fn contains(&self, item: &Q) -> bool;
    }

    /// A set that supports removals using items of type `&Q`.
    pub trait Remove<Q: ?Sized>: Contains<Q> {
        /// Removes the given item from the set and returns `true` if the set contained it.
        fn remove(&mut self, item: &Q) -> bool;
    }

    /// A set that supports insertion.
    pub trait Insert: Base + Extend<<Self as Base>::Item> {
        /// Inserts the given item into the set and returns `true` if the set did not contain it.
        // TODO: document replacement requirements
        fn insert(&mut self, item: Self::Item) -> bool;
    }

    /// A set.
    ///
    /// This trait is implemented for all types that implement `{Len, Clear, Insert, Remove}`.
    pub trait Set: Len + Clear + Insert + Remove<<Self as Base>::Item> {}

    impl<S: ?Sized> Set for S where S: Len + Clear + Insert + Remove<<S as Base>::Item> {}
}
<commit_msg>Default lookup traits' key type parameter to the base trait's<commit_after>//! Collection traits for generic programming.
//!
//! Code that uses these traits should use them as generally as possible. For example, consider the
//! following function that fills a map with default values for some keys:
//!
//! ```
//! use eclectic::map::*;
//!
//! fn fill<M, K>(keys: K) -> M
//! where
//!     M: Default + Map,
//!     K: IntoIterator<Item = M::Key>,
//!     M::Value: Default,
//! {
//!     let mut map = M::default();
//!     for key in keys { map.insert(key, M::Value::default()); }
//!     map
//! }
//! ```
//!
//! `Map` is a convenient shorthand for code that uses multiple map APIs, but this code only ever
//! calls `insert`, so it could be rewritten more generally as:
//!
//! ```
//! use eclectic::map;
//!
//! fn fill<M, K>(keys: K) -> M
//! where
//!     M: Default + map::Insert,
//!     K: IntoIterator<Item = M::Key>,
//!     M::Value: Default,
//! {
//!     let mut map = M::default();
//!     for key in keys { map.insert(key, M::Value::default()); }
//!     map
//! }
//! ```

mod std_impls;

/// A collection that contains a finite number of items.
pub trait Len {
    /// Checks if the collection is empty.
    fn is_empty(&self) -> bool { self.len() == 0 }

    /// Returns the number of items in the collection.
    fn len(&self) -> usize;
}

/// A collection that can be cleared.
pub trait Clear {
    /// Removes all items from the collection.
    fn clear(&mut self);
}

pub mod map {
    //! Maps.
    //!
    //! A map is a collection that associates keys with corresponding values, where the keys are
    //! distinguished according to some uniqueness criteria.

    use super::*;

    /// A trait that declares a map's key and value types.
    ///
    /// It is unusual to bound a type by this trait directly.
    pub trait Base {
        /// The map's key type.
        type Key;

        /// The map's value type.
        type Value;
    }

    /// A map that supports lookups using keys of type `&Q`.
    pub trait Get<Q: ?Sized = <Self as Base>::Key>: Base {
        /// Checks if the map contains the given key.
        fn contains_key(&self, key: &Q) -> bool { self.get(key).is_some() }

        /// Returns a reference to the value in the map corresponding to the given key.
        fn get(&self, key: &Q) -> Option<&Self::Value>;
    }

    /// A map that supports mutable lookups using keys of type `&Q`.
    pub trait GetMut<Q: ?Sized = <Self as Base>::Key>: Get<Q> {
        /// Returns a mutable reference to the value in the map corresponding to the given key.
        fn get_mut(&mut self, key: &Q) -> Option<&mut Self::Value>;
    }

    /// A map that supports removals using keys of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Base>::Key>: GetMut<Q> {
        /// Removes the given key from the map and returns its corresponding value, if any.
        fn remove(&mut self, key: &Q) -> Option<Self::Value>;
    }

    /// A map that supports insertion.
    pub trait Insert: Base + Extend<(<Self as Base>::Key, <Self as Base>::Value)> {
        /// Inserts the given key and value into the map and returns the previous value
        /// corresponding to the given key, if any.
        // TODO: document replacement requirements
        fn insert(&mut self, key: Self::Key, value: Self::Value) -> Option<Self::Value>;
    }

    /// A map.
    ///
    /// This trait is implemented for all types that implement `{Len, Clear, Insert, Remove}`.
    pub trait Map: Len + Clear + Insert + Remove {}

    impl<M: ?Sized> Map for M where M: Len + Clear + Insert + Remove {}

    /// A map that supports efficient in-place manipulation.
    ///
    /// `'a` is the lifetime of the map.
    pub trait EntryMap<'a>: Base where
        <Self as Base>::Key: 'a,
        <Self as Base>::Value: 'a,
    {
        /// The type of the map's occupied entries.
        type OccupiedEntry: OccupiedEntry<'a, Key = Self::Key, Value = Self::Value>;

        /// The type of the map's vacant entries.
        type VacantEntry: VacantEntry<'a, Key = Self::Key, Value = Self::Value>;

        /// Returns the entry in the map corresponding to the given key.
        fn entry(&'a mut self, key: Self::Key) -> Entry<Self::OccupiedEntry, Self::VacantEntry>;
    }

    /// An occupied map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait OccupiedEntry<'a> {
        /// The type of the map's keys.
        type Key: 'a;

        /// The type of the map's values.
        type Value: 'a;

        /// Returns a reference to the entry's value.
        fn get(&self) -> &Self::Value;

        /// Returns a mutable reference to the entry's value.
        fn get_mut(&mut self) -> &mut Self::Value;

        /// Returns a mutable reference to the entry's value with the same lifetime as the map.
        fn into_mut(self) -> &'a mut Self::Value;

        /// Replaces the entry's value with the given one and returns the old value.
        fn insert(&mut self, value: Self::Value) -> Self::Value {
            ::std::mem::replace(self.get_mut(), value)
        }

        /// Removes the entry from the map and returns its value.
        fn remove(self) -> Self::Value;
    }

    /// A vacant map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait VacantEntry<'a> {
        /// The type of the map's keys.
        type Key: 'a;

        /// The type of the map's values.
        type Value: 'a;

        /// Inserts the entry into the map with the given value and returns a mutable reference to
        /// it with the same lifetime as the map.
        fn insert(self, value: Self::Value) -> &'a mut Self::Value;
    }

    /// A map entry.
    #[derive(Debug)]
    pub enum Entry<OE, VE> {
        /// An occupied map entry.
        Occupied(OE),
        /// A vacant map entry.
        Vacant(VE),
    }

    impl<'a, OE, VE> Entry<OE, VE>
    where
        OE: OccupiedEntry<'a>,
        VE: VacantEntry<'a, Value = OE::Value>,
    {
        /// Ensures the entry is occupied by inserting it with the given default value if it is
        /// vacant.
        pub fn or_insert(self, default: VE::Value) -> &'a mut OE::Value {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(default),
            }
        }

        /// Ensures the entry is occupied by inserting it with the result of the given function if
        /// it is vacant.
        pub fn or_insert_with<F>(self, f: F) -> &'a mut OE::Value where F: FnOnce() -> VE::Value {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(f()),
            }
        }
    }

    #[cfg(test)]
    pub fn count<M, I>(items: I) -> M
    where
        M: Default + for<'a> map::EntryMap<'a, Value = usize>,
        I: IntoIterator<Item = M::Key>,
    {
        let mut map = M::default();
        for item in items { *map.entry(item).or_insert(0) += 1; }
        map
    }
}

pub mod set {
    //! Sets.
    //!
    //! A set is a collection whose items are distinguished according to some uniqueness criteria.

    use super::*;

    /// A trait that declares a set's item type.
    ///
    /// It is unusual to bound a type by this trait directly.
    pub trait Base {
        type Item;
    }

    /// A set that supports lookups using items of type `&Q`.
    pub trait Contains<Q: ?Sized = <Self as Base>::Item>: Base {
        /// Checks if the set contains the given item.
        fn contains(&self, item: &Q) -> bool;
    }

    /// A set that supports removals using items of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Base>::Item>: Contains<Q> {
        /// Removes the given item from the set and returns `true` if the set contained it.
        fn remove(&mut self, item: &Q) -> bool;
    }

    /// A set that supports insertion.
    pub trait Insert: Base + Extend<<Self as Base>::Item> {
        /// Inserts the given item into the set and returns `true` if the set did not contain it.
        // TODO: document replacement requirements
        fn insert(&mut self, item: Self::Item) -> bool;
    }

    /// A set.
    ///
    /// This trait is implemented for all types that implement `{Len, Clear, Insert, Remove}`.
    pub trait Set: Len + Clear + Insert + Remove {}

    impl<S: ?Sized> Set for S where S: Len + Clear + Insert + Remove {}
}
<|endoftext|>