<commit_before>//! This crate provide type for counting mutable borrow of a value. The `Bc<T>`
//! type is a small wrapper on top of a value of type `T` which count the number
//! of time the value has been mutably borrowed since it's creation.
//!
//! # Why?
//!
//! If you want to cache an expensive computation result, you need to have
//! information about wether the parameters of the computation have changed or
//! not. You can use a hash for that, but this have two shortcomings:
//!
//!  * You need to have values which implement the `Hash` trait. Some useful
//!    types like `f64` do not;
//!  * You need to have a cheap way to compute the hash.
//!
//! If computing the hash is harder or more expensive than doing the
//! computation, you are doomed. Or you can use `Bc<T>` which will give you
//! information about the number of borrow since the last computation. If this
//! number have changed, then it is very likely that the value have changed,
//! and that you need to redo your computation.
//!
//! # Limitations
//!
//! This can not be used a real hash algorithm, because the number of borrow can
//! change even if the value do not.
//!
//! If more than `usize::MAX` borrow occurs, the borrow counter will be wrapped
//! around to 0, and will not `panic` because of the overflow.
//!
//! # Performances
//!
//! The `Bc` type do not introduce notable overhead when borrowing. Here are the
//! benchmark results comparing a raw value and a borrow counted value:
//!
//! ```text
//! running 2 tests
//!    test counted ... bench:       1,061 ns/iter (+/- 12)
//!    test raw     ... bench:       1,059 ns/iter (+/- 16)
//! ```
//!
//! Using the number of borrow as hash value is way faster than doing the real
//! hash. Here is a benchmark for `[usize; 10000]` values:
//!
//! ```text
//! running 2 tests
//!    test counted ... bench:          22 ns/iter (+/- 1)
//!    test raw     ... bench:      49,011 ns/iter (+/- 755)
//! ```
//!
//! You can see the code for these benchmarks on [Github](https://github.com/Luthaf/bcount/tree/master/benches).
//!
//! # Example
//!
//! ```rust
//! extern crate bcount;
//! use bcount::Bc;
//!
//! fn main() {
//!     let mut a = Bc::new(vec![63, 67, 42]);
//!     assert_eq!(a.count(), 0);
//!
//!     do_work(&mut a);
//!     do_work(&mut a);
//!     do_work(&mut a);
//!     do_work(&mut a);
//!
//!     assert_eq!(a.count(), 4);
//!
//!     *a = vec![3, 4, 5];
//!     assert_eq!(a.count(), 5);
//! }
//!
//! fn do_work(_: &mut [usize]) {
//!     // Whatever, nobody cares
//! }
//!
//! ```

// TODO? Mbc (Mutable Borrow counter) & Cbc (*const* borrow counter) & Bc (*all* borrow counter)

#![deny(missing_docs)]
use std::ops::{Deref, DerefMut};

/// The borrow counter struct for type `T`.
pub struct Bc<T> {
    counter: usize,
    val: T
}

impl<T> Bc<T> {
    /// Create a new `Bc<T>` containing the value `val`.
    pub fn new(val: T) -> Bc<T> {
        Bc {
            val: val,
            counter: 0,
        }
    }

    /// Reset the borrow counter
    pub fn reset(&mut self) {
        self.counter = 0;
    }

    /// Get the number of time this structure has been mutably borrowed.
    pub fn count(&self) -> usize {
        self.counter
    }
}

impl<T> Deref for Bc<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.val
    }
}

impl<T> DerefMut for Bc<T> {
     fn deref_mut(&mut self) -> &mut T {
         self.counter = self.counter.wrapping_add(1);
         &mut self.val
     }
}

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

    fn do_nothing(_: &mut f64) {}

    #[test]
    fn count() {
        let mut a = Bc::new(5.0);
        assert_eq!(a.count(), 0);

        *a = 89.0;
        assert_eq!(a.count(), 1);

        do_nothing(&mut a);
        assert_eq!(a.count(), 2);
    }

    #[test]
    fn reset() {
        let mut a = Bc::new(3);

        assert_eq!(a.count(), 0);

        *a = 18;
        *a = 42;
        assert_eq!(a.count(), 2);

        a.reset();
        assert_eq!(a.count(), 0);
    }

    #[test]
    fn overflow() {
        let mut a = Bc::new(3);
        a.counter = usize::MAX - 1;

        *a = 18;
        *a = 18;
        assert_eq!(a.count(), 0);
    }
}
<commit_msg>Add a test for non mutable borrowing<commit_after>//! This crate provide type for counting mutable borrow of a value. The `Bc<T>`
//! type is a small wrapper on top of a value of type `T` which count the number
//! of time the value has been mutably borrowed since it's creation.
//!
//! # Why?
//!
//! If you want to cache an expensive computation result, you need to have
//! information about wether the parameters of the computation have changed or
//! not. You can use a hash for that, but this have two shortcomings:
//!
//!  * You need to have values which implement the `Hash` trait. Some useful
//!    types like `f64` do not;
//!  * You need to have a cheap way to compute the hash.
//!
//! If computing the hash is harder or more expensive than doing the
//! computation, you are doomed. Or you can use `Bc<T>` which will give you
//! information about the number of borrow since the last computation. If this
//! number have changed, then it is very likely that the value have changed,
//! and that you need to redo your computation.
//!
//! # Limitations
//!
//! This can not be used a real hash algorithm, because the number of borrow can
//! change even if the value do not.
//!
//! If more than `usize::MAX` borrow occurs, the borrow counter will be wrapped
//! around to 0, and will not `panic` because of the overflow.
//!
//! # Performances
//!
//! The `Bc` type do not introduce notable overhead when borrowing. Here are the
//! benchmark results comparing a raw value and a borrow counted value:
//!
//! ```text
//! running 2 tests
//!    test counted ... bench:       1,061 ns/iter (+/- 12)
//!    test raw     ... bench:       1,059 ns/iter (+/- 16)
//! ```
//!
//! Using the number of borrow as hash value is way faster than doing the real
//! hash. Here is a benchmark for `[usize; 10000]` values:
//!
//! ```text
//! running 2 tests
//!    test counted ... bench:          22 ns/iter (+/- 1)
//!    test raw     ... bench:      49,011 ns/iter (+/- 755)
//! ```
//!
//! You can see the code for these benchmarks on [Github](https://github.com/Luthaf/bcount/tree/master/benches).
//!
//! # Example
//!
//! ```rust
//! extern crate bcount;
//! use bcount::Bc;
//!
//! fn main() {
//!     let mut a = Bc::new(vec![63, 67, 42]);
//!     assert_eq!(a.count(), 0);
//!
//!     do_work(&mut a);
//!     do_work(&mut a);
//!     do_work(&mut a);
//!     do_work(&mut a);
//!
//!     assert_eq!(a.count(), 4);
//!
//!     *a = vec![3, 4, 5];
//!     assert_eq!(a.count(), 5);
//! }
//!
//! fn do_work(_: &mut [usize]) {
//!     // Whatever, nobody cares
//! }
//!
//! ```

// TODO? Mbc (Mutable Borrow counter) & Cbc (*const* borrow counter) & Bc (*all* borrow counter)

#![deny(missing_docs)]
use std::ops::{Deref, DerefMut};

/// The borrow counter struct for type `T`.
pub struct Bc<T> {
    counter: usize,
    val: T
}

impl<T> Bc<T> {
    /// Create a new `Bc<T>` containing the value `val`.
    pub fn new(val: T) -> Bc<T> {
        Bc {
            val: val,
            counter: 0,
        }
    }

    /// Reset the borrow counter
    pub fn reset(&mut self) {
        self.counter = 0;
    }

    /// Get the number of time this structure has been mutably borrowed.
    pub fn count(&self) -> usize {
        self.counter
    }
}

impl<T> Deref for Bc<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.val
    }
}

impl<T> DerefMut for Bc<T> {
     fn deref_mut(&mut self) -> &mut T {
         self.counter = self.counter.wrapping_add(1);
         &mut self.val
     }
}

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

    fn do_nothing(_: &mut f64) {}

    #[test]
    fn count() {
        let mut a = Bc::new(5.0);
        assert_eq!(a.count(), 0);

        *a = 89.0;
        assert_eq!(a.count(), 1);

        do_nothing(&mut a);
        assert_eq!(a.count(), 2);
    }

    #[test]
    fn reset() {
        let mut a = Bc::new(3);

        assert_eq!(a.count(), 0);

        *a = 18;
        *a = 42;
        assert_eq!(a.count(), 2);

        a.reset();
        assert_eq!(a.count(), 0);
    }

    #[test]
    fn overflow() {
        let mut a = Bc::new(3);
        a.counter = usize::MAX - 1;

        *a = 18;
        *a = 18;
        assert_eq!(a.count(), 0);
    }

    #[test]
    fn non_mutable() {
        fn observe(_: &f64) {/* Do nothing */}

        let a = Bc::new(3.0);
        assert_eq!(a.count(), 0);

        observe(&a);
        observe(&a);
        observe(&a);
        assert_eq!(a.count(), 0);
    }
}
<|endoftext|>


