<commit_before>//! ByteSize is an utility that easily makes bytes size representation
//! and helps its arithmetic operations.
//!
//! ## Example
//!
//! ```ignore
//! extern crate bytesize;
//!
//! use bytesize::ByteSize;
//!
//! fn byte_arithmetic_operator() {
//!   let x = ByteSize::mb(1);
//!   let y = ByteSize::kb(100);
//!
//!   let plus = x + y;
//!   print!("{} bytes", plus.as_u64());
//!
//!   let minus = ByteSize::tb(100) - ByteSize::gb(4);
//!   print!("{} bytes", minus.as_u64());
//! }
//! ```
//!
//! It also provides its human readable string as follows:
//!
//! ```ignore=
//!  assert_eq!("482 GiB".to_string(), ByteSize::gb(518).to_string(true));
//!  assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false));
//! ```

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

use std::fmt::{Debug, Display, Formatter, Result};
use std::ops::{Add, Mul};

/// byte size for 1 byte
pub const B: u64 = 1;
/// bytes size for 1 kilobyte
pub const KB: u64 = 1_000;
/// bytes size for 1 megabyte
pub const MB: u64 = 1_000_000;
/// bytes size for 1 gigabyte
pub const GB: u64 = 1_000_000_000;
/// bytes size for 1 terabyte
pub const TB: u64 = 1_000_000_000_000;
/// bytes size for 1 petabyte
pub const PB: u64 = 1_000_000_000_000_000;

/// bytes size for 1 kibibyte
pub const KIB: u64 = 1_024;
/// bytes size for 1 mebibyte
pub const MIB: u64 = 1_048_576;
/// bytes size for 1 gibibyte
pub const GIB: u64 = 1_073_741_824;
/// bytes size for 1 tebibyte
pub const TIB: u64 = 1_099_511_627_776;
/// bytes size for 1 pebibyte
pub const PIB: u64 = 1_125_899_906_842_624;

static UNITS: &'static str = "KMGTPE";
static UNITS_SI: &'static str = "kMGTPE";
static LN_KB: f64 = 6.931471806; // ln 1024
static LN_KIB: f64 = 6.907755279; // ln 1000

pub fn kb<V: Into<u64>>(size: V) -> u64 {
    size.into() * KB
}

pub fn kib<V: Into<u64>>(size: V) -> u64 {
    size.into() * KIB
}

pub fn mb<V: Into<u64>>(size: V) -> u64 {
    size.into() * MB
}

pub fn mib<V: Into<u64>>(size: V) -> u64 {
    size.into() * MIB
}

pub fn gb<V: Into<u64>>(size: V) -> u64 {
    size.into() * GB
}

pub fn gib<V: Into<u64>>(size: V) -> u64 {
    size.into() * GIB
}

pub fn tb<V: Into<u64>>(size: V) -> u64 {
    size.into() * TB
}

pub fn tib<V: Into<u64>>(size: V) -> u64 {
    size.into() * TIB
}

pub fn pb<V: Into<u64>>(size: V) -> u64 {
    size.into() * PB
}

pub fn pib<V: Into<u64>>(size: V) -> u64 {
    size.into() * PIB
}

/// Byte size representation
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ByteSize(pub u64);

impl ByteSize {
    #[inline(always)]
    pub const fn b(size: u64) -> ByteSize {
        ByteSize(size)
    }

    #[inline(always)]
    pub const fn kb(size: u64) -> ByteSize {
        ByteSize(size * KB)
    }

    #[inline(always)]
    pub const fn kib(size: u64) -> ByteSize {
        ByteSize(size * KIB)
    }

    #[inline(always)]
    pub const fn mb(size: u64) -> ByteSize {
        ByteSize(size * MB)
    }

    #[inline(always)]
    pub const fn mib(size: u64) -> ByteSize {
        ByteSize(size * MIB)
    }

    #[inline(always)]
    pub const fn gb(size: u64) -> ByteSize {
        ByteSize(size * GB)
    }

    #[inline(always)]
    pub const fn gib(size: u64) -> ByteSize {
        ByteSize(size * GIB)
    }

    #[inline(always)]
    pub const fn tb(size: u64) -> ByteSize {
        ByteSize(size * TB)
    }

    #[inline(always)]
    pub const fn tib(size: u64) -> ByteSize {
        ByteSize(size * TIB)
    }

    #[inline(always)]
    pub const fn pb(size: u64) -> ByteSize {
        ByteSize(size * PB)
    }

    #[inline(always)]
    pub const fn pib(size: u64) -> ByteSize {
        ByteSize(size * PIB)
    }

    #[inline(always)]
    pub fn as_u64(&self) -> u64 {
        self.0
    }

    #[inline(always)]
    pub fn to_string_as(&self, si_unit: bool) -> String {
        to_string(self.0, si_unit)
    }
}

pub fn to_string(bytes: u64, si_prefix: bool) -> String {
    let unit = if si_prefix { KIB } else { KB };
    let unit_base = if si_prefix { LN_KIB } else { LN_KB };
    let unit_prefix = if si_prefix {
        UNITS_SI.as_bytes()
    } else {
        UNITS.as_bytes()
    };
    let unit_suffix = if si_prefix { "iB" } else { "B" };

    if bytes < unit {
        format!("{} B", bytes)
    } else {
        let size = bytes as f64;
        let exp = match (size.ln() / unit_base) as usize {
            e if e == 0 => 1,
            e => e,
        };

        format!(
            "{:.1} {}{}",
            (size / unit.pow(exp as u32) as f64),
            unit_prefix[exp - 1] as char,
            unit_suffix
        )
    }
}

impl Display for ByteSize {
    fn fmt(&self, f: &mut Formatter) -> Result {
        f.pad(&to_string(self.0, false))
    }
}

impl Debug for ByteSize {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}", self)
    }
}

macro_rules! commutative_op {
    ($t:ty) => {
        impl Add<$t> for ByteSize {
            type Output = ByteSize;
            #[inline(always)]
            fn add(self, rhs: $t) -> ByteSize {
                ByteSize(self.0 + (rhs as u64))
            }
        }

        impl Add<ByteSize> for $t {
            type Output = ByteSize;
            #[inline(always)]
            fn add(self, rhs: ByteSize) -> ByteSize {
                ByteSize(rhs.0 + (self as u64))
            }
        }

        impl Mul<$t> for ByteSize {
            type Output = ByteSize;
            #[inline(always)]
            fn mul(self, rhs: $t) -> ByteSize {
                ByteSize(self.0 * (rhs as u64))
            }
        }

        impl Mul<ByteSize> for $t {
            type Output = ByteSize;
            #[inline(always)]
            fn mul(self, rhs: ByteSize) -> ByteSize {
                ByteSize(rhs.0 * (self as u64))
            }
        }
    };
}

commutative_op!(u64);
commutative_op!(u32);
commutative_op!(u16);
commutative_op!(u8);

impl Add<ByteSize> for ByteSize {
    type Output = ByteSize;

