<commit_before>//#![warn(missing_docs)]

pub unsafe trait StableAddress: Deref {}
pub unsafe trait CloneStableAddress: StableAddress + Clone {}

pub struct OwningRef<O, T: ?Sized> {
    owner: O,
    reference: *const T,
}

/////////////////////////////////////////////////////////////////////////////
// inherent API
/////////////////////////////////////////////////////////////////////////////

impl<O, T: ?Sized> OwningRef<O, T>
    where O: StableAddress, O: Deref<Target = T>,
{
    pub fn new(o: O) -> Self {
        let ptr: *const T = &*o;
        OwningRef {
            owner: o,
            reference: ptr,
        }
    }
}

impl<O, T: ?Sized> OwningRef<O, T> {
    pub fn owner(&self) -> &O {
        &self.owner
    }

    pub fn into_inner(self) -> O {
        self.owner
    }
}

impl<O, T: ?Sized> OwningRef<O, T>
    where O: StableAddress,
{
    pub fn map<F, U: ?Sized>(self, f: F) -> OwningRef<O, U>
        where F: FnOnce(&T) -> &U
    {
        let ptr = f(&*self) as *const _;

        OwningRef {
            owner: self.owner,
            reference: ptr,
        }
    }
}

/////////////////////////////////////////////////////////////////////////////
// std traits
/////////////////////////////////////////////////////////////////////////////

use std::ops::Deref;
use std::convert::From;
use std::fmt::{self, Debug};
use std::marker::{Send, Sync};

impl<O, T: ?Sized> Deref for OwningRef<O, T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe {
            &*self.reference
        }
    }
}

impl<O, T: ?Sized> From<O> for OwningRef<O, T>
    where O: StableAddress, O: Deref<Target = T>,
{
    fn from(owner: O) -> Self {
        OwningRef::new(owner)
    }
}

// ^ FIXME: Is a Into impl for calling into_inner() possible as well?

impl<O, T: ?Sized> Debug for OwningRef<O, T>
    where O: Debug, T: Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "OwningRef {{ owner: {:?}, reference: {:?} }}",
               self.owner(), &**self)
    }
}

impl<O, T: ?Sized> Clone for OwningRef<O, T>
    where O: CloneStableAddress,
{
    fn clone(&self) -> Self {
        OwningRef {
            owner: self.owner.clone(),
            reference: self.reference,
        }
    }
}

unsafe impl<O: Send, T: ?Sized> Send for OwningRef<O, T> {}
unsafe impl<O: Sync, T: ?Sized> Sync for OwningRef<O, T> {}

/////////////////////////////////////////////////////////////////////////////
// std types integration and convenience type defs
/////////////////////////////////////////////////////////////////////////////

use std::boxed::Box;
use std::rc::Rc;
use std::sync::Arc;

unsafe impl<T: ?Sized> StableAddress for Box<T> {}
unsafe impl<T> StableAddress for Vec<T> {}
unsafe impl StableAddress for String {}
unsafe impl<T: ?Sized> StableAddress for Rc<T> {}
unsafe impl<T: ?Sized> CloneStableAddress for Rc<T> {}
unsafe impl<T: ?Sized> StableAddress for Arc<T> {}
unsafe impl<T: ?Sized> CloneStableAddress for Arc<T> {}

pub type BoxRef<T, U = T> = OwningRef<Box<T>, U>;
pub type VecRef<T, U = T> = OwningRef<Vec<T>, U>;
pub type StringRef = OwningRef<String, str>;
pub type RcRef<T, U = T> = OwningRef<Rc<T>, U>;
pub type ArcRef<T, U = T> = OwningRef<Arc<T>, U>;

/*
FIXME: Find a nice way to construct these:

pub trait Erased {}
impl<T: ?Sized> Erased for T {}

pub type BoxRefEr<U> = OwningRef<Box<Erased>, U>;
pub type RcRefEr<U> = OwningRef<Rc<T>, U>;
pub type ArcRefEr<U> = OwningRef<Arc<T>, U>;
*/

#[cfg(test)]
mod tests {
    use super::{OwningRef, BoxRef, VecRef, StringRef, RcRef, ArcRef};

    use std::rc::Rc;
    use std::sync::Arc;

    #[derive(Debug, PartialEq)]
    struct Example(u32, String, [u8; 3]);
    fn example() -> Example {
        Example(42, "hello world".to_string(), [1, 2, 3])
    }

    #[test]
    fn new_deref() {
        let or: OwningRef<Box<()>, ()> = OwningRef::new(Box::new(()));
        assert_eq!(&*or, &());
    }

    #[test]
    fn into() {
        let or: OwningRef<Box<()>, ()> = Box::new(()).into();
        assert_eq!(&*or, &());
    }

    #[test]
    fn map_offset_ref() {
        let or: BoxRef<Example> = Box::new(example()).into();
        let or: BoxRef<_, u32> = or.map(|x| &x.0);
        assert_eq!(&*or, &42);

        let or: BoxRef<Example> = Box::new(example()).into();
        let or: BoxRef<_, u8> = or.map(|x| &x.2[1]);
        assert_eq!(&*or, &2);
    }

    #[test]
    fn map_heap_ref() {
        let or: BoxRef<Example> = Box::new(example()).into();
        let or: BoxRef<_, str> = or.map(|x| &x.1[..5]);
        assert_eq!(&*or, "hello");
    }

    #[test]
    fn map_static_ref() {
        let or: BoxRef<()> = Box::new(()).into();
        let or: BoxRef<_, str> = or.map(|_| "hello");
        assert_eq!(&*or, "hello");
    }

    #[test]
    fn map_chained() {
        let or: BoxRef<String> = Box::new(example().1).into();
        let or: BoxRef<_, str> = or.map(|x| &x[1..5]);
        let or: BoxRef<_, str> = or.map(|x| &x[..2]);
        assert_eq!(&*or, "el");
    }

    #[test]
    fn map_chained_inference() {
        let or = BoxRef::new(Box::new(example().1))
            .map(|x| &x[..5])
            .map(|x| &x[1..3]);
        assert_eq!(&*or, "el");
    }

    #[test]
    fn owner() {
        let or: BoxRef<String> = Box::new(example().1).into();
        let or = or.map(|x| &x[..5]);
        assert_eq!(&*or, "hello");
        assert_eq!(&**or.owner(), "hello world");
    }

    #[test]
    fn into_inner() {
        let or: BoxRef<String> = Box::new(example().1).into();
        let or = or.map(|x| &x[..5]);
        assert_eq!(&*or, "hello");
        let s = *or.into_inner();
        assert_eq!(&s, "hello world");
    }

    #[test]
    fn fmt_debug() {
        let or: BoxRef<String> = Box::new(example().1).into();
        let or = or.map(|x| &x[..5]);
        let s = format!("{:?}", or);
        assert_eq!(&s, "OwningRef { owner: \"hello world\", reference: \"hello\" }");
    }

    /////////////////////////////////////////////////////////////////////////
    // Tests of example uses cases for each supported owner type:
    /////////////////////////////////////////////////////////////////////////

    #[test]
    fn box_ref() {
        // Caching a reference to a struct field

        struct Foo {
            tag: u32,
            x: u16,
            y: u16,
            z: u16,
        }
        let foo = Foo { tag: 1, x: 100, y: 200, z: 300 };

        let or = BoxRef::new(Box::new(foo)).map(|foo| {
            match foo.tag {
                0 => &foo.x,
                1 => &foo.y,
                2 => &foo.z,
                _ => {
                    static INVALID: u16 = !0;
                    &INVALID
                }
            }
        });

        assert_eq!(*or, 200);
    }

    #[test]
    fn vec_ref() {
        // Cache a reference to an entry in a vector

        let v = VecRef::new(vec![1, 2, 3, 4, 5]).map(|v| &v[3]);
        assert_eq!(*v, 4);
    }

    #[test]
    fn string_ref() {
        // Caching a subslice of a String

        let s = StringRef::new("hello world".to_owned())
            .map(|s| s.split(' ').nth(1).unwrap());

        assert_eq!(&*s, "world");
    }

    #[test]
    fn rc_ref() {
        // Creating many subslices that share ownership of the backing storage

        let rc: Rc<[i32]> = Rc::new([1, 2, 3, 4]);
        let rc: RcRef<[i32]> = rc.into();
        assert_eq!(&*rc, &[1, 2, 3, 4]);

        let rc_a: RcRef<[i32]> = rc.clone().map(|s| &s[0..2]);
        let rc_b = rc.clone().map(|s| &s[1..3]);
        let rc_c = rc.clone().map(|s| &s[2..4]);
        assert_eq!(&*rc_a, &[1, 2]);
        assert_eq!(&*rc_b, &[2, 3]);
        assert_eq!(&*rc_c, &[3, 4]);

        let rc_c_a = rc_c.clone().map(|s| &s[1]);
        assert_eq!(&*rc_c_a, &4);
    }

    #[test]
    fn arc_ref() {
        // Calculate the sum of a atomic shared slice in parallel

        use std::thread;

        fn par_sum(rc: ArcRef<[i32]>) -> i32 {
            if rc.len() == 0 {
                return 0;
            } else if rc.len() == 1 {
                return rc[0];
            }
            let mid = rc.len() / 2;
            let left = rc.clone().map(|s| &s[..mid]);
            let right = rc.map(|s| &s[mid..]);

            let left = thread::spawn(move || par_sum(left));
            let right = thread::spawn(move || par_sum(right));

            left.join().unwrap() + right.join().unwrap()
        }

        let rc: Arc<[i32]> = Arc::new([1, 2, 3, 4]);
        let rc: ArcRef<[i32]> = rc.into();

        assert_eq!(par_sum(rc), 10);
    }

}
<commit_msg>Added support for erasable owners<commit_after>//#![warn(missing_docs)]