<commit_before>//! Ropey is a utf8 text rope for Rust.  It is fast, robust, and can handle
//! huge texts and memory-incoherent edits with ease.
//!
//! Ropey's atomic unit of text is Unicode scalar values (or `char`s in Rust)
//! encoded as utf8.  All of Ropey's editing and slicing operations are done
//! in terms of char indices which prevents accidental creation of invalid
//! utf8 data.
//!
//! The library is made up of four main components:
//!
//! - [`Rope`]: the main rope type.
//! - [`RopeSlice`]: an immutable view into part of a
//!   `Rope`.
//! - [`iter`]: iterators over `Rope`/`RopeSlice` data.
//! - [`RopeBuilder`]: an efficient incremental
//!   `Rope` builder.
//!
//!
//! # A Basic Example
//!
//! Let's say we want to open up a text file, replace the 516th line (the
//! writing was terrible!), and save it back to disk.  It's contrived, but will
//! give a good sampling of the APIs and how they work together.
//!
//! ```no_run
//! # use std::io::Result;
//! use std::fs::File;
//! use std::io::{BufReader, BufWriter};
//! use ropey::Rope;
//!
//! # fn do_stuff() -> Result<()> {
//! // Load a text file.
//! let mut text = Rope::from_reader(
//!     BufReader::new(File::open("my_great_book.txt")?)
//! )?;
//!
//! // Print the 516th line (zero-indexed) to see the terrible
//! // writing.
//! println!("{}", text.line(515));
//!
//! // Get the start/end char indices of the line.
//! let start_idx = text.line_to_char(515);
//! let end_idx = text.line_to_char(516);
//!
//! // Remove the line...
//! text.remove(start_idx..end_idx);
//!
//! // ...and replace it with something better.
//! text.insert(start_idx, "The flowers are... so... dunno.\n");
//!
//! // Print the changes, along with the previous few lines for context.
//! let start_idx = text.line_to_char(511);
//! let end_idx = text.line_to_char(516);
//! println!("{}", text.slice(start_idx..end_idx));
//!
//! // Write the file back out to disk.
//! text.write_to(
//!     BufWriter::new(File::create("my_great_book.txt")?)
//! )?;
//! # Ok(())
//! # }
//! # do_stuff().unwrap();
//! ```
//!
//! More examples can be found in the `examples` directory of the git
//! repository.  Many of those examples demonstrate doing non-trivial things
//! with Ropey such as grapheme handling, search-and-replace, and streaming
//! loading of non-utf8 text files.
//!
//!
//! # Low-level APIs
//!
//! Ropey also provides access to some of its low-level APIs, enabling client
//! code to efficiently work with a `Rope`'s data and implement new
//! functionality.  The most important of those API's are:
//!
//! - The [`chunk_at_*()`](Rope::chunk_at_byte)
//!   chunk-fetching methods of `Rope` and `RopeSlice`.
//! - The [`Chunks`](iter::Chunks) iterator.
//! - The functions in [`str_utils`] for operating on
//!   `&str` slices.
//!
//! Internally, each `Rope` stores text as a segemented collection of utf8
//! strings.  The chunk-fetching methods and `Chunks` iterator provide direct
//! access to those strings (or "chunks") as `&str` slices, allowing client
//! code to work directly with the underlying utf8 data.
//!
//! The chunk-fetching methods and `str_utils` functions are the basic
//! building blocks that Ropey itself uses to build much of its functionality.
//! For example, the [`Rope::byte_to_char()`]
//! method can be reimplemented as a free function like this:
//!
//! ```no_run
//! use ropey::{
//!     Rope,
//!     str_utils::byte_to_char_idx
//! };
//!
//! fn byte_to_char(rope: &Rope, byte_idx: usize) -> usize {
//!     let (chunk, b, c, _) = rope.chunk_at_byte(byte_idx);
//!     c + byte_to_char_idx(chunk, byte_idx - b)
//! }
//! ```
//!
//! And this will be just as efficient as Ropey's implementation.
//!
//! The chunk-fetching methods in particular are among the fastest functions
//! that Ropey provides, generally operating in the sub-hundred nanosecond
//! range for medium-sized (~200kB) documents on recent-ish computer systems.
//!
//!
//! # A Note About Line Endings
//!
//! Some of Ropey's APIs use the concept of line breaks or lines of text.
//! Ropey can be configured at build time via feature flags to recognize
//! different line breaks.
//!
//! Ropey always recognizes:
//!
//! - `U+000A`          — LF (Line Feed)
//! - `U+000D` `U+000A` — CRLF (Carriage Return + Line Feed)
//!
//! With the `cr_lines` feature, the following are also recognized:
//!
//! - `U+000D`          — CR (Carriage Return)
//!
//! With the `unicode_lines` feature, in addition to all of the
//! above, the following are also recognized:
//!
//! - `U+000B`          — VT (Vertical Tab)
//! - `U+000C`          — FF (Form Feed)
//! - `U+0085`          — NEL (Next Line)
//! - `U+2028`          — Line Separator
//! - `U+2029`          — Paragraph Separator
//!
//! (Note that `unicode_lines` implies `cr_lines`.  `unicode_lines` is
//! also enabled by default, so by default Ropey recognizes all Unicode
//! line breaks.)
//!
//! Ropey treats line breaks as being a part of the line that they mark
//! the end of.  That is to say, lines begin immediately _after_ a line
//! break.  For example, the text `"Hello\nworld"` has two lines:
//! `"Hello\n"` and `"world"`.  And the text `"Hello\nworld\n"` has three
//! lines: `"Hello\n"`, `"world\n"`, and `""`.
//!
//! CRLF pairs are always treated as a single line break, and are never split
//! across chunks.  Note, however, that slicing can still split them.

#![allow(clippy::collapsible_if)]
#![allow(clippy::inline_always)]
#![allow(clippy::needless_return)]
#![allow(clippy::redundant_field_names)]
#![allow(clippy::type_complexity)]

extern crate smallvec;
extern crate str_indices;

mod crlf;
mod rope;
mod rope_builder;
mod slice;
mod tree;

pub mod iter;
pub mod str_utils;

use std::ops::Bound;

pub use crate::rope::Rope;
pub use crate::rope_builder::RopeBuilder;
pub use crate::slice::RopeSlice;

//==============================================================
// Error reporting types.

/// Ropey's result type.
pub type Result<T> = std::result::Result<T, Error>;

/// Ropey's error type.
#[derive(Clone, Copy)]
#[non_exhaustive]
pub enum Error {
    /// Indicates that the passed byte index was out of bounds.
    ///
    /// Contains the index attempted and the actual length of the
    /// `Rope`/`RopeSlice` in bytes, in that order.
    ByteIndexOutOfBounds(usize, usize),

    /// Indicates that the passed char index was out of bounds.
    ///
    /// Contains the index attempted and the actual length of the
    /// `Rope`/`RopeSlice` in chars, in that order.
    CharIndexOutOfBounds(usize, usize),

    /// Indicates that the passed line index was out of bounds.
    ///
    /// Contains the index attempted and the actual length of the
    /// `Rope`/`RopeSlice` in lines, in that order.
    LineIndexOutOfBounds(usize, usize),

    /// Indicates that the passed utf16 code-unit index was out of
    /// bounds.
    ///
    /// Contains the index attempted and the actual length of the
    /// `Rope`/`RopeSlice` in utf16 code units, in that order.
    Utf16IndexOutOfBounds(usize, usize),

    /// Indicates that the passed byte index was not a char boundary.
    ///
    /// Contains the passed byte index.
    ByteIndexNotCharBoundary(usize),

    /// Indicates that the passed byte range didn't line up with char
    /// boundaries.
    ///
    /// Contains the [start, end) byte indices of the range, in that order.
    /// When either the start or end are `None`, that indicates a half-open
    /// range.
    ByteRangeNotCharBoundary(
        Option<usize>, // Start.
        Option<usize>, // End.
    ),

    /// Indicates that a reversed byte-index range (end < start) was
    /// encountered.
    ///
    /// Contains the [start, end) byte indices of the range, in that order.
    ByteRangeInvalid(
        usize, // Start.
        usize, // End.
    ),

    /// Indicates that a reversed char-index range (end < start) was
    /// encountered.
    ///
    /// Contains the [start, end) char indices of the range, in that order.
    CharRangeInvalid(
        usize, // Start.
        usize, // End.
    ),

    /// Indicates that the passed byte-index range was partially or fully
    /// out of bounds.
    ///
    /// Contains the [start, end) byte indices of the range and the actual
    /// length of the `Rope`/`RopeSlice` in bytes, in that order.  When
    /// either the start or end are `None`, that indicates a half-open range.
    ByteRangeOutOfBounds(
        Option<usize>, // Start.
        Option<usize>, // End.
        usize,         // Rope byte length.
    ),

    /// Indicates that the passed char-index range was partially or fully
    /// out of bounds.
    ///
    /// Contains the [start, end) char indices of the range and the actual
    /// length of the `Rope`/`RopeSlice` in chars, in that order.  When
    /// either the start or end are `None`, that indicates a half-open range.
    CharRangeOutOfBounds(
        Option<usize>, // Start.
        Option<usize>, // End.
        usize,         // Rope char length.
    ),
}

impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }

    // Deprecated in std.
    fn description(&self) -> &str {
        ""
    }

    // Deprecated in std.
    fn cause(&self) -> Option<&dyn std::error::Error> {
        None
    }
}

impl std::fmt::Debug for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match *self {
            Error::ByteIndexOutOfBounds(index, len) => {
                write!(
                    f,
                    "Byte index out of bounds: byte index {}, Rope/RopeSlice byte length {}",
                    index, len
                )
            }
            Error::CharIndexOutOfBounds(index, len) => {
                write!(
                    f,
                    "Char index out of bounds: char index {}, Rope/RopeSlice char length {}",
                    index, len
                )
            }
            Error::LineIndexOutOfBounds(index, len) => {
                write!(
                    f,
                    "Line index out of bounds: line index {}, Rope/RopeSlice line count {}",
                    index, len
                )
            }
            Error::Utf16IndexOutOfBounds(index, len) => {
                write!(f, "Utf16 code-unit index out of bounds: utf16 index {}, Rope/RopeSlice utf16 length {}", index, len)
            }
            Error::ByteIndexNotCharBoundary(index) => {
                write!(
                    f,
                    "Byte index is not a valid char boundary: byte index {}",
                    index
                )
            }
            Error::ByteRangeNotCharBoundary(start_idx_opt, end_idx_opt) => {
                write!(f, "Byte range does not align with char boundaries: range ")?;
                write_range(f, start_idx_opt, end_idx_opt)
            }
            Error::ByteRangeInvalid(start_idx, end_idx) => {
                write!(
                    f,
                    "Invalid byte range {}..{}: start must be <= end",
                    start_idx, end_idx
                )
            }
            Error::CharRangeInvalid(start_idx, end_idx) => {
                write!(
                    f,
                    "Invalid char range {}..{}: start must be <= end",
                    start_idx, end_idx
                )
            }
            Error::ByteRangeOutOfBounds(start_idx_opt, end_idx_opt, len) => {
                write!(f, "Byte range out of bounds: byte range ")?;
                write_range(f, start_idx_opt, end_idx_opt)?;
                write!(f, ", Rope/RopeSlice byte length {}", len)
            }
            Error::CharRangeOutOfBounds(start_idx_opt, end_idx_opt, len) => {
                write!(f, "Char range out of bounds: char range ")?;
                write_range(f, start_idx_opt, end_idx_opt)?;
                write!(f, ", Rope/RopeSlice char length {}", len)
            }
        }
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // Just re-use the debug impl.
        std::fmt::Debug::fmt(self, f)
    }
}

fn write_range(
    f: &mut std::fmt::Formatter<'_>,
    start_idx: Option<usize>,
    end_idx: Option<usize>,
) -> std::fmt::Result {
    match (start_idx, end_idx) {
        (None, None) => {
            write!(f, "..")
        }

        (Some(start), None) => {
            write!(f, "{}..", start)
        }

        (None, Some(end)) => {
            write!(f, "..{}", end)
        }

        (Some(start), Some(end)) => {
            write!(f, "{}..{}", start, end)
        }
    }
}

//==============================================================
// Range handling utilities.

#[inline(always)]
pub(crate) fn start_bound_to_num(b: Bound<&usize>) -> Option<usize> {
    match b {
        Bound::Included(n) => Some(*n),
        Bound::Excluded(n) => Some(*n + 1),
        Bound::Unbounded => None,
    }
}