    #[inline(always)]
    fn add(self, rhs: ByteSize) -> ByteSize {
        ByteSize(self.0 + rhs.0)
    }
}

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

    #[test]
    fn test_arithmetic_op() {
        let x = ByteSize::mb(1);
        let y = ByteSize::kb(100);

        assert_eq!((x + y).as_u64(), 1_100_000u64);

        assert_eq!((x + (100 * 1000) as u64).as_u64(), 1_100_000);

        assert_eq!((x * 2u64).as_u64(), 2_000_000);
    }

    #[test]
    fn test_arithmetic_primitives() {
        let x = ByteSize::mb(1);

        assert_eq!((x + MB as u64).as_u64(), 2_000_000);

        assert_eq!((x + MB as u32).as_u64(), 2_000_000);

        assert_eq!((x + KB as u16).as_u64(), 1_001_000);

        assert_eq!((x + B as u8).as_u64(), 1_000_001);
    }

    #[test]
    fn test_comparison() {
        assert!(ByteSize::mb(1) == ByteSize::kb(1000));
        assert!(ByteSize::mib(1) == ByteSize::kib(1024));
        assert!(ByteSize::mb(1) != ByteSize::kib(1024));
        assert!(ByteSize::mb(1) < ByteSize::kib(1024));
        assert!(ByteSize::b(0) < ByteSize::tib(1));
    }

    fn assert_display(expected: &str, b: ByteSize) {
        assert_eq!(expected, format!("{}", b));
    }

    #[test]
    fn test_display() {
        assert_display("215 B", ByteSize::b(215));
        assert_display("1.0 KB", ByteSize::kb(1));
        assert_display("301.0 KB", ByteSize::kb(301));
        assert_display("419.0 MB", ByteSize::mb(419));
        assert_display("518.0 GB", ByteSize::gb(518));
        assert_display("815.0 TB", ByteSize::tb(815));
        assert_display("609.0 PB", ByteSize::pb(609));
    }

    #[test]
    fn test_display_alignment() {
        assert_eq!("|357 B     |", format!("|{:10}|", ByteSize(357)));
        assert_eq!("|     357 B|", format!("|{:>10}|", ByteSize(357)));
        assert_eq!("|357 B     |", format!("|{:<10}|", ByteSize(357)));
        assert_eq!("|  357 B   |", format!("|{:^10}|", ByteSize(357)));

        assert_eq!("|-----357 B|", format!("|{:->10}|", ByteSize(357)));
        assert_eq!("|357 B-----|", format!("|{:-<10}|", ByteSize(357)));
        assert_eq!("|--357 B---|", format!("|{:-^10}|", ByteSize(357)));
    }

    fn assert_to_string(expected: &str, b: ByteSize, si: bool) {
        assert_eq!(expected.to_string(), b.to_string_as(si));
    }

    #[test]
    fn test_to_string_as() {
        assert_to_string("215 B", ByteSize::b(215), true);
        assert_to_string("215 B", ByteSize::b(215), false);

        assert_to_string("1.0 kiB", ByteSize::kib(1), true);
        assert_to_string("1.0 KB", ByteSize::kib(1), false);

        assert_to_string("293.9 kiB", ByteSize::kb(301), true);
        assert_to_string("301.0 KB", ByteSize::kb(301), false);

        assert_to_string("1.0 MiB", ByteSize::mib(1), true);
        assert_to_string("1048.6 KB", ByteSize::mib(1), false);

        // a bug case: https://github.com/flang-project/bytesize/issues/8
        assert_to_string("1.9 GiB", ByteSize::mib(1907), true);
        assert_to_string("2.0 GB", ByteSize::mib(1908), false);

        assert_to_string("399.6 MiB", ByteSize::mb(419), true);
        assert_to_string("419.0 MB", ByteSize::mb(419), false);

        assert_to_string("482.4 GiB", ByteSize::gb(518), true);
        assert_to_string("518.0 GB", ByteSize::gb(518), false);

        assert_to_string("741.2 TiB", ByteSize::tb(815), true);
        assert_to_string("815.0 TB", ByteSize::tb(815), false);

        assert_to_string("540.9 PiB", ByteSize::pb(609), true);
        assert_to_string("609.0 PB", ByteSize::pb(609), false);
    }

    #[test]
    fn test_default() {
        assert_eq!(ByteSize::b(0), ByteSize::default());
    }

    #[test]
    fn test_to_string() {
        assert_to_string("609.0 PB", ByteSize::pb(609), false);
    }
}
<commit_msg>ByteSize: Hash<commit_after>//! ByteSize is an utility that easily makes bytes size representation
//! and helps its arithmetic operations.
//!
//! ## Example
//!
//! ```ignore
//! extern crate bytesize;
//!
//! use bytesize::ByteSize;
//!
//! fn byte_arithmetic_operator() {
//!   let x = ByteSize::mb(1);
//!   let y = ByteSize::kb(100);
//!
//!   let plus = x + y;
//!   print!("{} bytes", plus.as_u64());
//!
//!   let minus = ByteSize::tb(100) - ByteSize::gb(4);
//!   print!("{} bytes", minus.as_u64());
//! }
//! ```
//!
//! It also provides its human readable string as follows:
//!
//! ```ignore=
//!  assert_eq!("482 GiB".to_string(), ByteSize::gb(518).to_string(true));
//!  assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false));
//! ```

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

use std::fmt::{Debug, Display, Formatter, Result};
use std::ops::{Add, Mul};

/// byte size for 1 byte
pub const B: u64 = 1;
/// bytes size for 1 kilobyte
pub const KB: u64 = 1_000;
/// bytes size for 1 megabyte
pub const MB: u64 = 1_000_000;
/// bytes size for 1 gigabyte
pub const GB: u64 = 1_000_000_000;
/// bytes size for 1 terabyte
pub const TB: u64 = 1_000_000_000_000;
/// bytes size for 1 petabyte
pub const PB: u64 = 1_000_000_000_000_000;

/// bytes size for 1 kibibyte
pub const KIB: u64 = 1_024;
/// bytes size for 1 mebibyte
pub const MIB: u64 = 1_048_576;
/// bytes size for 1 gibibyte
pub const GIB: u64 = 1_073_741_824;
/// bytes size for 1 tebibyte
pub const TIB: u64 = 1_099_511_627_776;
/// bytes size for 1 pebibyte
pub const PIB: u64 = 1_125_899_906_842_624;

static UNITS: &'static str = "KMGTPE";
static UNITS_SI: &'static str = "kMGTPE";
static LN_KB: f64 = 6.931471806; // ln 1024
static LN_KIB: f64 = 6.907755279; // ln 1000

pub fn kb<V: Into<u64>>(size: V) -> u64 {
    size.into() * KB
}

pub fn kib<V: Into<u64>>(size: V) -> u64 {
    size.into() * KIB
}

pub fn mb<V: Into<u64>>(size: V) -> u64 {
    size.into() * MB
}

pub fn mib<V: Into<u64>>(size: V) -> u64 {
    size.into() * MIB
}

pub fn gb<V: Into<u64>>(size: V) -> u64 {
    size.into() * GB
}

pub fn gib<V: Into<u64>>(size: V) -> u64 {
    size.into() * GIB
}

pub fn tb<V: Into<u64>>(size: V) -> u64 {
    size.into() * TB
}

pub fn tib<V: Into<u64>>(size: V) -> u64 {
    size.into() * TIB
}

pub fn pb<V: Into<u64>>(size: V) -> u64 {
    size.into() * PB
}

pub fn pib<V: Into<u64>>(size: V) -> u64 {
    size.into() * PIB
}

/// Byte size representation
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ByteSize(pub u64);

impl ByteSize {
    #[inline(always)]
    pub const fn b(size: u64) -> ByteSize {
        ByteSize(size)
    }

    #[inline(always)]
    pub const fn kb(size: u64) -> ByteSize {
        ByteSize(size * KB)
    }

    #[inline(always)]
    pub const fn kib(size: u64) -> ByteSize {
        ByteSize(size * KIB)
    }

    #[inline(always)]
    pub const fn mb(size: u64) -> ByteSize {
        ByteSize(size * MB)
    }

    #[inline(always)]
    pub const fn mib(size: u64) -> ByteSize {
        ByteSize(size * MIB)
    }

    #[inline(always)]
    pub const fn gb(size: u64) -> ByteSize {
        ByteSize(size * GB)
    }

    #[inline(always)]
    pub const fn gib(size: u64) -> ByteSize {
        ByteSize(size * GIB)
    }

    #[inline(always)]
    pub const fn tb(size: u64) -> ByteSize {
        ByteSize(size * TB)
    }

    #[inline(always)]
    pub const fn tib(size: u64) -> ByteSize {
        ByteSize(size * TIB)
    }

    #[inline(always)]
    pub const fn pb(size: u64) -> ByteSize {
        ByteSize(size * PB)
    }

    #[inline(always)]
    pub const fn pib(size: u64) -> ByteSize {
        ByteSize(size * PIB)
    }

    #[inline(always)]
    pub fn as_u64(&self) -> u64 {
        self.0
    }

    #[inline(always)]
    pub fn to_string_as(&self, si_unit: bool) -> String {
        to_string(self.0, si_unit)
    }
}

pub fn to_string(bytes: u64, si_prefix: bool) -> String {
    let unit = if si_prefix { KIB } else { KB };
    let unit_base = if si_prefix { LN_KIB } else { LN_KB };
    let unit_prefix = if si_prefix {
        UNITS_SI.as_bytes()
    } else {
        UNITS.as_bytes()
    };
    let unit_suffix = if si_prefix { "iB" } else { "B" };

    if bytes < unit {
        format!("{} B", bytes)
    } else {
        let size = bytes as f64;
        let exp = match (size.ln() / unit_base) as usize {
            e if e == 0 => 1,
            e => e,
        };

        format!(
            "{:.1} {}{}",
            (size / unit.pow(exp as u32) as f64),
            unit_prefix[exp - 1] as char,
            unit_suffix
        )
    }
}

impl Display for ByteSize {
    fn fmt(&self, f: &mut Formatter) -> Result {
        f.pad(&to_string(self.0, false))
    }
}

impl Debug for ByteSize {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}", self)
    }
}

macro_rules! commutative_op {
    ($t:ty) => {
        impl Add<$t> for ByteSize {
            type Output = ByteSize;
            #[inline(always)]
            fn add(self, rhs: $t) -> ByteSize {
                ByteSize(self.0 + (rhs as u64))
            }
        }

        impl Add<ByteSize> for $t {
            type Output = ByteSize;
            #[inline(always)]
            fn add(self, rhs: ByteSize) -> ByteSize {
                ByteSize(rhs.0 + (self as u64))
            }
        }

        impl Mul<$t> for ByteSize {
            type Output = ByteSize;
            #[inline(always)]
            fn mul(self, rhs: $t) -> ByteSize {
                ByteSize(self.0 * (rhs as u64))
            }
        }

        impl Mul<ByteSize> for $t {
            type Output = ByteSize;
            #[inline(always)]
            fn mul(self, rhs: ByteSize) -> ByteSize {
                ByteSize(rhs.0 * (self as u64))
            }
        }
    };
}

commutative_op!(u64);
commutative_op!(u32);
commutative_op!(u16);
commutative_op!(u8);

impl Add<ByteSize> for ByteSize {
    type Output = ByteSize;