pub unsafe trait StableAddress: Deref {}
pub unsafe trait CloneStableAddress: StableAddress + Clone {}

pub struct OwningRef<O, T: ?Sized> {
    owner: O,
    reference: *const T,
}

pub trait Erased {}
impl<T> Erased for T {}

pub unsafe trait IntoErased {
    type Erased;
    fn into_erased(self) -> Self::Erased;
}

/////////////////////////////////////////////////////////////////////////////
// inherent API
/////////////////////////////////////////////////////////////////////////////

impl<O, T: ?Sized> OwningRef<O, T> {
    pub fn new(o: O) -> Self
        where O: StableAddress,
        O: Deref<Target = T>,
    {
        OwningRef {
            reference: &*o,
            owner: o,
        }
    }

    pub fn map<F, U: ?Sized>(self, f: F) -> OwningRef<O, U>
        where O: StableAddress,
              F: FnOnce(&T) -> &U
    {
        OwningRef {
            reference: f(&self),
            owner: self.owner,
        }
    }

    pub fn erase_owner(self) -> OwningRef<O::Erased, T>
        where O: IntoErased,
    {
        OwningRef {
            reference: self.reference,
            owner: self.owner.into_erased(),
        }
    }

    pub fn owner(&self) -> &O {
        &self.owner
    }

    pub fn into_inner(self) -> O {
        self.owner
    }
}

/////////////////////////////////////////////////////////////////////////////
// std traits
/////////////////////////////////////////////////////////////////////////////

use std::ops::Deref;
use std::convert::From;
use std::fmt::{self, Debug};
use std::marker::{Send, Sync};

impl<O, T: ?Sized> Deref for OwningRef<O, T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe {
            &*self.reference
        }
    }
}

impl<O, T: ?Sized> From<O> for OwningRef<O, T>
    where O: StableAddress, O: Deref<Target = T>,
{
    fn from(owner: O) -> Self {
        OwningRef::new(owner)
    }
}

// ^ FIXME: Is a Into impl for calling into_inner() possible as well?

impl<O, T: ?Sized> Debug for OwningRef<O, T>
    where O: Debug, T: Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "OwningRef {{ owner: {:?}, reference: {:?} }}",
               self.owner(), &**self)
    }
}

impl<O, T: ?Sized> Clone for OwningRef<O, T>
    where O: CloneStableAddress,
{
    fn clone(&self) -> Self {
        OwningRef {
            owner: self.owner.clone(),
            reference: self.reference,
        }
    }
}

unsafe impl<O: Send, T: ?Sized> Send for OwningRef<O, T> {}
unsafe impl<O: Sync, T: ?Sized> Sync for OwningRef<O, T> {}

/////////////////////////////////////////////////////////////////////////////
// std types integration and convenience type defs
/////////////////////////////////////////////////////////////////////////////

use std::boxed::Box;
use std::rc::Rc;
use std::sync::Arc;

unsafe impl<T: ?Sized> StableAddress for Box<T> {}
unsafe impl<T> StableAddress for Vec<T> {}
unsafe impl StableAddress for String {}
unsafe impl<T: ?Sized> StableAddress for Rc<T> {}
unsafe impl<T: ?Sized> StableAddress for Arc<T> {}

unsafe impl<T: ?Sized> CloneStableAddress for Rc<T> {}
unsafe impl<T: ?Sized> CloneStableAddress for Arc<T> {}

pub type BoxRef<T, U = T> = OwningRef<Box<T>, U>;
pub type VecRef<T, U = T> = OwningRef<Vec<T>, U>;
pub type StringRef = OwningRef<String, str>;
pub type RcRef<T, U = T> = OwningRef<Rc<T>, U>;
pub type ArcRef<T, U = T> = OwningRef<Arc<T>, U>;

unsafe impl<'a, T: 'a> IntoErased for Box<T> {
    type Erased = Box<Erased + 'a>;
    fn into_erased(self) -> Self::Erased { self }
}
unsafe impl<'a, T: 'a> IntoErased for Rc<T> {
    type Erased = Rc<Erased + 'a>;
    fn into_erased(self) -> Self::Erased { self }
}
unsafe impl<'a, T: 'a> IntoErased for Arc<T> {
    type Erased = Arc<Erased + 'a>;
    fn into_erased(self) -> Self::Erased { self }
}

pub type ErasedBoxRef<U> = OwningRef<Box<Erased>, U>;
pub type ErasedRcRef<U> = OwningRef<Rc<Erased>, U>;
pub type ErasedArcRef<U> = OwningRef<Arc<Erased>, U>;

#[cfg(test)]
mod tests {
    use super::OwningRef;
    use super::{BoxRef, VecRef, StringRef, RcRef, ArcRef};
    use super::{Erased, ErasedBoxRef};

    use std::rc::Rc;
    use std::sync::Arc;

    #[derive(Debug, PartialEq)]
    struct Example(u32, String, [u8; 3]);
    fn example() -> Example {
        Example(42, "hello world".to_string(), [1, 2, 3])
    }

    #[test]
    fn new_deref() {
        let or: OwningRef<Box<()>, ()> = OwningRef::new(Box::new(()));
        assert_eq!(&*or, &());
    }

    #[test]
    fn into() {
        let or: OwningRef<Box<()>, ()> = Box::new(()).into();
        assert_eq!(&*or, &());
    }

    #[test]
    fn map_offset_ref() {
        let or: BoxRef<Example> = Box::new(example()).into();
        let or: BoxRef<_, u32> = or.map(|x| &x.0);
        assert_eq!(&*or, &42);

        let or: BoxRef<Example> = Box::new(example()).into();
        let or: BoxRef<_, u8> = or.map(|x| &x.2[1]);
        assert_eq!(&*or, &2);
    }

    #[test]
    fn map_heap_ref() {
        let or: BoxRef<Example> = Box::new(example()).into();
        let or: BoxRef<_, str> = or.map(|x| &x.1[..5]);
        assert_eq!(&*or, "hello");
    }

    #[test]
    fn map_static_ref() {
        let or: BoxRef<()> = Box::new(()).into();
        let or: BoxRef<_, str> = or.map(|_| "hello");
        assert_eq!(&*or, "hello");
    }

    #[test]
    fn map_chained() {
        let or: BoxRef<String> = Box::new(example().1).into();
        let or: BoxRef<_, str> = or.map(|x| &x[1..5]);
        let or: BoxRef<_, str> = or.map(|x| &x[..2]);
        assert_eq!(&*or, "el");
    }

    #[test]
    fn map_chained_inference() {
        let or = BoxRef::new(Box::new(example().1))
            .map(|x| &x[..5])
            .map(|x| &x[1..3]);
        assert_eq!(&*or, "el");
    }

    #[test]
    fn owner() {
        let or: BoxRef<String> = Box::new(example().1).into();
        let or = or.map(|x| &x[..5]);
        assert_eq!(&*or, "hello");
        assert_eq!(&**or.owner(), "hello world");
    }

    #[test]
    fn into_inner() {
        let or: BoxRef<String> = Box::new(example().1).into();
        let or = or.map(|x| &x[..5]);
        assert_eq!(&*or, "hello");
        let s = *or.into_inner();
        assert_eq!(&s, "hello world");
    }

    #[test]
    fn fmt_debug() {
        let or: BoxRef<String> = Box::new(example().1).into();
        let or = or.map(|x| &x[..5]);
        let s = format!("{:?}", or);
        assert_eq!(&s, "OwningRef { owner: \"hello world\", reference: \"hello\" }");
    }

    #[test]
    fn erased_owner() {
        let o1: BoxRef<Example, str> = BoxRef::new(Box::new(example()))
            .map(|x| &x.1[..]);

        let o2: BoxRef<String, str> = BoxRef::new(Box::new(example().1))
            .map(|x| &x[..]);

        let os: Vec<ErasedBoxRef<str>> = vec![o1.erase_owner(), o2.erase_owner()];
        assert!(os.iter().all(|e| &e[..] == "hello world"));
    }

    #[test]
    fn non_static_erased_owner() {
        let foo = [413, 612];
        let bar = &foo;

        let o: BoxRef<&[i32; 2]> = Box::new(bar).into();
        let o: BoxRef<&[i32; 2], i32> = o.map(|a: &&[i32; 2]| &a[0]);
        let o: BoxRef<Erased, i32> = o.erase_owner();

        assert_eq!(*o, 413);
    }

    /////////////////////////////////////////////////////////////////////////
    // Tests of example uses cases for each supported owner type:
    /////////////////////////////////////////////////////////////////////////

    #[test]
    fn box_ref() {
        // Caching a reference to a struct field

        struct Foo {
            tag: u32,
            x: u16,
            y: u16,
            z: u16,
        }
        let foo = Foo { tag: 1, x: 100, y: 200, z: 300 };

        let or = BoxRef::new(Box::new(foo)).map(|foo| {
            match foo.tag {
                0 => &foo.x,
                1 => &foo.y,
                2 => &foo.z,
                _ => {
                    static INVALID: u16 = !0;
                    &INVALID
                }
            }
        });

        assert_eq!(*or, 200);
    }

    #[test]
    fn vec_ref() {
        // Cache a reference to an entry in a vector

        let v = VecRef::new(vec![1, 2, 3, 4, 5]).map(|v| &v[3]);
        assert_eq!(*v, 4);
    }