#[inline(always)]
pub(crate) fn end_bound_to_num(b: Bound<&usize>) -> Option<usize> {
    match b {
        Bound::Included(n) => Some(*n + 1),
        Bound::Excluded(n) => Some(*n),
        Bound::Unbounded => None,
    }
}
<commit_msg>Documentation tweaks.<commit_after>//! Ropey is a utf8 text rope for Rust.  It is fast, robust, and can handle
//! huge texts and memory-incoherent edits with ease.
//!
//! Ropey's atomic unit of text is Unicode scalar values (or `char`s in Rust)
//! encoded as utf8.  All of Ropey's editing and slicing operations are done
//! in terms of char indices which prevents accidental creation of invalid
//! utf8 data.
//!
//! The library is made up of four main components:
//!
//! - [`Rope`]: the main rope type.
//! - [`RopeSlice`]: an immutable view into part of a
//!   `Rope`.
//! - [`iter`]: iterators over `Rope`/`RopeSlice` data.
//! - [`RopeBuilder`]: an efficient incremental
//!   `Rope` builder.
//!
//!
//! # A Basic Example
//!
//! Let's say we want to open up a text file, replace the 516th line (the
//! writing was terrible!), and save it back to disk.  It's contrived, but will
//! give a good sampling of the APIs and how they work together.
//!
//! ```no_run
//! # use std::io::Result;
//! use std::fs::File;
//! use std::io::{BufReader, BufWriter};
//! use ropey::Rope;
//!
//! # fn do_stuff() -> Result<()> {
//! // Load a text file.
//! let mut text = Rope::from_reader(
//!     BufReader::new(File::open("my_great_book.txt")?)
//! )?;
//!
//! // Print the 516th line (zero-indexed) to see the terrible
//! // writing.
//! println!("{}", text.line(515));
//!
//! // Get the start/end char indices of the line.
//! let start_idx = text.line_to_char(515);
//! let end_idx = text.line_to_char(516);
//!
//! // Remove the line...
//! text.remove(start_idx..end_idx);
//!
//! // ...and replace it with something better.
//! text.insert(start_idx, "The flowers are... so... dunno.\n");
//!
//! // Print the changes, along with the previous few lines for context.
//! let start_idx = text.line_to_char(511);
//! let end_idx = text.line_to_char(516);
//! println!("{}", text.slice(start_idx..end_idx));
//!
//! // Write the file back out to disk.
//! text.write_to(
//!     BufWriter::new(File::create("my_great_book.txt")?)
//! )?;
//! # Ok(())
//! # }
//! # do_stuff().unwrap();
//! ```
//!
//! More examples can be found in the `examples` directory of the git
//! repository.  Many of those examples demonstrate doing non-trivial things
//! with Ropey such as grapheme handling, search-and-replace, and streaming
//! loading of non-utf8 text files.
//!
//!
//! # Low-level APIs
//!
//! Ropey also provides access to some of its low-level APIs, enabling client
//! code to efficiently work with a `Rope`'s data and implement new
//! functionality.  The most important of those API's are:
//!
//! - The [`chunk_at_*()`](Rope::chunk_at_byte)
//!   chunk-fetching methods of `Rope` and `RopeSlice`.
//! - The [`Chunks`](iter::Chunks) iterator.
//! - The functions in [`str_utils`] for operating on
//!   `&str` slices.
//!
//! Internally, each `Rope` stores text as a segemented collection of utf8
//! strings.  The chunk-fetching methods and `Chunks` iterator provide direct
//! access to those strings (or "chunks") as `&str` slices, allowing client
//! code to work directly with the underlying utf8 data.
//!
//! The chunk-fetching methods and `str_utils` functions are the basic
//! building blocks that Ropey itself uses to build much of its functionality.
//! For example, the [`Rope::byte_to_char()`]
//! method can be reimplemented as a free function like this:
//!
//! ```no_run
//! use ropey::{
//!     Rope,
//!     str_utils::byte_to_char_idx
//! };
//!
//! fn byte_to_char(rope: &Rope, byte_idx: usize) -> usize {
//!     let (chunk, b, c, _) = rope.chunk_at_byte(byte_idx);
//!     c + byte_to_char_idx(chunk, byte_idx - b)
//! }
//! ```
//!
//! And this will be just as efficient as Ropey's implementation.
//!
//! The chunk-fetching methods in particular are among the fastest functions
//! that Ropey provides, generally operating in the sub-hundred nanosecond
//! range for medium-sized (~200kB) documents on recent-ish computer systems.
//!
//!
//! # A Note About Line Endings
//!
//! Some of Ropey's APIs use the concept of line breaks or lines of text.
//!
//! Ropey treats line breaks as being a part of the line they mark the
//! end of.  That is to say, lines begin immediately _after_ a line
//! break.  For example, the text `"Hello\nworld"` has two lines:
//! `"Hello\n"` and `"world"`.  And the text `"Hello\nworld\n"` has three
//! lines: `"Hello\n"`, `"world\n"`, and `""`.
//!
//! Ropey can be configured at build time via feature flags to recognize
//! different line breaks.  Ropey always recognizes:
//!
//! - `U+000A`          — LF (Line Feed)
//! - `U+000D` `U+000A` — CRLF (Carriage Return + Line Feed)
//!
//! With the `cr_lines` feature, the following are also recognized:
//!
//! - `U+000D`          — CR (Carriage Return)
//!
//! With the `unicode_lines` feature, in addition to all of the
//! above, the following are also recognized (bringing Ropey into
//! conformance with
//! [Unicode Annex #14](https://www.unicode.org/reports/tr14/#BK)):
//!
//! - `U+000B`          — VT (Vertical Tab)
//! - `U+000C`          — FF (Form Feed)
//! - `U+0085`          — NEL (Next Line)
//! - `U+2028`          — Line Separator
//! - `U+2029`          — Paragraph Separator
//!
//! (Note: `unicode_lines` is enabled by default, and always implies
//! `cr_lines`.)
//!
//! CRLF pairs are always treated as a single line break, and are never split
//! across chunks.  Note, however, that slicing can still split them.

#![allow(clippy::collapsible_if)]
#![allow(clippy::inline_always)]
#![allow(clippy::needless_return)]
#![allow(clippy::redundant_field_names)]
#![allow(clippy::type_complexity)]

extern crate smallvec;
extern crate str_indices;

mod crlf;
mod rope;
mod rope_builder;
mod slice;
mod tree;

pub mod iter;
pub mod str_utils;

use std::ops::Bound;

pub use crate::rope::Rope;
pub use crate::rope_builder::RopeBuilder;
pub use crate::slice::RopeSlice;

//==============================================================
// Error reporting types.

/// Ropey's result type.
pub type Result<T> = std::result::Result<T, Error>;

/// Ropey's error type.
#[derive(Clone, Copy)]
#[non_exhaustive]
pub enum Error {
    /// Indicates that the passed byte index was out of bounds.
    ///
    /// Contains the index attempted and the actual length of the
    /// `Rope`/`RopeSlice` in bytes, in that order.
    ByteIndexOutOfBounds(usize, usize),

    /// Indicates that the passed char index was out of bounds.
    ///
    /// Contains the index attempted and the actual length of the
    /// `Rope`/`RopeSlice` in chars, in that order.
    CharIndexOutOfBounds(usize, usize),

    /// Indicates that the passed line index was out of bounds.
    ///
    /// Contains the index attempted and the actual length of the
    /// `Rope`/`RopeSlice` in lines, in that order.
    LineIndexOutOfBounds(usize, usize),

    /// Indicates that the passed utf16 code-unit index was out of
    /// bounds.
    ///
    /// Contains the index attempted and the actual length of the
    /// `Rope`/`RopeSlice` in utf16 code units, in that order.
    Utf16IndexOutOfBounds(usize, usize),

    /// Indicates that the passed byte index was not a char boundary.
    ///
    /// Contains the passed byte index.
    ByteIndexNotCharBoundary(usize),

    /// Indicates that the passed byte range didn't line up with char
    /// boundaries.
    ///
    /// Contains the [start, end) byte indices of the range, in that order.
    /// When either the start or end are `None`, that indicates a half-open
    /// range.
    ByteRangeNotCharBoundary(
        Option<usize>, // Start.
        Option<usize>, // End.
    ),

    /// Indicates that a reversed byte-index range (end < start) was
    /// encountered.
    ///
    /// Contains the [start, end) byte indices of the range, in that order.
    ByteRangeInvalid(
        usize, // Start.
        usize, // End.
    ),

    /// Indicates that a reversed char-index range (end < start) was
    /// encountered.
    ///
    /// Contains the [start, end) char indices of the range, in that order.
    CharRangeInvalid(
        usize, // Start.
        usize, // End.
    ),

    /// Indicates that the passed byte-index range was partially or fully
    /// out of bounds.
    ///
    /// Contains the [start, end) byte indices of the range and the actual
    /// length of the `Rope`/`RopeSlice` in bytes, in that order.  When
    /// either the start or end are `None`, that indicates a half-open range.
    ByteRangeOutOfBounds(
        Option<usize>, // Start.
        Option<usize>, // End.
        usize,         // Rope byte length.
    ),

    /// Indicates that the passed char-index range was partially or fully
    /// out of bounds.
    ///
    /// Contains the [start, end) char indices of the range and the actual
    /// length of the `Rope`/`RopeSlice` in chars, in that order.  When
    /// either the start or end are `None`, that indicates a half-open range.
    CharRangeOutOfBounds(
        Option<usize>, // Start.
        Option<usize>, // End.
        usize,         // Rope char length.
    ),
}

impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }

    // Deprecated in std.
    fn description(&self) -> &str {
        ""
    }

    // Deprecated in std.
    fn cause(&self) -> Option<&dyn std::error::Error> {
        None
    }
}

impl std::fmt::Debug for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match *self {
            Error::ByteIndexOutOfBounds(index, len) => {
                write!(
                    f,
                    "Byte index out of bounds: byte index {}, Rope/RopeSlice byte length {}",
                    index, len
                )
            }
            Error::CharIndexOutOfBounds(index, len) => {
                write!(
                    f,
                    "Char index out of bounds: char index {}, Rope/RopeSlice char length {}",
                    index, len
                )
            }
            Error::LineIndexOutOfBounds(index, len) => {
                write!(
                    f,
                    "Line index out of bounds: line index {}, Rope/RopeSlice line count {}",
                    index, len
                )
            }
            Error::Utf16IndexOutOfBounds(index, len) => {
                write!(f, "Utf16 code-unit index out of bounds: utf16 index {}, Rope/RopeSlice utf16 length {}", index, len)
            }
            Error::ByteIndexNotCharBoundary(index) => {
                write!(
                    f,
                    "Byte index is not a valid char boundary: byte index {}",
                    index
                )
            }
            Error::ByteRangeNotCharBoundary(start_idx_opt, end_idx_opt) => {
                write!(f, "Byte range does not align with char boundaries: range ")?;
                write_range(f, start_idx_opt, end_idx_opt)
            }
            Error::ByteRangeInvalid(start_idx, end_idx) => {
                write!(
                    f,
                    "Invalid byte range {}..{}: start must be <= end",
                    start_idx, end_idx
                )
            }
            Error::CharRangeInvalid(start_idx, end_idx) => {
                write!(
                    f,
                    "Invalid char range {}..{}: start must be <= end",
                    start_idx, end_idx
                )
            }
            Error::ByteRangeOutOfBounds(start_idx_opt, end_idx_opt, len) => {
                write!(f, "Byte range out of bounds: byte range ")?;
                write_range(f, start_idx_opt, end_idx_opt)?;
                write!(f, ", Rope/RopeSlice byte length {}", len)
            }
            Error::CharRangeOutOfBounds(start_idx_opt, end_idx_opt, len) => {
                write!(f, "Char range out of bounds: char range ")?;
                write_range(f, start_idx_opt, end_idx_opt)?;
                write!(f, ", Rope/RopeSlice char length {}", len)
            }
        }
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // Just re-use the debug impl.
        std::fmt::Debug::fmt(self, f)
    }
}

fn write_range(
    f: &mut std::fmt::Formatter<'_>,
    start_idx: Option<usize>,
    end_idx: Option<usize>,
) -> std::fmt::Result {
    match (start_idx, end_idx) {
        (None, None) => {
            write!(f, "..")
        }

        (Some(start), None) => {
            write!(f, "{}..", start)
        }

        (None, Some(end)) => {
            write!(f, "..{}", end)
        }

        (Some(start), Some(end)) => {
            write!(f, "{}..{}", start, end)
        }
    }
}

//==============================================================
// Range handling utilities.

#[inline(always)]
pub(crate) fn start_bound_to_num(b: Bound<&usize>) -> Option<usize> {
    match b {
        Bound::Included(n) => Some(*n),
        Bound::Excluded(n) => Some(*n + 1),
        Bound::Unbounded => None,
    }
}