    #[inline(always)]
    fn add(self, rhs: ByteSize) -> ByteSize {
        ByteSize(self.0 + rhs.0)
    }
}

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

    #[test]
    fn test_arithmetic_op() {
        let x = ByteSize::mb(1);
        let y = ByteSize::kb(100);

        assert_eq!((x + y).as_u64(), 1_100_000u64);

        assert_eq!((x + (100 * 1000) as u64).as_u64(), 1_100_000);

        assert_eq!((x * 2u64).as_u64(), 2_000_000);
    }

    #[test]
    fn test_arithmetic_primitives() {
        let x = ByteSize::mb(1);

        assert_eq!((x + MB as u64).as_u64(), 2_000_000);

        assert_eq!((x + MB as u32).as_u64(), 2_000_000);

        assert_eq!((x + KB as u16).as_u64(), 1_001_000);

        assert_eq!((x + B as u8).as_u64(), 1_000_001);
    }

    #[test]
    fn test_comparison() {
        assert!(ByteSize::mb(1) == ByteSize::kb(1000));
        assert!(ByteSize::mib(1) == ByteSize::kib(1024));
        assert!(ByteSize::mb(1) != ByteSize::kib(1024));
        assert!(ByteSize::mb(1) < ByteSize::kib(1024));
        assert!(ByteSize::b(0) < ByteSize::tib(1));
    }

    fn assert_display(expected: &str, b: ByteSize) {
        assert_eq!(expected, format!("{}", b));
    }

    #[test]
    fn test_display() {
        assert_display("215 B", ByteSize::b(215));
        assert_display("1.0 KB", ByteSize::kb(1));
        assert_display("301.0 KB", ByteSize::kb(301));
        assert_display("419.0 MB", ByteSize::mb(419));
        assert_display("518.0 GB", ByteSize::gb(518));
        assert_display("815.0 TB", ByteSize::tb(815));
        assert_display("609.0 PB", ByteSize::pb(609));
    }

    #[test]
    fn test_display_alignment() {
        assert_eq!("|357 B     |", format!("|{:10}|", ByteSize(357)));
        assert_eq!("|     357 B|", format!("|{:>10}|", ByteSize(357)));
        assert_eq!("|357 B     |", format!("|{:<10}|", ByteSize(357)));
        assert_eq!("|  357 B   |", format!("|{:^10}|", ByteSize(357)));

        assert_eq!("|-----357 B|", format!("|{:->10}|", ByteSize(357)));
        assert_eq!("|357 B-----|", format!("|{:-<10}|", ByteSize(357)));
        assert_eq!("|--357 B---|", format!("|{:-^10}|", ByteSize(357)));
    }

    fn assert_to_string(expected: &str, b: ByteSize, si: bool) {
        assert_eq!(expected.to_string(), b.to_string_as(si));
    }

    #[test]
    fn test_to_string_as() {
        assert_to_string("215 B", ByteSize::b(215), true);
        assert_to_string("215 B", ByteSize::b(215), false);

        assert_to_string("1.0 kiB", ByteSize::kib(1), true);
        assert_to_string("1.0 KB", ByteSize::kib(1), false);

        assert_to_string("293.9 kiB", ByteSize::kb(301), true);
        assert_to_string("301.0 KB", ByteSize::kb(301), false);

        assert_to_string("1.0 MiB", ByteSize::mib(1), true);
        assert_to_string("1048.6 KB", ByteSize::mib(1), false);

        // a bug case: https://github.com/flang-project/bytesize/issues/8
        assert_to_string("1.9 GiB", ByteSize::mib(1907), true);
        assert_to_string("2.0 GB", ByteSize::mib(1908), false);

        assert_to_string("399.6 MiB", ByteSize::mb(419), true);
        assert_to_string("419.0 MB", ByteSize::mb(419), false);

        assert_to_string("482.4 GiB", ByteSize::gb(518), true);
        assert_to_string("518.0 GB", ByteSize::gb(518), false);

        assert_to_string("741.2 TiB", ByteSize::tb(815), true);
        assert_to_string("815.0 TB", ByteSize::tb(815), false);

        assert_to_string("540.9 PiB", ByteSize::pb(609), true);
        assert_to_string("609.0 PB", ByteSize::pb(609), false);
    }

    #[test]
    fn test_default() {
        assert_eq!(ByteSize::b(0), ByteSize::default());
    }

    #[test]
    fn test_to_string() {
        assert_to_string("609.0 PB", ByteSize::pb(609), false);
    }
}
<|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!()
    }
    */

    // 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);
    }
}
<commit_msg>Add more tests and stuff<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 struct ParameterCheckError {
    pub msg: &'static str,
}

impl ParameterCheckError {
    // NOTE: very likely to break because it relies on random strings
    // in libsvm
    pub fn from_ptr(ptr: *const libc::c_char) -> Option<ParameterCheckError> {
        use std::ffi::CStr;
        if ptr.is_null() {
            None
        } else {
            let err_str = unsafe { CStr::from_ptr(ptr) }.to_str();
            match err_str {
                Ok(s) => Some(ParameterCheckError { msg: s }),
                Err(_) => None,
            }
        }
    }
}

#[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() {
            return Err(
                ModelCreationError::ParameterCheckError(
                    ParameterCheckError::from_ptr(parameter_error).unwrap()));
        }
        // 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 test0 = vec![
            ([0.0, 0.0f64], -1),
            ([0.0, 1.0], -1),
            ([1.0, 0.0], 1),
            ([1.0, 1.0], 1),
        ];
        let test1 = vec![
            ([0.0, 1.0, 0.0f64], 0),
            ([0.0, 1.0, 1.0], 0),
            ([1.0, 0.0, 0.0], 1),
            ([1.0, 0.0, 1.0], 1),
        ];

        let parameters = Parameters::new()
            .c_svc(1.0, &[], &[]);
        {
            let model = Model::train(&test0, &parameters).unwrap();
            {
                let prediction = model.predict(&[0.0, -1.0]);
                assert_eq!(prediction, -1.0);
            }
            {
                let prediction = model.predict(&[0.7, -0.4]);
                assert_eq!(prediction, 1.0);
            }
        }
        {
            let model = Model::train(&test1, &parameters).unwrap();
            {
                let prediction = model.predict(&[0.0, 1.0, 0.2]);
                assert_eq!(prediction, 0.0);
            }
            {
                let prediction = model.predict(&[1.0, 0.0, -0.3]);
                assert_eq!(prediction, 1.0);
            }
        }

    }
    // TODO: add more tests
}
<|endoftext|>


<commit_before>// Module for parsing ISO Base Media Format aka video/mp4 streams.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

/// Basic ISO box structure.
struct Mp4Box {
    /// Four character box type
    name: u32,
    /// Size of the box in bytes
    size: u64,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Parse a box out of a data buffer.
fn read_box<T: ReadBytesExt>(src: &mut T) -> Option<Mp4Box> {
    let name = src.read_u32::<BigEndian>().unwrap();
    let tmp_size = src.read_u32::<BigEndian>().unwrap();
    let size = match tmp_size {
        1 => src.read_u64::<BigEndian>().unwrap(),
        _ => tmp_size as u64,
    };
    Some(Mp4Box{
        name: name,
        size: size,
    })
}

use std::fmt;
impl fmt::Display for Mp4Box {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let to_vec = |x| vec!((x >> 24 & 0xffu32) as u8,
                              (x >> 16 & 0xffu32) as u8,
                              (x >>  8 & 0xffu32) as u8,
                              (x & 0xffu32) as u8);
        let name_bytes = to_vec(self.name);
        let name = String::from_utf8_lossy(&name_bytes);
        write!(f, "'{}' {} bytes", name, self.size)
    }
}

#[test]
fn test_read_box() {
    use std::io::Cursor;
    let mut test = "test".to_string().into_bytes();
    for x in [0, 0, 0, 8].iter() {
        test.push(*x);
    }
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}

#[test]
fn test_read_box_long() {
    use std::io::Cursor;
    let mut test = "long".to_string().into_bytes();
    for x in [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 16, 0].iter() {
        test.push(*x);
    }
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1819242087);
    assert_eq!(parsed.size, 4096);
    println!("box {}", parsed);
}
<commit_msg>Export MP4Box and read_box.<commit_after>// Module for parsing ISO Base Media Format aka video/mp4 streams.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

/// Basic ISO box structure.
pub struct Mp4Box {
    /// Four character box type
    name: u32,
    /// Size of the box in bytes
    size: u64,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Parse a box out of a data buffer.
pub fn read_box<T: ReadBytesExt>(src: &mut T) -> Option<Mp4Box> {
    let name = src.read_u32::<BigEndian>().unwrap();
    let tmp_size = src.read_u32::<BigEndian>().unwrap();
    let size = match tmp_size {
        1 => src.read_u64::<BigEndian>().unwrap(),
        _ => tmp_size as u64,
    };
    Some(Mp4Box{
        name: name,
        size: size,
    })
}

use std::fmt;
impl fmt::Display for Mp4Box {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let to_vec = |x| vec!((x >> 24 & 0xffu32) as u8,
                              (x >> 16 & 0xffu32) as u8,
                              (x >>  8 & 0xffu32) as u8,
                              (x & 0xffu32) as u8);
        let name_bytes = to_vec(self.name);
        let name = String::from_utf8_lossy(&name_bytes);
        write!(f, "'{}' {} bytes", name, self.size)
    }
}