    #[test]
    fn string_ref() {
        // Caching a subslice of a String

        let s = StringRef::new("hello world".to_owned())
            .map(|s| s.split(' ').nth(1).unwrap());

        assert_eq!(&*s, "world");
    }

    #[test]
    fn rc_ref() {
        // Creating many subslices that share ownership of the backing storage

        let rc: Rc<[i32]> = Rc::new([1, 2, 3, 4]);
        let rc: RcRef<[i32]> = rc.into();
        assert_eq!(&*rc, &[1, 2, 3, 4]);

        let rc_a: RcRef<[i32]> = rc.clone().map(|s| &s[0..2]);
        let rc_b = rc.clone().map(|s| &s[1..3]);
        let rc_c = rc.clone().map(|s| &s[2..4]);
        assert_eq!(&*rc_a, &[1, 2]);
        assert_eq!(&*rc_b, &[2, 3]);
        assert_eq!(&*rc_c, &[3, 4]);

        let rc_c_a = rc_c.clone().map(|s| &s[1]);
        assert_eq!(&*rc_c_a, &4);
    }

    #[test]
    fn arc_ref() {
        // Calculate the sum of a atomic shared slice in parallel

        use std::thread;

        fn par_sum(rc: ArcRef<[i32]>) -> i32 {
            if rc.len() == 0 {
                return 0;
            } else if rc.len() == 1 {
                return rc[0];
            }
            let mid = rc.len() / 2;
            let left = rc.clone().map(|s| &s[..mid]);
            let right = rc.map(|s| &s[mid..]);

            let left = thread::spawn(move || par_sum(left));
            let right = thread::spawn(move || par_sum(right));

            left.join().unwrap() + right.join().unwrap()
        }

        let rc: Arc<[i32]> = Arc::new([1, 2, 3, 4]);
        let rc: ArcRef<[i32]> = rc.into();

        assert_eq!(par_sum(rc), 10);
    }

}
<|endoftext|>


<commit_before>//! Rust Excel reader
//!
//! # Status
//!
//! Reads excel workbooks and vba project. This mainly works except for
//! binary file format (xls and xlsb) where only VBA is currently supported.
//!
#![deny(missing_docs)]

extern crate zip;
extern crate quick_xml;
extern crate encoding;
extern crate byteorder;
#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate log;

mod errors;
mod utils;
mod xlsb;
mod xlsx;
mod xls;
pub mod vba;

use std::path::Path;
use std::collections::HashMap;
use std::fs::File;
use std::slice::Chunks;
use std::str::FromStr;

pub use errors::*;
use vba::VbaProject;

// https://msdn.microsoft.com/en-us/library/office/ff839168.aspx
/// An enum to represent all different excel errors that can appear as
/// a value in a worksheet cell
#[derive(Debug, Clone, PartialEq)]
pub enum CellErrorType {
    /// Division by 0 error
    Div0,
    /// Unavailable value error
    NA,
    /// Invalid name error
    Name,
    /// Null value error
    Null,
    /// Number error
    Num,
    /// Invalid cell reference error
    Ref,
    /// Value error
    Value,
    /// Getting data
    GettingData,
}

impl FromStr for CellErrorType {
    type Err = errors::Error;
    fn from_str(s: &str) -> Result<Self> {
        match s {
            "#DIV/0!" => Ok(CellErrorType::Div0),
            "#N/A" => Ok(CellErrorType::NA),
            "#NAME?" => Ok(CellErrorType::Name),
            "#NULL!" => Ok(CellErrorType::Null),
            "#NUM!" => Ok(CellErrorType::Num),
            "#REF!" => Ok(CellErrorType::Ref),
            "#VALUE!" => Ok(CellErrorType::Value),
            _ => Err(format!("{} is not an excel error", s).into()),
        }
    }
}

/// An enum to represent all different excel data types that can appear as
/// a value in a worksheet cell
#[derive(Debug, Clone, PartialEq)]
pub enum DataType {
    /// Unsigned integer
    Int(i64),
    /// Float
    Float(f64),
    /// String
    String(String),
    /// Boolean
    Bool(bool),
    /// Error
    Error(CellErrorType),
    /// Empty cell
    Empty,
}

/// Excel file types
enum FileType {
    /// Compound File Binary Format [MS-CFB] (xls, xla)
    Xls(xls::Xls),
    /// Regular xml zipped file (xlsx, xlsm, xlam)
    Xlsx(xlsx::Xlsx),
    /// Binary zipped file (xlsb)
    Xlsb(xlsb::Xlsb),
}

/// A wrapper struct over the Excel file
pub struct Excel {
    file: FileType,
    strings: Vec<String>,
    relationships: HashMap<Vec<u8>, String>,
    /// Map of sheet names/sheet path within zip archive
    sheets: HashMap<String, String>,
}

/// A struct which represents a squared selection of cells
#[derive(Debug, Default)]
pub struct Range {
    position: (u32, u32),
    size: (usize, usize),
    inner: Vec<DataType>,
}

/// An iterator to read `Range` struct row by row
pub struct Rows<'a> {
    inner: Chunks<'a, DataType>,
}

macro_rules! inner {
    ($s:expr, $func:ident()) => {{
        match $s.file {
            FileType::Xls(ref mut f) => f.$func(),
            FileType::Xlsx(ref mut f) => f.$func(),
            FileType::Xlsb(ref mut f) => f.$func(),
        }
    }};
    ($s:expr, $func:ident($first_arg:expr $(, $args:expr)*)) => {{
        match $s.file {
            FileType::Xls(ref mut f) => f.$func($first_arg $(, $args)*),
            FileType::Xlsx(ref mut f) => f.$func($first_arg $(, $args)*),
            FileType::Xlsb(ref mut f) => f.$func($first_arg $(, $args)*),
        }
    }};
}

impl Excel {
    /// Opens a new workbook
    pub fn open<P: AsRef<Path>>(path: P) -> Result<Excel> {
        let f = try!(File::open(&path));
        let file = match path.as_ref().extension().and_then(|s| s.to_str()) {
            Some("xls") | Some("xla") => FileType::Xls(try!(xls::Xls::new(f))),
            Some("xlsx") | Some("xlsm") | Some("xlam") => FileType::Xlsx(try!(xlsx::Xlsx::new(f))),
            Some("xlsb") => FileType::Xlsb(try!(xlsb::Xlsb::new(f))),
            Some(e) => return Err(format!("unrecognized extension: {:?}", e).into()),
            None => return Err("expecting a file with an extension".into()),
        };
        Ok(Excel {
            file: file,
            strings: vec![],
            relationships: HashMap::new(),
            sheets: HashMap::new(),
        })
    }

    /// Get all data from `Worksheet`
    pub fn worksheet_range(&mut self, name: &str) -> Result<Range> {
        if self.strings.is_empty() {
            let strings = try!(inner!(self, read_shared_strings()));
            self.strings = strings;
        }

        if self.relationships.is_empty() {
            let rels = try!(inner!(self, read_relationships()));
            self.relationships = rels;
        }

        if self.sheets.is_empty() {
            let sheets = try!(inner!(self, read_sheets_names(&self.relationships)));
            self.sheets = sheets;
        }

        match self.sheets.get(name) {
            Some(ref p) => inner!(self, read_worksheet_range(p, &self.strings)),
            None => Err(format!("Sheet '{}' does not exist", name).into()),
        }
    }

    /// Does the workbook contain a vba project
    pub fn has_vba(&mut self) -> bool {
        inner!(self, has_vba())
    }

    /// Gets vba project
    pub fn vba_project(&mut self) -> Result<VbaProject> {
        inner!(self, vba_project())
    }
}

/// A trait to share excel reader functions accross different `FileType`s
pub trait ExcelReader: Sized {
    /// Creates a new instance based on the actual file
    fn new(f: File) -> Result<Self>;
    /// Does the workbook contain a vba project
    fn has_vba(&mut self) -> bool;
    /// Gets vba project
    fn vba_project(&mut self) -> Result<VbaProject>;
    /// Read shared string list
    fn read_shared_strings(&mut self) -> Result<Vec<String>>;
    /// Read sheets from workbook.xml and get their corresponding path from relationships
    fn read_sheets_names(&mut self, relationships: &HashMap<Vec<u8>, String>) -> Result<HashMap<String, String>>;
    /// Read workbook relationships
    fn read_relationships(&mut self) -> Result<HashMap<Vec<u8>, String>>;
    /// Read worksheet data in corresponding worksheet path
    fn read_worksheet_range(&mut self, path: &str, strings: &[String]) -> Result<Range>;
}

impl Range {

    /// creates a new range
    pub fn new(position: (u32, u32), size: (usize, usize)) -> Range {
        Range {
            position: position,
            size: size,
            inner: vec![DataType::Empty; size.0 * size.1],
        }
    }

    /// get worksheet position (row, column)
    pub fn get_position(&self) -> (u32, u32) {
        self.position
    }

    /// get size
    pub fn get_size(&self) -> (usize, usize) {
        self.size
    }

    /// set inner value
    pub fn set_value(&mut self, pos: (u32, u32), value: DataType) {
        assert!(self.position <= pos);
        let idx = (pos.0 - self.position.0) * self.size.1 as u32 + pos.1 - self.position.1;
        self.inner[idx as usize] = value;
    }

    /// get cell value
    pub fn get_value(&self, i: usize, j: usize) -> &DataType {
        assert!((i, j) < self.size);
        let idx = i * self.size.1 + j;
        &self.inner[idx]
    }