#[inline(always)]
pub(crate) fn end_bound_to_num(b: Bound<&usize>) -> Option<usize> {
    match b {
        Bound::Included(n) => Some(*n + 1),
        Bound::Excluded(n) => Some(*n),
        Bound::Unbounded => None,
    }
}
<|endoftext|>


<commit_before>pub mod topic;
<commit_msg>EM: work on parsing input<commit_after>pub mod topic;
use std::num::ParseIntError;

fn parse_input(s: &str) -> Result<&str, &str> {
    let mut iter = s.split(", ");

    match (iter.next(), iter.next()) {
        (Some(topic), Some(n)) => {
            Ok("") // TODO: parse n
        },
        _ => Err("Bad input")
    }
}
<|endoftext|>


<commit_before>extern crate libsvm_sys;
extern crate libc;

use std::borrow::Borrow;

use std::ops::Deref;

use std::marker::PhantomData;

/// The node type used inside libsvm
pub type SvmNode = libsvm_sys::SvmNode;

/// A wrapper around the sparse vectors used in libsvm
pub struct SparseVector {
    pub inner: Vec<SvmNode>,
}

impl <'a> From<&'a [f64]> for SparseVector {
    fn from(fs: &[f64]) -> SparseVector {
        let vec = fs.iter()
            .enumerate()
            .filter(|&(_, x)| *x != 0.0)
            .map(|(idx, x)| SvmNode {
                index: idx as libc::c_int,
                value: *x as libc::c_double,
            })
            .chain(Some(SvmNode {
                index: -1 as libc::c_int,
                value: 0.0,
            }))
            .collect();
        SparseVector {
            inner: vec,
        }
    }
}

impl Deref for SparseVector {
    type Target = Vec<SvmNode>;
    fn deref(&self) -> &Vec<SvmNode> {
        &self.inner
    }
}

#[repr(C)]
pub enum SvmType {
    CSvc,
    NuSvc,
    OneClass,
    EpsilonSvr,
    NuSvr,
}

#[repr(C)]
pub enum KernelType {
    Linear,
    Poly,
    Rbf,
    Sigmoid,
    Precomputed,
}

impl SvmType {
    pub fn from_integral<T: Into<libc::c_int>>(t: T) -> Option<SvmType> {
        match t.into() {
            libsvm_sys::C_SVC =>       Some(SvmType::CSvc),
            libsvm_sys::NU_SVC =>      Some(SvmType::NuSvc),
            libsvm_sys::ONE_CLASS =>   Some(SvmType::OneClass),
            libsvm_sys::EPSILON_SVR => Some(SvmType::EpsilonSvr),
            libsvm_sys::NU_SVR =>      Some(SvmType::NuSvr),
            _ => None,
        }
    }
}

impl KernelType {
    pub fn from_integral<T: Into<libc::c_int>>(t: T) -> Option<KernelType> {
        match t.into() {
            libsvm_sys::LINEAR =>       Some(KernelType::Linear),
            libsvm_sys::POLY =>         Some(KernelType::Poly),
            libsvm_sys::RBF =>          Some(KernelType::Rbf),
            libsvm_sys::SIGMOID =>      Some(KernelType::Sigmoid),
            libsvm_sys::PRECOMPUTED =>  Some(KernelType::Precomputed),
            _ => None,
        }
    }
}

struct Problem<'a> {
    x: RefOrOwned<'a, SparseVector>,
    // needed to maintain the array of pointers in case svm_train uses that array
    x_raw: Vec<*const SvmNode>,
    y: RefOrOwned<'a, libc::c_double>,
}

enum RefOrOwned<'a, T: 'a> {
    Ref(&'a [T]),
    Owned(Vec<T>),
}

impl <'a, T> Deref for RefOrOwned<'a, T> {
    type Target = [T];
    fn deref(&self) -> &[T] {
        match self {
            &RefOrOwned::Ref(ref s) => s,
            &RefOrOwned::Owned(ref v) => &v,
        }
    }
}

pub struct Model<'a> {
    inner: *mut libsvm_sys::SvmModel,
    data: Option<Problem<'a>>,
}

pub struct Parameters<'a> {
    inner: libsvm_sys::SvmParameter,
    marker_: PhantomData<&'a [libc::c_double]>,
}

#[derive(Clone, Debug)]
pub enum ParameterCheckError {
    UnknownSvmType,
    UnknownKernelType,
    GammaNonpositive,
    KernelDegreeNonpositive,
    CacheSizeNonpositive,
    InvalidNu,
    PNonpositive,
    InvalidShrinking,
    InvalidProbability,
    Unsupported,
    InfeasibleNu,
}

#[derive(Clone, Debug)]
pub enum ModelCreationError {
    ParameterCheckError(ParameterCheckError),
    UnableToLoadModel,
    UnableToTrainModel,
}

#[derive(Clone, Debug)]
pub struct ModelSaveError;

impl <'a> Default for Parameters<'a> {
    fn default() -> Parameters<'a> {
        // TODO: use better default parameters
        Parameters {
            inner: libsvm_sys::SvmParameter {
                svm_type: SvmType::CSvc as libc::c_int,
                kernel_type: KernelType::Rbf as libc::c_int,
                degree: 0,
                gamma: 0.5,
                coef0: 0.0,

                cache_size: 64.0,
                eps: 1e-3,
                c: 1.0,
                nr_weight: 0,
                weight_label: 0 as *mut libc::c_int,
                weight: 0 as *mut libc::c_double,
                nu: 0.0,
                p: 0.0,
                shrinking: 0,
                probability: 0,
            },
            marker_: PhantomData,
        }
    }
}

/// A typesafe wrapper about libsvm that ensures that it is correctly
/// configured
impl <'a> Parameters<'a> {
    pub fn new() -> Parameters<'a> {
        Parameters::default()
    }

    pub fn linear(self) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.kernel_type = KernelType::Linear as libc::c_int;
        ret
    }

    pub fn poly(self, gamma: f64, coef0: f64, degree: isize) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.kernel_type = KernelType::Poly as libc::c_int;
        ret.inner.gamma = gamma as libc::c_double;
        ret.inner.coef0 = coef0 as libc::c_double;
        ret.inner.degree = degree as libc::c_int;
        ret
    }

    pub fn rbf(self, gamma: f64) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.kernel_type = KernelType::Rbf as libc::c_int;
        ret.inner.gamma = gamma as libc::c_double;
        ret
    }

    pub fn sigmoid(self, gamma: f64, coef: f64) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.kernel_type = KernelType::Sigmoid as libc::c_int;
        ret.inner.gamma = gamma as libc::c_double;
        ret.inner.coef0 = coef as libc::c_double;
        ret
    }

    pub fn precomputed(self) -> Parameters<'a> {
        // TODO: figure out a way to nicely wrap precomputed kernel semantics
        unimplemented!()
    }

    pub fn c_svc<'b>(self,
                     c: f64,
                     idxs: &'b [libc::c_int],
                     weights: &'b [libc::c_double]) -> Parameters<'b> {
        let mut ret = Parameters {
            inner: self.inner,
            marker_: PhantomData,
        };
        ret.inner.svm_type = SvmType::CSvc as libc::c_int;
        ret.inner.c = c;
        assert_eq!(idxs.len(), weights.len());
        ret.inner.nr_weight = idxs.len() as libc::c_int;
        ret.inner.weight_label = idxs.as_ptr();
        ret.inner.weight = weights.as_ptr();
        ret
    }

    pub fn nu_svc(self, nu: f64) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.svm_type = SvmType::NuSvc as libc::c_int;
        ret.inner.nu = nu as libc::c_double;
        ret
    }

    pub fn one_class(self, nu: f64) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.svm_type = SvmType::OneClass as libc::c_int;
        ret.inner.nu = nu as libc::c_double;
        ret
    }

    pub fn epsilon_svr(self, c: f64, p: f64) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.svm_type = SvmType::EpsilonSvr as libc::c_int;
        ret.inner.c = c as libc::c_double;
        ret.inner.p = p as libc::c_double;
        ret
    }

    pub fn nu_svr(self, c: f64, nu: f64) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.svm_type = SvmType::NuSvr as libc::c_int;
        ret.inner.c = c as libc::c_double;
        ret.inner.nu = nu as libc::c_double;
        ret
    }

    /// Sets the cache size used by libsvm in MB
    pub fn cache_size(self, sz: libc::c_double) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.cache_size = sz;
        ret
    }

    pub fn use_shrinking(self, b: bool) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.shrinking = if b { 1 } else { 0 };
        ret
    }

    pub fn estimate_probability(self, b: bool) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.probability = if b { 1 } else { 0 };
        ret
    }
}

impl <'a> Model<'a> {
    pub fn train<'b, T, C>(data: &[(T, C)], parameters: &Parameters<'b>) -> Result<Model<'a>, ModelCreationError> where
        T: Borrow<[f64]>, C: Copy + Into<libc::c_double>
    {
        // copy the data into a vector of sparse vectors
        let sparse: Vec<SparseVector> = data.iter()
            .map(|&(ref x, _)| SparseVector::from(x.borrow()))
            .collect();
        let classes = data.iter()
            .map(|&(_, y)| y.into())
            .collect();
        let sparse_ptr = sparse.iter()
            .map(|x| x.inner.as_ptr())
            .collect();

        let problem = Problem {
            x: RefOrOwned::Owned(sparse),
            x_raw: sparse_ptr,
            y: RefOrOwned::Owned(classes),
        };
        let svm_problem = libsvm_sys::SvmProblem {
            l: problem.x.len() as libc::c_int,
            y: problem.y.as_ptr(),
            x: problem.x_raw.as_ptr(),
        };
        // check parameters
        let parameter_error = unsafe {
            libsvm_sys::svm_check_parameter(
                &svm_problem as *const libsvm_sys::SvmProblem,
                &parameters.inner as *const libsvm_sys::SvmParameter)
        };
        // check result
        if parameter_error != std::ptr::null() {
            // TODO
        }
        // train the SVM model
        let svm_model = unsafe {
            libsvm_sys::svm_train(
                &svm_problem as *const libsvm_sys::SvmProblem,
                &parameters.inner as *const libsvm_sys::SvmParameter)
        };
        // check result
        if svm_model.is_null() {
            Err(ModelCreationError::UnableToTrainModel)
        } else {
            Ok(Model {
                inner: svm_model,
                data: Some(problem),
            })
        }
    }

    pub fn train_sparse<'b, C>(data: &[(&'a SparseVector, C)], parameters: &Parameters<'b>) -> Result<Model<'a>, ModelCreationError> where
        C: Copy + Into<u32>
    {
        // TODO: allow for zero copy training
        unimplemented!()
    }

    // TODO: make more type safe; should be using a Path instead of a &str
    pub fn load_model(path: &str) -> Result<Model<'a>, ModelCreationError> {
        let model = unsafe {
            libsvm_sys::svm_load_model(path.as_ptr() as *const libc::c_char)
        };

        if model.is_null() {
            Err(ModelCreationError::UnableToLoadModel)
        } else {
            Ok(Model {
                inner: model,
                data: None,
            })
        }
    }

    pub fn save_model(&self, path: &str) -> Result<(), ModelSaveError> {
        let ret = unsafe {
            libsvm_sys::svm_save_model(
                path.as_ptr() as *const libc::c_char,
                self.inner as *const libsvm_sys::SvmModel)
        };

        if ret < 0 {
            Err(ModelSaveError)
        } else {
            Ok(())
        }
    }

    pub fn svm_type(&self) -> Option<SvmType> {
        let ret = unsafe {
            libsvm_sys::svm_get_svm_type(self.inner as *const libsvm_sys::SvmModel)
        };
        SvmType::from_integral(ret)
    }

    pub fn nr_class(&self) -> libc::c_int {
        unsafe {
            libsvm_sys::svm_get_nr_class(self.inner as *const libsvm_sys::SvmModel)
        }
    }

    // TODO: provide type safe wrappers for labels and sv_indices
    // need a way to see if the model has labels or sv_indices
    pub fn labels(&self) -> Vec<libc::c_int> {
        unimplemented!()
    }

    pub fn sv_indices(&self) -> Vec<libc::c_int> {
        unimplemented!()
    }

    pub fn predict(&self, data: &[f64]) -> libc::c_double {
        let sparse = SparseVector::from(data);
        unsafe {
            libsvm_sys::svm_predict(
                self.inner as *const libsvm_sys::SvmModel,
                sparse.as_ptr()
            )
        }
    }

    pub fn predict_sparse(&self, data: &SparseVector) -> libc::c_double {
        unimplemented!()
    }
}