#[test]
fn test_read_box() {
    use std::io::Cursor;
    let mut test = "test".to_string().into_bytes();
    for x in [0, 0, 0, 8].iter() {
        test.push(*x);
    }
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}

#[test]
fn test_read_box_long() {
    use std::io::Cursor;
    let mut test = "long".to_string().into_bytes();
    for x in [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 16, 0].iter() {
        test.push(*x);
    }
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1819242087);
    assert_eq!(parsed.size, 4096);
    println!("box {}", parsed);
}
<|endoftext|>


<commit_before>//! # Tera
//! Tera is a template engine based on [Jinja2](http://jinja.pocoo.org/)
//! and the [Django template language](https://docs.djangoproject.com/en/1.9/topics/templates/).
//!
//! See the [site](tera.netlify.com) for features and to get started.

#![allow(missing_docs)]
//#![deny(missing_docs)]
#![allow(unused)]

#![cfg_attr(feature = "cargo-clippy", allow(block_in_if_condition_stmt, eq_op))]

extern crate serde;
extern crate serde_json;
extern crate glob;
extern crate pest;
#[macro_use]
extern crate pest_derive;
#[macro_use]
extern crate error_chain;
extern crate slug;
extern crate regex;
#[macro_use]
extern crate lazy_static;
extern crate url;
extern crate humansize;
extern crate chrono;
#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;
#[cfg(test)]
#[macro_use]
extern crate serde_derive;

#[macro_use]
mod macros;
mod errors;
mod context;
mod parser;
mod template;
mod utils;
mod builtins;
mod renderer;
mod tera;

// Library exports.

// Template is meant to be used internally only but is exported for test/bench.
#[doc(hidden)] pub use template::Template;
pub use context::Context;
pub use tera::Tera;
pub use errors::{Result, Error, ErrorKind};
pub use utils::{escape_html};
pub use builtins::global_functions::GlobalFn;
pub use builtins::filters::FilterFn;
pub use builtins::testers::TesterFn;
//// Re-export Value so apps/tools can encode data in Tera types
//// for now it's just an alias to serde_json::Value
pub use serde_json::value::{Value, from_value, to_value};

// Exposes the AST if one needs it but changing the AST is not considered
// a breaking change so it isn't public
#[doc(hidden)]
pub use parser::ast;
<commit_msg>Fix docs url in lib.rs<commit_after>//! # Tera
//! Tera is a template engine based on [Jinja2](http://jinja.pocoo.org/)
//! and the [Django template language](https://docs.djangoproject.com/en/1.9/topics/templates/).
//!
//! See the [site](https://tera.netlify.com) for features and to get started.

#![allow(missing_docs)]
//#![deny(missing_docs)]
#![allow(unused)]

#![cfg_attr(feature = "cargo-clippy", allow(block_in_if_condition_stmt, eq_op))]

extern crate serde;
extern crate serde_json;
extern crate glob;
extern crate pest;
#[macro_use]
extern crate pest_derive;
#[macro_use]
extern crate error_chain;
extern crate slug;
extern crate regex;
#[macro_use]
extern crate lazy_static;
extern crate url;
extern crate humansize;
extern crate chrono;
#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;
#[cfg(test)]
#[macro_use]
extern crate serde_derive;

#[macro_use]
mod macros;
mod errors;
mod context;
mod parser;
mod template;
mod utils;
mod builtins;
mod renderer;
mod tera;

// Library exports.

// Template is meant to be used internally only but is exported for test/bench.
#[doc(hidden)] pub use template::Template;
pub use context::Context;
pub use tera::Tera;
pub use errors::{Result, Error, ErrorKind};
pub use utils::{escape_html};
pub use builtins::global_functions::GlobalFn;
pub use builtins::filters::FilterFn;
pub use builtins::testers::TesterFn;
//// Re-export Value so apps/tools can encode data in Tera types
//// for now it's just an alias to serde_json::Value
pub use serde_json::value::{Value, from_value, to_value};

// Exposes the AST if one needs it but changing the AST is not considered
// a breaking change so it isn't public
#[doc(hidden)]
pub use parser::ast;
<|endoftext|>


<commit_before>/// 2D coordinate
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Coord {
    pub x: usize,
    pub y: usize
}

/// Rectangle defined by inclusive minimum and maximum coordinates
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Rect {
    /// Minimum coordinate (inclusive)
    min_coord: Coord,

    /// Maximum coordinate (inclusive)
    max_coord: Coord
}

/// 2D dimension
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Size {
    pub width: usize,
    pub height: usize
}

/// Container for 2D data
pub struct Vec2D<T> {
    elems: Vec<T>,
    size: Size
}

/// Mutable iterator over a Vec2D
pub struct RectIterMut<'a, Elem: 'a> {
    grid: std::marker::PhantomData<&'a mut Vec2D<Elem>>,

    rect: Rect,
    cur_elem: *mut Elem,
    cur_coord: Coord,
    stride: isize
}

impl Coord {
    /// Create a coordinate at (x, y)
    pub fn new(x: usize, y: usize) -> Coord {
        Coord {
            x: x,
            y: y
        }
    }
}

impl Rect {
    /// Calculate rectangle width
    pub fn width(&self) -> usize {
        return self.max_coord.x - self.min_coord.x + 1;
    }

    /// Calculate rectangle height
    pub fn height(&self) -> usize {
        return self.max_coord.y - self.min_coord.y + 1;
    }

    /// Calculate rectangle size
    pub fn size(&self) -> Size {
        Size::new(self.width(), self.height())
    }
}

impl Size {
    /// Create a 2D size of (width, height)
    pub fn new(width: usize, height: usize) -> Size {
        Size {
            width: width,
            height: height
        }
    }

    pub fn area(&self) -> usize {
        self.width * self.height
    }

    /// Return true if the coordinate fits within self's width and
    /// height, false otherwise.
    pub fn contains_coord(&self, coord: Coord) -> bool {
        coord.x < self.width && coord.y < self.height
    }
}

impl<Elem: Copy> Vec2D<Elem> {
    pub fn from_example(size: Size, example: &Elem) -> Vec2D<Elem> {
        Vec2D {
            elems: vec![*example; size.area()],
            size: size
        }
    }

    pub fn from_vec(size: Size, src: Vec<Elem>) -> Option<Vec2D<Elem>> {
        if size.area() == src.len() {
            Some(Vec2D {
                elems: src,
                size: size
            })
        }
        else {
            None
        }
    }

    pub fn rect_iter_mut<'a>(&'a mut self, rect: Rect) -> Option<RectIterMut<'a, Elem>> {
        if self.size.contains_coord(rect.max_coord) {
            Some(RectIterMut {
                grid: std::marker::PhantomData,
                stride: (self.size.width - rect.width() + 1) as isize,
                cur_elem: self.elems.as_mut_ptr(),
                rect: rect,
                cur_coord: rect.min_coord
            })
        }
        else {
            None
        }
    }
}

impl<'a, Elem> Iterator for RectIterMut<'a, Elem> {
    type Item = (Coord, &'a mut Elem);

    fn next(&mut self) -> Option<Self::Item> {
        if self.cur_coord.y <= self.rect.max_coord.y {
            let result = (self.cur_coord, unsafe { &mut *self.cur_elem });

            self.cur_coord.x += 1;
            if self.cur_coord.x <= self.rect.max_coord.x {
                unsafe { self.cur_elem = self.cur_elem.offset(1); }
            }
            else {
                self.cur_coord.x = self.rect.min_coord.x;
                self.cur_coord.y += 1;
                unsafe { self.cur_elem = self.cur_elem.offset(self.stride); }
            }
            Some(result)
        }
        else {
            None
        }
    }
}

impl Rect {
    /// Create a new Rect defined by inclusive minimum and maximum
    /// coordinates. If min_coord is greater than max_coord on either
    /// axis then None is returned.
    pub fn new(min_coord: Coord, max_coord: Coord) -> Option<Rect> {
        if min_coord.x <= max_coord.x && min_coord.y <= max_coord.y {
            Some(Rect {
                min_coord: min_coord,
                max_coord: max_coord
            })
        }
        else {
            None
        }
    }

}

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

    #[test]
    fn test_coord() {
        let coord = Coord::new(1, 2);
        assert_eq!(coord.x, 1);
        assert_eq!(coord.y, 2);
    }

    #[test]
    fn test_rect_iter_mut() {
        let elems = vec![1, 2, 3, 4];
        let mut grid = Vec2D::from_vec(Size::new(2, 2), elems).unwrap();
        let rect = Rect::new(Coord::new(0, 0), Coord::new(1, 1)).unwrap();

        let mut actual_coords = Vec::new();
        for (coord, elem) in grid.rect_iter_mut(rect).unwrap() {
            *elem = -(*elem);
            actual_coords.push((coord.x, coord.y));
        }
        assert_eq!(actual_coords, [(0, 0), (1, 0), (0, 1), (1, 1)]);
        assert_eq!(grid.elems, [-1, -2, -3, -4]);
    }
}
<commit_msg>Add more docstrings<commit_after>// Copyright 2015 Nicholas Bishop
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Vec2D is a very simple 2D container for storing rectangular data

#![deny(missing_docs)]

/// 2D coordinate
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Coord {
    /// X component
    pub x: usize,

    /// Y component
    pub y: usize
}