    /// get an iterator over inner rows
    pub fn rows(&self) -> Rows {
        let width = self.size.1;
        Rows { inner: self.inner.chunks(width) }
    }
}

impl<'a> Iterator for Rows<'a> {
    type Item = &'a [DataType];
    fn next(&mut self) -> Option<&'a [DataType]> {
        self.inner.next()
    }
}

#[test]
fn test_parse_error() {
    assert_eq!(CellErrorType::from_str("#DIV/0!").unwrap(), CellErrorType::Div0);
    assert_eq!(CellErrorType::from_str("#N/A").unwrap(), CellErrorType::NA);
    assert_eq!(CellErrorType::from_str("#NAME?").unwrap(), CellErrorType::Name);
    assert_eq!(CellErrorType::from_str("#NULL!").unwrap(), CellErrorType::Null);
    assert_eq!(CellErrorType::from_str("#NUM!").unwrap(), CellErrorType::Num);
    assert_eq!(CellErrorType::from_str("#REF!").unwrap(), CellErrorType::Ref);
    assert_eq!(CellErrorType::from_str("#VALUE!").unwrap(), CellErrorType::Value);
}

#[test]
fn test_dimensions() {
    assert_eq!(utils::get_row_column(b"A1").unwrap(), (1, 1));
    assert_eq!(utils::get_row_column(b"C107").unwrap(), (107, 3));
    assert_eq!(utils::get_dimension(b"C2:D35").unwrap(), ((2, 3), (34, 2)));
}
<commit_msg>add examples on src/lib.rs fns<commit_after>//! Rust Excel reader
//!
//! # Status
//!
//! Reads excel workbooks and vba project. This mainly works except for
//! binary file format (xls and xlsb) where only VBA is currently supported.
//!
#![deny(missing_docs)]

extern crate zip;
extern crate quick_xml;
extern crate encoding;
extern crate byteorder;
#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate log;

mod errors;
mod utils;
mod xlsb;
mod xlsx;
mod xls;
pub mod vba;

use std::path::Path;
use std::collections::HashMap;
use std::fs::File;
use std::slice::Chunks;
use std::str::FromStr;

pub use errors::*;
use vba::VbaProject;

// https://msdn.microsoft.com/en-us/library/office/ff839168.aspx
/// An enum to represent all different excel errors that can appear as
/// a value in a worksheet cell
#[derive(Debug, Clone, PartialEq)]
pub enum CellErrorType {
    /// Division by 0 error
    Div0,
    /// Unavailable value error
    NA,
    /// Invalid name error
    Name,
    /// Null value error
    Null,
    /// Number error
    Num,
    /// Invalid cell reference error
    Ref,
    /// Value error
    Value,
    /// Getting data
    GettingData,
}

impl FromStr for CellErrorType {
    type Err = errors::Error;
    fn from_str(s: &str) -> Result<Self> {
        match s {
            "#DIV/0!" => Ok(CellErrorType::Div0),
            "#N/A" => Ok(CellErrorType::NA),
            "#NAME?" => Ok(CellErrorType::Name),
            "#NULL!" => Ok(CellErrorType::Null),
            "#NUM!" => Ok(CellErrorType::Num),
            "#REF!" => Ok(CellErrorType::Ref),
            "#VALUE!" => Ok(CellErrorType::Value),
            _ => Err(format!("{} is not an excel error", s).into()),
        }
    }
}

/// An enum to represent all different excel data types that can appear as
/// a value in a worksheet cell
#[derive(Debug, Clone, PartialEq)]
pub enum DataType {
    /// Unsigned integer
    Int(i64),
    /// Float
    Float(f64),
    /// String
    String(String),
    /// Boolean
    Bool(bool),
    /// Error
    Error(CellErrorType),
    /// Empty cell
    Empty,
}

/// Excel file types
enum FileType {
    /// Compound File Binary Format [MS-CFB] (xls, xla)
    Xls(xls::Xls),
    /// Regular xml zipped file (xlsx, xlsm, xlam)
    Xlsx(xlsx::Xlsx),
    /// Binary zipped file (xlsb)
    Xlsb(xlsb::Xlsb),
}

/// A wrapper struct over the Excel file
pub struct Excel {
    file: FileType,
    strings: Vec<String>,
    relationships: HashMap<Vec<u8>, String>,
    /// Map of sheet names/sheet path within zip archive
    sheets: HashMap<String, String>,
}

/// A struct which represents a squared selection of cells
#[derive(Debug, Default)]
pub struct Range {
    position: (u32, u32),
    size: (usize, usize),
    inner: Vec<DataType>,
}

/// An iterator to read `Range` struct row by row
pub struct Rows<'a> {
    inner: Chunks<'a, DataType>,
}

macro_rules! inner {
    ($s:expr, $func:ident()) => {{
        match $s.file {
            FileType::Xls(ref mut f) => f.$func(),
            FileType::Xlsx(ref mut f) => f.$func(),
            FileType::Xlsb(ref mut f) => f.$func(),
        }
    }};
    ($s:expr, $func:ident($first_arg:expr $(, $args:expr)*)) => {{
        match $s.file {
            FileType::Xls(ref mut f) => f.$func($first_arg $(, $args)*),
            FileType::Xlsx(ref mut f) => f.$func($first_arg $(, $args)*),
            FileType::Xlsb(ref mut f) => f.$func($first_arg $(, $args)*),
        }
    }};
}

impl Excel {
    /// Opens a new workbook
    ///
    /// # Examples
    /// ```
    /// use office::Excel;
    ///
    /// # let path = format!("{}/tests/issues.xlsx", env!("CARGO_MANIFEST_DIR"));
    /// assert!(Excel::open(path).is_ok());
    /// ```
    pub fn open<P: AsRef<Path>>(path: P) -> Result<Excel> {
        let f = try!(File::open(&path));
        let file = match path.as_ref().extension().and_then(|s| s.to_str()) {
            Some("xls") | Some("xla") => FileType::Xls(try!(xls::Xls::new(f))),
            Some("xlsx") | Some("xlsm") | Some("xlam") => FileType::Xlsx(try!(xlsx::Xlsx::new(f))),
            Some("xlsb") => FileType::Xlsb(try!(xlsb::Xlsb::new(f))),
            Some(e) => return Err(format!("unrecognized extension: {:?}", e).into()),
            None => return Err("expecting a file with an extension".into()),
        };
        Ok(Excel {
            file: file,
            strings: vec![],
            relationships: HashMap::new(),
            sheets: HashMap::new(),
        })
    }

    /// Get all data from `Worksheet`
    ///
    /// # Examples
    /// ```
    /// use office::Excel;
    ///
    /// # let path = format!("{}/tests/issue3.xlsm", env!("CARGO_MANIFEST_DIR"));
    /// let mut workbook = Excel::open(path).unwrap();
    /// let range = workbook.worksheet_range("Sheet1").unwrap();
    /// ```
    pub fn worksheet_range(&mut self, name: &str) -> Result<Range> {
        if self.strings.is_empty() {
            let strings = try!(inner!(self, read_shared_strings()));
            self.strings = strings;
        }

        if self.relationships.is_empty() {
            let rels = try!(inner!(self, read_relationships()));
            self.relationships = rels;
        }

        if self.sheets.is_empty() {
            let sheets = try!(inner!(self, read_sheets_names(&self.relationships)));
            self.sheets = sheets;
        }

        match self.sheets.get(name) {
            Some(ref p) => inner!(self, read_worksheet_range(p, &self.strings)),
            None => Err(format!("Sheet '{}' does not exist", name).into()),
        }
    }

    /// Does the workbook contain a vba project
    pub fn has_vba(&mut self) -> bool {
        inner!(self, has_vba())
    }

    /// Gets vba project
    ///
    /// # Examples
    /// ```
    /// use office::Excel;
    ///
    /// # let path = format!("{}/tests/vba.xlsm", env!("CARGO_MANIFEST_DIR"));
    /// let mut workbook = Excel::open(path).unwrap();
    /// if workbook.has_vba() {
    ///     let mut vba = workbook.vba_project().unwrap();
    ///     let (references, modules) = vba.read_vba().unwrap();
    ///     println!("References: {:?}", references);
    ///     println!("Modules: {:?}", modules);
    /// }
    /// ```
    pub fn vba_project(&mut self) -> Result<VbaProject> {
        inner!(self, vba_project())
    }
}

/// A trait to share excel reader functions accross different `FileType`s
pub trait ExcelReader: Sized {
    /// Creates a new instance based on the actual file
    fn new(f: File) -> Result<Self>;
    /// Does the workbook contain a vba project
    fn has_vba(&mut self) -> bool;
    /// Gets vba project
    fn vba_project(&mut self) -> Result<VbaProject>;
    /// Read shared string list
    fn read_shared_strings(&mut self) -> Result<Vec<String>>;
    /// Read sheets from workbook.xml and get their corresponding path from relationships
    fn read_sheets_names(&mut self, relationships: &HashMap<Vec<u8>, String>) -> Result<HashMap<String, String>>;
    /// Read workbook relationships
    fn read_relationships(&mut self) -> Result<HashMap<Vec<u8>, String>>;
    /// Read worksheet data in corresponding worksheet path
    fn read_worksheet_range(&mut self, path: &str, strings: &[String]) -> Result<Range>;
}

impl Range {

    /// Creates a new range
    pub fn new(position: (u32, u32), size: (usize, usize)) -> Range {
        Range {
            position: position,
            size: size,
            inner: vec![DataType::Empty; size.0 * size.1],
        }
    }