impl <'a> Drop for Model<'a> {
    fn drop(&mut self) {
        let mut ptr = self.inner as *mut libsvm_sys::SvmModel;
        unsafe {
            libsvm_sys::svm_free_and_destroy_model(&mut ptr as *mut *mut libsvm_sys::SvmModel);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_works() {
        let testx = vec![
            ([0.0, 0.0f64], -1),
            ([0.0, 1.0], -1),
            ([1.0, 0.0], 1),
            ([1.0, 1.0], 1),
        ];
        let parameters = Parameters::new()
            .c_svc(1.0, &[], &[]);
        let model = Model::train(&testx, &parameters).unwrap();
        let prediction = model.predict(&[0.0, -1.0]);
        assert_eq!(prediction, -1.0);
    }
}
<commit_msg>Remove warnings<commit_after>extern crate libsvm_sys;
extern crate libc;

use std::borrow::Borrow;

use std::ops::Deref;

use std::marker::PhantomData;

/// The node type used inside libsvm
pub type SvmNode = libsvm_sys::SvmNode;

/// A wrapper around the sparse vectors used in libsvm
pub struct SparseVector {
    pub inner: Vec<SvmNode>,
}

impl <'a> From<&'a [f64]> for SparseVector {
    fn from(fs: &[f64]) -> SparseVector {
        let vec = fs.iter()
            .enumerate()
            .filter(|&(_, x)| *x != 0.0)
            .map(|(idx, x)| SvmNode {
                index: idx as libc::c_int,
                value: *x as libc::c_double,
            })
            .chain(Some(SvmNode {
                index: -1 as libc::c_int,
                value: 0.0,
            }))
            .collect();
        SparseVector {
            inner: vec,
        }
    }
}

impl Deref for SparseVector {
    type Target = Vec<SvmNode>;
    fn deref(&self) -> &Vec<SvmNode> {
        &self.inner
    }
}

#[repr(C)]
pub enum SvmType {
    CSvc,
    NuSvc,
    OneClass,
    EpsilonSvr,
    NuSvr,
}

#[repr(C)]
pub enum KernelType {
    Linear,
    Poly,
    Rbf,
    Sigmoid,
    Precomputed,
}

impl SvmType {
    pub fn from_integral<T: Into<libc::c_int>>(t: T) -> Option<SvmType> {
        match t.into() {
            libsvm_sys::C_SVC =>       Some(SvmType::CSvc),
            libsvm_sys::NU_SVC =>      Some(SvmType::NuSvc),
            libsvm_sys::ONE_CLASS =>   Some(SvmType::OneClass),
            libsvm_sys::EPSILON_SVR => Some(SvmType::EpsilonSvr),
            libsvm_sys::NU_SVR =>      Some(SvmType::NuSvr),
            _ => None,
        }
    }
}

impl KernelType {
    pub fn from_integral<T: Into<libc::c_int>>(t: T) -> Option<KernelType> {
        match t.into() {
            libsvm_sys::LINEAR =>       Some(KernelType::Linear),
            libsvm_sys::POLY =>         Some(KernelType::Poly),
            libsvm_sys::RBF =>          Some(KernelType::Rbf),
            libsvm_sys::SIGMOID =>      Some(KernelType::Sigmoid),
            libsvm_sys::PRECOMPUTED =>  Some(KernelType::Precomputed),
            _ => None,
        }
    }
}

struct Problem<'a> {
    x: RefOrOwned<'a, SparseVector>,
    // needed to maintain the array of pointers in case svm_train uses that array
    x_raw: Vec<*const SvmNode>,
    y: RefOrOwned<'a, libc::c_double>,
}

enum RefOrOwned<'a, T: 'a> {
    Ref(&'a [T]),
    Owned(Vec<T>),
}

impl <'a, T> Deref for RefOrOwned<'a, T> {
    type Target = [T];
    fn deref(&self) -> &[T] {
        match self {
            &RefOrOwned::Ref(ref s) => s,
            &RefOrOwned::Owned(ref v) => &v,
        }
    }
}

pub struct Model<'a> {
    inner: *mut libsvm_sys::SvmModel,
    data: Option<Problem<'a>>,
}

pub struct Parameters<'a> {
    inner: libsvm_sys::SvmParameter,
    marker_: PhantomData<&'a [libc::c_double]>,
}

#[derive(Clone, Debug)]
pub enum ParameterCheckError {
    UnknownSvmType,
    UnknownKernelType,
    GammaNonpositive,
    KernelDegreeNonpositive,
    CacheSizeNonpositive,
    InvalidNu,
    PNonpositive,
    InvalidShrinking,
    InvalidProbability,
    Unsupported,
    InfeasibleNu,
}

#[derive(Clone, Debug)]
pub enum ModelCreationError {
    ParameterCheckError(ParameterCheckError),
    UnableToLoadModel,
    UnableToTrainModel,
}

#[derive(Clone, Debug)]
pub struct ModelSaveError;

impl <'a> Default for Parameters<'a> {
    fn default() -> Parameters<'a> {
        // TODO: use better default parameters
        Parameters {
            inner: libsvm_sys::SvmParameter {
                svm_type: SvmType::CSvc as libc::c_int,
                kernel_type: KernelType::Rbf as libc::c_int,
                degree: 0,
                gamma: 0.5,
                coef0: 0.0,

                cache_size: 64.0,
                eps: 1e-3,
                c: 1.0,
                nr_weight: 0,
                weight_label: 0 as *mut libc::c_int,
                weight: 0 as *mut libc::c_double,
                nu: 0.0,
                p: 0.0,
                shrinking: 0,
                probability: 0,
            },
            marker_: PhantomData,
        }
    }
}

/// A typesafe wrapper about libsvm that ensures that it is correctly
/// configured
impl <'a> Parameters<'a> {
    pub fn new() -> Parameters<'a> {
        Parameters::default()
    }

    pub fn linear(self) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.kernel_type = KernelType::Linear as libc::c_int;
        ret
    }

    pub fn poly(self, gamma: f64, coef0: f64, degree: isize) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.kernel_type = KernelType::Poly as libc::c_int;
        ret.inner.gamma = gamma as libc::c_double;
        ret.inner.coef0 = coef0 as libc::c_double;
        ret.inner.degree = degree as libc::c_int;
        ret
    }

    pub fn rbf(self, gamma: f64) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.kernel_type = KernelType::Rbf as libc::c_int;
        ret.inner.gamma = gamma as libc::c_double;
        ret
    }

    pub fn sigmoid(self, gamma: f64, coef: f64) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.kernel_type = KernelType::Sigmoid as libc::c_int;
        ret.inner.gamma = gamma as libc::c_double;
        ret.inner.coef0 = coef as libc::c_double;
        ret
    }

    /*
    pub fn precomputed(self) -> Parameters<'a> {
        // TODO: figure out a way to nicely wrap precomputed kernel semantics
        unimplemented!()
    }
    */

    pub fn c_svc<'b>(self,
                     c: f64,
                     idxs: &'b [libc::c_int],
                     weights: &'b [libc::c_double]) -> Parameters<'b> {
        let mut ret = Parameters {
            inner: self.inner,
            marker_: PhantomData,
        };
        ret.inner.svm_type = SvmType::CSvc as libc::c_int;
        ret.inner.c = c;
        assert_eq!(idxs.len(), weights.len());
        ret.inner.nr_weight = idxs.len() as libc::c_int;
        ret.inner.weight_label = idxs.as_ptr();
        ret.inner.weight = weights.as_ptr();
        ret
    }

    pub fn nu_svc(self, nu: f64) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.svm_type = SvmType::NuSvc as libc::c_int;
        ret.inner.nu = nu as libc::c_double;
        ret
    }

    pub fn one_class(self, nu: f64) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.svm_type = SvmType::OneClass as libc::c_int;
        ret.inner.nu = nu as libc::c_double;
        ret
    }

    pub fn epsilon_svr(self, c: f64, p: f64) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.svm_type = SvmType::EpsilonSvr as libc::c_int;
        ret.inner.c = c as libc::c_double;
        ret.inner.p = p as libc::c_double;
        ret
    }

    pub fn nu_svr(self, c: f64, nu: f64) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.svm_type = SvmType::NuSvr as libc::c_int;
        ret.inner.c = c as libc::c_double;
        ret.inner.nu = nu as libc::c_double;
        ret
    }

    /// Sets the cache size used by libsvm in MB
    pub fn cache_size(self, sz: libc::c_double) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.cache_size = sz;
        ret
    }

    pub fn use_shrinking(self, b: bool) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.shrinking = if b { 1 } else { 0 };
        ret
    }

    pub fn estimate_probability(self, b: bool) -> Parameters<'a> {
        let mut ret = self;
        ret.inner.probability = if b { 1 } else { 0 };
        ret
    }
}