/// Rectangle defined by inclusive minimum and maximum coordinates
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Rect {
    /// Minimum coordinate (inclusive)
    min_coord: Coord,

    /// Maximum coordinate (inclusive)
    max_coord: Coord
}

/// Rectangle dimensions
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Size {
    /// Width of rectangle
    pub width: usize,
    /// Height of rectangle
    pub height: usize
}

/// Container for 2D data
pub struct Vec2D<T> {
    elems: Vec<T>,
    size: Size
}

/// Mutable iterator over a Vec2D
pub struct RectIterMut<'a, Elem: 'a> {
    grid: std::marker::PhantomData<&'a mut Vec2D<Elem>>,

    rect: Rect,
    cur_elem: *mut Elem,
    cur_coord: Coord,
    stride: isize
}

impl Coord {
    /// Create a coordinate at (x, y)
    pub fn new(x: usize, y: usize) -> Coord {
        Coord {
            x: x,
            y: y
        }
    }
}

impl Rect {
    /// Calculate rectangle width
    pub fn width(&self) -> usize {
        return self.max_coord.x - self.min_coord.x + 1;
    }

    /// Calculate rectangle height
    pub fn height(&self) -> usize {
        return self.max_coord.y - self.min_coord.y + 1;
    }

    /// Calculate rectangle size
    pub fn size(&self) -> Size {
        Size::new(self.width(), self.height())
    }
}

impl Size {
    /// Create a 2D size of (width, height)
    pub fn new(width: usize, height: usize) -> Size {
        Size {
            width: width,
            height: height
        }
    }

    /// width * height
    pub fn area(&self) -> usize {
        self.width * self.height
    }

    /// Return true if the coordinate fits within self's width and
    /// height, false otherwise.
    pub fn contains_coord(&self, coord: Coord) -> bool {
        coord.x < self.width && coord.y < self.height
    }
}

impl<Elem: Copy> Vec2D<Elem> {
    /// Create a Vec2D with the given `size`. All elements are
    /// initialized as copies of the `example` element.
    pub fn from_example(size: Size, example: &Elem) -> Vec2D<Elem> {
        Vec2D {
            elems: vec![*example; size.area()],
            size: size
        }
    }

    /// Create a Vec2D with the given `size`. The contents are set to
    /// `src`. None is returned if the `size` does not match the
    /// length of `src`.
    pub fn from_vec(size: Size, src: Vec<Elem>) -> Option<Vec2D<Elem>> {
        if size.area() == src.len() {
            Some(Vec2D {
                elems: src,
                size: size
            })
        }
        else {
            None
        }
    }

    /// Create a mutable iterator over a rectangular region of the
    /// Vec2D. None is returned if the given `rect` does not fit
    /// entirely within the Vec2D.
    pub fn rect_iter_mut<'a>(&'a mut self, rect: Rect) -> Option<RectIterMut<'a, Elem>> {
        if self.size.contains_coord(rect.max_coord) {
            Some(RectIterMut {
                grid: std::marker::PhantomData,
                stride: (self.size.width - rect.width() + 1) as isize,
                cur_elem: self.elems.as_mut_ptr(),
                rect: rect,
                cur_coord: rect.min_coord
            })
        }
        else {
            None
        }
    }
}

impl<'a, Elem> Iterator for RectIterMut<'a, Elem> {
    type Item = (Coord, &'a mut Elem);

    fn next(&mut self) -> Option<Self::Item> {
        if self.cur_coord.y <= self.rect.max_coord.y {
            let result = (self.cur_coord, unsafe { &mut *self.cur_elem });

            self.cur_coord.x += 1;
            if self.cur_coord.x <= self.rect.max_coord.x {
                unsafe { self.cur_elem = self.cur_elem.offset(1); }
            }
            else {
                self.cur_coord.x = self.rect.min_coord.x;
                self.cur_coord.y += 1;
                unsafe { self.cur_elem = self.cur_elem.offset(self.stride); }
            }
            Some(result)
        }
        else {
            None
        }
    }
}

impl Rect {
    /// Create a new Rect defined by inclusive minimum and maximum
    /// coordinates. If min_coord is greater than max_coord on either
    /// axis then None is returned.
    pub fn new(min_coord: Coord, max_coord: Coord) -> Option<Rect> {
        if min_coord.x <= max_coord.x && min_coord.y <= max_coord.y {
            Some(Rect {
                min_coord: min_coord,
                max_coord: max_coord
            })
        }
        else {
            None
        }
    }

}

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

    #[test]
    fn test_coord() {
        let coord = Coord::new(1, 2);
        assert_eq!(coord.x, 1);
        assert_eq!(coord.y, 2);
    }

    #[test]
    fn test_rect_iter_mut() {
        let elems = vec![1, 2, 3, 4];
        let mut grid = Vec2D::from_vec(Size::new(2, 2), elems).unwrap();
        let rect = Rect::new(Coord::new(0, 0), Coord::new(1, 1)).unwrap();

        let mut actual_coords = Vec::new();
        for (coord, elem) in grid.rect_iter_mut(rect).unwrap() {
            *elem = -(*elem);
            actual_coords.push((coord.x, coord.y));
        }
        assert_eq!(actual_coords, [(0, 0), (1, 0), (0, 1), (1, 1)]);
        assert_eq!(grid.elems, [-1, -2, -3, -4]);
    }
}
<|endoftext|>


<commit_before>// 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.

//! # LLDB
//!
//! This crate provides a safe binding to the public API for [LLDB], the
//! debugger provided by the [LLVM project]. LLDB provides a modern, high
//! performance debugger framework and is the default debugger for macOS
//! and iOS.
//!
//! ## Installation
//!
//! This crate works with Cargo and is on [crates.io].
//! Add it to your `Cargo.toml` like so:
//!
//! ```toml
//! lldb = "0.0.7"
//! ```
//!
//! ### macOS Installation Notes
//!
//! On macOS, this library relies upon being able to find
//! the `LLDB.framework` that is provided by Xcode.app.
//!
//! In your own application, you will need to configure the
//! `@rpath` for your execuable to point to the location
//! of the `LLDB.framework` that you are using. Doing this
//! automatically is not currently supported by Cargo.
//!
//! For testing, you can use the version provided by
//! Xcode.app by setting an environment variable:
//!
//! ```shell
//! export DYLD_FRAMEWORK_PATH=/Applications/Xcode.app/Contents/SharedFrameworks
//! ```
//!
//! ### Linux Installation Notes
//!
//! Support for building this has not yet been provided for Linux.
//! Contributions are welcome!
//!
//! ### Windows Installation Notes
//!
//! Support for building this has not yet been provided for Windows.
//! Contributions are welcome!
//!
//! ## Usage
//!
//! The primary entry point is [`SBDebugger`]. This will be how you
//! create a debug target and begin the actually interesting stuff.
//!
//! ## Important Classes
//!
//! The LLDB API provides many structs and a wide range of functionality. Some of the
//! most common usages will involve these structs and their corresponding methods:
//!
//! * [`SBDebugger`]: Manages the entire debug experience and creates [`SBTarget`]s.
//! * [`SBTarget`]: The target program running under the debugger.
//! * [`SBProcess`]: The process associated with the target program.
//! * [`SBThread`]: A thread of execution. [`SBProcess`] contains
//!   [`SBThread`]s.
//! * [`SBFrame`]: One of the stack frames associated with
//!   a thread. [`SBThread`] contains [`SBFrame`]s.
//! * [`SBSymbolContext`]: A container that stores various debugger
//!   related info.
//! * [`SBValue`]: The value of a variable, a register, or an
//!   expression.
//! * [`SBModule`]: An executable image and its associated object
//!   and symbol files.  [`SBTarget`] contains [`SBModule`]s.
//! * [`SBBreakpoint`]: A logical breakpoint and its associated
//!   settings. [`SBTarget`] contains [`SBBreakpoint`]s.
//! * [`SBSymbol`]: The symbol possibly associated with a stack frame.
//! * [`SBCompileUnit`]: A compilation unit, or compiled source file.
//! * [`SBFunction`]: A generic function, which can be inlined or not.
//! * [`SBBlock`]: A lexical block. [`SBFunction`] contains [`SBBlock`]s.
//! * [`SBLineEntry`]: Specifies an association with a contiguous range of
//!   instructions and a source file location. [`SBCompileUnit`] contains
//!   [`SBLineEntry`]s.
//!
//! ## Support and Maintenance
//!
//! I am developing this library largely on my own so far. I am able
//! to offer support and maintenance, but would very much appreciate
//! donations via [Patreon](https://patreon.com/endoli). I can also
//! provide commercial support, so feel free to
//! [contact me](mailto:bruce.mitchener@gmail.com).
//!
//! [LLDB]: http://lldb.llvm.org/
//! [LLVM project]: http://llvm.org/
//! [crates.io]: https://crates.io/crates/lldb
//! [`SBDebugger`]: struct.SBDebugger.html
//! [`SBTarget`]: struct.SBTarget.html
//! [`SBProcess`]: struct.SBProcess.html
//! [`SBThread`]: struct.SBThread.html
//! [`SBFrame`]: struct.SBFrame.html
//! [`SBSymbolContext`]: struct.SBSymbolContext.html
//! [`SBValue`]: struct.SBValue.html
//! [`SBModule`]: struct.SBModule.html
//! [`SBBreakpoint`]: struct.SBBreakpoint.html
//! [`SBSymbol`]: struct.SBSymbol.html
//! [`SBCompileUnit`]: struct.SBCompileUnit.html
//! [`SBFunction`]: struct.SBFunction.html
//! [`SBBlock`]: struct.SBBlock.html
//! [`SBLineEntry`]: struct.SBLineEntry.html