    /// Get top left cell position (row, column)
    pub fn get_position(&self) -> (u32, u32) {
        self.position
    }

    /// Get size
    pub fn get_size(&self) -> (usize, usize) {
        self.size
    }

    /// Set inner value
    ///
    /// Panics if indexes are out of range bounds
    ///
    /// # Examples
    /// ```
    /// use office::{Range, DataType};
    ///
    /// let mut range = Range::new((0, 0), (5, 2));
    /// assert_eq!(range.get_value(2, 1), &DataType::Empty);
    /// range.set_value((2, 1), DataType::Float(1.0));
    /// assert_eq!(range.get_value(2, 1), &DataType::Float(1.0));
    /// ```
    pub fn set_value(&mut self, pos: (u32, u32), value: DataType) {
        assert!(self.position <= pos);
        let idx = (pos.0 - self.position.0) * self.size.1 as u32 + pos.1 - self.position.1;
        self.inner[idx as usize] = value;
    }

    /// Get cell value
    ///
    /// Panics if indexes are out of range bounds
    pub fn get_value(&self, i: usize, j: usize) -> &DataType {
        assert!((i, j) < self.size);
        let idx = i * self.size.1 + j;
        &self.inner[idx]
    }

    /// Get an iterator over inner rows
    ///
    /// # Examples
    /// ```
    /// use office::{Range, DataType};
    ///
    /// let range = Range::new((0, 0), (5, 2));
    /// // with rows item row: &[DataType]
    /// assert_eq!(range.rows().flat_map(|row| row).count(), 10);
    /// ```
    pub fn rows(&self) -> Rows {
        let width = self.size.1;
        Rows { inner: self.inner.chunks(width) }
    }
}

impl<'a> Iterator for Rows<'a> {
    type Item = &'a [DataType];
    fn next(&mut self) -> Option<&'a [DataType]> {
        self.inner.next()
    }
}

#[test]
fn test_parse_error() {
    assert_eq!(CellErrorType::from_str("#DIV/0!").unwrap(), CellErrorType::Div0);
    assert_eq!(CellErrorType::from_str("#N/A").unwrap(), CellErrorType::NA);
    assert_eq!(CellErrorType::from_str("#NAME?").unwrap(), CellErrorType::Name);
    assert_eq!(CellErrorType::from_str("#NULL!").unwrap(), CellErrorType::Null);
    assert_eq!(CellErrorType::from_str("#NUM!").unwrap(), CellErrorType::Num);
    assert_eq!(CellErrorType::from_str("#REF!").unwrap(), CellErrorType::Ref);
    assert_eq!(CellErrorType::from_str("#VALUE!").unwrap(), CellErrorType::Value);
}

#[test]
fn test_dimensions() {
    assert_eq!(utils::get_row_column(b"A1").unwrap(), (1, 1));
    assert_eq!(utils::get_row_column(b"C107").unwrap(), (107, 3));
    assert_eq!(utils::get_dimension(b"C2:D35").unwrap(), ((2, 3), (34, 2)));
}
<|endoftext|>


<commit_before>#![doc(html_logo_url = "https://cdn.rawgit.com/urschrei/polylabel-rs/7a07336e85572eb5faaf0657c2383d7de5620cd8/ell.svg",
       html_root_url = "https://urschrei.github.io/polylabel-rs/")]
//! This crate provides a Rust implementation of the [Polylabel](https://github.com/mapbox/polylabel) algorithm
//! for finding the optimum position of a polygon label.
use std::cmp::Ordering;
use std::collections::BinaryHeap;

extern crate num_traits;
use self::num_traits::{Float, FromPrimitive, Signed};

extern crate geo;
use self::geo::{Point, Polygon};
use self::geo::algorithm::boundingbox::BoundingBox;
use self::geo::algorithm::distance::Distance;
use self::geo::algorithm::area::Area;
use self::geo::algorithm::centroid::Centroid;
use self::geo::algorithm::contains::Contains;

mod ffi;
pub use ffi::{polylabel_ffi, Array, WrapperArray, Position};

#[doc(hidden)]
#[allow(dead_code)]
pub extern "C" fn spare() {
    println!("");
}

/// Represention of a Quadtree cell
#[derive(Debug)]
struct Qcell<T>
where
    T: Float + Signed,
{
    centroid: Point<T>,
    // Half the cell size
    h: T,
    // Distance from centroid to polygon
    distance: T,
    // Maximum distance to polygon within a cell
    max_distance: T,
}

impl<T> Qcell<T>
where
    T: Float + Signed,
{
    fn new(x: T, y: T, h: T, distance: T, max_distance: T) -> Qcell<T> {
        Qcell {
            centroid: Point::new(x, y),
            h: h,
            distance: distance,
            max_distance: max_distance,
        }
    }
}