impl <'a> Model<'a> {
    pub fn train<'b, T, C>(data: &[(T, C)], parameters: &Parameters<'b>) -> Result<Model<'a>, ModelCreationError> where
        T: Borrow<[f64]>, C: Copy + Into<libc::c_double>
    {
        // copy the data into a vector of sparse vectors
        let sparse: Vec<SparseVector> = data.iter()
            .map(|&(ref x, _)| SparseVector::from(x.borrow()))
            .collect();
        let classes = data.iter()
            .map(|&(_, y)| y.into())
            .collect();
        let sparse_ptr = sparse.iter()
            .map(|x| x.inner.as_ptr())
            .collect();

        let problem = Problem {
            x: RefOrOwned::Owned(sparse),
            x_raw: sparse_ptr,
            y: RefOrOwned::Owned(classes),
        };
        let svm_problem = libsvm_sys::SvmProblem {
            l: problem.x.len() as libc::c_int,
            y: problem.y.as_ptr(),
            x: problem.x_raw.as_ptr(),
        };
        // check parameters
        let parameter_error = unsafe {
            libsvm_sys::svm_check_parameter(
                &svm_problem as *const libsvm_sys::SvmProblem,
                &parameters.inner as *const libsvm_sys::SvmParameter)
        };
        // check result
        if parameter_error != std::ptr::null() {
            // TODO
        }
        // train the SVM model
        let svm_model = unsafe {
            libsvm_sys::svm_train(
                &svm_problem as *const libsvm_sys::SvmProblem,
                &parameters.inner as *const libsvm_sys::SvmParameter)
        };
        // check result
        if svm_model.is_null() {
            Err(ModelCreationError::UnableToTrainModel)
        } else {
            Ok(Model {
                inner: svm_model,
                data: Some(problem),
            })
        }
    }

    /*
    pub fn train_sparse<'b, C>(data: &[(&'a SparseVector, C)], parameters: &Parameters<'b>) -> Result<Model<'a>, ModelCreationError> where
        C: Copy + Into<u32>
    {
        // TODO: allow for zero copy training
        unimplemented!()
    }
    */

    // FIXME: make more type safe; should be using a Path instead of a &str
    pub fn load_model(path: &str) -> Result<Model<'a>, ModelCreationError> {
        let model = unsafe {
            libsvm_sys::svm_load_model(path.as_ptr() as *const libc::c_char)
        };

        if model.is_null() {
            Err(ModelCreationError::UnableToLoadModel)
        } else {
            Ok(Model {
                inner: model,
                data: None,
            })
        }
    }

    pub fn save_model(&self, path: &str) -> Result<(), ModelSaveError> {
        let ret = unsafe {
            libsvm_sys::svm_save_model(
                path.as_ptr() as *const libc::c_char,
                self.inner as *const libsvm_sys::SvmModel)
        };

        if ret < 0 {
            Err(ModelSaveError)
        } else {
            Ok(())
        }
    }

    pub fn svm_type(&self) -> Option<SvmType> {
        let ret = unsafe {
            libsvm_sys::svm_get_svm_type(self.inner as *const libsvm_sys::SvmModel)
        };
        SvmType::from_integral(ret)
    }

    pub fn nr_class(&self) -> libc::c_int {
        unsafe {
            libsvm_sys::svm_get_nr_class(self.inner as *const libsvm_sys::SvmModel)
        }
    }

    // TODO: provide type safe wrappers for labels and sv_indices
    // need a way to see if the model has labels or sv_indices
    pub fn labels(&self) -> Vec<libc::c_int> {
        unimplemented!()
    }

    pub fn sv_indices(&self) -> Vec<libc::c_int> {
        unimplemented!()
    }

    pub fn predict(&self, data: &[f64]) -> libc::c_double {
        let sparse = SparseVector::from(data);
        unsafe {
            libsvm_sys::svm_predict(
                self.inner as *const libsvm_sys::SvmModel,
                sparse.as_ptr()
            )
        }
    }

    pub fn predict_sparse(&self, data: &SparseVector) -> libc::c_double {
        unsafe {
            libsvm_sys::svm_predict(
                self.inner as *const libsvm_sys::SvmModel,
                data.as_ptr()
            )
        }
    }
}

impl <'a> Drop for Model<'a> {
    fn drop(&mut self) {
        let mut ptr = self.inner as *mut libsvm_sys::SvmModel;
        unsafe {
            libsvm_sys::svm_free_and_destroy_model(&mut ptr as *mut *mut libsvm_sys::SvmModel);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_works() {
        let testx = vec![
            ([0.0, 0.0f64], -1),
            ([0.0, 1.0], -1),
            ([1.0, 0.0], 1),
            ([1.0, 1.0], 1),
        ];
        let parameters = Parameters::new()
            .c_svc(1.0, &[], &[]);
        let model = Model::train(&testx, &parameters).unwrap();
        let prediction = model.predict(&[0.0, -1.0]);
        assert_eq!(prediction, -1.0);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// ignore-lexer-test FIXME #15679

//! Operations on ASCII strings and characters

#![cfg_attr(feature = "unstable", feature(ascii))]

mod ascii;
mod ascii_string;
mod ascii_str;

use std::borrow::Borrow;
use std::ascii::AsciiExt;

pub use ascii::Ascii;
pub use ascii_string::AsciiString;
pub use ascii_str::AsciiStr;

/// Trait for converting into an ascii type.
pub trait AsciiCast<'a>: AsciiExt {
    type Target;

    /// Convert to an ascii type, return Err(()) on non-ASCII input.
    #[inline]
    fn to_ascii(&'a self) -> Result<Self::Target, ()> {
        if self.is_ascii() {
            Ok(unsafe { self.to_ascii_nocheck() })
        } else {
            Err(())
        }
    }

    /// Convert to an ascii type, not doing any range asserts
    unsafe fn to_ascii_nocheck(&'a self) -> Self::Target;
}

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast<T: ?Sized> : Sized
    where Self: Borrow<T>,
          T: AsciiExt<Owned=Self>
{
    /// Take ownership and cast to an ascii vector. On non-ASCII input return ownership of data
    /// that was attempted to cast to ascii in `Err(Self)`.
    #[inline]
    fn into_ascii(self) -> Result<AsciiString, Self> {
        if self.borrow().is_ascii() {
            Ok(unsafe { self.into_ascii_nocheck() })
        } else {
            Err(self)
        }
    }

    /// Take ownership and cast to an ascii vector.
    /// Does not perform validation checks.
    unsafe fn into_ascii_nocheck(self) -> AsciiString;
}

impl OwnedAsciiCast<str> for String {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> AsciiString {
        self.into_bytes().into_ascii_nocheck()
    }
}

impl OwnedAsciiCast<[u8]> for Vec<u8> {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> AsciiString {
        AsciiString::from_bytes_unchecked(self)
    }
}
<commit_msg>Fix warning on nightly<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// ignore-lexer-test FIXME #15679

//! Operations on ASCII strings and characters

mod ascii;
mod ascii_string;
mod ascii_str;

use std::borrow::Borrow;
use std::ascii::AsciiExt;

pub use ascii::Ascii;
pub use ascii_string::AsciiString;
pub use ascii_str::AsciiStr;

/// Trait for converting into an ascii type.
pub trait AsciiCast<'a>: AsciiExt {
    type Target;

    /// Convert to an ascii type, return Err(()) on non-ASCII input.
    #[inline]
    fn to_ascii(&'a self) -> Result<Self::Target, ()> {
        if self.is_ascii() {
            Ok(unsafe { self.to_ascii_nocheck() })
        } else {
            Err(())
        }
    }

    /// Convert to an ascii type, not doing any range asserts
    unsafe fn to_ascii_nocheck(&'a self) -> Self::Target;
}

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast<T: ?Sized> : Sized
    where Self: Borrow<T>,
          T: AsciiExt<Owned=Self>
{
    /// Take ownership and cast to an ascii vector. On non-ASCII input return ownership of data
    /// that was attempted to cast to ascii in `Err(Self)`.
    #[inline]
    fn into_ascii(self) -> Result<AsciiString, Self> {
        if self.borrow().is_ascii() {
            Ok(unsafe { self.into_ascii_nocheck() })
        } else {
            Err(self)
        }
    }

    /// Take ownership and cast to an ascii vector.
    /// Does not perform validation checks.
    unsafe fn into_ascii_nocheck(self) -> AsciiString;
}

impl OwnedAsciiCast<str> for String {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> AsciiString {
        self.into_bytes().into_ascii_nocheck()
    }
}

impl OwnedAsciiCast<[u8]> for Vec<u8> {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> AsciiString {
        AsciiString::from_bytes_unchecked(self)
    }
}
<|endoftext|>


<commit_before>#[macro_use] mod macros;
mod std_impls;

/// A collection.
pub trait Collection {
    /// Removes all items from the collection.
    fn clear(&mut self);

    /// 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 trait that declares a map's key and value types.
///
/// It is unusual to bound types by this trait directly. Consider using [`Map`](trait.Map.html)
/// instead.
pub trait BaseMap: Collection {
    /// The map's key type.
    type Key;

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

/// A map.
pub trait Map: MapLookup<<Self as BaseMap>::Key> {
    /// Inserts the given key and value into the map, returning the previous value associated with
    /// the key, or `None` if the map did not already contain the key.
    fn insert(&mut self, key: Self::Key, value: Self::Value) -> Option<Self::Value>;
}

/// A map that supports alternate key lookups.
pub trait MapLookup<Q: ?Sized>: BaseMap {
    /// 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 associated with the given key in the map, or `None` if
    /// the map does not contain the key.
    fn get(&self, key: &Q) -> Option<&Self::Value>;

    /// Returns a mutable reference to the value associated with the given key in the map, or
    /// `None` if the map does not contain the key.
    fn get_mut(&mut self, key: &Q) -> Option<&mut Self::Value>;

    /// Removes the given key from the map, returning the value associated with it, or `None` if
    /// the map did not contain the key.
    fn remove(&mut self, key: &Q) -> Option<Self::Value>;
}

/// A map that supports the entry API.
pub trait EntryMap<'a>: Map {
    /// The occupied entry type.
    type Occupied: OccupiedEntry<'a, Key = Self::Key, Value=Self::Value>;

    /// The vacant entry type.
    type Vacant: VacantEntry<'a, Key = Self::Key, Value=Self::Value>;

    /// Returns the given key's corresponding entry in the map for in-place manipulation.
    fn entry(&'a mut self, key: Self::Key) -> Entry<Self::Occupied, Self::Vacant>;
}

/// A map entry.
pub enum Entry<O, V> {
    /// An occupied entry.
    Occupied(O),
    /// A vacant entry.
    Vacant(V),
}

impl<'a, O, V> Entry<O, V>
where
    O: OccupiedEntry<'a>,
    V: VacantEntry<'a, Key = O::Key, Value=O::Value>
{
    /// Ensures that a value is in the entry by inserting the default if it is empty, and returns a
    /// mutable reference to the value.
    pub fn or_insert(self, default: O::Value) -> &'a mut O::Value {
        match self {
            Entry::Occupied(e) => e.into_mut(),
            Entry::Vacant(e) => e.insert(default),
        }
    }

    /// Ensures that a value is in the entry by inserting the result of the default function if it
    /// is empty, and returns a mutable reference to the value.
    pub fn or_insert_with<F>(self, default: F) -> &'a mut O::Value where F: FnOnce() -> O::Value {
        match self {
            Entry::Occupied(e) => e.into_mut(),
            Entry::Vacant(e) => e.insert(default()),
        }
    }
}

/// An occupied map entry.
pub trait OccupiedEntry<'a> {
    /// The entry's key type.
    type Key: 'a;

    /// The entry's value type.
    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;

    /// Sets the entry's value to the given one, returning the old value.
    fn insert(&mut self, value: Self::Value) -> Self::Value;

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

    /// Removes the entry, returning its value.
    fn remove(self) -> Self::Value;
}

/// A vacant map entry.
pub trait VacantEntry<'a> {
    /// The entry's key type.
    type Key: 'a;

    /// The entry's value type.
    type Value: 'a;

    /// Sets the entry's value to the given one, returning a mutable reference to the value with
    /// the lifetime of the map.
    fn insert(self, value: Self::Value) -> &'a mut Self::Value;
}

/// A trait that declares a set's item type.
///
/// It is unusual to bound types by this trait directly. Consider using [`Set`](trait.Set.html)
/// instead.
pub trait BaseSet: Collection {
    /// The set's item type.
    type Item;
}

/// A set.
pub trait Set: SetLookup<<Self as BaseSet>::Item> {
    /// Inserts the given item into the set, returning `true` if the set did not already contain
    /// the item.
    fn insert(&mut self, item: Self::Item) -> bool;
}

/// A set that supports alternate item lookups.
pub trait SetLookup<Q: ?Sized>: BaseSet {
    /// Checks if the set contains the given item.
    fn contains(&self, item: &Q) -> bool;

    /// Removes the given item from the set, returning `true` if the set contained the item.
    fn remove(&mut self, item: &Q) -> bool;
}
<commit_msg>fix associated type formatting<commit_after>#[macro_use] mod macros;
mod std_impls;

/// A collection.
pub trait Collection {
    /// Removes all items from the collection.
    fn clear(&mut self);

    /// 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 trait that declares a map's key and value types.
///
/// It is unusual to bound types by this trait directly. Consider using [`Map`](trait.Map.html)
/// instead.
pub trait BaseMap: Collection {
    /// The map's key type.
    type Key;

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

/// A map.
pub trait Map: MapLookup<<Self as BaseMap>::Key> {
    /// Inserts the given key and value into the map, returning the previous value associated with
    /// the key, or `None` if the map did not already contain the key.
    fn insert(&mut self, key: Self::Key, value: Self::Value) -> Option<Self::Value>;
}

/// A map that supports alternate key lookups.
pub trait MapLookup<Q: ?Sized>: BaseMap {
    /// 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 associated with the given key in the map, or `None` if
    /// the map does not contain the key.
    fn get(&self, key: &Q) -> Option<&Self::Value>;

    /// Returns a mutable reference to the value associated with the given key in the map, or
    /// `None` if the map does not contain the key.
    fn get_mut(&mut self, key: &Q) -> Option<&mut Self::Value>;

    /// Removes the given key from the map, returning the value associated with it, or `None` if
    /// the map did not contain the key.
    fn remove(&mut self, key: &Q) -> Option<Self::Value>;
}

/// A map that supports the entry API.
pub trait EntryMap<'a>: Map {
    /// The occupied entry type.
    type Occupied: OccupiedEntry<'a, Key = Self::Key, Value = Self::Value>;

    /// The vacant entry type.
    type Vacant: VacantEntry<'a, Key = Self::Key, Value = Self::Value>;

    /// Returns the given key's corresponding entry in the map for in-place manipulation.
    fn entry(&'a mut self, key: Self::Key) -> Entry<Self::Occupied, Self::Vacant>;
}

/// A map entry.
pub enum Entry<O, V> {
    /// An occupied entry.
    Occupied(O),
    /// A vacant entry.
    Vacant(V),
}

impl<'a, O, V> Entry<O, V>
where
    O: OccupiedEntry<'a>,
    V: VacantEntry<'a, Key = O::Key, Value = O::Value>
{
    /// Ensures that a value is in the entry by inserting the default if it is empty, and returns a
    /// mutable reference to the value.
    pub fn or_insert(self, default: O::Value) -> &'a mut O::Value {
        match self {
            Entry::Occupied(e) => e.into_mut(),
            Entry::Vacant(e) => e.insert(default),
        }
    }

    /// Ensures that a value is in the entry by inserting the result of the default function if it
    /// is empty, and returns a mutable reference to the value.
    pub fn or_insert_with<F>(self, default: F) -> &'a mut O::Value where F: FnOnce() -> O::Value {
        match self {
            Entry::Occupied(e) => e.into_mut(),
            Entry::Vacant(e) => e.insert(default()),
        }
    }
}

/// An occupied map entry.
pub trait OccupiedEntry<'a> {
    /// The entry's key type.
    type Key: 'a;

    /// The entry's value type.
    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;

    /// Sets the entry's value to the given one, returning the old value.
    fn insert(&mut self, value: Self::Value) -> Self::Value;

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

    /// Removes the entry, returning its value.
    fn remove(self) -> Self::Value;
}

/// A vacant map entry.
pub trait VacantEntry<'a> {
    /// The entry's key type.
    type Key: 'a;

