<commit_before>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86_64 systems and
//! provides Unix-like syscalls for primarily Rust applications

//#![deny(warnings)]
#![feature(alloc)]
#![feature(allocator_api)]
#![feature(asm)]
#![feature(collections)]
#![feature(concat_idents)]
#![feature(conservative_impl_trait)]
#![feature(const_atomic_usize_new)]
#![feature(const_fn)]
#![feature(const_max_value)]
#![feature(core_intrinsics)]
#![feature(drop_types_in_const)]
#![feature(global_allocator)]
#![feature(integer_atomics)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(never_type)]
#![feature(thread_local)]
#![feature(unique)]
#![no_std]

extern crate alloc_kernel as allocator;
pub extern crate x86;

extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate spin;

use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use scheme::FileHandle;

pub use consts::*;

#[macro_use]
/// Shared data structures
pub mod common;

/// Architecture-dependent stuff
#[macro_use]
pub mod arch;
pub use arch::*;

/// Constants like memory locations
pub mod consts;

/// ACPI table parsing
mod acpi;

/// Context management
pub mod context;

/// Architecture-independent devices
pub mod devices;

/// ELF file parsing
#[cfg(not(feature="doc"))]
pub mod elf;

/// External functions
pub mod externs;

/// Memory management
pub mod memory;

/// Panic
#[cfg(not(any(feature="doc", test)))]
pub mod panic;

/// Schemes, filesystem handlers
pub mod scheme;

/// Synchronization primitives
pub mod sync;

/// Syscall handlers
pub mod syscall;

/// Time
pub mod time;

/// Tests
#[cfg(test)]
pub mod tests;

#[global_allocator]
static ALLOCATOR: allocator::Allocator = allocator::Allocator;

#[cfg(feature = "multi_core")]
static MULTI_CORE_IS_NOT_SUPPORTED_AT_THE_MOMENT: u8 = ();

/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
pub extern fn userspace_init() {
    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));

    assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));

    syscall::exec(b"/bin/init", &[]).expect("failed to execute init");

    panic!("init returned");
}

/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
#[no_mangle]
pub extern fn kmain(cpus: usize) {
    CPU_ID.store(0, Ordering::SeqCst);
    CPU_COUNT.store(cpus, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?} {}", pid, cpus);

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// This is the main kernel entry point for secondary CPUs
#[no_mangle]
#[allow(unreachable_code, unused_variables)]
pub extern fn kmain_ap(id: usize) {
    loop {
        unsafe {
            interrupt::disable();
            interrupt::halt();
        }
    }

    if cfg!(feature = "multi_core"){
        CPU_ID.store(id, Ordering::SeqCst);

        context::init();

        let pid = syscall::getpid();
        println!("AP {}: {:?}", id, pid);

        loop {
            unsafe {
                interrupt::disable();
                if context::switch() {
                    interrupt::enable_and_nop();
                } else {
                    // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                    interrupt::enable_and_halt();
                }
            }
        }
    }

}

/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
    println!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
    {
        let contexts = context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
        }
    }
    syscall::exit(signal & 0x7F);
}
<commit_msg>hybrid -> micro<commit_after>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a microkernel that supports X86_64 systems and
//! provides Unix-like syscalls for primarily Rust applications

//#![deny(warnings)]
#![feature(alloc)]
#![feature(allocator_api)]
#![feature(asm)]
#![feature(collections)]
#![feature(concat_idents)]
#![feature(conservative_impl_trait)]
#![feature(const_atomic_usize_new)]
#![feature(const_fn)]
#![feature(const_max_value)]
#![feature(core_intrinsics)]
#![feature(drop_types_in_const)]
#![feature(global_allocator)]
#![feature(integer_atomics)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(never_type)]
#![feature(thread_local)]
#![feature(unique)]
#![no_std]

extern crate alloc_kernel as allocator;
pub extern crate x86;

extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate spin;

use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use scheme::FileHandle;

pub use consts::*;

#[macro_use]
/// Shared data structures
pub mod common;

/// Architecture-dependent stuff
#[macro_use]
pub mod arch;
pub use arch::*;

/// Constants like memory locations
pub mod consts;

/// ACPI table parsing
mod acpi;

/// Context management
pub mod context;

/// Architecture-independent devices
pub mod devices;

/// ELF file parsing
#[cfg(not(feature="doc"))]
pub mod elf;

/// External functions
pub mod externs;

/// Memory management
pub mod memory;

/// Panic
#[cfg(not(any(feature="doc", test)))]
pub mod panic;

/// Schemes, filesystem handlers
pub mod scheme;

/// Synchronization primitives
pub mod sync;

/// Syscall handlers
pub mod syscall;

/// Time
pub mod time;

/// Tests
#[cfg(test)]
pub mod tests;

#[global_allocator]
static ALLOCATOR: allocator::Allocator = allocator::Allocator;

#[cfg(feature = "multi_core")]
static MULTI_CORE_IS_NOT_SUPPORTED_AT_THE_MOMENT: u8 = ();

/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
pub extern fn userspace_init() {
    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));

    assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));

    syscall::exec(b"/bin/init", &[]).expect("failed to execute init");

    panic!("init returned");
}

/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
#[no_mangle]
pub extern fn kmain(cpus: usize) {
    CPU_ID.store(0, Ordering::SeqCst);
    CPU_COUNT.store(cpus, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?} {}", pid, cpus);

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// This is the main kernel entry point for secondary CPUs
#[no_mangle]
#[allow(unreachable_code, unused_variables)]
pub extern fn kmain_ap(id: usize) {
    loop {
        unsafe {
            interrupt::disable();
            interrupt::halt();
        }
    }

    if cfg!(feature = "multi_core"){
        CPU_ID.store(id, Ordering::SeqCst);

        context::init();

        let pid = syscall::getpid();
        println!("AP {}: {:?}", id, pid);

        loop {
            unsafe {
                interrupt::disable();
                if context::switch() {
                    interrupt::enable_and_nop();
                } else {
                    // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                    interrupt::enable_and_halt();
                }
            }
        }
    }

}

/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
    println!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
    {
        let contexts = context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
        }
    }
    syscall::exit(signal & 0x7F);
}
<|endoftext|>


<commit_before>pub extern crate tesseract_plumbing as plumbing;
extern crate tesseract_sys;
extern crate thiserror;

use self::thiserror::Error;
use std::ffi::CString;
use std::ffi::NulError;
use std::os::raw::c_int;
use std::str;

use self::tesseract_sys::{
    TessOcrEngineMode, TessOcrEngineMode_OEM_DEFAULT, TessOcrEngineMode_OEM_LSTM_ONLY,
    TessOcrEngineMode_OEM_TESSERACT_LSTM_COMBINED, TessOcrEngineMode_OEM_TESSERACT_ONLY,
};