impl<T> Ord for Qcell<T>
where
    T: Float + Signed,
{
    fn cmp(&self, other: &Qcell<T>) -> std::cmp::Ordering {
        self.max_distance.partial_cmp(&other.max_distance).unwrap()
    }
}
impl<T> PartialOrd for Qcell<T>
where
    T: Float + Signed,
{
    fn partial_cmp(&self, other: &Qcell<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl<T> Eq for Qcell<T>
where
    T: Float + Signed,
{
}
impl<T> PartialEq for Qcell<T>
where
    T: Float + Signed,
{
    fn eq(&self, other: &Qcell<T>) -> bool
    where
        T: Float,
    {
        self.max_distance == other.max_distance
    }
}

/// Signed distance from a Qcell's centroid to a Polygon's outline
/// Returned value is negative if the point is outside the polygon's exterior ring
fn signed_distance<T>(x: &T, y: &T, polygon: &Polygon<T>) -> T
where
    T: Float,
{
    let point = Point::new(*x, *y);
    let inside = polygon.contains(&point);
    // Use LineString distance, because Polygon distance returns 0.0 for inside
    let distance = point.distance(&polygon.exterior);
    if inside { distance } else { -distance }
}

/// Add a new Quadtree node made up of four `Qcell`s to the binary heap
fn add_quad<T>(mpq: &mut BinaryHeap<Qcell<T>>, cell: &Qcell<T>, nh: &T, polygon: &Polygon<T>)
where
    T: Float + Signed,
{
    let two = T::one() + T::one();
    // 1
    let mut new_dist = signed_distance(&(cell.centroid.x() - *nh), &(cell.centroid.y() - *nh), polygon);
    mpq.push(Qcell::new(
        cell.centroid.x() - *nh,
        cell.centroid.y() - *nh,
        *nh,
        new_dist,
        new_dist + *nh * two.sqrt(),
    ));
    // 2
    new_dist = signed_distance(&(cell.centroid.x() + *nh), &(cell.centroid.y() - *nh), polygon);
    mpq.push(Qcell::new(
        cell.centroid.x() + *nh,
        cell.centroid.y() - *nh,
        *nh,
        new_dist,
        new_dist + *nh * two.sqrt(),
    ));
    // 3
    new_dist = signed_distance(&(cell.centroid.x() - *nh), &(cell.centroid.y() + *nh), polygon);
    mpq.push(Qcell::new(
        cell.centroid.x() - *nh,
        cell.centroid.y() + *nh,
        *nh,
        new_dist,
        new_dist + *nh * two.sqrt(),
    ));
    // 4
    new_dist = signed_distance(&(cell.centroid.x() + *nh), &(cell.centroid.y() + *nh), polygon);
    mpq.push(Qcell::new(
        cell.centroid.x() + *nh,
        cell.centroid.y() + *nh,
        *nh,
        new_dist,
        new_dist + *nh * two.sqrt(),
    ));
}

/// Calculate a Polygon's ideal label position by calculating its ✨pole of inaccessibility✨
///
/// The calculation uses an [iterative grid-based algorithm](https://github.com/mapbox/polylabel#how-the-algorithm-works).
///
/// # Examples
///
/// ```
/// use polylabel::polylabel;
/// extern crate geo;
/// use self::geo::{Point, LineString, Polygon};
///
/// // An approximate `L` shape
/// let coords = vec![
///    (0.0, 0.0),
///    (4.0, 0.0),
///    (4.0, 1.0),
///    (1.0, 1.0),
///    (1.0, 4.0),
///    (0.0, 4.0),
///    (0.0, 0.0)];
///
/// let poly = Polygon::new(coords.into(), vec![]);
///
/// // Its centroid lies outside the polygon
/// assert_eq!(poly.centroid(), Point::new(1.3571428571428572, 1.3571428571428572));
///
/// let label_position = polylabel(&poly, &1.0);
/// // Optimum label position is inside the polygon
/// assert_eq!(label_position, Point::new(0.5625, 0.5625));
/// ```
///
pub fn polylabel<T>(polygon: &Polygon<T>, tolerance: &T) -> Point<T>
where
    T: Float + FromPrimitive + Signed,
{
    // special case for degenerate polygons
    if polygon.area() == T::zero() {
        // best_cell = Qcell {
        //     centroid = Point::new(polygon.exterior.0[0].x(), polygon.exterior.0[0].y())
        //     h: T::zero(),
        //     distance: distance,
        //     max_distance: max_distance
        // };
        return Point::new(T::zero(), T::zero());
    }
    let two = T::one() + T::one();
    // Initial best cell values
    let centroid = polygon.centroid().unwrap();
    let bbox = polygon.bbox().unwrap();
    let width = bbox.xmax - bbox.xmin;
    let height = bbox.ymax - bbox.ymin;
    let cell_size = width.min(height);
    // Special case for degenerate polygons
    if cell_size == T::zero() {
        return Point::new(bbox.xmin, bbox.ymin);
    }
    let mut h = cell_size / two;
    let distance = signed_distance(&centroid.x(), &centroid.y(), polygon);
    let max_distance = distance + T::zero() * two.sqrt();

    let mut best_cell = Qcell {
        centroid: Point::new(centroid.x(), centroid.y()),
        h: T::zero(),
        distance: distance,
        max_distance: max_distance,
    };

    // special case for rectangular polygons
    let bbox_cell_dist = signed_distance(
        &(bbox.xmin + width / two),
        &(bbox.ymin + height / two),
        polygon,
    );
    let bbox_cell = Qcell {
        centroid: Point::new(bbox.xmin + width / two, bbox.ymin + height / two),
        h: T::zero(),
        distance: bbox_cell_dist,
        max_distance: bbox_cell_dist + T::zero() * two.sqrt(),
    };

    if bbox_cell.distance > best_cell.distance {
        best_cell = bbox_cell;
    }

    // Priority queue
    let mut cell_queue: BinaryHeap<Qcell<T>> = BinaryHeap::new();
    // Build an initial quadtree node, which covers the Polygon
    let mut x = bbox.xmin;
    let mut y;
    while x < bbox.xmax {
        y = bbox.ymin;
        while y < bbox.ymax {
            let latest_dist = signed_distance(&(x + h), &(y + h), polygon);
            cell_queue.push(Qcell {
                centroid: Point::new(x + h, y + h),
                h: h,
                distance: latest_dist,
                max_distance: latest_dist + h * two.sqrt(),
            });
            y = y + cell_size;
        }
        x = x + cell_size;
    }
    // Now try to find better solutions
    while !cell_queue.is_empty() {
        let cell = cell_queue.pop().unwrap();
        // Update the best cell if we find a cell with greater distance
        if cell.distance > best_cell.distance {
            best_cell.centroid = Point::new(cell.centroid.x(), cell.centroid.y());
            best_cell.h = cell.h;
            best_cell.distance = cell.distance;
            best_cell.max_distance = cell.max_distance;
        }
        // Bail out of this iteration if we can't find a better solution
        if cell.max_distance - best_cell.distance <= *tolerance {
            continue;
        }
        // Otherwise, add a new quadtree node and start again
        h = cell.h / two;
        add_quad(&mut cell_queue, &cell, &h, polygon);
    }
    // We've exhausted the queue, so return the best solution we've found
    Point::new(best_cell.centroid.x(), best_cell.centroid.y())
}

#[cfg(test)]
mod tests {
    use std::collections::BinaryHeap;
    use super::{polylabel, Qcell};
    use geo::{Point, Polygon};
    use geo::contains::Contains;
    #[test]
    // polygons are those used in Shapely's tests
    fn test_polylabel() {
        let coords = include!("poly1.rs");
        let poly = Polygon::new(coords.into(), vec![]);
        let res = polylabel(&poly, &10.000);
        assert_eq!(res, Point::new(59.35615556364569, 121.83919629746435));
    }
    #[test]
    // does a concave polygon contain the calculated point?
    // relevant because the centroid lies outside the polygon in this case
    fn test_concave() {
        let coords = include!("poly2.rs");
        let poly = Polygon::new(coords.into(), vec![]);
        let res = polylabel(&poly, &1.0);
        assert!(poly.contains(&res));
    }
    #[test]
    fn polygon_l_test() {
        // an L shape
        let coords = vec![
            (0.0, 0.0),
            (4.0, 0.0),
            (4.0, 1.0),
            (1.0, 1.0),
            (1.0, 4.0),
            (0.0, 4.0),
            (0.0, 0.0),
        ];
        let poly = Polygon::new(coords.into(), vec![]);
        let res = polylabel(&poly, &0.10);
        assert_eq!(res, Point::new(0.5625, 0.5625));
    }
    #[test]
    fn degenerate_polygon_test() {
        let a_coords = vec![(0.0, 0.0), (1.0, 0.0), (2.0, 0.0), (0.0, 0.0)];
        let a_poly = Polygon::new(a_coords.into(), vec![]);
        let a_res = polylabel(&a_poly, &1.0);
        assert_eq!(a_res, Point::new(0.0, 0.0));
    }
    #[test]
    fn degenerate_polygon_test_2() {
        let b_coords = vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)];
        let b_poly = Polygon::new(b_coords.into(), vec![]);
        let b_res = polylabel(&b_poly, &1.0);
        assert_eq!(b_res, Point::new(0.0, 0.0));
    }
    #[test]
    // Is our priority queue behaving as it should?
    fn test_queue() {
        let a = Qcell {
            centroid: Point::new(1.0, 2.0),
            h: 3.0,
            distance: 4.0,
            max_distance: 8.0,
        };
        let b = Qcell {
            centroid: Point::new(1.0, 2.0),
            h: 3.0,
            distance: 4.0,
            max_distance: 7.0,
        };
        let c = Qcell {
            centroid: Point::new(1.0, 2.0),
            h: 3.0,
            distance: 4.0,
            max_distance: 9.0,
        };
        let mut v = vec![];
        v.push(a);
        v.push(b);
        v.push(c);
        let mut q = BinaryHeap::from(v);
        assert_eq!(q.pop().unwrap().max_distance, 9.0);
        assert_eq!(q.pop().unwrap().max_distance, 8.0);
        assert_eq!(q.pop().unwrap().max_distance, 7.0);
    }
}
<commit_msg>Simplify quadtree node addition<commit_after>#![doc(html_logo_url = "https://cdn.rawgit.com/urschrei/polylabel-rs/7a07336e85572eb5faaf0657c2383d7de5620cd8/ell.svg",
       html_root_url = "https://urschrei.github.io/polylabel-rs/")]
//! This crate provides a Rust implementation of the [Polylabel](https://github.com/mapbox/polylabel) algorithm
//! for finding the optimum position of a polygon label.
use std::cmp::Ordering;
use std::collections::BinaryHeap;

extern crate num_traits;
use self::num_traits::{Float, FromPrimitive, Signed};

extern crate geo;
use self::geo::{Point, Polygon};
use self::geo::algorithm::boundingbox::BoundingBox;
use self::geo::algorithm::distance::Distance;
use self::geo::algorithm::area::Area;
use self::geo::algorithm::centroid::Centroid;
use self::geo::algorithm::contains::Contains;

mod ffi;
pub use ffi::{polylabel_ffi, Array, WrapperArray, Position};

#[doc(hidden)]
#[allow(dead_code)]
pub extern "C" fn spare() {
    println!("");
}

/// Represention of a Quadtree cell
#[derive(Debug)]
struct Qcell<T>
where
    T: Float + Signed,
{
    centroid: Point<T>,
    // Half the cell size
    h: T,
    // Distance from centroid to polygon
    distance: T,
    // Maximum distance to polygon within a cell
    max_distance: T,
}

impl<T> Qcell<T>
where
    T: Float + Signed,
{
    fn new(x: T, y: T, h: T, distance: T, max_distance: T) -> Qcell<T> {
        Qcell {
            centroid: Point::new(x, y),
            h: h,
            distance: distance,
            max_distance: max_distance,
        }
    }
}