#![warn(missing_docs)]
#![deny(trivial_numeric_casts, unstable_features,
        unused_import_braces, unused_qualifications)]

extern crate lldb_sys as sys;

#[cfg(feature = "graphql")]
#[macro_use]
extern crate juniper;

pub use sys::{lldb_addr_t, lldb_offset_t, lldb_pid_t, lldb_tid_t, lldb_user_id_t};

pub use sys::{AccessType, AddressClass, BasicType, BreakpointEventType, ByteOrder,
              CommandArgumentType, CommandFlags, ConnectionStatus, DescriptionLevel,
              DynamicValueType, EmulateInstructionOptions, Encoding, ErrorType,
              ExpressionEvaluationPhase, ExpressionResults, FilePermissions, Format,
              FrameComparison, FunctionNameType, GdbSignal, InputReaderAction,
              InputReaderGranularity, InstrumentationRuntimeType, LanguageType, LaunchFlags,
              MatchType, MemberFunctionKind, PathType, Permissions, QueueItemKind, QueueKind,
              RegisterKind, ReturnStatus, RunMode, ScriptLanguage, SectionType, StateType,
              StopReason, SymbolContextItem, SymbolType, TemplateArgumentKind, TypeClass,
              TypeFlags, TypeOptions, TypeSummaryCapping, ValueType, WatchpointEventType,
              WatchpointKind};

mod address;
mod attachinfo;
mod block;
mod breakpoint;
mod breakpointlist;
mod breakpointlocation;
mod broadcaster;
mod compileunit;
mod data;
mod debugger;
mod error;
mod event;
mod expressionoptions;
mod filespec;
mod filespeclist;
mod frame;
mod function;
mod instruction;
mod instructionlist;
mod launchinfo;
mod lineentry;
mod listener;
mod module;
mod modulespec;
mod platform;
mod process;
mod queue;
mod queueitem;
mod section;
mod stream;
mod stringlist;
mod structureddata;
mod symbol;
mod symbolcontext;
mod target;
mod thread;
mod types;
mod typelist;
mod value;
mod valuelist;
mod variablesoptions;
mod watchpoint;

pub use self::address::SBAddress;
pub use self::attachinfo::SBAttachInfo;
pub use self::block::SBBlock;
pub use self::breakpoint::{SBBreakpoint, SBBreakpointLocationIter};
pub use self::breakpointlist::{SBBreakpointList, SBBreakpointListIter};
pub use self::breakpointlocation::SBBreakpointLocation;
pub use self::broadcaster::SBBroadcaster;
pub use self::compileunit::SBCompileUnit;
pub use self::data::SBData;
pub use self::debugger::{SBDebugger, SBDebuggerTargetIter};
pub use self::error::SBError;
pub use self::event::SBEvent;
pub use self::expressionoptions::SBExpressionOptions;
pub use self::filespec::SBFileSpec;
pub use self::filespeclist::{SBFileSpecList, SBFileSpecListIter};
pub use self::frame::SBFrame;
pub use self::function::SBFunction;
pub use self::instruction::SBInstruction;
pub use self::instructionlist::{SBInstructionList, SBInstructionListIter};
pub use self::launchinfo::SBLaunchInfo;
pub use self::lineentry::SBLineEntry;
pub use self::listener::SBListener;
pub use self::module::{SBModule, SBModuleSectionIter};
pub use self::modulespec::SBModuleSpec;
pub use self::platform::SBPlatform;
pub use self::process::{SBProcess, SBProcessEvent, SBProcessEventRestartedReasonIter,
                        SBProcessQueueIter, SBProcessThreadIter};
pub use self::queue::{SBQueue, SBQueueQueueItemIter, SBQueueThreadIter};
pub use self::queueitem::SBQueueItem;
pub use self::section::{SBSection, SBSectionSubSectionIter};
pub use self::stream::SBStream;
pub use self::stringlist::{SBStringList, SBStringListIter};
pub use self::structureddata::SBStructuredData;
pub use self::symbol::SBSymbol;
pub use self::symbolcontext::SBSymbolContext;
pub use self::target::{SBTarget, SBTargetBreakpointIter, SBTargetEvent, SBTargetEventModuleIter,
                       SBTargetModuleIter, SBTargetWatchpointIter};
pub use self::thread::{SBThread, SBThreadEvent, SBThreadFrameIter};
pub use self::types::SBType;
pub use self::typelist::{SBTypeList, SBTypeListIter};
pub use self::value::SBValue;
pub use self::valuelist::{SBValueList, SBValueListIter};
pub use self::variablesoptions::SBVariablesOptions;
pub use self::watchpoint::SBWatchpoint;

/// Which syntax should be used in disassembly?
///
/// On x86, there are 2 syntaxes used for disassembly. Other
/// architectures need not be concerned by this and can just
/// use `DisassemblyFlavor::Default` all the time.
#[derive(Clone, Copy, Debug)]
pub enum DisassemblyFlavor {
    /// The primary syntax used by the GNU Assembler and in the
    /// Linux world.
    ///
    /// AT&T syntax:
    ///
    /// * Operations has a suffix, indicating the operand size.
    /// * Prefixes registers with `%` and immediate values with `$`.
    /// * Orders operands with source first, then destination.
    /// * Memory operands are somewhat complicated.
    ///
    /// For example:
    ///
    /// ```asm
    /// movb $0x05, %al
    /// ```
    ///
    /// This syntax is described in detail in [GAS Syntax].
    ///
    /// [GAS Syntax]: https://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax
    ATT,
    /// The default syntax.
    Default,
    /// The primary syntax used on Windows.
    ///
    /// This differs from AT&T syntax in that:
    ///
    /// * Operations are not suffixed.
    /// * Registers are not prefixed with `%`, immediate values have a suffix.
    /// * Operands are ordered so that the destination is first, then the source.
    ///
    /// For example:
    ///
    /// ```asm
    /// mov al, 05h
    /// ```
    ///
    Intel,
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>Update Linux build notes.<commit_after>// 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.

//! # LLDB
//!
//! This crate provides a safe binding to the public API for [LLDB], the
//! debugger provided by the [LLVM project]. LLDB provides a modern, high
//! performance debugger framework and is the default debugger for macOS
//! and iOS.
//!
//! ## Installation
//!
//! This crate works with Cargo and is on [crates.io].
//! Add it to your `Cargo.toml` like so:
//!
//! ```toml
//! lldb = "0.0.7"
//! ```
//!
//! ### macOS Installation Notes
//!
//! On macOS, this library relies upon being able to find
//! the `LLDB.framework` that is provided by Xcode.app.
//!
//! In your own application, you will need to configure the
//! `@rpath` for your execuable to point to the location
//! of the `LLDB.framework` that you are using. Doing this
//! automatically is not currently supported by Cargo.
//!
//! For testing, you can use the version provided by
//! Xcode.app by setting an environment variable:
//!
//! ```shell
//! export DYLD_FRAMEWORK_PATH=/Applications/Xcode.app/Contents/SharedFrameworks
//! ```
//!
//! ### Linux Installation Notes
//!
//! Install the `lldb` and `lldb-dev` packages for your platform so that
//! you have both LLDB itself installed as well as the headers and
//! other support files required.
//!
//! ### Windows Installation Notes
//!
//! Support for building this has not yet been provided for Windows.
//! Contributions are welcome!
//!
//! ## Usage
//!
//! The primary entry point is [`SBDebugger`]. This will be how you
//! create a debug target and begin the actually interesting stuff.
//!
//! ## Important Classes
//!
//! The LLDB API provides many structs and a wide range of functionality. Some of the
//! most common usages will involve these structs and their corresponding methods:
//!
//! * [`SBDebugger`]: Manages the entire debug experience and creates [`SBTarget`]s.
//! * [`SBTarget`]: The target program running under the debugger.
//! * [`SBProcess`]: The process associated with the target program.
//! * [`SBThread`]: A thread of execution. [`SBProcess`] contains
//!   [`SBThread`]s.
//! * [`SBFrame`]: One of the stack frames associated with
//!   a thread. [`SBThread`] contains [`SBFrame`]s.
//! * [`SBSymbolContext`]: A container that stores various debugger
//!   related info.
//! * [`SBValue`]: The value of a variable, a register, or an
//!   expression.
//! * [`SBModule`]: An executable image and its associated object
//!   and symbol files.  [`SBTarget`] contains [`SBModule`]s.
//! * [`SBBreakpoint`]: A logical breakpoint and its associated
//!   settings. [`SBTarget`] contains [`SBBreakpoint`]s.
//! * [`SBSymbol`]: The symbol possibly associated with a stack frame.
//! * [`SBCompileUnit`]: A compilation unit, or compiled source file.
//! * [`SBFunction`]: A generic function, which can be inlined or not.
//! * [`SBBlock`]: A lexical block. [`SBFunction`] contains [`SBBlock`]s.
//! * [`SBLineEntry`]: Specifies an association with a contiguous range of
//!   instructions and a source file location. [`SBCompileUnit`] contains
//!   [`SBLineEntry`]s.
//!
//! ## Support and Maintenance
//!
//! I am developing this library largely on my own so far. I am able
//! to offer support and maintenance, but would very much appreciate
//! donations via [Patreon](https://patreon.com/endoli). I can also
//! provide commercial support, so feel free to
//! [contact me](mailto:bruce.mitchener@gmail.com).
//!
//! [LLDB]: http://lldb.llvm.org/
//! [LLVM project]: http://llvm.org/
//! [crates.io]: https://crates.io/crates/lldb
//! [`SBDebugger`]: struct.SBDebugger.html
//! [`SBTarget`]: struct.SBTarget.html
//! [`SBProcess`]: struct.SBProcess.html
//! [`SBThread`]: struct.SBThread.html
//! [`SBFrame`]: struct.SBFrame.html
//! [`SBSymbolContext`]: struct.SBSymbolContext.html
//! [`SBValue`]: struct.SBValue.html
//! [`SBModule`]: struct.SBModule.html
//! [`SBBreakpoint`]: struct.SBBreakpoint.html
//! [`SBSymbol`]: struct.SBSymbol.html
//! [`SBCompileUnit`]: struct.SBCompileUnit.html
//! [`SBFunction`]: struct.SBFunction.html
//! [`SBBlock`]: struct.SBBlock.html
//! [`SBLineEntry`]: struct.SBLineEntry.html

#![warn(missing_docs)]
#![deny(trivial_numeric_casts, unstable_features,
        unused_import_braces, unused_qualifications)]