    /// The entry's value type.
    type Value: 'a;

    /// Sets the entry's value to the given one, returning a mutable reference to the value with
    /// the lifetime of the map.
    fn insert(self, value: Self::Value) -> &'a mut Self::Value;
}

/// A trait that declares a set's item type.
///
/// It is unusual to bound types by this trait directly. Consider using [`Set`](trait.Set.html)
/// instead.
pub trait BaseSet: Collection {
    /// The set's item type.
    type Item;
}

/// A set.
pub trait Set: SetLookup<<Self as BaseSet>::Item> {
    /// Inserts the given item into the set, returning `true` if the set did not already contain
    /// the item.
    fn insert(&mut self, item: Self::Item) -> bool;
}

/// A set that supports alternate item lookups.
pub trait SetLookup<Q: ?Sized>: BaseSet {
    /// Checks if the set contains the given item.
    fn contains(&self, item: &Q) -> bool;

    /// Removes the given item from the set, returning `true` if the set contained the item.
    fn remove(&mut self, item: &Q) -> bool;
}
<|endoftext|>


<commit_before>//! # Poisson-disk distribution generation
//!
//! Generates distribution of points where:
//!
//! * For each point there is disk of certain radius which doesn't intersect
//! with any other disk of other points
//! * Samples fill the space uniformly
//!
extern crate modulo;

extern crate sphere;

extern crate rand;
use rand::{Rand, Rng};
extern crate num;
use num::{Zero, One};

extern crate nalgebra as na;
use na::{Dim, Norm, Iterable, IterableMut};

#[macro_use]
extern crate lazy_static;

use std::cmp::PartialEq;
use std::ops::{Sub, Mul, Add, Div};
use std::marker::PhantomData;

pub use algo::*;

mod algo;
mod math;
mod utils;
mod debug;

/// Describes what traits the algorithm needs to be able to work.
pub trait VecLike:
    IterableMut<f64> +
    Iterable<f64> +
    Add<Output = Self> +
    Sub<Output = Self> +
    Mul<f64, Output = Self> +
    Div<f64, Output = Self> +
    Norm<f64> +
    PartialEq +
    Zero +
    One +
    Dim +
    Copy {}
impl<T> VecLike for T where T:
    IterableMut<f64> +
    Iterable<f64> +
    Add<Output = T> +
    Sub<Output = T> +
    Mul<f64, Output = T> +
    Div<f64, Output = T> +
    Norm<f64> +
    PartialEq +
    Zero +
    One +
    Dim +
    Copy {}

/// Builds PoissonGen with wanted properties.
///
/// # Examples
///
/// ```¨
/// extern crate poisson;
/// extern crate rand;
/// extern crate nalgebra as na;
/// type Vec2 = na::Vec2<f64>;
/// use poisson::PoissonDisk;
///
/// fn main() {
///     let mut poisson = PoissonDisk::new(rand::weak_rng()).build_radius::<Vec2>(0.1);
///     let vecs = poisson.generate();
///     println!("{:?}", vecs);
/// }
/// ```
#[derive(Default, Clone, Debug)]
pub struct PoissonDisk<R>
    where R: Rng
{
    rand: R,
    periodicity: bool,
}

impl<R> PoissonDisk<R> where R: Rng
{
    /// Creates new Poisson-disk generator builder with random generator specified.
    pub fn new(rand: R) -> Self {
        PoissonDisk {
            rand: rand,
            periodicity: false,
        }
    }

    /// Sets the generator to generate perioditic Poisson-disk distributions.
    pub fn perioditic(mut self) -> Self {
        self.periodicity = true;
        self
    }

    /// Builds the generator with relative radius specified.
    /// Radius should be ]0, 1]
    pub fn build_relative_radius<V>(self, radius: f64) -> PoissonGen<R, V>
        where V: VecLike
    {
        assert!(0. < radius);
        assert!(radius <= 1.);
        PoissonGen::new(self.rand, radius * (2f64.sqrt() / 2.), self.periodicity)
    }

    /// Builds the generator with radius specified.
    /// Radius should be ]0, √2 / 2]
    pub fn build_radius<V>(self, radius: f64) -> PoissonGen<R, V>
        where V: VecLike
    {
        assert!(0. < radius);
        assert!(radius <= (2f64.sqrt() / 2.));
        PoissonGen::new(self.rand, radius, self.periodicity)
    }

    /// Builds the generator with radius calculated so that approximately specified number of samples are generated.
    /// Amount of samples should be larger than 0.
    /// Relative radius should be [0, 1].
    /// For non-perioditic this is supported only for 2, 3 and 4 dimensional generation.
    pub fn build_samples<V>(self, samples: u32, relative_radius: f64) -> PoissonGen<R, V>
        where V: VecLike
    {
        assert!(self.periodicity || V::dim(None) < 5);
        assert!(samples > 0);
        assert!(relative_radius >= 0.);
        assert!(relative_radius <= 1.);
        PoissonGen::new(self.rand,
                        math::calc_radius::<V>(samples, relative_radius, self.periodicity),
                        self.periodicity)
    }
}

/// Generates Poisson-disk distribution in [0, 1]² area with O(N) time and space complexity relative to the number of samples generated.
/// Based on Ebeida, Mohamed S., et al. "A Simple Algorithm for Maximal Poisson‐Disk Sampling in High Dimensions." Computer Graphics Forum. Vol. 31. No. 2pt4. Blackwell Publishing Ltd, 2012.
#[derive(Clone, Debug)]
pub struct PoissonGen<R, V>
    where R: Rng,
          V: VecLike
{
    dim: PhantomData<V>,
    rand: R,
    radius: f64,
    periodicity: bool,
    a: f64,
}

impl<R, V> PoissonGen<R, V>
    where R: Rng,
          V: VecLike
{
    /// Sets the radius of the generator.
    pub fn set_radius(&mut self, radius: f64) {
        assert!(0. < radius);
        assert!(radius <= (2f64.sqrt() / 2.));
        self.radius = radius;
    }

    /// Returns the radius of the generator.
    pub fn radius(&self) -> f64 {
        self.radius
    }
    /// Returns the periodicity of the generator.
    pub fn periodicity(&self) -> bool {
        self.periodicity
    }

    /// Generates a vector with Poisson-disk distribution in area [0, 1]²
    pub fn generate(&mut self) -> Vec<V> {
        self.into_iter().collect()
    }

    pub fn iter_mut<'a>(&'a mut self) -> PoissonIterMut<'a, R, V> {
        self.into_iter()
    }
}

impl<R, V> PoissonGen<R, V>
    where R: Rng,
          V: VecLike
{
    fn new(rand: R, radius: f64, periodicity: bool) -> PoissonGen<R, V> {
        let dim = V::dim(None);
        PoissonGen {
            dim: PhantomData,
            radius: radius,
            rand: rand,
            periodicity: periodicity,
            a: match dim {
                2 => 0.3,
                3 => 0.3,
                4 => 0.6,
                5 => 10.,
                6 => 700.,
                // TODO: Figure out what are optimal values beyond 6 dimensions
                _ => 700. + 100. * dim as f64,
            },
        }
    }
}

impl<'a, R, V> IntoIterator for PoissonGen<R, V>
    where R: Rng,
          V: VecLike
{
    type IntoIter = PoissonIter<R, V>;
    type Item = V;
    fn into_iter(mut self) -> PoissonIter<R, V> {
        let algo = PoissonAlgo::new(&mut self);
        PoissonIter {
            poisson: self,
            algo: algo,
        }
    }
}

#[derive(Clone)]
pub struct PoissonIter<R, V>
    where R: Rng,
          V: VecLike
{
    poisson: PoissonGen<R, V>,
    algo: PoissonAlgo<V>,
}

impl<R, V> PoissonIter<R, V>
    where R: Rng,
          V: VecLike
{
    pub fn insert(&mut self, value: V) {
        self.algo.insert(value);
    }

    /// Returns the radius of the generator.
    pub fn radius(&self) -> f64 {
        self.poisson.radius()
    }
    /// Returns the periodicity of the generator.
    pub fn periodicity(&self) -> bool {
        self.poisson.periodicity()
    }

    pub fn stays_legal(&self, value: V) -> bool {
        self.algo.stays_legal(&self.poisson, value)
    }
}