impl<T> Ord for Qcell<T>
where
    T: Float + Signed,
{
    fn cmp(&self, other: &Qcell<T>) -> std::cmp::Ordering {
        self.max_distance.partial_cmp(&other.max_distance).unwrap()
    }
}
impl<T> PartialOrd for Qcell<T>
where
    T: Float + Signed,
{
    fn partial_cmp(&self, other: &Qcell<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl<T> Eq for Qcell<T>
where
    T: Float + Signed,
{
}
impl<T> PartialEq for Qcell<T>
where
    T: Float + Signed,
{
    fn eq(&self, other: &Qcell<T>) -> bool
    where
        T: Float,
    {
        self.max_distance == other.max_distance
    }
}

/// Signed distance from a Qcell's centroid to a Polygon's outline
/// Returned value is negative if the point is outside the polygon's exterior ring
fn signed_distance<T>(x: &T, y: &T, polygon: &Polygon<T>) -> T
where
    T: Float,
{
    let point = Point::new(*x, *y);
    let inside = polygon.contains(&point);
    // Use LineString distance, because Polygon distance returns 0.0 for inside
    let distance = point.distance(&polygon.exterior);
    if inside { distance } else { -distance }
}

/// Add a new Quadtree node made up of four `Qcell`s to the binary heap
fn add_quad<T>(
    mpq: &mut BinaryHeap<Qcell<T>>,
    cell: &Qcell<T>,
    new_height: &T,
    polygon: &Polygon<T>,
) where
    T: Float + Signed,
{
    let two = T::one() + T::one();
    let centroid_x = cell.centroid.x();
    let centroid_y = cell.centroid.y();
    for combo in &[
        (centroid_x - *new_height, centroid_y - *new_height),
        (centroid_x + *new_height, centroid_y - *new_height),
        (centroid_x - *new_height, centroid_y + *new_height),
        (centroid_x + *new_height, centroid_y + *new_height),
    ]
    {
        let mut new_dist = signed_distance(&combo.0, &combo.1, polygon);
        mpq.push(Qcell::new(
            combo.0,
            combo.1,
            *new_height,
            new_dist,
            new_dist + *new_height * two.sqrt(),
        ));
    }
}

/// Calculate a Polygon's ideal label position by calculating its ✨pole of inaccessibility✨
///
/// The calculation uses an [iterative grid-based algorithm](https://github.com/mapbox/polylabel#how-the-algorithm-works).
///
/// # Examples
///
/// ```
/// use polylabel::polylabel;
/// extern crate geo;
/// use self::geo::{Point, LineString, Polygon};
///
/// // An approximate `L` shape
/// let coords = vec![
///    (0.0, 0.0),
///    (4.0, 0.0),
///    (4.0, 1.0),
///    (1.0, 1.0),
///    (1.0, 4.0),
///    (0.0, 4.0),
///    (0.0, 0.0)];
///
/// let poly = Polygon::new(coords.into(), vec![]);
///
/// // Its centroid lies outside the polygon
/// assert_eq!(poly.centroid(), Point::new(1.3571428571428572, 1.3571428571428572));
///
/// let label_position = polylabel(&poly, &1.0);
/// // Optimum label position is inside the polygon
/// assert_eq!(label_position, Point::new(0.5625, 0.5625));
/// ```
///
pub fn polylabel<T>(polygon: &Polygon<T>, tolerance: &T) -> Point<T>
where
    T: Float + FromPrimitive + Signed,
{
    // special case for degenerate polygons
    if polygon.area() == T::zero() {
        // best_cell = Qcell {
        //     centroid = Point::new(polygon.exterior.0[0].x(), polygon.exterior.0[0].y())
        //     h: T::zero(),
        //     distance: distance,
        //     max_distance: max_distance
        // };
        return Point::new(T::zero(), T::zero());
    }
    let two = T::one() + T::one();
    // Initial best cell values
    let centroid = polygon.centroid().unwrap();
    let bbox = polygon.bbox().unwrap();
    let width = bbox.xmax - bbox.xmin;
    let height = bbox.ymax - bbox.ymin;
    let cell_size = width.min(height);
    // Special case for degenerate polygons
    if cell_size == T::zero() {
        return Point::new(bbox.xmin, bbox.ymin);
    }
    let mut h = cell_size / two;
    let distance = signed_distance(&centroid.x(), &centroid.y(), polygon);
    let max_distance = distance + T::zero() * two.sqrt();

    let mut best_cell = Qcell {
        centroid: Point::new(centroid.x(), centroid.y()),
        h: T::zero(),
        distance: distance,
        max_distance: max_distance,
    };

    // special case for rectangular polygons
    let bbox_cell_dist = signed_distance(
        &(bbox.xmin + width / two),
        &(bbox.ymin + height / two),
        polygon,
    );
    let bbox_cell = Qcell {
        centroid: Point::new(bbox.xmin + width / two, bbox.ymin + height / two),
        h: T::zero(),
        distance: bbox_cell_dist,
        max_distance: bbox_cell_dist + T::zero() * two.sqrt(),
    };

    if bbox_cell.distance > best_cell.distance {
        best_cell = bbox_cell;
    }

    // Priority queue
    let mut cell_queue: BinaryHeap<Qcell<T>> = BinaryHeap::new();
    // Build an initial quadtree node, which covers the Polygon
    let mut x = bbox.xmin;
    let mut y;
    while x < bbox.xmax {
        y = bbox.ymin;
        while y < bbox.ymax {
            let latest_dist = signed_distance(&(x + h), &(y + h), polygon);
            cell_queue.push(Qcell {
                centroid: Point::new(x + h, y + h),
                h: h,
                distance: latest_dist,
                max_distance: latest_dist + h * two.sqrt(),
            });
            y = y + cell_size;
        }
        x = x + cell_size;
    }
    // Now try to find better solutions
    while !cell_queue.is_empty() {
        let cell = cell_queue.pop().unwrap();
        // Update the best cell if we find a cell with greater distance
        if cell.distance > best_cell.distance {
            best_cell.centroid = Point::new(cell.centroid.x(), cell.centroid.y());
            best_cell.h = cell.h;
            best_cell.distance = cell.distance;
            best_cell.max_distance = cell.max_distance;
        }
        // Bail out of this iteration if we can't find a better solution
        if cell.max_distance - best_cell.distance <= *tolerance {
            continue;
        }
        // Otherwise, add a new quadtree node and start again
        h = cell.h / two;
        add_quad(&mut cell_queue, &cell, &h, polygon);
    }
    // We've exhausted the queue, so return the best solution we've found
    Point::new(best_cell.centroid.x(), best_cell.centroid.y())
}

#[cfg(test)]
mod tests {
    use std::collections::BinaryHeap;
    use super::{polylabel, Qcell};
    use geo::{Point, Polygon};
    use geo::contains::Contains;
    #[test]
    // polygons are those used in Shapely's tests
    fn test_polylabel() {
        let coords = include!("poly1.rs");
        let poly = Polygon::new(coords.into(), vec![]);
        let res = polylabel(&poly, &10.000);
        assert_eq!(res, Point::new(59.35615556364569, 121.83919629746435));
    }
    #[test]
    // does a concave polygon contain the calculated point?
    // relevant because the centroid lies outside the polygon in this case
    fn test_concave() {
        let coords = include!("poly2.rs");
        let poly = Polygon::new(coords.into(), vec![]);
        let res = polylabel(&poly, &1.0);
        assert!(poly.contains(&res));
    }
    #[test]
    fn polygon_l_test() {
        // an L shape
        let coords = vec![
            (0.0, 0.0),
            (4.0, 0.0),
            (4.0, 1.0),
            (1.0, 1.0),
            (1.0, 4.0),
            (0.0, 4.0),
            (0.0, 0.0),
        ];
        let poly = Polygon::new(coords.into(), vec![]);
        let res = polylabel(&poly, &0.10);
        assert_eq!(res, Point::new(0.5625, 0.5625));
    }
    #[test]
    fn degenerate_polygon_test() {
        let a_coords = vec![(0.0, 0.0), (1.0, 0.0), (2.0, 0.0), (0.0, 0.0)];
        let a_poly = Polygon::new(a_coords.into(), vec![]);
        let a_res = polylabel(&a_poly, &1.0);
        assert_eq!(a_res, Point::new(0.0, 0.0));
    }
    #[test]
    fn degenerate_polygon_test_2() {
        let b_coords = vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)];
        let b_poly = Polygon::new(b_coords.into(), vec![]);
        let b_res = polylabel(&b_poly, &1.0);
        assert_eq!(b_res, Point::new(0.0, 0.0));
    }
    #[test]
    // Is our priority queue behaving as it should?
    fn test_queue() {
        let a = Qcell {
            centroid: Point::new(1.0, 2.0),
            h: 3.0,
            distance: 4.0,
            max_distance: 8.0,
        };
        let b = Qcell {
            centroid: Point::new(1.0, 2.0),
            h: 3.0,
            distance: 4.0,
            max_distance: 7.0,
        };
        let c = Qcell {
            centroid: Point::new(1.0, 2.0),
            h: 3.0,
            distance: 4.0,
            max_distance: 9.0,
        };
        let mut v = vec![];
        v.push(a);
        v.push(b);
        v.push(c);
        let mut q = BinaryHeap::from(v);
        assert_eq!(q.pop().unwrap().max_distance, 9.0);
        assert_eq!(q.pop().unwrap().max_distance, 8.0);
        assert_eq!(q.pop().unwrap().max_distance, 7.0);
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, PartialEq, Eq)]
struct GitStatus {
    branch: Option<BranchInfo>,
    upstream: Option<UpstreamInfo>,
    staged: bool,
    unstaged: bool,
    untracked: bool,
    ignored: bool,
}

#[derive(Debug, PartialEq, Eq)]
struct BranchInfo {
    object_id: String,
    branch: Option<String>,
}

#[derive(Debug, PartialEq, Eq)]
struct UpstreamInfo {
    upstream: String,
    ahead: bool,
    behind: bool,
}

impl GitStatus {
    fn new(status_txt: &str) -> Result<GitStatus, &'static str> {
        let mut s = GitStatus {
            branch: None,
            upstream: None,
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        for line in status_txt.lines() {
            let words: Vec<&str> = line.split(' ').collect();
            if let Some(&first) = words.first() {
                match first {
                    "#" => {
                    },
                    "1" => {
                        s.staged = true;
                        s.unstaged = true;
                    },
                    "?" => {
                        s.untracked = true;
                    },
                    "!" => {
                        s.ignored = true;
                    },
                    _ => {},
                }
            }
        }
        Ok(s)
    }
}

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

    #[test]
    fn parse_clean() {
        let test_status = "\n";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                branch: None,
                upstream: None,
                staged: false,
                unstaged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_dirty() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
1 M. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
1 .M N... 100644 100644 100644 5e8a8090976077ddf16252a560460a20dbbdd6a5 5e8a8090976077ddf16252a560460a20dbbdd6a5 gh-pages.sh
? foo.txt
! ignored.txt
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                branch: Some(BranchInfo {
                    object_id: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                    branch: Some(String::from("master")),
                }),
                upstream: Some(UpstreamInfo {
                    upstream: String::from("origin/master"),
                    ahead: true,
                    behind: true,
                }),
                staged: true,
                unstaged: true,
                untracked: true,
                ignored: true,
            }
        );
    }

    #[test]
    fn parse_branch() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