extern crate lldb_sys as sys;

#[cfg(feature = "graphql")]
#[macro_use]
extern crate juniper;

pub use sys::{lldb_addr_t, lldb_offset_t, lldb_pid_t, lldb_tid_t, lldb_user_id_t};

pub use sys::{AccessType, AddressClass, BasicType, BreakpointEventType, ByteOrder,
              CommandArgumentType, CommandFlags, ConnectionStatus, DescriptionLevel,
              DynamicValueType, EmulateInstructionOptions, Encoding, ErrorType,
              ExpressionEvaluationPhase, ExpressionResults, FilePermissions, Format,
              FrameComparison, FunctionNameType, GdbSignal, InputReaderAction,
              InputReaderGranularity, InstrumentationRuntimeType, LanguageType, LaunchFlags,
              MatchType, MemberFunctionKind, PathType, Permissions, QueueItemKind, QueueKind,
              RegisterKind, ReturnStatus, RunMode, ScriptLanguage, SectionType, StateType,
              StopReason, SymbolContextItem, SymbolType, TemplateArgumentKind, TypeClass,
              TypeFlags, TypeOptions, TypeSummaryCapping, ValueType, WatchpointEventType,
              WatchpointKind};

mod address;
mod attachinfo;
mod block;
mod breakpoint;
mod breakpointlist;
mod breakpointlocation;
mod broadcaster;
mod compileunit;
mod data;
mod debugger;
mod error;
mod event;
mod expressionoptions;
mod filespec;
mod filespeclist;
mod frame;
mod function;
mod instruction;
mod instructionlist;
mod launchinfo;
mod lineentry;
mod listener;
mod module;
mod modulespec;
mod platform;
mod process;
mod queue;
mod queueitem;
mod section;
mod stream;
mod stringlist;
mod structureddata;
mod symbol;
mod symbolcontext;
mod target;
mod thread;
mod types;
mod typelist;
mod value;
mod valuelist;
mod variablesoptions;
mod watchpoint;

pub use self::address::SBAddress;
pub use self::attachinfo::SBAttachInfo;
pub use self::block::SBBlock;
pub use self::breakpoint::{SBBreakpoint, SBBreakpointLocationIter};
pub use self::breakpointlist::{SBBreakpointList, SBBreakpointListIter};
pub use self::breakpointlocation::SBBreakpointLocation;
pub use self::broadcaster::SBBroadcaster;
pub use self::compileunit::SBCompileUnit;
pub use self::data::SBData;
pub use self::debugger::{SBDebugger, SBDebuggerTargetIter};
pub use self::error::SBError;
pub use self::event::SBEvent;
pub use self::expressionoptions::SBExpressionOptions;
pub use self::filespec::SBFileSpec;
pub use self::filespeclist::{SBFileSpecList, SBFileSpecListIter};
pub use self::frame::SBFrame;
pub use self::function::SBFunction;
pub use self::instruction::SBInstruction;
pub use self::instructionlist::{SBInstructionList, SBInstructionListIter};
pub use self::launchinfo::SBLaunchInfo;
pub use self::lineentry::SBLineEntry;
pub use self::listener::SBListener;
pub use self::module::{SBModule, SBModuleSectionIter};
pub use self::modulespec::SBModuleSpec;
pub use self::platform::SBPlatform;
pub use self::process::{SBProcess, SBProcessEvent, SBProcessEventRestartedReasonIter,
                        SBProcessQueueIter, SBProcessThreadIter};
pub use self::queue::{SBQueue, SBQueueQueueItemIter, SBQueueThreadIter};
pub use self::queueitem::SBQueueItem;
pub use self::section::{SBSection, SBSectionSubSectionIter};
pub use self::stream::SBStream;
pub use self::stringlist::{SBStringList, SBStringListIter};
pub use self::structureddata::SBStructuredData;
pub use self::symbol::SBSymbol;
pub use self::symbolcontext::SBSymbolContext;
pub use self::target::{SBTarget, SBTargetBreakpointIter, SBTargetEvent, SBTargetEventModuleIter,
                       SBTargetModuleIter, SBTargetWatchpointIter};
pub use self::thread::{SBThread, SBThreadEvent, SBThreadFrameIter};
pub use self::types::SBType;
pub use self::typelist::{SBTypeList, SBTypeListIter};
pub use self::value::SBValue;
pub use self::valuelist::{SBValueList, SBValueListIter};
pub use self::variablesoptions::SBVariablesOptions;
pub use self::watchpoint::SBWatchpoint;

/// Which syntax should be used in disassembly?
///
/// On x86, there are 2 syntaxes used for disassembly. Other
/// architectures need not be concerned by this and can just
/// use `DisassemblyFlavor::Default` all the time.
#[derive(Clone, Copy, Debug)]
pub enum DisassemblyFlavor {
    /// The primary syntax used by the GNU Assembler and in the
    /// Linux world.
    ///
    /// AT&T syntax:
    ///
    /// * Operations has a suffix, indicating the operand size.
    /// * Prefixes registers with `%` and immediate values with `$`.
    /// * Orders operands with source first, then destination.
    /// * Memory operands are somewhat complicated.
    ///
    /// For example:
    ///
    /// ```asm
    /// movb $0x05, %al
    /// ```
    ///
    /// This syntax is described in detail in [GAS Syntax].
    ///
    /// [GAS Syntax]: https://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax
    ATT,
    /// The default syntax.
    Default,
    /// The primary syntax used on Windows.
    ///
    /// This differs from AT&T syntax in that:
    ///
    /// * Operations are not suffixed.
    /// * Registers are not prefixed with `%`, immediate values have a suffix.
    /// * Operands are ordered so that the destination is first, then the source.
    ///
    /// For example:
    ///
    /// ```asm
    /// mov al, 05h
    /// ```
    ///
    Intel,
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>//! A collection of synchronization primitives that build on the primitives available in the
//! standard library.

use std::sync::{Mutex, Condvar};
use std::time::Duration;

/// A synchronization primitive that signals when its count reaches zero.
///
/// With a `CountdownEvent`, it's possible to cause one thread to wait on a set of computations
/// occurring in other threads by making the other threads interact with the counter as they perform
/// their work.
///
/// The main limitation of a CountdownEvent is that once its counter reaches zero (even by starting
/// there), any attempts to update the counter will return `CountdownError::AlreadySet` until the
/// counter is reset by calling `reset` or `reset_to_count`.
///
/// # Example
///
/// ```
/// use synchronoise::CountdownEvent;
/// use std::sync::Arc;
/// use std::thread;
/// use std::time::Duration;
///
/// let counter = Arc::new(CountdownEvent::new(5));
///
/// for i in 0..5 {
///     let signal = counter.clone();
///     thread::spawn(move || {
///         thread::sleep(Duration::from_secs(3));
///         println!("thread {} activated!", i);
///         signal.decrement();
///     });
/// }
///
/// counter.wait();
///
/// println!("all done!");
/// ```
pub struct CountdownEvent {
    initial: isize,
    counter: Mutex<isize>,
    lock: Condvar,
}

///The collection of errors that can be returned by `CountdownEvent` methods.
pub enum CountdownError {
    ///Returned when adding to a counter would have caused it to overflow.
    SaturatedCounter,
    ///Returned when attempting to signal would have caused the counter to go below zero.
    TooManySignals,
    ///Returned when attempting to modify the counter after it has reached zero.
    AlreadySet,
}

impl CountdownEvent {
    ///Creates a new `CountdownEvent`, initialized to the given count.
    pub fn new(count: isize) -> CountdownEvent {
        CountdownEvent {
            initial: count,
            counter: Mutex::new(count),
            lock: Condvar::new(),
        }
    }