#[derive(Debug, Error)]
pub enum InitializeError {
    #[error("Conversion to CString failed")]
    CStringError(#[from] NulError),
    #[error("TessBaseApi failed to initialize")]
    TessBaseAPIInitError(#[from] plumbing::TessBaseApiInitError),
}

#[derive(Debug, Error)]
pub enum SetImageError {
    #[error("Conversion to CString failed")]
    CStringError(#[from] NulError),
    #[error("Failed to read image")]
    PixReadError(#[from] plumbing::leptonica_plumbing::PixReadError),
}

#[derive(Debug, Error)]
pub enum SetVariableError {
    #[error("Conversion to CString failed")]
    CStringError(#[from] NulError),
    #[error("TessBaseApi failed to set variable")]
    TessBaseAPISetVariableError(#[from] plumbing::TessBaseApiSetVariableError),
}

#[derive(Debug, Error)]
pub enum TesseractError {
    #[error("Failed to set language")]
    InitializeError(#[from] InitializeError),
    #[error("Failed to set image")]
    SetImageError(#[from] SetImageError),
    #[error("Errored whilst recognizing")]
    RecognizeError(#[from] plumbing::TessBaseApiRecogniseError),
    #[error("Errored whilst getting text")]
    GetTextError(#[from] plumbing::TessBaseApiGetUtf8TextError),
    #[error("Errored whilst getting HOCR text")]
    GetHOCRTextError(#[from] plumbing::TessBaseApiGetHocrTextError),
    #[error("Errored whilst setting frame")]
    SetFrameError(#[from] plumbing::TessBaseApiSetImageSafetyError),
    #[error("Errored whilst setting image from mem")]
    SetImgFromMemError(#[from] plumbing::leptonica_plumbing::PixReadMemError),
    #[error("Errored whilst setting variable")]
    SetVariableError(#[from] SetVariableError),
}

/// https://tesseract-ocr.github.io/tessapi/5.x/a01818.html#a04550a0ed1279562027bf2fc92c421aead84e1ef94e50df1622b4fcd189c6c00b
pub enum OcrEngineMode {
    /// Run Tesseract only - fastest; deprecated
    Default,
    /// Run just the LSTM line recognizer.
    LstmOnly,
    /// Run the LSTM recognizer, but allow fallback
    /// to Tesseract when things get difficult.
    /// deprecated
    TesseractLstmCombined,
    /// Specify this mode,
    /// to indicate that any of the above modes
    /// should be automatically inferred from the
    /// variables in the language-specific config,
    /// command-line configs, or if not specified
    /// in any of the above should be set to the
    /// default OEM_TESSERACT_ONLY.
    TesseractOnly,
}

impl OcrEngineMode {
    fn to_value(&self) -> TessOcrEngineMode {
        match *self {
            OcrEngineMode::Default => TessOcrEngineMode_OEM_DEFAULT,
            OcrEngineMode::LstmOnly => TessOcrEngineMode_OEM_LSTM_ONLY,
            OcrEngineMode::TesseractLstmCombined => TessOcrEngineMode_OEM_TESSERACT_LSTM_COMBINED,
            OcrEngineMode::TesseractOnly => TessOcrEngineMode_OEM_TESSERACT_ONLY,
        }
    }
}

pub struct Tesseract(plumbing::TessBaseApi);

impl Tesseract {
    pub fn new(datapath: Option<&str>, language: Option<&str>) -> Result<Self, InitializeError> {
        let mut tess = Tesseract(plumbing::TessBaseApi::create());
        let datapath = match datapath {
            Some(i) => Some(CString::new(i)?),
            None => None,
        };
        let language = match language {
            Some(i) => Some(CString::new(i)?),
            None => None,
        };

        tess.0.init_2(datapath.as_deref(), language.as_deref())?;
        Ok(tess)
    }

    pub fn new_with_oem(
        datapath: Option<&str>,
        language: Option<&str>,
        oem: OcrEngineMode,
    ) -> Result<Self, InitializeError> {
        let mut tess = Tesseract(plumbing::TessBaseApi::create());
        let datapath = match datapath {
            Some(i) => Some(CString::new(i)?),
            None => None,
        };
        let language = match language {
            Some(i) => Some(CString::new(i)?),
            None => None,
        };

        tess.0
            .init_4(datapath.as_deref(), language.as_deref(), oem.to_value())?;
        Ok(tess)
    }

    pub fn set_image(mut self, filename: &str) -> Result<Self, SetImageError> {
        let pix = plumbing::leptonica_plumbing::Pix::read(&CString::new(filename)?)?;
        self.0.set_image_2(&pix);
        Ok(self)
    }
    pub fn set_frame(
        mut self,
        frame_data: &[u8],
        width: i32,
        height: i32,
        bytes_per_pixel: i32,
        bytes_per_line: i32,
    ) -> Result<Self, plumbing::TessBaseApiSetImageSafetyError> {
        self.0
            .set_image(frame_data, width, height, bytes_per_pixel, bytes_per_line)?;
        Ok(self)
    }
    pub fn set_image_from_mem(
        mut self,
        img: &[u8],
    ) -> Result<Self, plumbing::leptonica_plumbing::PixReadMemError> {
        let pix = plumbing::leptonica_plumbing::Pix::read_mem(img)?;
        self.0.set_image_2(&pix);
        Ok(self)
    }

    pub fn set_source_resolution(mut self, ppi: i32) -> Self {
        self.0.set_source_resolution(ppi);
        self
    }

    pub fn set_variable(mut self, name: &str, value: &str) -> Result<Self, SetVariableError> {
        self.0
            .set_variable(&CString::new(name)?, &CString::new(value)?)?;
        Ok(self)
    }
    pub fn recognize(mut self) -> Result<Self, plumbing::TessBaseApiRecogniseError> {
        self.0.recognize()?;
        Ok(self)
    }
    pub fn get_text(&mut self) -> Result<String, plumbing::TessBaseApiGetUtf8TextError> {
        Ok(self
            .0
            .get_utf8_text()?
            .as_ref()
            .to_string_lossy()
            .into_owned())
    }
    pub fn mean_text_conf(&mut self) -> i32 {
        self.0.mean_text_conf()
    }

    /// Get the text encoded as HTML with bounding box tags
    ///
    /// See [img.html](../img.html) for an example.
    pub fn get_hocr_text(
        &mut self,
        page: c_int,
    ) -> Result<String, plumbing::TessBaseApiGetHocrTextError> {
        Ok(self
            .0
            .get_hocr_text(page)?
            .as_ref()
            .to_string_lossy()
            .into_owned())
    }
}

pub fn ocr(filename: &str, language: &str) -> Result<String, TesseractError> {
    Ok(Tesseract::new(None, Some(language))?
        .set_image(filename)?
        .recognize()?
        .get_text()?)
}

pub fn ocr_from_frame(
    frame_data: &[u8],
    width: i32,
    height: i32,
    bytes_per_pixel: i32,
    bytes_per_line: i32,
    language: &str,
) -> Result<String, TesseractError> {
    Ok(Tesseract::new(None, Some(language))?
        .set_frame(frame_data, width, height, bytes_per_pixel, bytes_per_line)?
        .recognize()?
        .get_text()?)
}

#[test]
fn ocr_test() -> Result<(), TesseractError> {
    assert_eq!(
        ocr("img.png", "eng")?,
        include_str!("../img.txt").to_string()
    );
    Ok(())
}

#[test]
fn ocr_from_frame_test() -> Result<(), TesseractError> {
    assert_eq!(
        ocr_from_frame(include_bytes!("../img.tiff"), 2256, 324, 3, 2256 * 3, "eng")?,
        include_str!("../img.txt").to_string()
    );
    Ok(())
}

#[test]
fn ocr_from_mem_with_ppi() -> Result<(), TesseractError> {
    let mut cube = Tesseract::new(None, Some("eng"))?
        .set_image_from_mem(include_bytes!("../img.tiff"))?
        .set_source_resolution(70);
    assert_eq!(&cube.get_text()?, include_str!("../img.txt"));
    Ok(())
}

#[test]
fn expanded_test() -> Result<(), TesseractError> {
    let mut cube = Tesseract::new(None, Some("eng"))?
        .set_image("img.png")?
        .set_variable("tessedit_char_blacklist", "z")?
        .recognize()?;
    assert_eq!(&cube.get_text()?, include_str!("../img.txt"));
    Ok(())
}

#[test]
fn hocr_test() -> Result<(), TesseractError> {
    let mut cube = Tesseract::new(None, Some("eng"))?.set_image("img.png")?;
    assert!(&cube.get_hocr_text(0)?.contains("
 Result<(), TesseractError> {
    let only_tesseract_str =
        Tesseract::new_with_oem(None, Some("eng"), OcrEngineMode::TesseractOnly)?
            .set_image("img.png")?
            .recognize()?
            .get_text()?;

    let only_lstm_str = Tesseract::new_with_oem(None, Some("eng"), OcrEngineMode::LstmOnly)?
        .set_image("img.png")?
        .recognize()?
        .get_text()?;

    assert_ne!(only_tesseract_str, only_lstm_str);
    Ok(())
}

#[test]
fn oem_ltsm_only_test() -> Result<(), TesseractError> {
    let only_lstm_str = Tesseract::new_with_oem(None, Some("eng"), OcrEngineMode::LstmOnly)?
        .set_image("img.png")?
        .recognize()?
        .get_text()?;

    assert_eq!(only_lstm_str, include_str!("../img.txt"));
    Ok(())
}
<commit_msg>tsv text API call support (#30)<commit_after>pub extern crate tesseract_plumbing as plumbing;
extern crate tesseract_sys;
extern crate thiserror;

use self::thiserror::Error;
use std::ffi::CString;
use std::ffi::NulError;
use std::os::raw::c_int;
use std::str;

use self::tesseract_sys::{
    TessOcrEngineMode, TessOcrEngineMode_OEM_DEFAULT, TessOcrEngineMode_OEM_LSTM_ONLY,
    TessOcrEngineMode_OEM_TESSERACT_LSTM_COMBINED, TessOcrEngineMode_OEM_TESSERACT_ONLY,
};

#[derive(Debug, Error)]
pub enum InitializeError {
    #[error("Conversion to CString failed")]
    CStringError(#[from] NulError),
    #[error("TessBaseApi failed to initialize")]
    TessBaseAPIInitError(#[from] plumbing::TessBaseApiInitError),
}

#[derive(Debug, Error)]
pub enum SetImageError {
    #[error("Conversion to CString failed")]
    CStringError(#[from] NulError),
    #[error("Failed to read image")]
    PixReadError(#[from] plumbing::leptonica_plumbing::PixReadError),
}

#[derive(Debug, Error)]
pub enum SetVariableError {
    #[error("Conversion to CString failed")]
    CStringError(#[from] NulError),
    #[error("TessBaseApi failed to set variable")]
    TessBaseAPISetVariableError(#[from] plumbing::TessBaseApiSetVariableError),
}

#[derive(Debug, Error)]
pub enum TesseractError {
    #[error("Failed to set language")]
    InitializeError(#[from] InitializeError),
    #[error("Failed to set image")]
    SetImageError(#[from] SetImageError),
    #[error("Errored whilst recognizing")]
    RecognizeError(#[from] plumbing::TessBaseApiRecogniseError),
    #[error("Errored whilst getting text")]
    GetTextError(#[from] plumbing::TessBaseApiGetUtf8TextError),
    #[error("Errored whilst getting HOCR text")]
    GetHOCRTextError(#[from] plumbing::TessBaseApiGetHocrTextError),
    #[error("Errored whilst getting TSV text")]
    GetTsvTextError(#[from] plumbing::TessBaseApiGetTsvTextError),
    #[error("Errored whilst setting frame")]
    SetFrameError(#[from] plumbing::TessBaseApiSetImageSafetyError),
    #[error("Errored whilst setting image from mem")]
    SetImgFromMemError(#[from] plumbing::leptonica_plumbing::PixReadMemError),
    #[error("Errored whilst setting variable")]
    SetVariableError(#[from] SetVariableError),
}

/// https://tesseract-ocr.github.io/tessapi/5.x/a01818.html#a04550a0ed1279562027bf2fc92c421aead84e1ef94e50df1622b4fcd189c6c00b
pub enum OcrEngineMode {
    /// Run Tesseract only - fastest; deprecated
    Default,
    /// Run just the LSTM line recognizer.
    LstmOnly,
    /// Run the LSTM recognizer, but allow fallback
    /// to Tesseract when things get difficult.
    /// deprecated
    TesseractLstmCombined,
    /// Specify this mode,
    /// to indicate that any of the above modes
    /// should be automatically inferred from the
    /// variables in the language-specific config,
    /// command-line configs, or if not specified
    /// in any of the above should be set to the
    /// default OEM_TESSERACT_ONLY.
    TesseractOnly,
}

impl OcrEngineMode {
    fn to_value(&self) -> TessOcrEngineMode {
        match *self {
            OcrEngineMode::Default => TessOcrEngineMode_OEM_DEFAULT,
            OcrEngineMode::LstmOnly => TessOcrEngineMode_OEM_LSTM_ONLY,
            OcrEngineMode::TesseractLstmCombined => TessOcrEngineMode_OEM_TESSERACT_LSTM_COMBINED,
            OcrEngineMode::TesseractOnly => TessOcrEngineMode_OEM_TESSERACT_ONLY,
        }
    }
}

pub struct Tesseract(plumbing::TessBaseApi);

impl Tesseract {
    pub fn new(datapath: Option<&str>, language: Option<&str>) -> Result<Self, InitializeError> {
        let mut tess = Tesseract(plumbing::TessBaseApi::create());
        let datapath = match datapath {
            Some(i) => Some(CString::new(i)?),
            None => None,
        };
        let language = match language {
            Some(i) => Some(CString::new(i)?),
            None => None,
        };

        tess.0.init_2(datapath.as_deref(), language.as_deref())?;
        Ok(tess)
    }

    pub fn new_with_oem(
        datapath: Option<&str>,
        language: Option<&str>,
        oem: OcrEngineMode,
    ) -> Result<Self, InitializeError> {
        let mut tess = Tesseract(plumbing::TessBaseApi::create());
        let datapath = match datapath {
            Some(i) => Some(CString::new(i)?),
            None => None,
        };
        let language = match language {
            Some(i) => Some(CString::new(i)?),
            None => None,
        };

        tess.0
            .init_4(datapath.as_deref(), language.as_deref(), oem.to_value())?;
        Ok(tess)
    }

    pub fn set_image(mut self, filename: &str) -> Result<Self, SetImageError> {
        let pix = plumbing::leptonica_plumbing::Pix::read(&CString::new(filename)?)?;
        self.0.set_image_2(&pix);
        Ok(self)
    }
    pub fn set_frame(
        mut self,
        frame_data: &[u8],
        width: i32,
        height: i32,
        bytes_per_pixel: i32,
        bytes_per_line: i32,
    ) -> Result<Self, plumbing::TessBaseApiSetImageSafetyError> {
        self.0
            .set_image(frame_data, width, height, bytes_per_pixel, bytes_per_line)?;
        Ok(self)
    }
    pub fn set_image_from_mem(
        mut self,
        img: &[u8],
    ) -> Result<Self, plumbing::leptonica_plumbing::PixReadMemError> {
        let pix = plumbing::leptonica_plumbing::Pix::read_mem(img)?;
        self.0.set_image_2(&pix);
        Ok(self)
    }

    pub fn set_source_resolution(mut self, ppi: i32) -> Self {
        self.0.set_source_resolution(ppi);
        self
    }

    pub fn set_variable(mut self, name: &str, value: &str) -> Result<Self, SetVariableError> {
        self.0
            .set_variable(&CString::new(name)?, &CString::new(value)?)?;
        Ok(self)
    }
    pub fn recognize(mut self) -> Result<Self, plumbing::TessBaseApiRecogniseError> {
        self.0.recognize()?;
        Ok(self)
    }
    pub fn get_text(&mut self) -> Result<String, plumbing::TessBaseApiGetUtf8TextError> {
        Ok(self
            .0
            .get_utf8_text()?
            .as_ref()
            .to_string_lossy()
            .into_owned())
    }
    pub fn mean_text_conf(&mut self) -> i32 {
        self.0.mean_text_conf()
    }

    /// Get the text encoded as HTML with bounding box tags
    ///
    /// See [img.html](../img.html) for an example.
    pub fn get_hocr_text(
        &mut self,
        page: c_int,
    ) -> Result<String, plumbing::TessBaseApiGetHocrTextError> {
        Ok(self
            .0
            .get_hocr_text(page)?
            .as_ref()
            .to_string_lossy()
            .into_owned())
    }

    /// Get the text encoded as TSV, including bounding boxes, confidence
    ///
    /// See [char* TessBaseAPI::GetTSVText](https://github.com/tesseract-ocr/tesseract/blob/cdebe13d81e2ad2a83be533886750f5491b25262/src/api/baseapi.cpp#L1398)
    pub fn get_tsv_text(
        &mut self,
        page: c_int,
    ) -> Result<String, plumbing::TessBaseApiGetTsvTextError> {
        Ok(self
            .0
            .get_tsv_text(page)?
            .as_ref()
            .to_string_lossy()
            .into_owned())
    }
}

pub fn ocr(filename: &str, language: &str) -> Result<String, TesseractError> {
    Ok(Tesseract::new(None, Some(language))?
        .set_image(filename)?
        .recognize()?
        .get_text()?)
}

pub fn ocr_from_frame(
    frame_data: &[u8],
    width: i32,
    height: i32,
    bytes_per_pixel: i32,
    bytes_per_line: i32,
    language: &str,
) -> Result<String, TesseractError> {
    Ok(Tesseract::new(None, Some(language))?
        .set_frame(frame_data, width, height, bytes_per_pixel, bytes_per_line)?
        .recognize()?
        .get_text()?)
}

#[test]
fn ocr_test() -> Result<(), TesseractError> {
    assert_eq!(
        ocr("img.png", "eng")?,
        include_str!("../img.txt").to_string()
    );
    Ok(())
}

#[test]
fn ocr_from_frame_test() -> Result<(), TesseractError> {
    assert_eq!(
        ocr_from_frame(include_bytes!("../img.tiff"), 2256, 324, 3, 2256 * 3, "eng")?,
        include_str!("../img.txt").to_string()
    );
    Ok(())
}

#[test]
fn ocr_from_mem_with_ppi() -> Result<(), TesseractError> {
    let mut cube = Tesseract::new(None, Some("eng"))?
        .set_image_from_mem(include_bytes!("../img.tiff"))?
        .set_source_resolution(70);
    assert_eq!(&cube.get_text()?, include_str!("../img.txt"));
    Ok(())
}

#[test]
fn expanded_test() -> Result<(), TesseractError> {
    let mut cube = Tesseract::new(None, Some("eng"))?
        .set_image("img.png")?
        .set_variable("tessedit_char_blacklist", "z")?
        .recognize()?;
    assert_eq!(&cube.get_text()?, include_str!("../img.txt"));
    Ok(())
}

#[test]
fn hocr_test() -> Result<(), TesseractError> {
    let mut cube = Tesseract::new(None, Some("eng"))?.set_image("img.png")?;
    assert!(&cube.get_hocr_text(0)?.contains("
 Result<(), TesseractError> {
    let only_tesseract_str =
        Tesseract::new_with_oem(None, Some("eng"), OcrEngineMode::TesseractOnly)?
            .set_image("img.png")?
            .recognize()?
            .get_text()?;

    let only_lstm_str = Tesseract::new_with_oem(None, Some("eng"), OcrEngineMode::LstmOnly)?
        .set_image("img.png")?
        .recognize()?
        .get_text()?;

    assert_ne!(only_tesseract_str, only_lstm_str);
    Ok(())
}

#[test]
fn oem_ltsm_only_test() -> Result<(), TesseractError> {
    let only_lstm_str = Tesseract::new_with_oem(None, Some("eng"), OcrEngineMode::LstmOnly)?
        .set_image("img.png")?
        .recognize()?
        .get_text()?;

    assert_eq!(only_lstm_str, include_str!("../img.txt"));
    Ok(())
}
<|endoftext|>


<commit_before>#![feature(plugin, str_char, slice_patterns, convert, core)]
#![plugin(regex_macros)]
extern crate regex;
extern crate chrono;
#[macro_use]
extern crate log as l;

pub mod log;
pub mod format;

use std::error::FromError;
use std::{ io, result };

use chrono::format::ParseError;

pub type Result<T> = result::Result<T, IlcError>;

#[derive(Debug, PartialEq)]
pub enum IlcError {
    Parse(String),
    Chrono(ParseError),
    Io(io::Error)
}

impl FromError<ParseError> for IlcError {
    fn from_error(err: ParseError) -> IlcError { IlcError::Chrono(err) }
}

impl FromError<io::Error> for IlcError {
    fn from_error(err: io::Error) -> IlcError { IlcError::Io(err) }
}
<commit_msg>Update for removal of std::error::FromError<commit_after>#![feature(plugin, slice_patterns, core)]
#![plugin(regex_macros)]
extern crate regex;
extern crate chrono;
#[macro_use]
extern crate log as l;

pub mod log;
pub mod format;

use std::convert::From;
use std::{ io, result };

use chrono::format::ParseError;

pub type Result<T> = result::Result<T, IlcError>;

#[derive(Debug)]
pub enum IlcError {
    Parse(String),
    Chrono(ParseError),
    Io(io::Error)
}

impl From<ParseError> for IlcError {
    fn from(err: ParseError) -> IlcError { IlcError::Chrono(err) }
}

impl From<io::Error> for IlcError {
    fn from(err: io::Error) -> IlcError { IlcError::Io(err) }
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use syn::{parse_expr, parse_item, Abi, BareFnArg, BareFnTy, Block, Constness, Expr, ExprKind,
          FnArg, FnDecl, Generics, Ident, Item, ItemKind, Pat, Path, PathSegment, UnOp, Unsafety,
          Visibility};
use quote::{Tokens, ToTokens};
use std::option::Option;

#[proc_macro_attribute]
pub fn runtime_target_feature(features: TokenStream, function: TokenStream) -> TokenStream {
    let features_string = features.to_string();

    let features_str = strip_quotes(strip_parens(features_string.as_str()));

    let features = features_str
        .split(",")
        .map(Feature::new)
        .collect::<Vec<_>>();

    let have_features = features
        .iter()
        .map(|ref x| x.checker_expr())
        .collect::<Vec<_>>();

    let function_string = function.to_string();

    let function_item = syn::parse_item(&function_string).unwrap();
    let function_type = function_item_to_type(&function_item.node);

    let (function_decl, function_unsafety, function_constness, function_abi, function_generics) =
        match function_item.node {
            ItemKind::Fn(ref a, b, c, ref d, ref e, _) => (a.as_ref(), b, c, d, e),
            _ => panic!("item must be a function"),
        };

    let args = function_decl
        .inputs
        .iter()
        .map(fn_arg_to_expr)
        .collect::<Vec<_>>();

    let setup_ident = Ident::new("setup");
    let default_ident = Ident::new("default");
    let features_ident: Ident = features.iter()
        .map(|x| x.to_ident_string())
        .fold("".to_string(), |acc, x| acc + &x) // TODO: separator
        .into();

    let function_item_default = Item {
        ident: default_ident.clone(),
        vis: Visibility::Inherited,
        attrs: function_item.attrs.clone(),
        node: function_item.node.clone(),
    };

    let function_item_with_features = Item {
        ident: features_ident.clone(),
        vis: Visibility::Inherited,
        attrs: function_item.attrs.clone(),
        node: function_item.node.clone(),
    };

    let setup_args = args.clone();

    let setup_block_tokens = quote! {
        {
            pub extern crate runtime_target_feature_rt as rt;

            let chosen_function = if #(#have_features)&&* {
                #features_ident
            } else {
                #default_ident
            };

            PTR.store(chosen_function, rt::atomic::Ordering::Relaxed);

            chosen_function(#(#setup_args),*)
        }
    };

    let setup_block = parse_block(setup_block_tokens.as_str());
    let setup_node = ItemKind::Fn(Box::new(function_decl.clone()),
                                  function_unsafety,
                                  function_constness,
                                  function_abi.clone(),
                                  function_generics.clone(),
                                  setup_block);

    let function_item_setup = Item {
        ident: setup_ident.clone(),
        vis: Visibility::Inherited,
        attrs: function_item.attrs.clone(),
        node: setup_node,
    };

    let dispatch_function_block_tokens = quote! {
        {
            pub extern crate runtime_target_feature_rt as rt;

            static PTR: rt::atomic::Atomic<#function_type> = rt::atomic::Atomic::new(#setup_ident);

            #function_item_setup

            #function_item_default

            #[target_feature = #features_str]
            #function_item_with_features

            PTR.load(rt::atomic::Ordering::Relaxed)(#(#args),*)
        }
    };

    let dispatch_function_block = parse_block(dispatch_function_block_tokens.as_str());

    let dispatch_function_node = ItemKind::Fn(Box::new(function_decl.clone()),
                                              function_unsafety,
                                              function_constness,
                                              function_abi.clone(),
                                              function_generics.clone(),
                                              dispatch_function_block);

    let dispatch_function = Item {
        ident: function_item.ident.clone(),
        vis: function_item.vis,
        attrs: function_item.attrs.clone(),
        node: dispatch_function_node,
    };

    let mut tokens = Tokens::new();
    dispatch_function.to_tokens(&mut tokens);
    println!("{}", tokens);
    tokens.parse().unwrap()
}

fn parse_block(input: &str) -> Box<Block> {
    Box::new(match parse_expr(input).unwrap().node {
                 ExprKind::Block(_, block) => block,
                 _ => unreachable!(),
             })
}

fn strip_parens(str_with_parens: &str) -> &str {
    if !(str_with_parens.starts_with("(") || str_with_parens.ends_with(")")) {
        panic!("attribute arguments must begin with '(' and end with ')'");
    }

    &str_with_parens[1..str_with_parens.len() - 1].trim()
}

fn strip_quotes(str_with_quotes: &str) -> &str {
    if !(str_with_quotes.starts_with("\"") || str_with_quotes.ends_with("\"")) {
        panic!("attribute arguments must be a string literal");
    }

    &str_with_quotes[1..str_with_quotes.len() - 1].trim()
}

fn function_item_to_type(item_kind: &ItemKind) -> BareFnTy {
    let (decl, unsafety, abi, generics): (&FnDecl, Unsafety, &Option<Abi>, &Generics) =
        match *item_kind {
            ItemKind::Fn(ref a, b, _, ref d, ref e, _) => (&*a, b, d, e),
            _ => panic!("item must be a function"),
        };

    let inputs = decl.inputs
        .iter()
        .map(|x| match *x {
                 FnArg::Captured(_, ref ty) => ty,
                 FnArg::Ignored(ref ty) => ty,
                 _ => panic!("self not supported"),
             })
        .map(|ty| {
                 BareFnArg {
                     name: Option::None,
                     ty: ty.clone(),
                 }
             })
        .collect::<Vec<_>>();

    let lifetimes = Vec::new(); // TODO

    BareFnTy {
        unsafety: unsafety,
        abi: abi.clone(),
        lifetimes: lifetimes,
        inputs: inputs,
        output: decl.output.clone(),
        variadic: decl.variadic,
    }
}

fn fn_arg_to_expr(arg: &FnArg) -> Expr {
    match *arg {
        FnArg::Captured(ref pat, _) => {
            match *pat {
                Pat::Ident(_, ref ident, _) => {
                    Expr {
                        node: ExprKind::Path(Option::None, Path::from(ident.clone())),
                        attrs: Vec::new(),
                    }
                }
                _ => panic!("pattern must be identifier"),
            }
        }
        _ => panic!("argument must be captured"),
    }
}

enum Feature<'a> {
    Enable(&'a str),
    Disable(&'a str),
}

impl<'a> Feature<'a> {
    fn new(feature_str: &'a str) -> Self {
        if feature_str.starts_with("+") {
            Feature::Enable(&feature_str[1..])
        } else if feature_str.starts_with("-") {
            Feature::Disable(&feature_str[1..])
        } else {
            panic!("feature must begin with '+' or '-'");
        }
    }

    fn name(&self) -> &str {
        match *self {
            Feature::Enable(x) => x,
            Feature::Disable(x) => x,
        }
    }

    fn to_ident_string(&self) -> String {
        match *self {
            Feature::Enable(x) => "enable_".to_string() + x,
            Feature::Disable(x) => "disable_".to_string() + x,
        }
    }

    fn checker_expr(&self) -> Expr {
        let segments = ["rt", &("have_".to_string() + self.name())]
            .iter()
            .map(|x| PathSegment::from(*x))
            .collect();
        let path = Path {
            global: false,
            segments: segments,
        };
        let function = Expr {
            node: ExprKind::Path(Option::None, path),
            attrs: Vec::new(),
        };
        let call = Expr {
            node: ExprKind::Call(Box::new(function), Vec::new()),
            attrs: Vec::new(),
        };
        match *self {
            Feature::Enable(_) => call,
            Feature::Disable(_) => {
                Expr {
                    node: ExprKind::Unary(UnOp::Not, Box::new(call)),
                    attrs: Vec::new(),
                }
            }
        }
    }
}
<commit_msg>remove duplicate extern crate<commit_after>#![feature(proc_macro)]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use syn::{parse_expr, parse_item, Abi, BareFnArg, BareFnTy, Block, Constness, Expr, ExprKind,
          FnArg, FnDecl, Generics, Ident, Item, ItemKind, Pat, Path, PathSegment, UnOp, Unsafety,
          Visibility};
use quote::{Tokens, ToTokens};
use std::option::Option;

#[proc_macro_attribute]
pub fn runtime_target_feature(features: TokenStream, function: TokenStream) -> TokenStream {
    let features_string = features.to_string();

    let features_str = strip_quotes(strip_parens(features_string.as_str()));

    let features = features_str
        .split(",")
        .map(Feature::new)
        .collect::<Vec<_>>();

    let have_features = features
        .iter()
        .map(|ref x| x.checker_expr())
        .collect::<Vec<_>>();

    let function_string = function.to_string();

    let function_item = syn::parse_item(&function_string).unwrap();
    let function_type = function_item_to_type(&function_item.node);

    let (function_decl, function_unsafety, function_constness, function_abi, function_generics) =
        match function_item.node {
            ItemKind::Fn(ref a, b, c, ref d, ref e, _) => (a.as_ref(), b, c, d, e),
            _ => panic!("item must be a function"),
        };

    let args = function_decl
        .inputs
        .iter()
        .map(fn_arg_to_expr)
        .collect::<Vec<_>>();

    let setup_ident = Ident::new("setup");
    let default_ident = Ident::new("default");
    let features_ident: Ident = features.iter()
        .map(|x| x.to_ident_string())
        .fold("".to_string(), |acc, x| acc + &x) // TODO: separator
        .into();

    let function_item_default = Item {
        ident: default_ident.clone(),
        vis: Visibility::Inherited,
        attrs: function_item.attrs.clone(),
        node: function_item.node.clone(),
    };

    let function_item_with_features = Item {
        ident: features_ident.clone(),
        vis: Visibility::Inherited,
        attrs: function_item.attrs.clone(),
        node: function_item.node.clone(),
    };

    let setup_args = args.clone();

    let setup_block_tokens = quote! {
        {
            let chosen_function = if #(#have_features)&&* {
                #features_ident
            } else {
                #default_ident
            };

            PTR.store(chosen_function, rt::atomic::Ordering::Relaxed);

            chosen_function(#(#setup_args),*)
        }
    };

    let setup_block = parse_block(setup_block_tokens.as_str());
    let setup_node = ItemKind::Fn(Box::new(function_decl.clone()),
                                  function_unsafety,
                                  function_constness,
                                  function_abi.clone(),
                                  function_generics.clone(),
                                  setup_block);

    let function_item_setup = Item {
        ident: setup_ident.clone(),
        vis: Visibility::Inherited,
        attrs: function_item.attrs.clone(),
        node: setup_node,
    };

    let dispatch_function_block_tokens = quote! {
        {
            pub extern crate runtime_target_feature_rt as rt;

            static PTR: rt::atomic::Atomic<#function_type> = rt::atomic::Atomic::new(#setup_ident);

            #function_item_setup

            #function_item_default

            #[target_feature = #features_str]
            #function_item_with_features

            PTR.load(rt::atomic::Ordering::Relaxed)(#(#args),*)
        }
    };

    let dispatch_function_block = parse_block(dispatch_function_block_tokens.as_str());

    let dispatch_function_node = ItemKind::Fn(Box::new(function_decl.clone()),
                                              function_unsafety,
                                              function_constness,
                                              function_abi.clone(),
                                              function_generics.clone(),
                                              dispatch_function_block);

    let dispatch_function = Item {
        ident: function_item.ident.clone(),
        vis: function_item.vis,
        attrs: function_item.attrs.clone(),
        node: dispatch_function_node,
    };

    let mut tokens = Tokens::new();
    dispatch_function.to_tokens(&mut tokens);
    println!("{}", tokens);
    tokens.parse().unwrap()
}

fn parse_block(input: &str) -> Box<Block> {
    Box::new(match parse_expr(input).unwrap().node {
                 ExprKind::Block(_, block) => block,
                 _ => unreachable!(),
             })
}

fn strip_parens(str_with_parens: &str) -> &str {
    if !(str_with_parens.starts_with("(") || str_with_parens.ends_with(")")) {
        panic!("attribute arguments must begin with '(' and end with ')'");
    }

    &str_with_parens[1..str_with_parens.len() - 1].trim()
}

fn strip_quotes(str_with_quotes: &str) -> &str {
    if !(str_with_quotes.starts_with("\"") || str_with_quotes.ends_with("\"")) {
        panic!("attribute arguments must be a string literal");
    }

    &str_with_quotes[1..str_with_quotes.len() - 1].trim()
}

fn function_item_to_type(item_kind: &ItemKind) -> BareFnTy {
    let (decl, unsafety, abi, generics): (&FnDecl, Unsafety, &Option<Abi>, &Generics) =
        match *item_kind {
            ItemKind::Fn(ref a, b, _, ref d, ref e, _) => (&*a, b, d, e),
            _ => panic!("item must be a function"),
        };

    let inputs = decl.inputs
        .iter()
        .map(|x| match *x {
                 FnArg::Captured(_, ref ty) => ty,
                 FnArg::Ignored(ref ty) => ty,
                 _ => panic!("self not supported"),
             })
        .map(|ty| {
                 BareFnArg {
                     name: Option::None,
                     ty: ty.clone(),
                 }
             })
        .collect::<Vec<_>>();

    let lifetimes = Vec::new(); // TODO

    BareFnTy {
        unsafety: unsafety,
        abi: abi.clone(),
        lifetimes: lifetimes,
        inputs: inputs,
        output: decl.output.clone(),
        variadic: decl.variadic,
    }
}

fn fn_arg_to_expr(arg: &FnArg) -> Expr {
    match *arg {
        FnArg::Captured(ref pat, _) => {
            match *pat {
                Pat::Ident(_, ref ident, _) => {
                    Expr {
                        node: ExprKind::Path(Option::None, Path::from(ident.clone())),
                        attrs: Vec::new(),
                    }
                }
                _ => panic!("pattern must be identifier"),
            }
        }
        _ => panic!("argument must be captured"),
    }
}

enum Feature<'a> {
    Enable(&'a str),
    Disable(&'a str),
}

impl<'a> Feature<'a> {
    fn new(feature_str: &'a str) -> Self {
        if feature_str.starts_with("+") {
            Feature::Enable(&feature_str[1..])
        } else if feature_str.starts_with("-") {
            Feature::Disable(&feature_str[1..])
        } else {
            panic!("feature must begin with '+' or '-'");
        }
    }

    fn name(&self) -> &str {
        match *self {
            Feature::Enable(x) => x,
            Feature::Disable(x) => x,
        }
    }

    fn to_ident_string(&self) -> String {
        match *self {
            Feature::Enable(x) => "enable_".to_string() + x,
            Feature::Disable(x) => "disable_".to_string() + x,
        }
    }

    fn checker_expr(&self) -> Expr {
        let segments = ["rt", &("have_".to_string() + self.name())]
            .iter()
            .map(|x| PathSegment::from(*x))
            .collect();
        let path = Path {
            global: false,
            segments: segments,
        };
        let function = Expr {
            node: ExprKind::Path(Option::None, path),
            attrs: Vec::new(),
        };
        let call = Expr {
            node: ExprKind::Call(Box::new(function), Vec::new()),
            attrs: Vec::new(),
        };
        match *self {
            Feature::Enable(_) => call,
            Feature::Disable(_) => {
                Expr {
                    node: ExprKind::Unary(UnOp::Not, Box::new(call)),
                    attrs: Vec::new(),
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Matthew Fornaciari <mattforni@gmail.com>
//! A dead simple implementation of command line argument parsing and validation
//! built on top of the [getopts](https://crates.io/crates/getopts) crate.
//!
//! In order to use the `args` crate simply create an `Args` object and begin
//! registering possible command line options via the `flag(...)` and `option(...)`
//! methods. Once all options have been registered, parse arguments directly from the
//! command line, or provide a vector of your own arguments.
//!
//! Any errors encountered during parsing will be returned wrapped in an `ArgsError`.
//! If there are no errors during parsing values may be retrieved from the `args`
//! object by simply calling `value_of(...)` and `validated_value_of(...)`.
//!
//! That's it!
//!
//! # Usage
//!
//! This crate is [on crates.io](https://crates.io/crates/args) and can be
//! used by adding `args` to the dependencies in your project's `Cargo.toml`.
//!
//! ```toml
//! [dependencies]
//! args = "2.0"
//! ```
//!
//! and this to your crate root:
//!
//! ```rust
//! extern crate args;
//! ```
//!
//! # Example
//!
//! The following example shows simple command line parsing for an application that
//! requires a number of iterations between zero *(0)* and ten *(10)* to be specified,
//! accepts an optional log file name and responds to the help flag.
//!
//! ```rust
//! extern crate args;
//! extern crate getopts;
//!
//! use getopts::Occur;
//! use std::process::exit;
//!
//! use args::{Args,ArgsError};
//! use args::validations::{Order,OrderValidation};
//!
//! const PROGRAM_DESC: &'static str = "Run this program";
//! const PROGRAM_NAME: &'static str = "program";
//!
//! fn main() {
//!     match parse(&vec!("-i", "5")) {
//!         Ok(_) => println!("Successfully parsed args"),
//!         Err(error) => {
//!             println!("{}", error);
//!             exit(1);
//!         }
//!     };
//! }
//!
//! fn parse(input: &Vec<&str>) -> Result<(), ArgsError> {
//!     let mut args = Args::new(PROGRAM_NAME, PROGRAM_DESC);
//!     args.flag("h", "help", "Print the usage menu");
//!     args.option("i",
//!         "iter",
//!         "The number of times to run this program",
//!         "TIMES",
//!         Occur::Req,
//!         None);
//!     args.option("l",
//!         "log_file",
//!         "The name of the log file",
//!         "NAME",
//!         Occur::Optional,
//!         Some(String::from("output.log")));
//!
//!     try!(args.parse(input));
//!
//!     let help = try!(args.value_of("help"));
//!     if help {
//!         args.full_usage();
//!         return Ok(());
//!     }
//!
//!     let gt_0 = Box::new(OrderValidation::new(Order::GreaterThan, 0u32));
//!     let lt_10 = Box::new(OrderValidation::new(Order::LessThanOrEqual, 10u32));
//!
//!     let iters = try!(args.validated_value_of("iter", &[gt_0, lt_10]));
//!     for iter in 0..iters {
//!         println!("Working on iteration {}", iter);
//!     }
//!     println!("All done.");
//!
//!     Ok(())
//! }
//! ```
//!

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
    html_root_url = "https://doc.rust-lang.org/")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

#[macro_use] extern crate log;
extern crate getopts;

use getopts::{Fail,HasArg,Occur,Options};
use std::collections::BTreeMap;
use std::collections::btree_map::Iter;
use std::env;
use std::ffi::OsStr;
use std::fmt::{self,Display,Formatter};
use std::iter::IntoIterator;
use std::str::FromStr;

pub use self::errors::ArgsError;

use self::options::Opt;
use self::validations::Validation;

pub mod traits;
pub mod validations;

mod errors;
mod options;
#[cfg(test)] mod tst;

const COLUMN_WIDTH: usize = 20;
const SCOPE_PARSE: &'static str = "parse";
const SEPARATOR: &'static str = ",";

/// A dead simple implementation of command line argument parsing and validation.
pub struct Args {
    description: String,
    options: Options,
    opts: BTreeMap<String, Box<Opt>>,
    opt_names: Vec<String>,
    program_name: String,
    values: BTreeMap<String, String>
}

impl Args {
    // Public associated methods
    /// Creates an empty set of command line options.
    pub fn new(program_name: &str, description: &str) -> Args {
        debug!("Creating new args object for '{}'", program_name);

        Args {
            description: description.to_string(),
            options: Options::new(),
            opts: BTreeMap::new(),
            opt_names: Vec::new(),
            program_name: program_name.to_string(),
            values: BTreeMap::new()
        }
    }

    // Public instance methods
    /// Registers an optional flag argument that does not take an argument and defaults to false.
    ///
    /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none
    /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none
    /// * `desc` - A description of the flag for the usage message
    pub fn flag(&mut self,
            short_name: &str,
            long_name: &str,
            desc: &str) -> &mut Args {
        self.register_opt(
            options::new(short_name,
                long_name,
                desc,
                "",
                HasArg::No,
                Occur::Optional,
                None
            )
        );

        self
    }

    /// Generates a combination of the short and verbose usage messages.
    pub fn full_usage(&self) -> String {
        format!("{}\n\n{}", self.short_usage(), self.usage())
    }

    /// Returns a `bool` indicating whether or not any options are registered.
    pub fn has_options(&self) -> bool {
        !self.opts.is_empty()
    }

    /// Returns a `bool` indicating whether or not a argument is present.
    pub fn has_value(&self, opt_name: &str) -> bool {
        self.values.get(opt_name).is_some()
    }

    /// Returns an iterator visiting all key-value pairs in alphabetical order.
    pub fn iter(&self) -> Iter<String, String> {
        self.values.iter()
    }

    /// Registers an option explicitly.
    ///
    /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none
    /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none
    /// * `desc` - A description of the flag for the usage message
    /// * `hint` - A hint to be used in place of the argument in the usage message,
    /// e.g. `"FILE"` for a `-o FILE` option
    /// * `occur` - An enum representing whether the option is required or not
    /// * `default` - The default value for this option if there should be one
    pub fn option(&mut self,
            short_name: &str,
            long_name: &str,
            desc: &str,
            hint: &str,
            occur: Occur,
            default: Option<String>) -> &mut Args {
        self.register_opt(
            options::new(short_name,
                long_name,
                desc,
                hint,
                HasArg::Yes,
                occur,
                default
            )
        );

        self
    }

    /// Parses arguments according to the registered options.
    ///
    /// # Failures
    /// Fails if any errors are encountered during parsing.
    pub fn parse<C: IntoIterator>(&mut self, raw_args: C) -> Result<(), ArgsError> where C::Item: AsRef<OsStr> {
        debug!("Parsing args for '{}'", self.program_name);

        // Get matches and return an error if there is a problem parsing
        let matches = match self.options.parse(raw_args) {
            Ok(matches) => { matches },
            Err(error) => { return Err(ArgsError::new(SCOPE_PARSE, &error.to_string())) }
        };

        // Find matches and store the values (or a default)
        for opt_name in &self.opt_names {
            let option = self.opts.get(opt_name);
            if option.is_none() {
                return Err(ArgsError::new(SCOPE_PARSE, &Fail::UnrecognizedOption(opt_name.to_string()).to_string()));
            }

            let opt = option.unwrap();
            let value = opt.parse(&matches).unwrap_or("".to_string());
            if !value.is_empty() {
                self.values.insert(opt_name.to_string(), value);
            } else {
                if opt.is_required() {
                    return Err(ArgsError::new(SCOPE_PARSE, &Fail::ArgumentMissing(opt_name.to_string()).to_string()));
                }
            }
        }

        debug!("Args: {:?}", self.values);
        Ok(())
    }

    /// Parses arguments directly from the command line according to the registered options.
    ///
    /// # Failures
    /// Fails if any errors are encountered during parsing.
    pub fn parse_from_cli(&mut self) -> Result<(), ArgsError> {
        // Retrieve the cli args and throw out the program name
        let mut raw_args: Vec<String> = env::args().collect();
        if !raw_args.is_empty() { raw_args.remove(0); }

        self.parse(&mut raw_args)
    }

    /// Generates a one-line usage summary from the registered options.
    pub fn short_usage(&self) -> String {
        self.options.short_usage(&self.program_name)
    }

    /// Generates a verbose usage summary from the registered options.
    pub fn usage(&self) -> String {
        if !self.has_options() { return format!("{}\n", self.description); }
        self.options.usage(&self.description)
    }

    /// Retrieves the optional value of the `Opt` identified by `opt_name`, casts it to
    /// the type specified by `T` and wraps it in an optional.
    ///
    /// # Failures
    ///
    /// See `value_of`
    fn optional_value_of<T: FromStr>(&self, opt_name: &str) -> Result<Option<T>, ArgsError> {
        if self.has_value(opt_name) {
            Ok(Some(try!(self.value_of::<T>(opt_name))))
        } else {
            Ok(None)
        }
    }

    /// Retrieves the optional value of the `Opt` identified by `opt_name`, casts it to
    /// the type specified by `T`, runs all provided `Validation`s, and wraps it in an Option<T>.
    ///
    /// # Failures
    ///
    /// See `validated_value_of`
    fn validated_optional_value_of<T: FromStr>(&self, opt_name: &str, validations:
        &[Box<Validation<T=T>>]) -> Result<Option<T>, ArgsError> {
        if self.has_value(opt_name) {
            Ok(Some(try!(self.validated_value_of::<T>(opt_name, validations))))
        } else {
            Ok(None)
        }
    }

    /// Retrieves the value of the `Opt` identified by `opt_name`, casts it to
    /// the type specified by `T` and then runs all provided `Validation`s.
    ///
    /// # Failures
    ///
    /// Returns `Err(ArgsError)` if no `Opt` correspond to `opt_name`, if the value cannot
    /// be cast to type `T` or if any validation is considered invalid.
    pub fn validated_value_of<T: FromStr>(
            &self, opt_name: &str, validations: &[Box<Validation<T=T>>]) -> Result<T, ArgsError> {
        // If the value does not have an error, run validations
        self.value_of::<T>(opt_name).and_then(|value| {
            for validation in validations {
                // If any validations fail, break the loop and return the error
                if validation.is_invalid(&value) { return Err(validation.error(&value)); }
            }

            Ok(value)
        })
    }

    /// Retrieves the value for the `Opt` identified by `opt_name` and casts it to
    /// the type specified by `T`.
    ///
    /// # Failures
    ///
    /// Returns `Err(ArgsError)` if no `Opt` corresponds to `opt_name` or if the
    /// value cannot be cast to type `T`.
    pub fn value_of<T: FromStr>(&self, opt_name: &str) -> Result<T, ArgsError> {
        self.values.get(opt_name).ok_or(
            ArgsError::new(opt_name, "does not have a value")
        ).and_then(|value_string| {
            T::from_str(value_string).or(
                Err(ArgsError::new(opt_name, &format!("unable to parse '{}'", value_string)))
            )
        })
    }

    /// Retrieves a vector of values for the `Opt` identified by `opt_name` and
    /// casts each of them to the type specified by `T`.
    ///
    /// # Failures
    ///
    /// Returns `Err(ArgsError)` if no `Opt` corresponds to `opt_name` or if any
    /// of the values cannot be cast to type `T`.
    pub fn values_of<T: FromStr>(&self, opt_name: &str) -> Result<Vec<T>, ArgsError> {
        self.values.get(opt_name).ok_or(
            ArgsError::new(opt_name, "does not have a value")
        ).and_then(|values_str| {
            values_str.split(SEPARATOR).map(|value| {
                T::from_str(value).or(
                    Err(ArgsError::new(opt_name, &format!("unable to parse '{}'", value)))
                )
            }).collect()
        })
    }

    // Private instance methods
    fn register_opt(&mut self, opt: Box<Opt>) {
        if !self.opt_names.contains(&opt.name()) {
            debug!("Registering {}", opt);
            opt.register(&mut self.options);
            self.opt_names.push(opt.name().to_string());
            self.opts.insert(opt.name().to_string(), opt);
        } else {
            warn!("{} is already registered, ignoring", opt.name());
        }
    }
}

impl Display for Args {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let mut display = String::new();
        display.push_str(&format!("{}\n{}",
            to_column("Args"), column_underline()));
        for (key, value) in self.values.clone() {
            display.push_str(&format!("\n{}\t{}",
                to_column(&key), to_column(&value)));
        }
        write!(f, "{}", display)
    }
}

// Private associated methods
fn column_underline() -> String {
    let mut underline = String::new();
    for _ in 0..COLUMN_WIDTH { underline.push_str("="); }
    underline
}

fn to_column(string: &str) -> String {
    let mut string = string.to_string();
    string = if string.len() > COLUMN_WIDTH {
        string.truncate(COLUMN_WIDTH- 3);
        format!("{}...", string)
    } else { string };
    let mut spaces = String::new();
    for _ in 0..(COLUMN_WIDTH - string.len()) { spaces.push_str(" "); }
    format!("{}{}", string, spaces)
}

<commit_msg>made `optional_validated` and `optional_value` public<commit_after>// Copyright 2016 Matthew Fornaciari <mattforni@gmail.com>
//! A dead simple implementation of command line argument parsing and validation
//! built on top of the [getopts](https://crates.io/crates/getopts) crate.
//!
//! In order to use the `args` crate simply create an `Args` object and begin
//! registering possible command line options via the `flag(...)` and `option(...)`
//! methods. Once all options have been registered, parse arguments directly from the
//! command line, or provide a vector of your own arguments.
//!
//! Any errors encountered during parsing will be returned wrapped in an `ArgsError`.
//! If there are no errors during parsing values may be retrieved from the `args`
//! object by simply calling `value_of(...)` and `validated_value_of(...)`.
//!
//! That's it!
//!
//! # Usage
//!
//! This crate is [on crates.io](https://crates.io/crates/args) and can be
//! used by adding `args` to the dependencies in your project's `Cargo.toml`.
//!
//! ```toml
//! [dependencies]
//! args = "2.0"
//! ```
//!
//! and this to your crate root:
//!
//! ```rust
//! extern crate args;
//! ```
//!
//! # Example
//!
//! The following example shows simple command line parsing for an application that
//! requires a number of iterations between zero *(0)* and ten *(10)* to be specified,
//! accepts an optional log file name and responds to the help flag.
//!
//! ```rust
//! extern crate args;
//! extern crate getopts;
//!
//! use getopts::Occur;
//! use std::process::exit;
//!
//! use args::{Args,ArgsError};
//! use args::validations::{Order,OrderValidation};
//!
//! const PROGRAM_DESC: &'static str = "Run this program";
//! const PROGRAM_NAME: &'static str = "program";
//!
//! fn main() {
//!     match parse(&vec!("-i", "5")) {
//!         Ok(_) => println!("Successfully parsed args"),
//!         Err(error) => {
//!             println!("{}", error);
//!             exit(1);
//!         }
//!     };
//! }
//!
//! fn parse(input: &Vec<&str>) -> Result<(), ArgsError> {
//!     let mut args = Args::new(PROGRAM_NAME, PROGRAM_DESC);
//!     args.flag("h", "help", "Print the usage menu");
//!     args.option("i",
//!         "iter",
//!         "The number of times to run this program",
//!         "TIMES",
//!         Occur::Req,
//!         None);
//!     args.option("l",
//!         "log_file",
//!         "The name of the log file",
//!         "NAME",
//!         Occur::Optional,
//!         Some(String::from("output.log")));
//!
//!     try!(args.parse(input));
//!
//!     let help = try!(args.value_of("help"));
//!     if help {
//!         args.full_usage();
//!         return Ok(());
//!     }
//!
//!     let gt_0 = Box::new(OrderValidation::new(Order::GreaterThan, 0u32));
//!     let lt_10 = Box::new(OrderValidation::new(Order::LessThanOrEqual, 10u32));
//!
//!     let iters = try!(args.validated_value_of("iter", &[gt_0, lt_10]));
//!     for iter in 0..iters {
//!         println!("Working on iteration {}", iter);
//!     }
//!     println!("All done.");
//!
//!     Ok(())
//! }
//! ```
//!

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
    html_root_url = "https://doc.rust-lang.org/")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

#[macro_use] extern crate log;
extern crate getopts;

use getopts::{Fail,HasArg,Occur,Options};
use std::collections::BTreeMap;
use std::collections::btree_map::Iter;
use std::env;
use std::ffi::OsStr;
use std::fmt::{self,Display,Formatter};
use std::iter::IntoIterator;
use std::str::FromStr;

pub use self::errors::ArgsError;

use self::options::Opt;
use self::validations::Validation;

pub mod traits;
pub mod validations;

mod errors;
mod options;
#[cfg(test)] mod tst;

const COLUMN_WIDTH: usize = 20;
const SCOPE_PARSE: &'static str = "parse";
const SEPARATOR: &'static str = ",";

/// A dead simple implementation of command line argument parsing and validation.
pub struct Args {
    description: String,
    options: Options,
    opts: BTreeMap<String, Box<Opt>>,
    opt_names: Vec<String>,
    program_name: String,
    values: BTreeMap<String, String>
}

impl Args {
    // Public associated methods
    /// Creates an empty set of command line options.
    pub fn new(program_name: &str, description: &str) -> Args {
        debug!("Creating new args object for '{}'", program_name);

        Args {
            description: description.to_string(),
            options: Options::new(),
            opts: BTreeMap::new(),
            opt_names: Vec::new(),
            program_name: program_name.to_string(),
            values: BTreeMap::new()
        }
    }

    // Public instance methods
    /// Registers an optional flag argument that does not take an argument and defaults to false.
    ///
    /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none
    /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none
    /// * `desc` - A description of the flag for the usage message
    pub fn flag(&mut self,
            short_name: &str,
            long_name: &str,
            desc: &str) -> &mut Args {
        self.register_opt(
            options::new(short_name,
                long_name,
                desc,
                "",
                HasArg::No,
                Occur::Optional,
                None
            )
        );

        self
    }

    /// Generates a combination of the short and verbose usage messages.
    pub fn full_usage(&self) -> String {
        format!("{}\n\n{}", self.short_usage(), self.usage())
    }

    /// Returns a `bool` indicating whether or not any options are registered.
    pub fn has_options(&self) -> bool {
        !self.opts.is_empty()
    }

    /// Returns a `bool` indicating whether or not a argument is present.
    pub fn has_value(&self, opt_name: &str) -> bool {
        self.values.get(opt_name).is_some()
    }

    /// Returns an iterator visiting all key-value pairs in alphabetical order.
    pub fn iter(&self) -> Iter<String, String> {
        self.values.iter()
    }

    /// Registers an option explicitly.
    ///
    /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none
    /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none
    /// * `desc` - A description of the flag for the usage message
    /// * `hint` - A hint to be used in place of the argument in the usage message,
    /// e.g. `"FILE"` for a `-o FILE` option
    /// * `occur` - An enum representing whether the option is required or not
    /// * `default` - The default value for this option if there should be one
    pub fn option(&mut self,
            short_name: &str,
            long_name: &str,
            desc: &str,
            hint: &str,
            occur: Occur,
            default: Option<String>) -> &mut Args {
        self.register_opt(
            options::new(short_name,
                long_name,
                desc,
                hint,
                HasArg::Yes,
                occur,
                default
            )
        );

        self
    }

    /// Parses arguments according to the registered options.
    ///
    /// # Failures
    /// Fails if any errors are encountered during parsing.
    pub fn parse<C: IntoIterator>(&mut self, raw_args: C) -> Result<(), ArgsError> where C::Item: AsRef<OsStr> {
        debug!("Parsing args for '{}'", self.program_name);

        // Get matches and return an error if there is a problem parsing
        let matches = match self.options.parse(raw_args) {
            Ok(matches) => { matches },
            Err(error) => { return Err(ArgsError::new(SCOPE_PARSE, &error.to_string())) }
        };

        // Find matches and store the values (or a default)
        for opt_name in &self.opt_names {
            let option = self.opts.get(opt_name);
            if option.is_none() {
                return Err(ArgsError::new(SCOPE_PARSE, &Fail::UnrecognizedOption(opt_name.to_string()).to_string()));
            }

            let opt = option.unwrap();
            let value = opt.parse(&matches).unwrap_or("".to_string());
            if !value.is_empty() {
                self.values.insert(opt_name.to_string(), value);
            } else {
                if opt.is_required() {
                    return Err(ArgsError::new(SCOPE_PARSE, &Fail::ArgumentMissing(opt_name.to_string()).to_string()));
                }
            }
        }

        debug!("Args: {:?}", self.values);
        Ok(())
    }

    /// Parses arguments directly from the command line according to the registered options.
    ///
    /// # Failures
    /// Fails if any errors are encountered during parsing.
    pub fn parse_from_cli(&mut self) -> Result<(), ArgsError> {
        // Retrieve the cli args and throw out the program name
        let mut raw_args: Vec<String> = env::args().collect();
        if !raw_args.is_empty() { raw_args.remove(0); }

        self.parse(&mut raw_args)
    }

    /// Generates a one-line usage summary from the registered options.
    pub fn short_usage(&self) -> String {
        self.options.short_usage(&self.program_name)
    }

    /// Generates a verbose usage summary from the registered options.
    pub fn usage(&self) -> String {
        if !self.has_options() { return format!("{}\n", self.description); }
        self.options.usage(&self.description)
    }

    /// Retrieves the optional value of the `Opt` identified by `opt_name`, casts it to
    /// the type specified by `T`, runs all provided `Validation`s, and wraps it in an Option<T>.
    ///
    /// # Failures
    ///
    /// See `validated_value_of`
    pub fn optional_validated_value_of<T>(&self, opt_name: &str, validations: &[Box<Validation<T=T>>])
                                          -> Result<Option<T>, ArgsError> where T: FromStr {
        if self.has_value(opt_name) {
            Ok(Some(try!(self.validated_value_of::<T>(opt_name, validations))))
        } else {
            Ok(None)
        }
    }

    /// Retrieves the optional value of the `Opt` identified by `opt_name`, casts it to
    /// the type specified by `T` and wraps it in an optional.
    ///
    /// # Failures
    ///
    /// See `value_of`
    pub fn optional_value_of<T: FromStr>(&self, opt_name: &str) -> Result<Option<T>, ArgsError> {
        if self.has_value(opt_name) {
            Ok(Some(try!(self.value_of::<T>(opt_name))))
        } else {
            Ok(None)
        }
    }

    /// Retrieves the value of the `Opt` identified by `opt_name`, casts it to
    /// the type specified by `T` and then runs all provided `Validation`s.
    ///
    /// # Failures
    ///
    /// Returns `Err(ArgsError)` if no `Opt` correspond to `opt_name`, if the value cannot
    /// be cast to type `T` or if any validation is considered invalid.
    pub fn validated_value_of<T>(&self, opt_name: &str, validations: &[Box<Validation<T=T>>])
        -> Result<T, ArgsError> where T: FromStr {
        // If the value does not have an error, run validations
        self.value_of::<T>(opt_name).and_then(|value| {
            for validation in validations {
                // If any validations fail, break the loop and return the error
                if validation.is_invalid(&value) { return Err(validation.error(&value)); }
            }

            Ok(value)
        })
    }

    /// Retrieves the value for the `Opt` identified by `opt_name` and casts it to
    /// the type specified by `T`.
    ///
    /// # Failures
    ///
    /// Returns `Err(ArgsError)` if no `Opt` corresponds to `opt_name` or if the
    /// value cannot be cast to type `T`.
    pub fn value_of<T: FromStr>(&self, opt_name: &str) -> Result<T, ArgsError> {
        self.values.get(opt_name).ok_or(
            ArgsError::new(opt_name, "does not have a value")
        ).and_then(|value_string| {
            T::from_str(value_string).or(
                Err(ArgsError::new(opt_name, &format!("unable to parse '{}'", value_string)))
            )
        })
    }

    /// Retrieves a vector of values for the `Opt` identified by `opt_name` and
    /// casts each of them to the type specified by `T`.
    ///
    /// # Failures
    ///
    /// Returns `Err(ArgsError)` if no `Opt` corresponds to `opt_name` or if any
    /// of the values cannot be cast to type `T`.
    pub fn values_of<T: FromStr>(&self, opt_name: &str) -> Result<Vec<T>, ArgsError> {
        self.values.get(opt_name).ok_or(
            ArgsError::new(opt_name, "does not have a value")
        ).and_then(|values_str| {
            values_str.split(SEPARATOR).map(|value| {
                T::from_str(value).or(
                    Err(ArgsError::new(opt_name, &format!("unable to parse '{}'", value)))
                )
            }).collect()
        })
    }

    // Private instance methods
    fn register_opt(&mut self, opt: Box<Opt>) {
        if !self.opt_names.contains(&opt.name()) {
            debug!("Registering {}", opt);
            opt.register(&mut self.options);
            self.opt_names.push(opt.name().to_string());
            self.opts.insert(opt.name().to_string(), opt);
        } else {
            warn!("{} is already registered, ignoring", opt.name());
        }
    }
}

impl Display for Args {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let mut display = String::new();
        display.push_str(&format!("{}\n{}",
            to_column("Args"), column_underline()));
        for (key, value) in self.values.clone() {
            display.push_str(&format!("\n{}\t{}",
                to_column(&key), to_column(&value)));
        }
        write!(f, "{}", display)
    }
}

// Private associated methods
fn column_underline() -> String {
    let mut underline = String::new();
    for _ in 0..COLUMN_WIDTH { underline.push_str("="); }
    underline
}

fn to_column(string: &str) -> String {
    let mut string = string.to_string();
    string = if string.len() > COLUMN_WIDTH {
        string.truncate(COLUMN_WIDTH- 3);
        format!("{}...", string)
    } else { string };
    let mut spaces = String::new();
    for _ in 0..(COLUMN_WIDTH - string.len()) { spaces.push_str(" "); }
    format!("{}{}", string, spaces)
}

<|endoftext|>


<commit_before>extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;

#[proc_macro_derive(OptionalStruct)]
pub fn optional_struct(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_derive_input(&s).unwrap();
    let gen = create_optional_struct(&ast);
    gen.parse().unwrap()
}

fn create_optional_struct(ast: &syn::DeriveInput) -> quote::Tokens {
    let name = &ast.ident;

    if let syn::Body::Struct(ref variant_data) = ast.body {
        if let &syn::VariantData::Struct(ref fields) = variant_data {

            let mut attributes = quote!{};
            let mut assigners = quote!{};
            for field in fields {
                let ref type_name = &field.ty;
                let ref field_name = &field.ident.clone().unwrap();
                let next_attribute = quote! { pub Option<#type_name> #field_name, };
                attributes = quote!{ #attributes #next_attribute };
                let next_assigner = quote!{
                    if let Some(attribute) = optional_struct.#field_name {
                        self.#field_name = attribute;
                    }
                };
                assigners = quote!{ #assigners #next_assigner };

                return quote!{
                    struct Optional#name {
                        #attributes
                    }

                    impl #name {
                        pub fn apply_options(&mut self, optional_struct: &Optional#name) {
                            #assigners
                        }
                    }
                };
            }
        }
    }

    panic!("OptionalStruct only supports non-tuple structs for now");
}

#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
<commit_msg>fixed output's struc name<commit_after>extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use quote::Ident;

#[proc_macro_derive(OptionalStruct)]
pub fn optional_struct(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_derive_input(&s).unwrap();
    let gen = create_optional_struct(&ast);
    gen.parse().unwrap()
}

fn create_optional_struct(ast: &syn::DeriveInput) -> quote::Tokens {
    if let syn::Body::Struct(ref variant_data) = ast.body {
        if let &syn::VariantData::Struct(ref fields) = variant_data {
            let struct_name = &ast.ident;
            let struct_name_string = quote!{#struct_name}.to_string();
            let mut optional_struct_name = String::from("Optional");
            optional_struct_name.push_str(&struct_name_string);
            let optional_struct_name = Ident::new(optional_struct_name);

            let mut attributes = quote!{};
            let mut assigners = quote!{};
            for field in fields {
                let ref type_name = &field.ty;
                let ref field_name = &field.ident.clone().unwrap();
                let next_attribute = quote! { pub #field_name: Option<#type_name>, };
                attributes = quote!{ #attributes #next_attribute };
                let next_assigner = quote!{
                    if let Some(attribute) = optional_struct.#field_name {
                        self.#field_name = attribute;
                    }
                };
                assigners = quote!{ #assigners #next_assigner };

                return
                       quote!{
                    pub struct #optional_struct_name {
                        #attributes
                    }

                    impl #struct_name {
                        pub fn apply_options(&mut self, optional_struct: &#optional_struct_name) {
                            #assigners
                        }
                    }
                };
            }
        }
    }

    panic!("OptionalStruct only supports non-tuple structs for now");
}

#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
<|endoftext|>


<commit_before>//! Iterator-based `linspace` and `logspace` functions

#![deny(missing_docs, warnings)]
#![feature(macro_rules, phase)]

#[cfg(test)]
extern crate quickcheck;
#[cfg(test)]
#[phase(plugin)]
extern crate quickcheck_macros;

use std::num::{Float, mod};

#[cfg(test)]
mod test;

/// Iterator that yields equally spaced numbers in the linear scale
#[deriving(Copy)]
pub struct Linspace<T: Float> {
    start: T,
    state: uint,
    step: T,
    stop: uint,
}

impl<T> DoubleEndedIterator<T> for Linspace<T> where T: Float {
    fn next_back(&mut self) -> Option<T> {
        if self.state == self.stop {
            None
        } else {
            self.stop -= 1;
            Some(self.start + self.step * num::cast(self.stop).unwrap())
        }
    }
}

impl<T> Iterator<T> for Linspace<T> where T: Float {
    fn next(&mut self) -> Option<T> {
        if self.state == self.stop {
            None
        } else {
            let next = self.start + self.step * num::cast(self.state).unwrap();
            self.state += 1;
            Some(next)
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        let exact = self.stop - self.state;
        (exact, Some(exact))
    }
}

/// Iterator that yields equally spaced numbers in the logarithmic scale
#[deriving(Copy)]
pub struct Logspace<T: Float> {
    start: T,
    state: uint,
    step: T,
    stop: uint,
}

impl<T> DoubleEndedIterator<T> for Logspace<T> where T: Float {
    fn next_back(&mut self) -> Option<T> {
        if self.state == self.stop {
            None
        } else {
            self.stop -= 1;
            Some((self.start + self.step * num::cast(self.stop).unwrap()).exp())
        }
    }
}

impl<T> Iterator<T> for Logspace<T> where T: Float {
    fn next(&mut self) -> Option<T> {
        if self.state == self.stop {
            None
        } else {
            let next = self.start + self.step * num::cast(self.state).unwrap();
            self.state += 1;
            Some(next.exp())
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        let exact = self.stop - self.state;
        (exact, Some(exact))
    }
}

/// Returns an iterator that yields `n` evenly spaced numbers over the `[start, end]` interval
///
/// # Panics
///
/// Panics if `end` < `start`
///
/// # Examples
///
/// **Note** These assertions will likely fail because of rounding errors. (In real applications
/// you shouldn't directly use equality between floats, but instead check that the absolute
/// difference is within some tolerance)
///
/// ``` ignore
/// assert_eq!(vec![2., 2.25, 2.5, 2.75, 3.], linspace(2., 3., 5).collect())
/// assert_eq!(vec![3., 2.75, 2.5, 2.25, 2.], linspace(2., 3., 5).rev().collect())
/// ```
pub fn linspace<T>(start: T, end: T, n: uint) -> Linspace<T> where T: Float {
    assert!(start <= end);

    let step = if n < 2 {
        // NB The value of `step` doesn't matter in these cases
        Float::zero()
    } else {
        (end - start) / num::cast(n - 1).unwrap()
    };

    Linspace {
        start: start,
        state: 0,
        step: step,
        stop: n,
    }
}

/// Logarithmic version of `linspace`
///
/// # Panics
///
/// Panics if `start` or `end` is a non-positive number, or if `end` < `start`
///
/// # Examples
///
/// **Note** These assertions will likely fail because of rounding errors. (In real applications
/// you shouldn't directly use equality between floats, but instead check that the absolute
/// difference is within some tolerance)
///
/// ``` ignore
/// assert_eq!(vec![0.1, 1., 10., 100.], logspace(0.1, 100., 4).collect())
/// assert_eq!(vec![100., 10., 1., 0.1], logspace(0.1, 100., 4).rev().collect())
/// ```
pub fn logspace<T>(start: T, end: T, n: uint) -> Logspace<T> where T: Float {
    assert!(start > Float::zero() && end > Float::zero() && start <= end);

    let (start, end) = (start.ln(), end.ln());

    let step = if n < 2 {
        // NB The value of `step` doesn't matter in these cases
        Float::zero()
    } else {
        (end - start) / num::cast(n - 1).unwrap()
    };

    Logspace {
        start: start,
        state: 0,
        step: step,
        stop: n,
    }
}
<commit_msg>fix(lib): update to rust nightly<commit_after>//! Iterator-based `linspace` and `logspace` functions

#![deny(missing_docs, warnings)]
#![feature(associated_types, macro_rules, phase)]

#[cfg(test)]
extern crate quickcheck;
#[cfg(test)]
#[phase(plugin)]
extern crate quickcheck_macros;

use std::num::{Float, self};

#[cfg(test)]
mod test;

/// Iterator that yields equally spaced numbers in the linear scale
#[derive(Copy)]
pub struct Linspace<T: Float> {
    start: T,
    state: uint,
    step: T,
    stop: uint,
}

impl<T> DoubleEndedIterator for Linspace<T> where T: Float {
    fn next_back(&mut self) -> Option<T> {
        if self.state == self.stop {
            None
        } else {
            self.stop -= 1;
            Some(self.start + self.step * num::cast(self.stop).unwrap())
        }
    }
}

impl<T> Iterator for Linspace<T> where T: Float {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        if self.state == self.stop {
            None
        } else {
            let next = self.start + self.step * num::cast(self.state).unwrap();
            self.state += 1;
            Some(next)
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        let exact = self.stop - self.state;
        (exact, Some(exact))
    }
}

/// Iterator that yields equally spaced numbers in the logarithmic scale
#[derive(Copy)]
pub struct Logspace<T: Float> {
    start: T,
    state: uint,
    step: T,
    stop: uint,
}

impl<T> DoubleEndedIterator for Logspace<T> where T: Float {
    fn next_back(&mut self) -> Option<T> {
        if self.state == self.stop {
            None
        } else {
            self.stop -= 1;
            Some((self.start + self.step * num::cast(self.stop).unwrap()).exp())
        }
    }
}

impl<T> Iterator for Logspace<T> where T: Float {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        if self.state == self.stop {
            None
        } else {
            let next = self.start + self.step * num::cast(self.state).unwrap();
            self.state += 1;
            Some(next.exp())
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        let exact = self.stop - self.state;
        (exact, Some(exact))
    }
}

/// Returns an iterator that yields `n` evenly spaced numbers over the `[start, end]` interval
///
/// # Panics
///
/// Panics if `end` < `start`
///
/// # Examples
///
/// **Note** These assertions will likely fail because of rounding errors. (In real applications
/// you shouldn't directly use equality between floats, but instead check that the absolute
/// difference is within some tolerance)
///
/// ``` ignore
/// assert_eq!(vec![2., 2.25, 2.5, 2.75, 3.], linspace(2., 3., 5).collect())
/// assert_eq!(vec![3., 2.75, 2.5, 2.25, 2.], linspace(2., 3., 5).rev().collect())
/// ```
pub fn linspace<T>(start: T, end: T, n: uint) -> Linspace<T> where T: Float {
    assert!(start <= end);

    let step = if n < 2 {
        // NB The value of `step` doesn't matter in these cases
        Float::zero()
    } else {
        (end - start) / num::cast(n - 1).unwrap()
    };

    Linspace {
        start: start,
        state: 0,
        step: step,
        stop: n,
    }
}

/// Logarithmic version of `linspace`
///
/// # Panics
///
/// Panics if `start` or `end` is a non-positive number, or if `end` < `start`
///
/// # Examples
///
/// **Note** These assertions will likely fail because of rounding errors. (In real applications
/// you shouldn't directly use equality between floats, but instead check that the absolute
/// difference is within some tolerance)
///
/// ``` ignore
/// assert_eq!(vec![0.1, 1., 10., 100.], logspace(0.1, 100., 4).collect())
/// assert_eq!(vec![100., 10., 1., 0.1], logspace(0.1, 100., 4).rev().collect())
/// ```
pub fn logspace<T>(start: T, end: T, n: uint) -> Logspace<T> where T: Float {
    assert!(start > Float::zero() && end > Float::zero() && start <= end);

    let (start, end) = (start.ln(), end.ln());

    let step = if n < 2 {
        // NB The value of `step` doesn't matter in these cases
        Float::zero()
    } else {
        (end - start) / num::cast(n - 1).unwrap()
    };

    Logspace {
        start: start,
        state: 0,
        step: step,
        stop: n,
    }
}
<|endoftext|>