";
        assert_eq!(
            GitStatus::new(test_status).unwrap().branch,
            Some(BranchInfo {
                object_id: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: Some(String::from("master")),
            })
        );
    }

    #[test]
    fn parse_upstream() {
        let test_status = "\
# branch.upstream origin/master
# branch.ab +1 -1
";
        assert_eq!(
            GitStatus::new(test_status).unwrap().upstream,
            Some(UpstreamInfo {
                upstream: String::from("origin/master"),
                ahead: true,
                behind: true,
            })
        );
    }

    #[test]
    fn parse_staged_and_unstaged_on_same_file() {
        let test_status = "\
1 MM N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_detached_head() {
        let test_status = "\
# branch.oid 2a7bb916bba69a5fc9d428acc80b1bce64e3e0bc
# branch.head (detached)
";
        assert_eq!(
            GitStatus::new(test_status).unwrap().branch,
            Some(BranchInfo {
                object_id: String::from("2a7bb916bba69a5fc9d428acc80b1bce64e3e0bc"),
                branch: None
            })
        );
    }
}
<commit_msg>More test coverage<commit_after>#[derive(Debug, PartialEq, Eq)]
struct GitStatus {
    branch: Option<BranchInfo>,
    upstream: Option<UpstreamInfo>,
    staged: bool,
    unstaged: bool,
    untracked: bool,
    ignored: bool,
}

#[derive(Debug, PartialEq, Eq)]
struct BranchInfo {
    object_id: String,
    branch: Option<String>,
}

#[derive(Debug, PartialEq, Eq)]
struct UpstreamInfo {
    upstream: String,
    ahead: bool,
    behind: bool,
}

impl GitStatus {
    fn new(status_txt: &str) -> Result<GitStatus, &'static str> {
        let mut s = GitStatus {
            branch: None,
            upstream: None,
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        for line in status_txt.lines() {
            let words: Vec<&str> = line.split(' ').collect();
            if let Some(&first) = words.first() {
                match first {
                    "#" => {
                    },
                    "1" => {
                        s.staged = true;
                        s.unstaged = true;
                    },
                    "?" => {
                        s.untracked = true;
                    },
                    "!" => {
                        s.ignored = true;
                    },
                    _ => {},
                }
            }
        }
        Ok(s)
    }
}

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

    #[test]
    fn parse_clean() {
        let test_status = "\n";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                branch: None,
                upstream: None,
                staged: false,
                unstaged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_branch() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
";
        assert_eq!(
            GitStatus::new(test_status).unwrap().branch,
            Some(BranchInfo {
                object_id: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: Some(String::from("master")),
            })
        );
    }

    #[test]
    fn parse_detached_head() {
        let test_status = "\
# branch.oid 2a7bb916bba69a5fc9d428acc80b1bce64e3e0bc
# branch.head (detached)
";
        assert_eq!(
            GitStatus::new(test_status).unwrap().branch,
            Some(BranchInfo {
                object_id: String::from("2a7bb916bba69a5fc9d428acc80b1bce64e3e0bc"),
                branch: None
            })
        );
    }

    #[test]
    fn parse_upstream() {
        let test_status = "\
# branch.upstream origin/master
# branch.ab +1 -1
";
        assert_eq!(
            GitStatus::new(test_status).unwrap().upstream,
            Some(UpstreamInfo {
                upstream: String::from("origin/master"),
                ahead: true,
                behind: true,
            })
        );
    }

    #[test]
    fn parse_staged_only() {
        let test_status = "1 M. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md\n";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_unstaged_only() {
        let test_status = "1 .M N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 README.md\n";
        let s = GitStatus::new(test_status).unwrap();
        assert!(!s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_both_staged_and_unstaged() {
        let test_status = "1 MM N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md\n";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_untracked() {
        let test_status = "? foo.txt\n";
        assert!(GitStatus::new(test_status).unwrap().untracked);
    }

    #[test]
    fn parse_ignored() {
        let test_status = "! node_modules/\n";
        assert!(GitStatus::new(test_status).unwrap().ignored);
    }

    #[test]
    fn parse_very_dirty() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
1 M. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
1 .M N... 100644 100644 100644 5e8a8090976077ddf16252a560460a20dbbdd6a5 5e8a8090976077ddf16252a560460a20dbbdd6a5 gh-pages.sh
? foo.txt
! ignored.txt
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                branch: Some(BranchInfo {
                    object_id: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                    branch: Some(String::from("master")),
                }),
                upstream: Some(UpstreamInfo {
                    upstream: String::from("origin/master"),
                    ahead: true,
                    behind: true,
                }),
                staged: true,
                unstaged: true,
                untracked: true,
                ignored: true,
            }
        );
    }
}
<|endoftext|>


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

use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::fs;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

extern crate git2;
extern crate glob;
extern crate rustc_serialize;

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";

/// A single version of crate published to the index
#[derive(RustcDecodable)]
pub struct Version {
    pub name: String,
    pub vers: String,
    pub deps: Vec<Dependency>,
    pub cksum: String,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

/// A single dependency of a specific crate version
#[derive(RustcDecodable)]
pub struct Dependency {
    pub name: String,
    pub req: String,
    pub features: Vec<String>,
    pub optional: bool,
    pub default_features: bool,
    pub target: Option<String>,
    pub kind: Option<String>
}

/// Constructed from `Index::crates`
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|p| Crate::from_crate_index_path(&p))
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(std::iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new(path: PathBuf) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self)  -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new(path: PathBuf) -> Index {
        Index{path: path}
    }

    /// Determines if *anything* exists at the path specified from the constructor
    pub fn exists(&self) -> bool {
        fs::metadata(&self.path).is_ok()
    }

    /// Clones the index to the path specified from the constructor
    pub fn clone(&self) -> Result<(), git2::Error> {
        let _ = try!(git2::Repository::clone(INDEX_GIT_URL, &self.path));
        Ok(())
    }

    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        self.crate_index_paths()
            .find(|path| path.file_name().unwrap().to_str().unwrap().eq_ignore_ascii_case(crate_name))
            .map(|p| Crate::from_crate_index_path(&p))
    }

    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone())  // TODO: remove this clone
    }

    /// Generates a map of dependencies where the keys are crate names and the values are vectors
    /// of crate names that are its dependencies
    pub fn dependency_map(&self) -> HashMap<String, Vec<String>> {
        let mut map = HashMap::new();
        for crate_ in self.crates() {
            let version = crate_.latest_version();
            let mut deps_names = version.deps.iter().map(|d| d.name.clone()).collect::<Vec<_>>();
            deps_names.sort_by(|a, b| a.cmp(b));
            deps_names.dedup();
            map.insert(version.name.clone(), deps_names);
        }

        map
    }
}

pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    pub fn from_crate_index_path(index_path: &PathBuf) -> Crate {
        let mut versions = vec![];
        let file = fs::File::open(&index_path).unwrap();
        for line in BufReader::new(file).lines() {
            let version: Version = rustc_serialize::json::decode(&line.unwrap()).unwrap();
            versions.push(version);
        }
        Crate {versions: versions}
    }

    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len()]
    }
}

#[test]
fn test_dependencies() {
    let index = Index::new("_test".into());
    if !index.exists() {
        index.clone().unwrap();
    }
}
<commit_msg>Simpler constructor name<commit_after>// Copyright 2015 Corey Farwell
// Copyright 2015 Contributors of github.com/huonw/crates.io-graph
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::fs;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

extern crate git2;
extern crate glob;
extern crate rustc_serialize;

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";

/// A single version of crate published to the index
#[derive(RustcDecodable)]
pub struct Version {
    pub name: String,
    pub vers: String,
    pub deps: Vec<Dependency>,
    pub cksum: String,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

/// A single dependency of a specific crate version
#[derive(RustcDecodable)]
pub struct Dependency {
    pub name: String,
    pub req: String,
    pub features: Vec<String>,
    pub optional: bool,
    pub default_features: bool,
    pub target: Option<String>,
    pub kind: Option<String>
}

/// Constructed from `Index::crates`
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|p| Crate::new(&p))
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(std::iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new(path: PathBuf) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self)  -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new(path: PathBuf) -> Index {
        Index{path: path}
    }

    /// Determines if *anything* exists at the path specified from the constructor
    pub fn exists(&self) -> bool {
        fs::metadata(&self.path).is_ok()
    }

    /// Clones the index to the path specified from the constructor
    pub fn clone(&self) -> Result<(), git2::Error> {
        let _ = try!(git2::Repository::clone(INDEX_GIT_URL, &self.path));
        Ok(())
    }

    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        self.crate_index_paths()
            .find(|path| path.file_name().unwrap().to_str().unwrap().eq_ignore_ascii_case(crate_name))
            .map(|p| Crate::new(&p))
    }

    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone())  // TODO: remove this clone
    }

    /// Generates a map of dependencies where the keys are crate names and the values are vectors
    /// of crate names that are its dependencies
    pub fn dependency_map(&self) -> HashMap<String, Vec<String>> {
        let mut map = HashMap::new();
        for crate_ in self.crates() {
            let version = crate_.latest_version();
            let mut deps_names = version.deps.iter().map(|d| d.name.clone()).collect::<Vec<_>>();
            deps_names.sort_by(|a, b| a.cmp(b));
            deps_names.dedup();
            map.insert(version.name.clone(), deps_names);
        }

        map
    }
}

pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    pub fn new(index_path: &PathBuf) -> Crate {
        let mut versions = vec![];
        let file = fs::File::open(&index_path).unwrap();
        for line in BufReader::new(file).lines() {
            let version: Version = rustc_serialize::json::decode(&line.unwrap()).unwrap();
            versions.push(version);
        }
        Crate {versions: versions}
    }

    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len()]
    }
}

#[test]
fn test_dependencies() {
    let index = Index::new("_test".into());
    if !index.exists() {
        index.clone().unwrap();
    }
}
<|endoftext|>