    ///Resets the counter to the count given to `new`.
    ///
    ///This function is safe because the `&mut self` enforces that no other references or locks
    ///exist.
    pub fn reset(&mut self) {
        self.counter = Mutex::new(self.initial);
        self.lock = Condvar::new();
    }

    ///Resets the counter to the given count.
    ///
    ///This function is safe because the `&mut self` enforces that no other references or locks
    ///exist.
    pub fn reset_to_count(&mut self, count: isize) {
        self.initial = count;
        self.reset();
    }

    ///Returns the current counter value.
    pub fn count(&self) -> isize {
        let lock = self.counter.lock().unwrap();

        *lock
    }

    ///Adds the given count to the counter.
    ///
    ///# Errors
    ///
    ///If the counter is already at or below zero, this function will return an error.
    ///
    ///If the given count would overflow an `isize`, this function will return an error.
    pub fn add(&self, count: isize) -> Result<(), CountdownError> {
        let mut lock = self.counter.lock().unwrap();

        if *lock <= 0 {
            return Err(CountdownError::AlreadySet);
        }

        if let Some(new_count) = count.checked_add(*lock) {
            *lock = new_count;
        } else {
            return Err(CountdownError::SaturatedCounter);
        }

        Ok(())
    }

    ///Subtracts the given count to the counter, and returns whether this caused any waiting
    ///threads to wake up.
    ///
    ///# Errors
    ///
    ///If the counter was already at or below zero, this function will return an error.
    ///
    ///If the given count is greater than the current counter, this function will return an error.
    pub fn signal(&self, count: isize) -> Result<bool, CountdownError> {
        let mut lock = self.counter.lock().unwrap();

        if *lock == 0 {
            return Err(CountdownError::AlreadySet);
        }

        if count <= *lock {
            *lock -= count;
        } else {
            return Err(CountdownError::TooManySignals);
        }

        if *lock == 0 {
            self.lock.notify_all();
            Ok(true)
        } else {
            Ok(false)
        }
    }

    ///Adds one to the count.
    ///
    ///# Errors
    ///
    ///See [`add`] for the situations where this function will return an error.
    ///
    ///[`add`]: fn.add.html
    pub fn increment(&self) -> Result<(), CountdownError> {
        self.add(1)
    }

    ///Subtracts one from the counter, and returns whether this caused any waiting threads to wake
    ///up.
    ///
    ///# Errors
    ///
    ///See [`signal`] for the situations where this function will return an error.
    ///
    ///[`signal`]: fn.signal.html
    pub fn decrement(&self) -> Result<bool, CountdownError> {
        self.signal(1)
    }

    ///Blocks the current thread until the counter reaches zero.
    ///
    ///This function will block indefinitely until the counter reaches zero. It will return
    ///immediately if it is already at zero.
    pub fn wait(&self) {
        let mut count = self.counter.lock().unwrap();

        while *count > 0 {
            count = self.lock.wait(count).unwrap();
        }
    }

    ///Blocks the current thread until the timer reaches zero, or until the given timeout elapses,
    ///returning the count at the time of wakeup and whether the timeout is known to have elapsed.
    ///
    ///This function will return immediately if the counter was already at zero. Otherwise, it will
    ///block for roughly no longer than `timeout`. Due to limitations in the platform specific
    ///implementation of `std::sync::Condvar`, this method could spuriously wake up both before the timeout
    ///elapsed and without the count being zero.
    pub fn wait_timeout(&self, timeout: Duration) -> (isize, bool) {
        let count = self.counter.lock().unwrap();

        if *count == 0 {
            return (*count, false);
        }

        let (count, status) = self.lock.wait_timeout(count, timeout).unwrap();

        (*count, status.timed_out())
    }
}
<commit_msg>fix method links in CountdownEvent docs<commit_after>//! A collection of synchronization primitives that build on the primitives available in the
//! standard library.

use std::sync::{Mutex, Condvar};
use std::time::Duration;

/// A synchronization primitive that signals when its count reaches zero.
///
/// With a `CountdownEvent`, it's possible to cause one thread to wait on a set of computations
/// occurring in other threads by making the other threads interact with the counter as they perform
/// their work.
///
/// The main limitation of a CountdownEvent is that once its counter reaches zero (even by starting
/// there), any attempts to update the counter will return `CountdownError::AlreadySet` until the
/// counter is reset by calling `reset` or `reset_to_count`.
///
/// # Example
///
/// ```
/// use synchronoise::CountdownEvent;
/// use std::sync::Arc;
/// use std::thread;
/// use std::time::Duration;
///
/// let counter = Arc::new(CountdownEvent::new(5));
///
/// for i in 0..5 {
///     let signal = counter.clone();
///     thread::spawn(move || {
///         thread::sleep(Duration::from_secs(3));
///         println!("thread {} activated!", i);
///         signal.decrement();
///     });
/// }
///
/// counter.wait();
///
/// println!("all done!");
/// ```
pub struct CountdownEvent {
    initial: isize,
    counter: Mutex<isize>,
    lock: Condvar,
}

///The collection of errors that can be returned by `CountdownEvent` methods.
pub enum CountdownError {
    ///Returned when adding to a counter would have caused it to overflow.
    SaturatedCounter,
    ///Returned when attempting to signal would have caused the counter to go below zero.
    TooManySignals,
    ///Returned when attempting to modify the counter after it has reached zero.
    AlreadySet,
}

impl CountdownEvent {
    ///Creates a new `CountdownEvent`, initialized to the given count.
    pub fn new(count: isize) -> CountdownEvent {
        CountdownEvent {
            initial: count,
            counter: Mutex::new(count),
            lock: Condvar::new(),
        }
    }

    ///Resets the counter to the count given to `new`.
    ///
    ///This function is safe because the `&mut self` enforces that no other references or locks
    ///exist.
    pub fn reset(&mut self) {
        self.counter = Mutex::new(self.initial);
        self.lock = Condvar::new();
    }

    ///Resets the counter to the given count.
    ///
    ///This function is safe because the `&mut self` enforces that no other references or locks
    ///exist.
    pub fn reset_to_count(&mut self, count: isize) {
        self.initial = count;
        self.reset();
    }

    ///Returns the current counter value.
    pub fn count(&self) -> isize {
        let lock = self.counter.lock().unwrap();

        *lock
    }

    ///Adds the given count to the counter.
    ///
    ///# Errors
    ///
    ///If the counter is already at or below zero, this function will return an error.
    ///
    ///If the given count would overflow an `isize`, this function will return an error.
    pub fn add(&self, count: isize) -> Result<(), CountdownError> {
        let mut lock = self.counter.lock().unwrap();

        if *lock <= 0 {
            return Err(CountdownError::AlreadySet);
        }

        if let Some(new_count) = count.checked_add(*lock) {
            *lock = new_count;
        } else {
            return Err(CountdownError::SaturatedCounter);
        }

        Ok(())
    }

    ///Subtracts the given count to the counter, and returns whether this caused any waiting
    ///threads to wake up.
    ///
    ///# Errors
    ///
    ///If the counter was already at or below zero, this function will return an error.
    ///
    ///If the given count is greater than the current counter, this function will return an error.
    pub fn signal(&self, count: isize) -> Result<bool, CountdownError> {
        let mut lock = self.counter.lock().unwrap();

        if *lock == 0 {
            return Err(CountdownError::AlreadySet);
        }

        if count <= *lock {
            *lock -= count;
        } else {
            return Err(CountdownError::TooManySignals);
        }

        if *lock == 0 {
            self.lock.notify_all();
            Ok(true)
        } else {
            Ok(false)
        }
    }

    ///Adds one to the count.
    ///
    ///# Errors
    ///
    ///See [`add`] for the situations where this function will return an error.
    ///
    ///[`add`]: #method.add
    pub fn increment(&self) -> Result<(), CountdownError> {
        self.add(1)
    }

    ///Subtracts one from the counter, and returns whether this caused any waiting threads to wake
    ///up.
    ///
    ///# Errors
    ///
    ///See [`signal`] for the situations where this function will return an error.
    ///
    ///[`signal`]: #method.signal
    pub fn decrement(&self) -> Result<bool, CountdownError> {
        self.signal(1)
    }

    ///Blocks the current thread until the counter reaches zero.
    ///
    ///This function will block indefinitely until the counter reaches zero. It will return
    ///immediately if it is already at zero.
    pub fn wait(&self) {
        let mut count = self.counter.lock().unwrap();

        while *count > 0 {
            count = self.lock.wait(count).unwrap();
        }
    }

    ///Blocks the current thread until the timer reaches zero, or until the given timeout elapses,
    ///returning the count at the time of wakeup and whether the timeout is known to have elapsed.
    ///
    ///This function will return immediately if the counter was already at zero. Otherwise, it will
    ///block for roughly no longer than `timeout`. Due to limitations in the platform specific
    ///implementation of `std::sync::Condvar`, this method could spuriously wake up both before the timeout
    ///elapsed and without the count being zero.
    pub fn wait_timeout(&self, timeout: Duration) -> (isize, bool) {
        let count = self.counter.lock().unwrap();

        if *count == 0 {
            return (*count, false);
        }

        let (count, status) = self.lock.wait_timeout(count, timeout).unwrap();

        (*count, status.timed_out())
    }
}
<|endoftext|>