impl<R, V> Iterator for PoissonIter<R, V>
    where R: Rng,
          V: VecLike
{
    type Item = V;
    fn next(&mut self) -> Option<V> {
        self.algo.next(&mut self.poisson)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.algo.size_hint(&self.poisson)
    }
}

impl<R, V> Extend<V> for PoissonIter<R, V>
    where R: Rng,
          V: VecLike
{
    fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=V> {
        for t in iterable {
            self.insert(t);
        }
    }
}

impl<'a, R, V> IntoIterator for &'a mut PoissonGen<R, V>
    where R: Rng,
          V: VecLike
{
    type IntoIter = PoissonIterMut<'a, R, V>;
    type Item = V;
    fn into_iter(self) -> PoissonIterMut<'a, R, V> {
        let algo = PoissonAlgo::new(self);
        PoissonIterMut {
            poisson: self,
            algo: algo,
        }
    }
}

pub struct PoissonIterMut<'a, R, V>
    where R: Rng + 'a,
          V: VecLike + 'a
{
    poisson: &'a mut PoissonGen<R, V>,
    algo: PoissonAlgo<V>,
}

impl<'a, R, V> PoissonIterMut<'a, R, V>
    where R: Rng,
          V: VecLike
{
    pub fn insert(&mut self, value: V) {
        self.algo.insert(value);
    }

    /// Returns the radius of the generator.
    pub fn radius(&self) -> f64 {
        self.poisson.radius()
    }
    /// Returns the periodicity of the generator.
    pub fn periodicity(&self) -> bool {
        self.poisson.periodicity()
    }

    pub fn stays_legal(&self, value: V) -> bool {
        self.algo.stays_legal(&self.poisson, value)
    }
}

impl<'a, R, V> Iterator for PoissonIterMut<'a, R, V>
    where R: Rng,
          V: VecLike
{
    type Item = V;
    fn next(&mut self) -> Option<V> {
        self.algo.next(self.poisson)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.algo.size_hint(&self.poisson)
    }
}

impl<'a, R, V> Extend<V> for PoissonIterMut<'a, R, V>
    where R: Rng,
          V: VecLike
{
    fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=V> {
        for t in iterable {
            self.insert(t);
        }
    }
}
<commit_msg>Removed mistakenly left line.<commit_after>//! # Poisson-disk distribution generation
//!
//! Generates distribution of points where:
//!
//! * For each point there is disk of certain radius which doesn't intersect
//! with any other disk of other points
//! * Samples fill the space uniformly
//!
extern crate modulo;

extern crate sphere;

extern crate rand;
use rand::{Rand, Rng};
extern crate num;
use num::{Zero, One};

extern crate nalgebra as na;
use na::{Dim, Norm, Iterable, IterableMut};

#[macro_use]
extern crate lazy_static;

use std::cmp::PartialEq;
use std::ops::{Sub, Mul, Add, Div};
use std::marker::PhantomData;

pub use algo::*;

mod algo;
mod math;
mod utils;

/// Describes what traits the algorithm needs to be able to work.
pub trait VecLike:
    IterableMut<f64> +
    Iterable<f64> +
    Add<Output = Self> +
    Sub<Output = Self> +
    Mul<f64, Output = Self> +
    Div<f64, Output = Self> +
    Norm<f64> +
    PartialEq +
    Zero +
    One +
    Dim +
    Copy {}
impl<T> VecLike for T where T:
    IterableMut<f64> +
    Iterable<f64> +
    Add<Output = T> +
    Sub<Output = T> +
    Mul<f64, Output = T> +
    Div<f64, Output = T> +
    Norm<f64> +
    PartialEq +
    Zero +
    One +
    Dim +
    Copy {}

/// Builds PoissonGen with wanted properties.
///
/// # Examples
///
/// ```¨
/// extern crate poisson;
/// extern crate rand;
/// extern crate nalgebra as na;
/// type Vec2 = na::Vec2<f64>;
/// use poisson::PoissonDisk;
///
/// fn main() {
///     let mut poisson = PoissonDisk::new(rand::weak_rng()).build_radius::<Vec2>(0.1);
///     let vecs = poisson.generate();
///     println!("{:?}", vecs);
/// }
/// ```
#[derive(Default, Clone, Debug)]
pub struct PoissonDisk<R>
    where R: Rng
{
    rand: R,
    periodicity: bool,
}

impl<R> PoissonDisk<R> where R: Rng
{
    /// Creates new Poisson-disk generator builder with random generator specified.
    pub fn new(rand: R) -> Self {
        PoissonDisk {
            rand: rand,
            periodicity: false,
        }
    }

    /// Sets the generator to generate perioditic Poisson-disk distributions.
    pub fn perioditic(mut self) -> Self {
        self.periodicity = true;
        self
    }

    /// Builds the generator with relative radius specified.
    /// Radius should be ]0, 1]
    pub fn build_relative_radius<V>(self, radius: f64) -> PoissonGen<R, V>
        where V: VecLike
    {
        assert!(0. < radius);
        assert!(radius <= 1.);
        PoissonGen::new(self.rand, radius * (2f64.sqrt() / 2.), self.periodicity)
    }

    /// Builds the generator with radius specified.
    /// Radius should be ]0, √2 / 2]
    pub fn build_radius<V>(self, radius: f64) -> PoissonGen<R, V>
        where V: VecLike
    {
        assert!(0. < radius);
        assert!(radius <= (2f64.sqrt() / 2.));
        PoissonGen::new(self.rand, radius, self.periodicity)
    }

    /// Builds the generator with radius calculated so that approximately specified number of samples are generated.
    /// Amount of samples should be larger than 0.
    /// Relative radius should be [0, 1].
    /// For non-perioditic this is supported only for 2, 3 and 4 dimensional generation.
    pub fn build_samples<V>(self, samples: u32, relative_radius: f64) -> PoissonGen<R, V>
        where V: VecLike
    {
        assert!(self.periodicity || V::dim(None) < 5);
        assert!(samples > 0);
        assert!(relative_radius >= 0.);
        assert!(relative_radius <= 1.);
        PoissonGen::new(self.rand,
                        math::calc_radius::<V>(samples, relative_radius, self.periodicity),
                        self.periodicity)
    }
}

/// Generates Poisson-disk distribution in [0, 1]² area with O(N) time and space complexity relative to the number of samples generated.
/// Based on Ebeida, Mohamed S., et al. "A Simple Algorithm for Maximal Poisson‐Disk Sampling in High Dimensions." Computer Graphics Forum. Vol. 31. No. 2pt4. Blackwell Publishing Ltd, 2012.
#[derive(Clone, Debug)]
pub struct PoissonGen<R, V>
    where R: Rng,
          V: VecLike
{
    dim: PhantomData<V>,
    rand: R,
    radius: f64,
    periodicity: bool,
    a: f64,
}

impl<R, V> PoissonGen<R, V>
    where R: Rng,
          V: VecLike
{
    /// Sets the radius of the generator.
    pub fn set_radius(&mut self, radius: f64) {
        assert!(0. < radius);
        assert!(radius <= (2f64.sqrt() / 2.));
        self.radius = radius;
    }

    /// Returns the radius of the generator.
    pub fn radius(&self) -> f64 {
        self.radius
    }
    /// Returns the periodicity of the generator.
    pub fn periodicity(&self) -> bool {
        self.periodicity
    }

    /// Generates a vector with Poisson-disk distribution in area [0, 1]²
    pub fn generate(&mut self) -> Vec<V> {
        self.into_iter().collect()
    }

    pub fn iter_mut<'a>(&'a mut self) -> PoissonIterMut<'a, R, V> {
        self.into_iter()
    }
}

impl<R, V> PoissonGen<R, V>
    where R: Rng,
          V: VecLike
{
    fn new(rand: R, radius: f64, periodicity: bool) -> PoissonGen<R, V> {
        let dim = V::dim(None);
        PoissonGen {
            dim: PhantomData,
            radius: radius,
            rand: rand,
            periodicity: periodicity,
            a: match dim {
                2 => 0.3,
                3 => 0.3,
                4 => 0.6,
                5 => 10.,
                6 => 700.,
                // TODO: Figure out what are optimal values beyond 6 dimensions
                _ => 700. + 100. * dim as f64,
            },
        }
    }
}

impl<'a, R, V> IntoIterator for PoissonGen<R, V>
    where R: Rng,
          V: VecLike
{
    type IntoIter = PoissonIter<R, V>;
    type Item = V;
    fn into_iter(mut self) -> PoissonIter<R, V> {
        let algo = PoissonAlgo::new(&mut self);
        PoissonIter {
            poisson: self,
            algo: algo,
        }
    }
}

#[derive(Clone)]
pub struct PoissonIter<R, V>
    where R: Rng,
          V: VecLike
{
    poisson: PoissonGen<R, V>,
    algo: PoissonAlgo<V>,
}

impl<R, V> PoissonIter<R, V>
    where R: Rng,
          V: VecLike
{
    pub fn insert(&mut self, value: V) {
        self.algo.insert(value);
    }

    /// Returns the radius of the generator.
    pub fn radius(&self) -> f64 {
        self.poisson.radius()
    }
    /// Returns the periodicity of the generator.
    pub fn periodicity(&self) -> bool {
        self.poisson.periodicity()
    }

    pub fn stays_legal(&self, value: V) -> bool {
        self.algo.stays_legal(&self.poisson, value)
    }
}

impl<R, V> Iterator for PoissonIter<R, V>
    where R: Rng,
          V: VecLike
{
    type Item = V;
    fn next(&mut self) -> Option<V> {
        self.algo.next(&mut self.poisson)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.algo.size_hint(&self.poisson)
    }
}

impl<R, V> Extend<V> for PoissonIter<R, V>
    where R: Rng,
          V: VecLike
{
    fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=V> {
        for t in iterable {
            self.insert(t);
        }
    }
}

impl<'a, R, V> IntoIterator for &'a mut PoissonGen<R, V>
    where R: Rng,
          V: VecLike
{
    type IntoIter = PoissonIterMut<'a, R, V>;
    type Item = V;
    fn into_iter(self) -> PoissonIterMut<'a, R, V> {
        let algo = PoissonAlgo::new(self);
        PoissonIterMut {
            poisson: self,
            algo: algo,
        }
    }
}

pub struct PoissonIterMut<'a, R, V>
    where R: Rng + 'a,
          V: VecLike + 'a
{
    poisson: &'a mut PoissonGen<R, V>,
    algo: PoissonAlgo<V>,
}

impl<'a, R, V> PoissonIterMut<'a, R, V>
    where R: Rng,
          V: VecLike
{
    pub fn insert(&mut self, value: V) {
        self.algo.insert(value);
    }

    /// Returns the radius of the generator.
    pub fn radius(&self) -> f64 {
        self.poisson.radius()
    }
    /// Returns the periodicity of the generator.
    pub fn periodicity(&self) -> bool {
        self.poisson.periodicity()
    }

    pub fn stays_legal(&self, value: V) -> bool {
        self.algo.stays_legal(&self.poisson, value)
    }
}

impl<'a, R, V> Iterator for PoissonIterMut<'a, R, V>
    where R: Rng,
          V: VecLike
{
    type Item = V;
    fn next(&mut self) -> Option<V> {
        self.algo.next(self.poisson)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.algo.size_hint(&self.poisson)
    }
}

impl<'a, R, V> Extend<V> for PoissonIterMut<'a, R, V>
    where R: Rng,
          V: VecLike
{
    fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=V> {
        for t in iterable {
            self.insert(t);
        }
    }
}
<|endoftext|>