<commit_before>//! This sub module contains extra structs used as widget properties.

use std::{collections::HashSet, fmt::Debug, path::PathBuf};

use dces::prelude::{Component, ComponentStore, Entity};

pub use self::layout::*;
pub use self::widget::*;
use crate::{into_property_source, render, theming, utils};

mod layout;
mod widget;

/// Get the property of a widget.
pub fn get_property<T>(key: &str, entity: Entity, store: &ComponentStore) -> T
where
    T: Clone + Component,
{
    store.get::<T>(key, entity).map(|r| r.clone()).unwrap()
}

/// Handles the key of a given entity.
/// It returns its property, if it does exits. If not, it returns the value of the key.
pub fn get_property_or_value<T>(key: &str, entity: Entity, store: &ComponentStore, value: T) -> T
where
    T: Clone + Component,
{
    if let Ok(property) = store.get::<T>(key, entity).map(|r| r.clone()) {
        return property;
    }
    value
}

/// Used to build or share a property.
#[derive(PartialEq, Debug)]
pub enum PropertySource
 {
    Source(Entity),
    KeySource(String, Entity),
    Value(P),
}

impl
 From<Entity> for PropertySource
 {
    fn from(entity: Entity) -> Self {
        PropertySource::Source(entity)
    }
}

/// Used to convert components / properties into a PropertySource object.
pub trait IntoPropertySource
 {
    fn into_source(self) -> PropertySource
;
}

/// Used ot generate attached properties.
pub struct AttachedProperty

where
    P: Component + Debug,
{
    pub key: String,
    pub property_source: PropertySource
,
}

impl
 AttachedProperty

where
    P: Component + Debug,
{
    /// Create a new attached property.
    pub fn new(key: impl Into<String>, property_source: impl IntoPropertySource
) -> Self {
        AttachedProperty {
            key: key.into(),
            property_source: property_source.into_source(),
        }
    }
}

// Implementation of PropertySource for default types
into_property_source!(bool);
into_property_source!(char);
into_property_source!(String: &str, utils::Value);
into_property_source!(usize);
into_property_source!(u32);
into_property_source!(f32: utils::Value);
into_property_source!(f64: i32, f32, utils::Value);
into_property_source!(i32);
into_property_source!(i64);

into_property_source!(PathBuf);

// Implementation of PropertySource for utils types
into_property_source!(utils::Alignment: &str);
into_property_source!(utils::Brush: &str, utils::Color, utils::Value);
into_property_source!(utils::Orientation: &str);
into_property_source!(utils::Point: f64, i32, (i32, i32), (f64, f64));
into_property_source!(utils::Size: f64, i32, (i32, i32), (f64, f64));
into_property_source!(
    utils::Rectangle: (i32, i32, i32, i32),
    (f64, f64, f64, f64),
    (utils::Point, utils::Size)
);
into_property_source!(
    utils::Thickness: i32,
    f64,
    (i32, i32),
    (f64, f64),
    (i32, i32, i32, i32),
    (f64, f64, f64, f64),
    utils::Value
);
into_property_source!(utils::SelectionMode: &str);
into_property_source!(utils::Visibility: &str);
into_property_source!(Vec<String>);
into_property_source!(utils::Filter: &str, String, Vec<String>, Vec<&str>);

// Implementation of css types
into_property_source!(theming::Selector: &str, String);
into_property_source!(theming::Theme);

// Implementation of render property types
into_property_source!(render::Image: &str, String, (u32, u32, Vec<u32>));

// Implementation of custom property types
into_property_source!(Blocks: BlocksBuilder, &str, String);
into_property_source!(utils::Constraint: utils::ConstraintBuilder);
into_property_source!(DefaultRenderPipeline);
into_property_source!(ScrollViewerMode: (&str, &str));
into_property_source!(SelectedEntities: HashSet<Entity>);
into_property_source!(SelectedIndices: HashSet<usize>);
into_property_source!(TextSelection: (usize, usize));
into_property_source!(FocusState);
into_property_source!(KeyboardState);
<commit_msg>orbtk_core: update module `properties`<commit_after>//! This sub module contains extra structs used as widget properties.

use std::{collections::HashSet, fmt::Debug, path::PathBuf};

use dces::prelude::{Component, ComponentStore, Entity};

pub use self::layout::*;
pub use self::widget::*;
use crate::{into_property_source, render, theming, utils};

mod layout;
mod widget;

/// Get the property of a widget.
pub fn get_property<T>(key: &str, entity: Entity, store: &ComponentStore) -> T
where
    T: Clone + Component,
{
    store.get::<T>(key, entity).map(|r| r.clone()).unwrap()
}

/// Handles the key of a given entity.
/// It returns its property, if it does exits. If not, it returns the value of the key.
pub fn get_property_or_value<T>(key: &str, entity: Entity, store: &ComponentStore, value: T) -> T
where
    T: Clone + Component,
{
    if let Ok(property) = store.get::<T>(key, entity).map(|r| r.clone()) {
        return property;
    }
    value
}

/// Used to build or share a property.
#[derive(Debug, PartialEq)]
pub enum PropertySource
 {
    Source(Entity),
    KeySource(String, Entity),
    Value(P),
}

impl
 From<Entity> for PropertySource
 {
    fn from(entity: Entity) -> Self {
        PropertySource::Source(entity)
    }
}

/// Used to convert components / properties into a PropertySource object.
pub trait IntoPropertySource
 {
    fn into_source(self) -> PropertySource
;
}

/// Used ot generate attached properties.
pub struct AttachedProperty

where
    P: Component + Debug,
{
    pub key: String,
    pub property_source: PropertySource
,
}

impl
 AttachedProperty

where
    P: Component + Debug,
{
    /// Create a new attached property.
    pub fn new(key: impl Into<String>, property_source: impl IntoPropertySource
) -> Self {
        AttachedProperty {
            key: key.into(),
            property_source: property_source.into_source(),
        }
    }
}

// Implementation of PropertySource for default types
into_property_source!(bool);
into_property_source!(char);
into_property_source!(String: &str, utils::Value);
into_property_source!(usize);
into_property_source!(u32);
into_property_source!(f32: utils::Value);
into_property_source!(f64: i32, f32, utils::Value);
into_property_source!(i32);
into_property_source!(i64);

into_property_source!(PathBuf);

// Implementation of PropertySource for utils types
into_property_source!(utils::Alignment: &str);
into_property_source!(utils::Brush: &str, utils::Color, utils::Value);
into_property_source!(utils::Constraint: utils::ConstraintBuilder);
into_property_source!(utils::Filter: &str, String, Vec<String>, Vec<&str>);
into_property_source!(utils::Orientation: &str);
into_property_source!(utils::Point: f64, i32, (i32, i32), (f64, f64));
into_property_source!(utils::SelectionMode: &str);
into_property_source!(utils::Size: f64, i32, (i32, i32), (f64, f64));
into_property_source!(
    utils::Rectangle: (i32, i32, i32, i32),
    (f64, f64, f64, f64),
    (utils::Point, utils::Size)
);
into_property_source!(
    utils::Thickness: i32,
    f64,
    (i32, i32),
    (f64, f64),
    (i32, i32, i32, i32),
    (f64, f64, f64, f64),
    utils::Value
);
into_property_source!(utils::Visibility: &str);
into_property_source!(Vec<String>);

// Implementation of css types
into_property_source!(theming::Selector: &str, String);
into_property_source!(theming::Theme);

// Implementation of render property types
into_property_source!(render::Image: &str, String, (u32, u32, Vec<u32>));

// Implementation of custom property types
into_property_source!(Blocks: BlocksBuilder, &str, String);
into_property_source!(DefaultRenderPipeline);
into_property_source!(FocusState);
into_property_source!(KeyboardState);
into_property_source!(ScrollViewerMode: (&str, &str));
into_property_source!(SelectedEntities: HashSet<Entity>);
into_property_source!(SelectedIndices: HashSet<usize>);
into_property_source!(TextSelection: (usize, usize));
<|endoftext|>


<commit_before>extern crate getopts;
use getopts::Options;
use std::env;
use std::fs::File;
use std::io;
use std::io::Read;

fn read_blend_file(inp: &str) -> io::Result<()> {
    // open file
    let file = try!(File::open(inp));
    // read 12 bytes from the Blender file
    let mut take = file.take(12u64);
    let mut header = String::new();
    try!(take.read_to_string(&mut header));
    println!("header = \"{}\"", header);
    // compare first 7 chars to "BLENDER"
    if header.len() >= 7 {
        let mut blender = header;
        blender.truncate(7); // first 7 chars
        if blender == "BLENDER" {
            println!("starts with \"BLENDER\" ...");
            // TODO: check version (next 5 chars in header)
            // TODO: check for 32-bit pointers vs. 64-bit pointers
        }
    } else {
        println!("WARNING: FILE is not a Blender file");
    }
    Ok(())
}

fn do_work(inp: &str, out: Option<String>) {
    println!("FILE = {}", inp);
    match out {
        Some(x) => println!("output file name: {}", x),
        None => println!("no output file name"),
    }
    read_blend_file(inp);
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} FILE [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optopt("o", "", "set output file name", "NAME");
    opts.optflag("h", "help", "print this help menu");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    let output = matches.opt_str("o");
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };
    do_work(&input, output);
}
<commit_msg>We need a byte representation and a copy of the header.<commit_after>extern crate getopts;
use getopts::Options;
use std::env;
use std::fs::File;
use std::io;
use std::io::Read;

fn read_blend_file(inp: &str) -> io::Result<()> {
    // open file
    let file = try!(File::open(inp));
    // read 12 bytes from the Blender file
    let mut take = file.take(12u64);
    let mut header = String::new();
    try!(take.read_to_string(&mut header));
    println!("header = \"{}\"", header);
    // compare first 7 chars to "BLENDER"
    if header.len() >= 7 {
        // create copy of header without moving value
        let mut blender = String::new();
        blender = blender + &header;
        blender.truncate(7); // first 7 chars
        if blender == "BLENDER" {
            println!("starts with \"BLENDER\" ...");
            // TODO: check version (next 5 chars in header)

            // switch to byte copy of String representation
            let bytes = header.into_bytes();
            // check 7th char of header
            println!("7th char of header = '{}'", bytes[7] as char);
            // TODO: check for 32-bit pointers vs. 64-bit pointers
        }
    } else {
        println!("WARNING: FILE is not a Blender file");
    }
    Ok(())
}

fn do_work(inp: &str, out: Option<String>) {
    println!("FILE = {}", inp);
    match out {
        Some(x) => println!("output file name: {}", x),
        None => println!("no output file name"),
    }
    read_blend_file(inp);
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} FILE [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optopt("o", "", "set output file name", "NAME");
    opts.optflag("h", "help", "print this help menu");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    let output = matches.opt_str("o");
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };
    do_work(&input, output);
}
<|endoftext|>


<commit_before>use core::mem;

use super::int::Int;

pub mod conv;
pub mod add;
pub mod pow;
pub mod sub;

/// Trait for some basic operations on floats
pub trait Float: Sized + Copy {
    /// A uint of the same with as the float
    type Int: Int;

    /// The bitwidth of the float type
    const BITS: u32;

    /// The bitwidth of the significand
    const SIGNIFICAND_BITS: u32;

    /// The bitwidth of the exponent
    const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1;

    /// The maximum value of the exponent
    const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1;

    /// The exponent bias value
    const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1;

    /// A mask for the sign bit
    const SIGN_MASK: Self::Int;

    /// A mask for the significand
    const SIGNIFICAND_MASK: Self::Int;

    // The implicit bit of the float format
    const IMPLICIT_BIT: Self::Int;

    /// A mask for the exponent
    const EXPONENT_MASK: Self::Int;

    /// Returns `self` transmuted to `Self::Int`
    fn repr(self) -> Self::Int;

    #[cfg(test)]
    /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
    /// represented in multiple different ways. This method returns `true` if two NaNs are
    /// compared.
    fn eq_repr(self, rhs: Self) -> bool;

    /// Returns a `Self::Int` transmuted back to `Self`
    fn from_repr(a: Self::Int) -> Self;

    /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position.
    fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self;

    /// Returns (normalized exponent, normalized significand)
    fn normalize(significand: Self::Int) -> (i32, Self::Int);
}

// FIXME: Some of this can be removed if RFC Issue #1424 is resolved
//        https://github.com/rust-lang/rfcs/issues/1424
impl Float for f32 {
    type Int = u32;
    const BITS: u32 = 32;
    const SIGNIFICAND_BITS: u32 = 23;

    const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1);
    const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1;
    const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS;
    const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK);

    fn repr(self) -> Self::Int {
        unsafe { mem::transmute(self) }
    }
    #[cfg(test)]
    fn eq_repr(self, rhs: Self) -> bool {
        if self.is_nan() && rhs.is_nan() {
            true
        } else {
            self.repr() == rhs.repr()
        }
    }
    fn from_repr(a: Self::Int) -> Self {
        unsafe { mem::transmute(a) }
    }
    fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self {
        Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) |
            ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) |
            (significand & Self::SIGNIFICAND_MASK))
    }
    fn normalize(significand: Self::Int) -> (i32, Self::Int) {
        let shift = significand.leading_zeros()
            .wrapping_sub((1u32 << Self::SIGNIFICAND_BITS).leading_zeros());
        (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int)
    }
}
impl Float for f64 {
    type Int = u64;
    const BITS: u32 = 64;
    const SIGNIFICAND_BITS: u32 = 52;

    const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1);
    const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1;
    const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS;
    const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK);

    fn repr(self) -> Self::Int {
        unsafe { mem::transmute(self) }
    }
    #[cfg(test)]
    fn eq_repr(self, rhs: Self) -> bool {
        if self.is_nan() && rhs.is_nan() {
            true
        } else {
            self.repr() == rhs.repr()
        }
    }
    fn from_repr(a: Self::Int) -> Self {
        unsafe { mem::transmute(a) }
    }
    fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self {
        Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) |
            ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) |
            (significand & Self::SIGNIFICAND_MASK))
    }
    fn normalize(significand: Self::Int) -> (i32, Self::Int) {
        let shift = significand.leading_zeros()
            .wrapping_sub((1u64 << Self::SIGNIFICAND_BITS).leading_zeros());
        (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int)
    }
}
<commit_msg>Introduce a float_impl! macro to avoid duplication<commit_after>use core::mem;

use super::int::Int;

pub mod conv;
pub mod add;
pub mod pow;
pub mod sub;

/// Trait for some basic operations on floats
pub trait Float: Sized + Copy {
    /// A uint of the same with as the float
    type Int: Int;

    /// The bitwidth of the float type
    const BITS: u32;

    /// The bitwidth of the significand
    const SIGNIFICAND_BITS: u32;

    /// The bitwidth of the exponent
    const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1;

    /// The maximum value of the exponent
    const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1;

    /// The exponent bias value
    const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1;

    /// A mask for the sign bit
    const SIGN_MASK: Self::Int;

    /// A mask for the significand
    const SIGNIFICAND_MASK: Self::Int;

    // The implicit bit of the float format
    const IMPLICIT_BIT: Self::Int;

    /// A mask for the exponent
    const EXPONENT_MASK: Self::Int;

    /// Returns `self` transmuted to `Self::Int`
    fn repr(self) -> Self::Int;

    #[cfg(test)]
    /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
    /// represented in multiple different ways. This method returns `true` if two NaNs are
    /// compared.
    fn eq_repr(self, rhs: Self) -> bool;

    /// Returns a `Self::Int` transmuted back to `Self`
    fn from_repr(a: Self::Int) -> Self;

    /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position.
    fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self;

    /// Returns (normalized exponent, normalized significand)
    fn normalize(significand: Self::Int) -> (i32, Self::Int);
}

// FIXME: Some of this can be removed if RFC Issue #1424 is resolved
//        https://github.com/rust-lang/rfcs/issues/1424
macro_rules! float_impl {
    ($ty:ident, $ity:ident, $bits:expr, $significand_bits:expr) => {
        impl Float for $ty {
            type Int = $ity;
            const BITS: u32 = $bits;
            const SIGNIFICAND_BITS: u32 = $significand_bits;

            const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1);
            const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1;
            const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS;
            const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK);

            fn repr(self) -> Self::Int {
                unsafe { mem::transmute(self) }
            }
            #[cfg(test)]
            fn eq_repr(self, rhs: Self) -> bool {
                if self.is_nan() && rhs.is_nan() {
                    true
                } else {
                    self.repr() == rhs.repr()
                }
            }
            fn from_repr(a: Self::Int) -> Self {
                unsafe { mem::transmute(a) }
            }
            fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self {
                Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) |
                    ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) |
                    (significand & Self::SIGNIFICAND_MASK))
            }
            fn normalize(significand: Self::Int) -> (i32, Self::Int) {
                let shift = significand.leading_zeros()
                    .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros());
                (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int)
            }
        }
    }
}

float_impl!(f32, u32, 32, 23);
float_impl!(f64, u64, 64, 52);
<|endoftext|>


<commit_before>extern crate libc;

use std::num::Int;
use std::ptr;
use std::mem;

use constants::LINE_SIZE;

#[repr(C)]
pub struct GCHeader {
    object_size: libc::size_t,
    variables: libc::size_t,
    reference_count: libc::size_t,
    spans_lines: bool,
    forwarded: bool,
    logged: bool,
    marked: bool,
    new: bool,
}

#[repr(C)]
pub struct GCObject {
    header: GCHeader,
    vmt_pointer: *mut u8,
}

impl GCObject {
    pub fn new(size: uint, variables: uint) -> GCObject {
        return GCObject {
            header: GCHeader {
                object_size: size as libc::size_t,
                variables: variables as libc::size_t,
                reference_count: 0,
                spans_lines: size > LINE_SIZE,
                forwarded: false,
                logged: false,
                marked: false,
                new: true,
            },
            vmt_pointer: ptr::null_mut(),
        }
    }

    pub fn object_size(&self) -> uint {
        return self.header.object_size as uint;
    }

    pub fn children(&mut self) -> Vec<*mut GCObject> {
        let base: *const *mut GCObject = unsafe{ mem::transmute(&self.vmt_pointer) };
        return range(1, self.header.variables + 1)
               .map(|i| unsafe{ *base.offset(i as int) })
               .collect();
    }

    pub fn decrement(&mut self) -> bool {
        self.header.reference_count = Int::saturating_sub(self.header.reference_count, 1);
        debug!("Decrement object {:p} to {}", self, self.header.reference_count);
        return self.header.reference_count == 0;
    }

    pub fn increment(&mut self) -> bool {
        self.header.reference_count += 1;
        debug!("Increment object {:p} to {} (new={})", self,
            self.header.reference_count, self.header.new);
        if self.header.new {
            self.header.new = false;
            return true;
        }
        return false;
    }

    pub fn set_logged(&mut self, new: bool) -> bool {
        debug!("Set object {:p} logged={}", self, new);
        let logged = self.header.logged;
        self.header.logged = new;
        return logged;
    }

    pub fn spans_lines(&self) -> bool {
        return self.header.spans_lines;
    }
}

<commit_msg>Implement GCObject.{is_marked(), set_marked()}<commit_after>extern crate libc;

use std::num::Int;
use std::ptr;
use std::mem;

use constants::LINE_SIZE;

#[repr(C)]
pub struct GCHeader {
    object_size: libc::size_t,
    variables: libc::size_t,
    reference_count: libc::size_t,
    spans_lines: bool,
    forwarded: bool,
    logged: bool,
    marked: bool,
    new: bool,
}

#[repr(C)]
pub struct GCObject {
    header: GCHeader,
    vmt_pointer: *mut u8,
}

impl GCObject {
    pub fn new(size: uint, variables: uint) -> GCObject {
        return GCObject {
            header: GCHeader {
                object_size: size as libc::size_t,
                variables: variables as libc::size_t,
                reference_count: 0,
                spans_lines: size > LINE_SIZE,
                forwarded: false,
                logged: false,
                marked: false,
                new: true,
            },
            vmt_pointer: ptr::null_mut(),
        }
    }

    pub fn object_size(&self) -> uint {
        return self.header.object_size as uint;
    }

    pub fn children(&mut self) -> Vec<*mut GCObject> {
        let base: *const *mut GCObject = unsafe{ mem::transmute(&self.vmt_pointer) };
        return range(1, self.header.variables + 1)
               .map(|i| unsafe{ *base.offset(i as int) })
               .collect();
    }

    pub fn decrement(&mut self) -> bool {
        self.header.reference_count = Int::saturating_sub(self.header.reference_count, 1);
        debug!("Decrement object {:p} to {}", self, self.header.reference_count);
        return self.header.reference_count == 0;
    }

    pub fn increment(&mut self) -> bool {
        self.header.reference_count += 1;
        debug!("Increment object {:p} to {} (new={})", self,
            self.header.reference_count, self.header.new);
        if self.header.new {
            self.header.new = false;
            return true;
        }
        return false;
    }

    pub fn set_logged(&mut self, new: bool) -> bool {
        debug!("Set object {:p} logged={}", self, new);
        let logged = self.header.logged;
        self.header.logged = new;
        return logged;
    }

    pub fn set_marked(&mut self, new: bool) -> bool {
        debug!("Set object {:p} marked={}", self, new);
        let marked = self.header.marked;
        self.header.marked = new;
        return marked;
    }

    pub fn is_marked(&self) -> bool {
        return self.header.marked;
    }

    pub fn spans_lines(&self) -> bool {
        return self.header.spans_lines;
    }
}

<|endoftext|>


<commit_before>// Copyright 2013 Luis de Bethencourt <luis@debethencourt.com>
// Copyright 2013 The Rust Project Developers
// http://rust-lang.org

// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
 * Gregorian Calendar module for the datetime library of the Rust programming
 * language
 *
 * Implements a hybrid calendar that supports both the Julian and Gregorian
 * calendar systems.
 *
 * http://en.wikipedia.org/wiki/Gregorian_calendar
 * http://en.wikipedia.org/wiki/Julian_calendar
 */

static YEARBASE: int = 1900;
static DAYSPERLYEAR: uint = 366;
static DAYSPERNYEAR: uint = 365;
static DAYSPERWEEK: uint = 7;
//static DAYSBEFOREMONTH: ~[~[uint]] = [
static DAYSBEFOREMONTH: [[uint, ..13], ..2] = [
    /* Normal years */
    [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365],
    /* Leap years */
    [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]
];

pub fn is_leap_year(year: uint) -> bool {
    (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))
}

pub fn year_size(year: uint) -> uint {
    if is_leap_year(year) { DAYSPERLYEAR } else { DAYSPERNYEAR }
}

pub struct GCalendar {
    /*
     * Calendar object with date and time.
     */
    sec: uint,         /* Seconds       [0-59]  */
    min: uint,         /* Minutes       [0-59]  */
    hour: uint,        /* Hours         [0-23]  */
    mday: uint,        /* Day           [0-30]  */
    month: uint,       /* Month         [0-11]  */
    year: uint,        /* Year - 1900           */
    wday: uint,        /* Day of week   [0-6]   */
    yday: uint         /* Days in year  [0-365] */
}

impl GCalendar {
    /**
    * Allocates a GCalendar object at epoch.
    */
    pub fn new_at_epoch() -> GCalendar {
        GCalendar {
            sec: 0,
            min: 0,
            hour: 0,
            mday: 0,
            month: 0,
            year: 0,
            wday: 0,
            yday: 0,
        }
    }

    /**
    * Allocates a GCalendar object at the given date and time.
    */
    pub fn new(sec: uint, min: uint, hour: uint, mday: uint, month: uint,
            year: uint, wday: uint, yday: uint) -> GCalendar {
        GCalendar {
            sec: sec,
            min: min,
            hour: hour,
            mday: mday,
            month: month,
            year: year,
            wday: wday,
            yday: yday,
        }
    }

    /**
    * Allocates a GCalendar object from the milliseconds elapsed since epoch.
    */
    pub fn new_from_epoch(since_epoch: uint) -> GCalendar {
        let epoch_year = 1970;
        let mut year = epoch_year;

        let millisecs_day = 86400000;

        let mut dayclock = since_epoch % millisecs_day;
        let mut dayno = since_epoch / millisecs_day;

        let hour = dayclock / 3600000;
        dayclock = dayclock - (hour * 3600000);
        let min = dayclock / 60000;
        dayclock = dayclock - (min * 60000);
        let sec = dayclock / 1000;
        let wday = (dayno + 4) % 7;

        while (dayno >= year_size(year)) {
            dayno -= year_size(year);
            year += 1;
        }
        let yday = dayno;

        let ip = DAYSBEFOREMONTH[if is_leap_year(year) {1} else {0}];
        let mut month = 11;
        while (dayno < ip[month]) {
            month -= 1;
        }
        dayno -= ip[month];

        GCalendar {
            sec: sec,
            min: min,
            hour: hour,
            mday: dayno + 1,
            month: month  + 1,
            year: year,
            wday: wday,
            yday: yday,
        }
    }

    pub fn get_sec(&self) -> uint {
        self.sec
    }

    pub fn get_min(&self) -> uint {
        self.min
    }

    pub fn get_hour(&self) -> uint {
        self.hour
    }

    pub fn get_day_of_month(&self) -> uint {
        self.mday
    }

    pub fn get_month(&self) -> uint {
        self.month
    }

    pub fn get_year(&self) -> uint {
        self.year
    }

    pub fn get_day_of_week(&self) -> uint {
        self.wday
    }

    pub fn get_day_of_year(&self) -> uint {
        self.yday
    }

    pub fn mktime(&self) -> uint {
        /* Convert a broken down time structure to a simple representation:
        * seconds since Epoch.
        */
        // FIXME: Optimize way to calculate intervening leap days
        let mut intervening_leap_days: uint = 0;
        let mut y: uint = self.year;
        while (y > 1970) {
            if is_leap_year(y) {intervening_leap_days += 1;}
            y -= 1;
        }

	let years = (self.year - 1970);
	let days = 365 * years + self.yday + intervening_leap_days;
	let hours = 24 * days + self.hour;
	let minutes = 60 * hours + self.min;
	let seconds = 60 * minutes + self.sec;

        seconds
    }

    pub fn iso_week_days (&self, yday: uint, wday: uint) -> int {
        /* The number of days from the first day of the first ISO week of this
        * year to the year day YDAY with week day WDAY.
        * ISO weeks start on Monday. The first ISO week has the year's first
        * Thursday.
        * YDAY may be as small as yday_minimum.
        */
        let yday: int = yday as int;
        let wday: int = wday as int;
        let iso_week_start_wday: int = 1; /* Monday */
        let iso_week1_wday: int = 4;      /* Thursday */
        let yday_minimum: int = 366;
        /* Add enough to the first operand of % to make it nonnegative. */
        let big_enough_multiple_of_7: int = (yday_minimum / 7 + 2) * 7;

        yday - (yday - wday + iso_week1_wday + big_enough_multiple_of_7) % 7
            + iso_week1_wday - iso_week_start_wday
     }

    pub fn iso_week (&self, ch: char) -> ~str {
        let mut year: uint = self.year;
        let mut days: int = self.iso_week_days (self.yday, self.wday);

        if (days < 0) {
            /* This ISO week belongs to the previous year. */
            year -= 1;
            days = self.iso_week_days (self.yday + (year_size(year)),
                                       self.wday);
        } else {
            let d: int = self.iso_week_days (self.yday - (year_size(year)),
                                             self.wday);
            if (0 <= d) {
                /* This ISO week belongs to the next year. */
                year += 1;
                days = d;
            }
        }

        match ch {
            'G' => format!("{}", year),
            'g' => format!("{:02u}", (year % 100 + 100) % 100),
            'V' => format!("{:02d}", days / 7 + 1),
            _ => ~""
        }
    }

    pub fn get_date(&self, ch: char) -> ~str {
        println(format!("here with {}", ch));
        let die = || format!("strftime: can't understand this format {} ", ch);
        match ch {
            'A' => match self.wday {
                0 => ~"Sunday",
                1 => ~"Monday",
                2 => ~"Tuesday",
                3 => ~"Wednesday",
                4 => ~"Thursday",
                5 => ~"Friday",
                6 => ~"Saturday",
                _ => die()
            },
            'a' => match self.wday {
                0 => ~"Sun",
                1 => ~"Mon",
                2 => ~"Tue",
                3 => ~"Wed",
                4 => ~"Thu",
                5 => ~"Fri",
                6 => ~"Sat",
                _ => die()
            },
            'B' => match self.month {
                1 => ~"January",
                2 => ~"February",
                3 => ~"March",
                4 => ~"April",
                5 => ~"May",
                6 => ~"June",
                7 => ~"July",
                8 => ~"August",
                9 => ~"September",
                10 => ~"October",
                11 => ~"November",
                12 => ~"December",
                _ => die()
            },
            'b' | 'h' => match self.month {
                1 => ~"Jan",
                2 => ~"Feb",
                3 => ~"Mar",
                4 => ~"Apr",
                5 => ~"May",
                6 => ~"Jun",
                7 => ~"Jul",
                8 => ~"Aug",
                9 => ~"Sep",
                10 => ~"Oct",
                11 => ~"Nov",
                12 => ~"Dec",
                _  => die()
            },
            'C' => format!("{:02u}", self.year / 100),
            'c' => {
                format!("{} {} {} {} {}",
                     self.get_date('a'),
                     self.get_date('b'),
                     self.get_date('e'),
                     self.get_date('T'),
                     self.get_date('Y'))
            }
            'D' | 'x' => {
                format!("{}/{}/{}",
                     self.get_date('m'),
                     self.get_date('d'),
                     self.get_date('y'))
            }
            'd' => format!("{:02u}", self.mday),
            'e' => format!("{:2u}", self.mday),
            'f' => format!("{:09u}", self.sec),
            'F' => {
                format!("{}-{}-{}",
                     self.get_date('Y'),
                     self.get_date('m'),
                     self.get_date('d'))
            }
            'G' => self.iso_week ('G'),
            'g' => self.iso_week ('g'),
            'H' => format!("{:02u}", self.hour),
            'I' => {
                let mut h = self.hour;
                if h > 12 { h -= 12 }
                format!("{:02u}", h)
            }
            'j' => format!("{:03u}", self.yday + 1),
            'k' => format!("{:2u}", self.hour),
            'l' => {
                let mut h = self.hour;
                if h == 0 { h = 12 }
                if h > 12 { h -= 12 }
                format!("{:2u}", h)
            }
            'M' => format!("{:02u}", self.min),
            'm' => format!("{:02u}", self.month),
            'n' => ~"\n",
            'P' => if self.hour < 12 { ~"am" } else { ~"pm" },
            'p' => if self.hour < 12 { ~"AM" } else { ~"PM" },
            'R' => {
                format!("{}:{}",
                     self.get_date('H'),
                     self.get_date('M'))
            }
            'r' => {
                format!("{}:{}:{} {}",
                     self.get_date('I'),
                     self.get_date('M'),
                     self.get_date('S'),
                     self.get_date('p'))
            }
            'S' => format!("{:02u}", self.sec),
            's' => format!("{}", self.mktime()),
            'T' | 'X' => {
                format!("{}:{}:{}",
                     self.get_date('H'),
                     self.get_date('M'),
                     self.get_date('S'))
            }
            't' => ~"\t",
            'U' => format!("{:02u}", (self.yday - self.wday + 7) / 7),
            'u' => {
                let i = self.wday;
                (if i == 0 { 7 } else { i }).to_str()
            }
            'V' => self.iso_week ('V'),
            'v' => {
                format!("{}-{}-{}",
                     self.get_date('e'),
                     self.get_date('b'),
                     self.get_date('Y'))
            }
            'W' => format!("{:02u}", (self.yday - (self.wday - 1 + 7) % 7 + 7) / 7),
            'w' => self.wday.to_str(),
            'Y' => self.year.to_str(),
            'y' => format!("{:02u}", self.year % 100),
            'Z' => ~"UTC",
            'z' => ~"-0000",
            '%' => ~"%",
            _   => die()
        }
    }
}

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

    #[test]
    fn new() {
        let gc = GCalendar::new(21, 0, 12, 23, 9, 1983, 5, 265);
        assert_eq!(gc.get_sec(), 21);
        assert_eq!(gc.get_min(), 0);
        assert_eq!(gc.get_hour(), 12);
        assert_eq!(gc.get_day_of_month(), 23);
        assert_eq!(gc.get_month(), 9);
        assert_eq!(gc.get_year(), 1983);
    }

    #[test]
    fn new_from_epoch() {
        let gc = GCalendar::new_from_epoch(433166421023);
        assert_eq!(gc.get_day_of_week(), 5);
        assert_eq!(gc.get_day_of_year(), 265);
    }
}
<commit_msg>gcalendar: add ydhms_diff()<commit_after>// Copyright 2013 Luis de Bethencourt <luis@debethencourt.com>
// Copyright 2013 The Rust Project Developers
// http://rust-lang.org

// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
 * Gregorian Calendar module for the datetime library of the Rust programming
 * language
 *
 * Implements a hybrid calendar that supports both the Julian and Gregorian
 * calendar systems.
 *
 * http://en.wikipedia.org/wiki/Gregorian_calendar
 * http://en.wikipedia.org/wiki/Julian_calendar
 */

static YEARBASE: int = 1900;
static DAYSPERLYEAR: uint = 366;
static DAYSPERNYEAR: uint = 365;
static DAYSPERWEEK: uint = 7;
static DAYSBEFOREMONTH: [[uint, ..13], ..2] = [
    /* Normal years */
    [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365],
    /* Leap years */
    [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]
];

pub fn is_leap_year(year: uint) -> bool {
    (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))
}

pub fn year_size(year: uint) -> uint {
    if is_leap_year(year) { DAYSPERLYEAR } else { DAYSPERNYEAR }
}

pub struct GCalendar {
    /*
     * Calendar object with date and time.
     */
    sec: uint,         /* Seconds       [0-59]  */
    min: uint,         /* Minutes       [0-59]  */
    hour: uint,        /* Hours         [0-23]  */
    mday: uint,        /* Day           [0-30]  */
    month: uint,       /* Month         [0-11]  */
    year: uint,        /* Year - 1900           */
    wday: uint,        /* Day of week   [0-6]   */
    yday: uint         /* Days in year  [0-365] */
}

impl GCalendar {
    /**
    * Allocates a GCalendar object at epoch.
    */
    pub fn new_at_epoch() -> GCalendar {
        GCalendar {
            sec: 0,
            min: 0,
            hour: 0,
            mday: 0,
            month: 0,
            year: 0,
            wday: 0,
            yday: 0,
        }
    }

    /**
    * Allocates a GCalendar object at the given date and time.
    */
    pub fn new(sec: uint, min: uint, hour: uint, mday: uint, month: uint,
            year: uint, wday: uint, yday: uint) -> GCalendar {
        GCalendar {
            sec: sec,
            min: min,
            hour: hour,
            mday: mday,
            month: month,
            year: year,
            wday: wday,
            yday: yday,
        }
    }

    /**
    * Allocates a GCalendar object from the milliseconds elapsed since epoch.
    */
    pub fn new_from_epoch(since_epoch: uint) -> GCalendar {
        let epoch_year = 1970;
        let mut year = epoch_year;

        let millisecs_day = 86400000;

        let mut dayclock = since_epoch % millisecs_day;
        let mut dayno = since_epoch / millisecs_day;

        let hour = dayclock / 3600000;
        dayclock = dayclock - (hour * 3600000);
        let min = dayclock / 60000;
        dayclock = dayclock - (min * 60000);
        let sec = dayclock / 1000;
        let wday = (dayno + 4) % 7;

        while (dayno >= year_size(year)) {
            dayno -= year_size(year);
            year += 1;
        }
        let yday = dayno;

        let ip = DAYSBEFOREMONTH[if is_leap_year(year) {1} else {0}];
        let mut month = 11;
        while (dayno < ip[month]) {
            month -= 1;
        }
        dayno -= ip[month];

        GCalendar {
            sec: sec,
            min: min,
            hour: hour,
            mday: dayno + 1,
            month: month  + 1,
            year: year,
            wday: wday,
            yday: yday,
        }
    }

    pub fn get_sec(&self) -> uint {
        self.sec
    }

    pub fn get_min(&self) -> uint {
        self.min
    }

    pub fn get_hour(&self) -> uint {
        self.hour
    }

    pub fn get_day_of_month(&self) -> uint {
        self.mday
    }

    pub fn get_month(&self) -> uint {
        self.month
    }

    pub fn get_year(&self) -> uint {
        self.year
    }

    pub fn get_day_of_week(&self) -> uint {
        self.wday
    }

    pub fn get_day_of_year(&self) -> uint {
        self.yday
    }

    pub fn ydhms_diff(&self, year1: uint, yday1: uint, hour1: uint, min1: uint,
                      sec1: uint, year0: uint, yday0: uint, hour0: uint,
                      min0: uint, sec0: uint) -> uint {
        /* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
        * (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds.
        */
        // FIXME: Optimize way to calculate intervening leap days
        let mut intervening_leap_days: uint = 0;
        let mut y: uint = year1;
        while (y > year0) {
            if is_leap_year(y) {intervening_leap_days += 1;}
            y -= 1;
        }

        let years = (year1 - year0);
        let days = 365 * years + yday1 - yday0 + intervening_leap_days;
        let hours = 24 * days + hour1 - hour0;
        let minutes = 60 * hours + min1 - min0;
        60 * minutes + sec1 - sec0
    }

    pub fn mktime(&self) -> uint {
        /* Convert a broken down time structure to a simple representation:
        * seconds since Epoch.
        */
        self.ydhms_diff(self.year, self.yday, self.hour, self.min, self.sec,
                        1970, 0, 0, 0, 0)
    }

    pub fn iso_week_days (&self, yday: uint, wday: uint) -> int {
        /* The number of days from the first day of the first ISO week of this
        * year to the year day YDAY with week day WDAY.
        * ISO weeks start on Monday. The first ISO week has the year's first
        * Thursday.
        * YDAY may be as small as yday_minimum.
        */
        let yday: int = yday as int;
        let wday: int = wday as int;
        let iso_week_start_wday: int = 1; /* Monday */
        let iso_week1_wday: int = 4;      /* Thursday */
        let yday_minimum: int = 366;
        /* Add enough to the first operand of % to make it nonnegative. */
        let big_enough_multiple_of_7: int = (yday_minimum / 7 + 2) * 7;

        yday - (yday - wday + iso_week1_wday + big_enough_multiple_of_7) % 7
            + iso_week1_wday - iso_week_start_wday
     }

    pub fn iso_week (&self, ch: char) -> ~str {
        let mut year: uint = self.year;
        let mut days: int = self.iso_week_days (self.yday, self.wday);

        if (days < 0) {
            /* This ISO week belongs to the previous year. */
            year -= 1;
            days = self.iso_week_days (self.yday + (year_size(year)),
                                       self.wday);
        } else {
            let d: int = self.iso_week_days (self.yday - (year_size(year)),
                                             self.wday);
            if (0 <= d) {
                /* This ISO week belongs to the next year. */
                year += 1;
                days = d;
            }
        }

        match ch {
            'G' => format!("{}", year),
            'g' => format!("{:02u}", (year % 100 + 100) % 100),
            'V' => format!("{:02d}", days / 7 + 1),
            _ => ~""
        }
    }

    pub fn get_date(&self, ch: char) -> ~str {
        let die = || format!("strftime: can't understand this format {} ", ch);
        match ch {
            'A' => match self.wday {
                0 => ~"Sunday",
                1 => ~"Monday",
                2 => ~"Tuesday",
                3 => ~"Wednesday",
                4 => ~"Thursday",
                5 => ~"Friday",
                6 => ~"Saturday",
                _ => die()
            },
            'a' => match self.wday {
                0 => ~"Sun",
                1 => ~"Mon",
                2 => ~"Tue",
                3 => ~"Wed",
                4 => ~"Thu",
                5 => ~"Fri",
                6 => ~"Sat",
                _ => die()
            },
            'B' => match self.month {
                1 => ~"January",
                2 => ~"February",
                3 => ~"March",
                4 => ~"April",
                5 => ~"May",
                6 => ~"June",
                7 => ~"July",
                8 => ~"August",
                9 => ~"September",
                10 => ~"October",
                11 => ~"November",
                12 => ~"December",
                _ => die()
            },
            'b' | 'h' => match self.month {
                1 => ~"Jan",
                2 => ~"Feb",
                3 => ~"Mar",
                4 => ~"Apr",
                5 => ~"May",
                6 => ~"Jun",
                7 => ~"Jul",
                8 => ~"Aug",
                9 => ~"Sep",
                10 => ~"Oct",
                11 => ~"Nov",
                12 => ~"Dec",
                _  => die()
            },
            'C' => format!("{:02u}", self.year / 100),
            'c' => {
                format!("{} {} {} {} {}",
                     self.get_date('a'),
                     self.get_date('b'),
                     self.get_date('e'),
                     self.get_date('T'),
                     self.get_date('Y'))
            }
            'D' | 'x' => {
                format!("{}/{}/{}",
                     self.get_date('m'),
                     self.get_date('d'),
                     self.get_date('y'))
            }
            'd' => format!("{:02u}", self.mday),
            'e' => format!("{:2u}", self.mday),
            'f' => format!("{:09u}", self.sec),
            'F' => {
                format!("{}-{}-{}",
                     self.get_date('Y'),
                     self.get_date('m'),
                     self.get_date('d'))
            }
            'G' => self.iso_week ('G'),
            'g' => self.iso_week ('g'),
            'H' => format!("{:02u}", self.hour),
            'I' => {
                let mut h = self.hour;
                if h > 12 { h -= 12 }
                format!("{:02u}", h)
            }
            'j' => format!("{:03u}", self.yday + 1),
            'k' => format!("{:2u}", self.hour),
            'l' => {
                let mut h = self.hour;
                if h == 0 { h = 12 }
                if h > 12 { h -= 12 }
                format!("{:2u}", h)
            }
            'M' => format!("{:02u}", self.min),
            'm' => format!("{:02u}", self.month),
            'n' => ~"\n",
            'P' => if self.hour < 12 { ~"am" } else { ~"pm" },
            'p' => if self.hour < 12 { ~"AM" } else { ~"PM" },
            'R' => {
                format!("{}:{}",
                     self.get_date('H'),
                     self.get_date('M'))
            }
            'r' => {
                format!("{}:{}:{} {}",
                     self.get_date('I'),
                     self.get_date('M'),
                     self.get_date('S'),
                     self.get_date('p'))
            }
            'S' => format!("{:02u}", self.sec),
            's' => format!("{}", self.mktime()),
            'T' | 'X' => {
                format!("{}:{}:{}",
                     self.get_date('H'),
                     self.get_date('M'),
                     self.get_date('S'))
            }
            't' => ~"\t",
            'U' => format!("{:02u}", (self.yday - self.wday + 7) / 7),
            'u' => {
                let i = self.wday;
                (if i == 0 { 7 } else { i }).to_str()
            }
            'V' => self.iso_week ('V'),
            'v' => {
                format!("{}-{}-{}",
                     self.get_date('e'),
                     self.get_date('b'),
                     self.get_date('Y'))
            }
            'W' => format!("{:02u}", (self.yday - (self.wday - 1 + 7) % 7 + 7) / 7),
            'w' => self.wday.to_str(),
            'Y' => self.year.to_str(),
            'y' => format!("{:02u}", self.year % 100),
            'Z' => ~"UTC",
            'z' => ~"-0000",
            '%' => ~"%",
            _   => die()
        }
    }
}

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

    #[test]
    fn new() {
        let gc = GCalendar::new(21, 0, 12, 23, 9, 1983, 5, 265);
        assert_eq!(gc.get_sec(), 21);
        assert_eq!(gc.get_min(), 0);
        assert_eq!(gc.get_hour(), 12);
        assert_eq!(gc.get_day_of_month(), 23);
        assert_eq!(gc.get_month(), 9);
        assert_eq!(gc.get_year(), 1983);
    }

    #[test]
    fn new_from_epoch() {
        let gc = GCalendar::new_from_epoch(433166421023);
        assert_eq!(gc.get_day_of_week(), 5);
        assert_eq!(gc.get_day_of_year(), 265);
    }
}
<|endoftext|>


<commit_before>pub struct Point<T> {
    x: T,
    y: T
}

pub fn Point<T>(x: T, y: T) -> Point<T> {
    return Point{x: x, y: y};
}

impl<T:Clone + Add<T,T>> Add<Point<T>, Point<T>> for Point<T> {
    fn add(&self, other: &Point<T>) -> Point<T> {
        return Point(self.x + other.x, self.y + other.y);
    }
}

#[test]
fn test_add() {
    let p1 = Point(2, 3);
    let p2 = Point(1, 5);
    let p3 = p1 + p2;
    assert_eq!((p3.x, p3.y), (3, 8));
}
<commit_msg>implement point scaling<commit_after>pub struct Point<T> {
    x: T,
    y: T
}

pub fn Point<T>(x: T, y: T) -> Point<T> {
    return Point{x: x, y: y};
}

impl<T:Clone + Add<T,T>> Add<Point<T>, Point<T>> for Point<T> {
    fn add(&self, other: &Point<T>) -> Point<T> {
        return Point(self.x + other.x, self.y + other.y);
    }
}

impl<T:Clone + Mul<T,T>> Point<T> {
    pub fn scale(&self, factor: T) -> Point<T> {
        return Point(self.x * factor, self.y * factor);
    }
}

#[test]
fn test_add() {
    let p1 = Point(2, 3);
    let p2 = Point(1, 5);
    let p3 = p1 + p2;
    assert_eq!((p3.x, p3.y), (3, 8));
}

#[test]
fn test_scale() {
    let p = Point(2, 3).scale(2);
    assert_eq!((p.x, p.y), (4, 6));
}
<|endoftext|>


<commit_before>use gtfs::error::Error;
use csv::{DeserializeRecordsIntoIter, StringRecord, Reader, ErrorKind, DeserializeError, Position};
use serde;
use std;

pub struct GTFSIterator<R, T>
    where R: std::io::Read,
          T: serde::de::DeserializeOwned
{
    iter: DeserializeRecordsIntoIter<R, T>,
    headers: StringRecord,
    filename: String,
}

impl<T> GTFSIterator<std::fs::File, T>
    where T: serde::de::DeserializeOwned
{
    pub fn from_path(filename: &str) -> Result<GTFSIterator<std::fs::File, T>, Error>
    {
        let csv = match Reader::from_path(filename) {
            Ok(c) => c,
            Err(e) => return Err(Error::Csv(filename.to_string(), e))
        };
        GTFSIterator::new(csv, filename)
    }
}

impl<R, T> GTFSIterator<R, T>
    where R: std::io::Read,
          T: serde::de::DeserializeOwned
{
    pub fn new(mut reader: Reader<R>, filename: &str) -> Result<GTFSIterator<R, T>, Error> {
        let headers = match reader.headers() {
            Ok(r) => r.clone(),
            Err(e) => return Err(Error::Csv(filename.to_string(), e))
        };
        Ok(GTFSIterator{
            iter: reader.into_deserialize(),
            headers: headers,
            filename: filename.to_string()
        })
    }

    fn wrap_fielderror(&self, err: &DeserializeError, position: &Option<Position>) -> Error {
        let fieldname = match err.field() {
            Some(field_pos) => Some(match self.headers.get(field_pos as usize) {
                Some(field) => field.to_string(),
                None => format!("field {}", field_pos).to_string()
            }),
            None => None
        };
        // TODO:: What if position.line() is None?
        Error::FieldError(String::clone(&self.filename), position.as_ref().unwrap().line(), err.kind().clone(), fieldname)
    }
}

impl<R, T> Iterator for GTFSIterator<R, T>
    where R: std::io::Read,
          T: serde::de::DeserializeOwned
{
    type Item = Result<T, Error>;

    fn next(&mut self) -> Option<Result<T, Error>> {
        match self.iter.next() {
            Some(r) => Some(match r {
                Err(e) => match e.into_kind() {
                    ErrorKind::Deserialize{ref pos, ref err} => Err(self.wrap_fielderror(err, pos)),
                    k => Err(Error::LineError(String::clone(&self.filename), k))
                },
                Ok(s) => Ok(s)
            }),
            None => None
        }
    }
}

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

    #[derive(Debug, Deserialize, PartialEq)]
    struct Test {
        foo: String,
        bar: f64,
        #[serde(deserialize_with = "deserialize_dow_field")]  // makes 0 or 1 into bool
        baz: bool
    }

    #[test]
    fn test_parse_records() {
        let data = "\
foo,bar,baz
Foo,1.0,0
";
        let expected = Test { foo: "Foo".to_string(), bar: 1.0, baz: false };

        let reader = csv::Reader::from_reader(data.as_bytes());
        let mut iter : GTFSIterator<_, Test> = GTFSIterator::new(reader, "test.txt").unwrap();
        assert_eq!(&expected, iter.next().unwrap().as_ref().unwrap());
    }

    #[test]
    fn test_error_parsing_primitive_fields() {
        let data = "\
foo,bar,baz
Foo,w,0
";
        let expected = "error parsing bar in test.txt:2 - invalid float literal";

        let reader = csv::Reader::from_reader(data.as_bytes());
        let mut iter : GTFSIterator<_, Test> = GTFSIterator::new(reader, "test.txt").unwrap();

        let result = iter.next().unwrap().err().unwrap();
        assert_eq!(expected, format!("{}", result));
    }

    #[test]
    fn test_error_parsing_custom_fields() {
        let data = "\
foo,bar,baz
Foo,1,3
";
        // ugly: Can deserialize_dow_field take a DeRecordWrap instead to add field info?
        let expected = "error parsing test.txt:2 - day of week field was not 0 or 1";

        let reader = csv::Reader::from_reader(data.as_bytes());
        let mut iter : GTFSIterator<_, Test> = GTFSIterator::new(reader, "test.txt").unwrap();

        let result = iter.next().unwrap().err().unwrap();
        assert_eq!(expected, format!("{}", result));
    }

    #[test]
    fn test_error_parsing_bad_lines() {
        let data = "\
foo,bar,baz
Foo,1
";
        // ugly: Can deserialize_dow_field take a DeRecordWrap instead to add field info?
        let expected = "error parsing test.txt:2 - expected 3 fields but got 2 fields";

        let reader = csv::Reader::from_reader(data.as_bytes());
        let mut iter : GTFSIterator<_, Test> = GTFSIterator::new(reader, "test.txt").unwrap();
        let result = iter.next().unwrap().err().unwrap();
        assert_eq!(expected, format!("{}", result));
    }

    #[test]
    fn test_error_file_missing() {
        let result : Result<GTFSIterator<_, Test>, Error> = GTFSIterator::from_path("./examples/definitelynothere");
        assert_eq!("error parsing ./examples/definitelynothere - No such file or directory (os error 2)", format!("{}", result.err().unwrap()))
    }
}
<commit_msg>Deserialization fails if there is unexpected whitespace<commit_after>use gtfs::error::Error;
use csv::{DeserializeRecordsIntoIter, StringRecord, Reader, ErrorKind, DeserializeError, Position};
use serde;
use std;

pub struct GTFSIterator<R, T>
    where R: std::io::Read,
          T: serde::de::DeserializeOwned
{
    iter: DeserializeRecordsIntoIter<R, T>,
    headers: StringRecord,
    filename: String,
}

impl<T> GTFSIterator<std::fs::File, T>
    where T: serde::de::DeserializeOwned
{
    pub fn from_path(filename: &str) -> Result<GTFSIterator<std::fs::File, T>, Error>
    {
        let csv = match Reader::from_path(filename) {
            Ok(c) => c,
            Err(e) => return Err(Error::Csv(filename.to_string(), e))
        };
        GTFSIterator::new(csv, filename)
    }
}

impl<R, T> GTFSIterator<R, T>
    where R: std::io::Read,
          T: serde::de::DeserializeOwned
{
    pub fn new(mut reader: Reader<R>, filename: &str) -> Result<GTFSIterator<R, T>, Error> {
        let headers = match reader.headers() {
            Ok(r) => r.clone(),
            Err(e) => return Err(Error::Csv(filename.to_string(), e))
        };
        Ok(GTFSIterator{
            iter: reader.into_deserialize(),
            headers: headers,
            filename: filename.to_string()
        })
    }

    fn wrap_fielderror(&self, err: &DeserializeError, position: &Option<Position>) -> Error {
        let fieldname = match err.field() {
            Some(field_pos) => Some(match self.headers.get(field_pos as usize) {
                Some(field) => field.to_string(),
                None => format!("field {}", field_pos).to_string()
            }),
            None => None
        };
        // TODO:: What if position.line() is None?
        Error::FieldError(String::clone(&self.filename), position.as_ref().unwrap().line(), err.kind().clone(), fieldname)
    }
}

impl<R, T> Iterator for GTFSIterator<R, T>
    where R: std::io::Read,
          T: serde::de::DeserializeOwned
{
    type Item = Result<T, Error>;

    fn next(&mut self) -> Option<Result<T, Error>> {
        match self.iter.next() {
            Some(r) => Some(match r {
                Err(e) => match e.into_kind() {
                    ErrorKind::Deserialize{ref pos, ref err} => Err(self.wrap_fielderror(err, pos)),
                    k => Err(Error::LineError(String::clone(&self.filename), k))
                },
                Ok(s) => Ok(s)
            }),
            None => None
        }
    }
}

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

    #[derive(Debug, Deserialize, PartialEq)]
    struct Test {
        foo: String,
        bar: f64,
        #[serde(deserialize_with = "deserialize_dow_field")]  // makes 0 or 1 into bool
        baz: bool
    }

    #[test]
    fn test_parse_records() {
        let data = "\
foo,bar,baz
Foo,1.0,0
";
        let expected = Test { foo: "Foo".to_string(), bar: 1.0, baz: false };

        let reader = csv::Reader::from_reader(data.as_bytes());
        let mut iter : GTFSIterator<_, Test> = GTFSIterator::new(reader, "test.txt").unwrap();
        assert_eq!(&expected, iter.next().unwrap().as_ref().unwrap());
    }

    #[test]
    #[ignore]  // probably worth getting involved in https://github.com/BurntSushi/rust-csv/issues/78
    fn test_parse_primitive_fields_with_whitespace() {
        let data = "\
foo,bar,baz
Foo,  1.0,0
";
        let expected = Test { foo: "Foo".to_string(), bar: 1.0, baz: false };

        let reader = csv::Reader::from_reader(data.as_bytes());
        let mut iter : GTFSIterator<_, Test> = GTFSIterator::new(reader, "test.txt").unwrap();
        assert_eq!(&expected, iter.next().unwrap().as_ref().unwrap());
    }

    #[test]
    fn test_error_parsing_primitive_fields() {
        let data = "\
foo,bar,baz
Foo,w,0
";
        let expected = "error parsing bar in test.txt:2 - invalid float literal";

        let reader = csv::Reader::from_reader(data.as_bytes());
        let mut iter : GTFSIterator<_, Test> = GTFSIterator::new(reader, "test.txt").unwrap();

        let result = iter.next().unwrap().err().unwrap();
        assert_eq!(expected, format!("{}", result));
    }

    #[test]
    fn test_error_parsing_custom_fields() {
        let data = "\
foo,bar,baz
Foo,1,3
";
        // ugly: Can deserialize_dow_field take a DeRecordWrap instead to add field info?
        let expected = "error parsing test.txt:2 - day of week field was not 0 or 1";

        let reader = csv::Reader::from_reader(data.as_bytes());
        let mut iter : GTFSIterator<_, Test> = GTFSIterator::new(reader, "test.txt").unwrap();

        let result = iter.next().unwrap().err().unwrap();
        assert_eq!(expected, format!("{}", result));
    }

    #[test]
    fn test_error_parsing_bad_lines() {
        let data = "\
foo,bar,baz
Foo,1
";
        // ugly: Can deserialize_dow_field take a DeRecordWrap instead to add field info?
        let expected = "error parsing test.txt:2 - expected 3 fields but got 2 fields";

        let reader = csv::Reader::from_reader(data.as_bytes());
        let mut iter : GTFSIterator<_, Test> = GTFSIterator::new(reader, "test.txt").unwrap();
        let result = iter.next().unwrap().err().unwrap();
        assert_eq!(expected, format!("{}", result));
    }

    #[test]
    fn test_error_file_missing() {
        let result : Result<GTFSIterator<_, Test>, Error> = GTFSIterator::from_path("./examples/definitelynothere");
        assert_eq!("error parsing ./examples/definitelynothere - No such file or directory (os error 2)", format!("{}", result.err().unwrap()))
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;

use bs58::FromBase58;

use MultiHash;

pub use self::error::*;

mod error {
    error_chain! {
    }
}

impl FromStr for MultiHash {
    type Err = Error;

    fn from_str(s: &str) -> Result<MultiHash> {
        Ok(try!(MultiHash::from_bytes(try!(s.from_base58()))))
    }
}

<commit_msg>Fix error chain<commit_after>use std::str::FromStr;

use bs58::FromBase58;

use MultiHash;

pub use self::error::*;

mod error {
    use bs58;

    error_chain! {
        foreign_links {
            bs58::FromBase58Error, Base58;
        }
    }
}

impl FromStr for MultiHash {
    type Err = Error;

    fn from_str(s: &str) -> Result<MultiHash> {
        Ok(try!(MultiHash::from_bytes(try!(s.from_base58()))))
    }
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;
use regex;
use regex::Regex;

pub struct Docopt {
    program: String,
    usages: Alternates,
    descs: HashMap<String, AtomDesc>,
    short_to: HashMap<String, String>,
    last_desc_added: Option<String>,
}

impl fmt::Show for Docopt {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::FormatError> {
        try!(writeln!(f, "====="))
        try!(writeln!(f, "Program: {}", self.program))
        try!(writeln!(f, "Option descriptions:"))
        for (k, v) in self.descs.iter() {
            try!(writeln!(f, "  '{}' => {}", k, v))
        }
        try!(writeln!(f, "Short abbreviations:"))
        for (k, v) in self.short_to.iter() {
            try!(writeln!(f, "  '{}' => '{}'", k, v))
        }
        writeln!(f, "=====")
    }
}

type Alternates = Vec<Pattern>;
struct Pattern { pats: Vec<Repeatable> }
struct Repeatable { repeats: bool, expr: Expr }

enum Expr {
    Grouped(Alternates),
    Optional(Alternates),
    Options,
    Atom(String), // key in Docopt.descs
}

#[deriving(Show)]
struct AtomDesc {
    name: String,

    /// Set to true if this atom is ever repeated in any context.
    /// For positional arguments, non-argument flags and commands, repetition
    /// means that they become countable.
    /// For flags with arguments, repetition means multiple distinct values
    /// can be specified (and are represented as a Vec).
    repeats: bool,
    atype: AtomType,
}

#[deriving(Show)]
enum AtomType {
    Arg, // positional
    Command,
    Flag(ArgDesc),
}

#[deriving(Show, PartialEq)]
enum ArgDesc {
    Zero,
    One,
    // Default implies One
    Default(String),
}

macro_rules! err(
    ($($arg:tt)*) => (return Err(format!($($arg)*)))
)

impl Docopt {
    pub fn new(doc: &str) -> Result<Docopt, String> {
        let mut d = Docopt {
            program: "".to_string(),
            usages: vec!(),
            descs: HashMap::new(),
            short_to: HashMap::new(),
            last_desc_added: None,
        };
        try!(d.parse(doc));
        Ok(d)
    }

    fn parse(&mut self, doc: &str) -> Result<(), String> {
        let musage = regex!(r"(?is)usage:\s+(?P<prog>\S+)(?P<pats>.*?)\n\s*\n");
        let caps = match musage.captures(doc) {
            None => err!("Could not find usage patterns in doc string."),
            Some(caps) => caps,
        };
        if caps.name("prog").is_empty() {
            err!("Could not find program name in doc string.")
        }
        self.program = caps.name("prog").to_string();

        // Before we parse the usage patterns, we look for option descriptions.
        // We do this because the information in option descriptions can be
        // used to resolve ambiguities in usage patterns (i.e., whether
        // `--flag ARG` is a flag with an argument or not).
        //
        // From the docopt page, "every" line starting with a `-` or a `--`
        // is considered an option description. Instead, we restrict the lines
        // to any line *not* in the usage pattern section.
        let (pstart, pend) = caps.pos(0).unwrap();
        let (before, after) = (doc.slice_to(pstart), doc.slice_from(pend));
        // We process every line here (instead of restricting to lines starting
        // with "-") because we need to check every line for a default value.
        // The default value always belongs to the most recently defined desc.
        for line in before.lines().chain(after.lines()) {
            try!(self.parse_desc(line));
        }

        let mprog = format!("(?s)(.*?)({}|$)", regex::quote(caps.name("prog")));
        let pats = Regex::new(mprog.as_slice()).unwrap();
        for _ in pats.captures_iter(caps.name("pats")) {
            // println!("${}$", pat.at(1).trim());
        }
        Ok(())
    }

    fn parse_desc(&mut self, full_desc: &str) -> Result<(), String> {
        let desc = full_desc.trim();
        if !regex!(r"^(-\S|--\S)").is_match(desc) {
            try!(self.parse_default(full_desc));
            return Ok(())
        }
        // Get rid of the description, which must be at least two spaces
        // after the flag or argument.
        let desc = regex!("  .*$").replace(desc, "");
        // Normalize `-x, --xyz` to `-x --xyz`.
        let desc = regex!(r"([^-\s]), -").replace(desc.as_slice(), "$1 -");
        let desc = desc.as_slice().trim();

        let rflags = regex!("(?:(?P<long>--[^ \t=]+)|(?P<short>-[^ \t=]+))\
                             (?:(?: |=)(?P<arg>[^-]\\S*))?");
        let (mut short, mut long) = ("".to_string(), "".to_string());
        let mut arg = Zero;
        let mut last_end = 0;
        for flags in rflags.captures_iter(desc) {
            last_end = flags.pos(0).unwrap().val1();
            let (s, l) = (flags.name("short"), flags.name("long"));
            if !s.is_empty() {
                if !short.is_empty() {
                    err!("Only one short flag is allowed in an option \
                          description, but found '{}' and '{}'.", short, s)
                }
                short = s.to_string()
            }
            if !l.is_empty() {
                if !long.is_empty() {
                    err!("Only one long flag is allowed in an option \
                          description, but found '{}' and '{}'.", long, l)
                }
                long = l.to_string()
            }
            if flags.name("arg").len() > 0 {
                try!(err_if_invalid_arg(flags.name("arg")));
                arg = One; // may be changed to default later
            }
        }
        // Make sure that we consumed everything. If there are leftovers,
        // then there is some malformed description. Alert the user.
        assert!(last_end <= desc.len());
        if last_end < desc.len() {
            err!("Extraneous text '{}' in option description '{}'.",
                 desc.slice_from(last_end), desc)
        }
        try!(self.add_desc(short, long, arg))
        self.parse_default(full_desc)
    }

    fn parse_default(&mut self, desc: &str) -> Result<(), String> {
        let rdefault = regex!(r"(?i)\[default:(?P<val>[^]]*)\]");
        let defval =
            match rdefault.captures(desc) {
                None => return Ok(()),
                Some(c) => c.name("val").trim(),
            };
        let last_desc_key =
            match self.last_desc_added {
                Some(ref key) => key.clone(),
                None => err!("Found default value '{}' in '{}' before first \
                              option description.", defval, desc),
            };
        let desc = self.lookup(&last_desc_key)
                   .expect(format!("BUG: last opt desc key ('{}') is invalid.",
                                   last_desc_key).as_slice());
        desc.atype = Flag(Default(defval.to_string()));
        Ok(())
    }

    fn add_desc(&mut self, short: String, long: String, arg: ArgDesc)
               -> Result<(), String> {
        assert!(!short.is_empty() || !long.is_empty());
        if !short.is_empty() && short.len() != 2 {
            err!("Short flag '{}' is not of the form '-x'.", short);
        }
        if self.lookup(&short).is_some() {
            err!("Short flag '{}' is defined more than once.", short);
        }
        if self.lookup(&long).is_some() {
            err!("Long flag '{}' is defined more than once.", long);
        }
        let mut canonical = long;
        if canonical.is_empty() {
            canonical = short.clone();
        }
        if !short.is_empty() {
            self.short_to.insert(short, canonical.clone());
        }
        self.last_desc_added = Some(canonical.clone());
        self.descs.insert(canonical.clone(), AtomDesc {
            name: canonical,
            repeats: false, // not known yet; discovered in usage patterns
            atype: Flag(arg), // arg desc may change if default value is found
        });
        Ok(())
    }

    fn lookup<'a>(&'a mut self, flag: &String) -> Option<&'a mut AtomDesc> {
        let key =
            if is_short(flag.as_slice()) {
                match self.short_to.find(flag) {
                    Some(long) => long,
                    None => return None,
                }
            } else {
                flag
            };
        self.descs.find_mut(key)
    }
}

fn err_if_invalid_arg(s: &str) -> Result<(), String> {
    if !is_arg(s) {
        err!("Argument '{}' is not of the form ARG or <arg>.", s)
    } else {
        Ok(())
    }
}

fn is_short(s: &str) -> bool { return regex!(r"^-[^-]+$").is_match(s) }
fn is_long(s: &str) -> bool { return regex!(r"^--\S+$").is_match(s) }
fn is_arg(s: &str) -> bool { return regex!(r"^(\p{Lu}+|<[^>]+>)$").is_match(s) }
fn is_cmd(s: &str) -> bool { return regex!(r"^(-|--|[^-]\S+)$").is_match(s) }
<commit_msg>More progress on usage parser.<commit_after>use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::rc::Rc;
use std::str::{MaybeOwned, Owned, Slice};
use regex;
use regex::Regex;

pub struct Docopt {
    program: String,
    usages: Vec<Pattern>,
    descs: AtomOptions,
    last_atom_added: Option<Atom>, // context for [default: ...]
}

type AtomOptions = HashMap<Atom, Rc<RefCell<Options>>>;

#[deriving(Show)]
enum Pattern {
    Alternates(Vec<Pattern>),
    Sequence(Vec<Pattern>),
    Repeat(Box<Pattern>),
    Optional(Box<Pattern>),
    Options,
    Atom(Atom),
}

#[deriving(PartialEq, Eq, Hash, Clone, Show)]
enum Atom {
    Short(char),
    Long(String),
    Command(String),
    Positional(String),
}

#[deriving(Clone, Show)]
struct Options {
    /// Set to true if this atom is ever repeated in any context.
    /// For positional arguments, non-argument flags and commands, repetition
    /// means that they become countable.
    /// For flags with arguments, repetition means multiple distinct values
    /// can be specified (and are represented as a Vec).
    repeats: bool,

    /// This specifies whether this atom has any arguments.
    /// For commands and positional arguments, this is always Zero.
    /// Flags can have zero or one argument, with an optionally default value.
    arg: Argument,
}

#[deriving(Clone, Show, PartialEq)]
enum Argument {
    Zero,
    One,
    // Default implies One
    Default(String),
}

impl Argument {
    fn has_arg(&self) -> bool {
        match *self {
            Zero => false,
            One | Default(_) => true,
        }
    }
}

impl Pattern {
    fn flatten(self) -> Pattern {
        match self {
            Alternates(mut ps) => {
                // assert!(!ps.is_empty());
                if ps.len() == 1 {
                    ps.pop().unwrap().flatten()
                } else {
                    Alternates(ps.move_iter().map(|p| p.flatten()).collect())
                }
            }
            Sequence(mut ps) => {
                // assert!(!ps.is_empty());
                if ps.len() == 1 {
                    ps.pop().unwrap().flatten()
                } else {
                    Sequence(ps.move_iter().map(|p| p.flatten()).collect())
                }
            }
            Repeat(p) => Repeat(box p.flatten()),
            Optional(p) => Optional(box p.flatten()),
            Options => Options,
            Atom(name) => Atom(name),
        }
    }
}

macro_rules! err(
    ($($arg:tt)*) => (return Err(format!($($arg)*)))
)

impl Docopt {
    pub fn new(doc: &str) -> Result<Docopt, String> {
        let mut d = Docopt {
            program: "".to_string(),
            usages: vec!(),
            descs: HashMap::new(),
            last_atom_added: None,
        };
        try!(d.parse(doc));
        Ok(d)
    }

    fn parse(&mut self, doc: &str) -> Result<(), String> {
        let musage = regex!(r"(?is)usage:\s+(?P<prog>\S+)(?P<pats>.*?)\n\s*\n");
        let caps = match musage.captures(doc) {
            None => err!("Could not find usage patterns in doc string."),
            Some(caps) => caps,
        };
        if caps.name("prog").is_empty() {
            err!("Could not find program name in doc string.")
        }
        self.program = caps.name("prog").to_string();

        // Before we parse the usage patterns, we look for option descriptions.
        // We do this because the information in option descriptions can be
        // used to resolve ambiguities in usage patterns (i.e., whether
        // `--flag ARG` is a flag with an argument or not).
        //
        // From the docopt page, "every" line starting with a `-` or a `--`
        // is considered an option description. Instead, we restrict the lines
        // to any line *not* in the usage pattern section.
        let (pstart, pend) = caps.pos(0).unwrap();
        let (before, after) = (doc.slice_to(pstart), doc.slice_from(pend));
        // We process every line here (instead of restricting to lines starting
        // with "-") because we need to check every line for a default value.
        // The default value always belongs to the most recently defined desc.
        for line in before.lines().chain(after.lines()) {
            try!(self.parse_desc(line));
        }

        let mprog = format!("(?s)(.*?)({}|$)", regex::quote(caps.name("prog")));
        let pats = Regex::new(mprog.as_slice()).unwrap();
        for pat in pats.captures_iter(caps.name("pats")) {
            let pattern = try!(PatParser::new(self, pat.at(1)).pattern());
            self.usages.push(pattern);
        }
        Ok(())
    }

    fn parse_desc(&mut self, full_desc: &str) -> Result<(), String> {
        let desc = full_desc.trim();
        if !regex!(r"^(-\S|--\S)").is_match(desc) {
            try!(self.parse_default(full_desc));
            return Ok(())
        }
        // Get rid of the description, which must be at least two spaces
        // after the flag or argument.
        let desc = regex!("  .*$").replace(desc, "");
        // Normalize `-x, --xyz` to `-x --xyz`.
        let desc = regex!(r"([^-\s]), -").replace(desc.as_slice(), "$1 -");
        let desc = desc.as_slice().trim();

        let rflags = regex!("(?:(?P<long>--[^ \t=]+)|(?P<short>-[^ \t=]+))\
                             (?:(?: |=)(?P<arg>[^-]\\S*))?");
        let (mut short, mut long) = ("".to_string(), "".to_string());
        let mut has_arg = false;
        let mut last_end = 0;
        for flags in rflags.captures_iter(desc) {
            last_end = flags.pos(0).unwrap().val1();
            let (s, l) = (flags.name("short"), flags.name("long"));
            if !s.is_empty() {
                if !short.is_empty() {
                    err!("Only one short flag is allowed in an option \
                          description, but found '{}' and '{}'.", short, s)
                }
                short = s.to_string()
            }
            if !l.is_empty() {
                if !long.is_empty() {
                    err!("Only one long flag is allowed in an option \
                          description, but found '{}' and '{}'.", long, l)
                }
                long = l.to_string()
            }
            if flags.name("arg").len() > 0 {
                try!(err_if_invalid_arg(flags.name("arg")));
                has_arg = true; // may be changed to default later
            }
        }
        // Make sure that we consumed everything. If there are leftovers,
        // then there is some malformed description. Alert the user.
        assert!(last_end <= desc.len());
        if last_end < desc.len() {
            err!("Extraneous text '{}' in option description '{}'.",
                 desc.slice_from(last_end), desc)
        }
        try!(self.add_desc(short.as_slice(), long.as_slice(), has_arg))
        // Looking for default in this line must come after adding the
        // description, otherwise `parse_default` won't know which option
        // to assign it to.
        self.parse_default(full_desc)
    }

    fn parse_default(&mut self, desc: &str) -> Result<(), String> {
        let rdefault = regex!(r"(?i)\[default:(?P<val>[^]]*)\]");
        let defval =
            match rdefault.captures(desc) {
                None => return Ok(()),
                Some(c) => c.name("val").trim(),
            };
        let last_atom =
            match self.last_atom_added {
                None => err!("Found default value '{}' in '{}' before first \
                              option description.", defval, desc),
                Some(ref atom) => atom,
            };
        let mut opts =
            self.descs.find(last_atom)
            .expect(format!("BUG: last opt desc key ('{}') is invalid.",
                            last_atom).as_slice())
            .borrow_mut();
        match opts.arg {
            One => {}, // OK
            Zero =>
                err!("Cannot assign default value '{}' to flag '{}' \
                      that has no arguments.", defval, last_atom),
            Default(ref curval) =>
                err!("Flag '{}' already has a default value \
                      of '{}' (second default value: '{}').",
                     last_atom, curval, defval),
        }
        opts.arg = Default(defval.to_string());
        Ok(())
    }

    fn add_desc(&mut self, short: &str, long: &str, has_arg: bool)
               -> Result<(), String> {
        assert!(!short.is_empty() || !long.is_empty());
        if !short.is_empty() && short.char_len() != 2 {
            err!("Short flag '{}' is not of the form '-x'.", short);
        }
        let opts = Rc::new(RefCell::new(Options {
            repeats: false, // not known yet; discovered in usage patterns
            arg: if has_arg { One } else { Zero }, // default? we don't know yet
        }));

        if !short.is_empty() {
            self.descs.insert(as_short(short), opts.clone());
            if long.is_empty() {
                self.last_atom_added = Some(as_short(short));
            }
        }
        if !long.is_empty() {
            self.descs.insert(as_long(long), opts);
            self.last_atom_added = Some(as_long(long))
        }
        Ok(())
    }
}

struct PatParser<'a> {
    dopt: &'a mut Docopt,
    tokens: Vec<String>, // used while parsing a single usage pattern
    curi: uint, // ^^ index into pattern chars
    seen: HashSet<Atom>, // atoms seen, used to track whether repeated
}

impl<'a> PatParser<'a> {
    fn new(dopt: &'a mut Docopt, pat: &str) -> PatParser<'a> {
        // Normalize `[xyz]` -> `[ xyz ]` so that grouping operators are
        // tokenized easily. Don't worry about introducing extra spaces.
        let rpat = regex!(r"\.\.\.|\[|\]|\(|\)|\|");
        let pat = rpat.replace_all(pat.trim(), " $0 ");
        PatParser {
            dopt: dopt,
            tokens: pat.as_slice().words().map(|s| s.to_string()).collect(),
            curi: 0,
            seen: HashSet::new(),
        }
    }

    fn pattern(&mut self) -> Result<Pattern, String> {
        let mut alts = vec!();
        while !self.is_eof() {
            match self.cur() {
                "]" | ")" => { self.next(); break },
                _ => alts.push(try!(self.alternate())),
            }
        }
        Ok(Alternates(alts).flatten())
    }

    fn alternate(&mut self) -> Result<Pattern, String> {
        let mut seq = vec!();
        while !self.is_eof() {
            match self.cur() {
                // "..." => {
                    // err!("'...' must appear directly after a group, argument, \
                          // flag or command.")
                // }
                "-" | "--" => {
                    // As per specification, `-` and `--` by themselves are
                    // just commands that should be interpreted conventionally.
                    seq.push(try!(self.command()));
                    self.next();
                }
                "|" => {
                    if seq.is_empty() {
                        err!("Unexpected '|'. Not in form 'a | b | c'.")
                    }
                    try!(self.next_noeof("pattern"));
                    return Ok(Sequence(seq))
                }
                "]" | ")" => {
                    // if alt.pats.is_empty() {
                        // err!("Unexpected '{}'. Empty groups are not allowed.",
                             // self.cur())
                    // }
                    return Ok(Sequence(seq))
                }
                "[" => {
                    // Check for special '[options]' shortcut.
                    if self.peekis("options") && self.peekpeekis("]") {
                        seq.push(Options);
                        self.next(); // cur == options
                        self.next(); // cur == ]
                        self.next();
                        continue
                    }
                    seq.push(Optional(box try!(self.group("]"))));
                }
                "(" => {
                    seq.push(try!(self.group(")")));
                }
                _ => {
                    if is_short(self.cur()) {
                        println!("Short: {}", self.cur());
                    } else if is_long(self.cur()) {
                        seq.push(try!(self.flag_long()));
                        // println!("Long: {}", self.cur());
                        // let rep = try!(self.flag_long());
                        // alt.pats.push(rep);
                    } else if is_arg(self.cur()) {
                        // These are always positional.
                        // Arguments for -s and --short are picked up
                        // when parsing flags.
                        seq.push(try!(self.positional()));
                    } else if is_cmd(self.cur()) {
                        seq.push(try!(self.command()));
                    } else {
                        err!("Unknown token type '{}'.", self.cur())
                    }
                    self.next();
                }
            }
        }
        Ok(Sequence(seq))
    }

    fn flag_long(&mut self) -> Result<Pattern, String> {
        let (atom, mut arg) = try!(parse_long_equal(self.cur()));
        if self.dopt.descs.contains_key(&atom) {
            // Options already exist for this atom, so we must check to make
            // sure things are consistent.
            let opts = self.dopt.descs.get(&atom).borrow().clone();
            if arg.has_arg() && !opts.arg.has_arg() {
                err!("Flag '{}' does not take any arguments.", atom)
            } else if !arg.has_arg() && opts.arg.has_arg() {
                // Look for `--flag ARG`
                try!(self.next_noeof(format!(
                     "Expected argument for flag '{}' but found EOF.",
                     atom).as_slice()));
                if !is_arg(self.cur()) {
                    err!("Expected argument for flag '{}', but found \
                          malformed argument '{}'.", atom, self.cur())
                }
                arg = One; // we have an argument!
            }
        }
        let pat = self.maybe_repeat(Atom(atom.clone()));
        self.update_options(arg, &pat);
        Ok(pat)
    }

    fn command(&mut self) -> Result<Pattern, String> {
        let atom = Atom(as_cmd(self.cur()));
        let pat = self.maybe_repeat(atom);
        self.update_options(Zero, &pat);
        Ok(pat)
    }

    fn positional(&mut self) -> Result<Pattern, String> {
        let atom = Atom(as_arg(self.cur()));
        let pat = self.maybe_repeat(atom);
        self.update_options(Zero, &pat);
        Ok(pat)
    }

    fn update_options(&mut self, arg: Argument, atom_or_repeat: &Pattern) {
        let (atom, rep) =
            match atom_or_repeat {
                &Atom(ref atom) => (atom, false),
                &Repeat(box Atom(ref atom)) => (atom, true),
                _ => fail!("BUG: unexpected pattern: {}", atom_or_repeat),
            };
        let seen = self.seen.contains(atom);
        if !self.dopt.descs.contains_key(atom) {
            let opts = Rc::new(RefCell::new(Options { repeats: rep, arg: arg }));
            self.dopt.descs.insert(atom.clone(), opts);
        } else {
            let mut opts = self.dopt.descs.get(atom).borrow_mut();
            opts.repeats = opts.repeats || rep || seen;
        }
        self.seen.insert(atom.clone());
    }

    fn group(&mut self, end: &str) -> Result<Pattern, String> {
        try!(self.next_noeof("pattern"));
        let pat = try!(self.pattern());
        if !self.previs(end) {
            err!("Expected '{}' but got '{}'.", end, self.prev())
        }
        Ok(self.maybe_repeat(pat))
    }

    fn maybe_repeat(&mut self, pat: Pattern) -> Pattern {
        if self.peekis("...") {
            self.next();
            Repeat(box pat)
        } else {
            pat
        }
    }

    fn is_eof(&self) -> bool {
        self.curi == self.tokens.len()
    }
    fn next(&mut self) {
        if self.curi == self.tokens.len() {
            return
        }
        self.curi += 1;
    }
    fn next_noeof(&mut self, expected: &str) -> Result<(), String> {
        self.next();
        if self.curi == self.tokens.len() {
            err!("Expected '{}' but reached end of usage pattern.", expected)
        }
        Ok(())
    }
    fn cur<'r>(&'r self) -> &'r str {
        self.tokens.get(self.curi).as_slice()
    }
    fn prev<'r>(&'r self) -> &'r str {
        self.tokens.get(self.curi - 1).as_slice()
    }
    fn cur_or_eof<'r>(&'r self) -> MaybeOwned<'r> {
        if self.is_eof() {
            Owned("EOF".to_string())
        } else {
            Slice(self.cur())
        }
    }
    fn curis(&self, is: &str) -> bool {
        !self.is_eof() && self.cur() == is
    }
    fn previs(&self, is: &str) -> bool {
        self.curi > 0 && self.tokens.get(self.curi - 1).as_slice() == is
    }
    fn peekis(&self, is: &str) -> bool {
        if self.curi + 1 >= self.tokens.len() {
            return false
        }
        self.tokens.get(self.curi + 1).as_slice() == is
    }
    fn peekpeekis(&self, is: &str) -> bool {
        if self.curi + 2 >= self.tokens.len() {
            return false
        }
        self.tokens.get(self.curi + 2).as_slice() == is
    }
}

fn err_if_invalid_arg(s: &str) -> Result<(), String> {
    if !is_arg(s) {
        err!("Argument '{}' is not of the form ARG or <arg>.", s)
    } else {
        Ok(())
    }
}

// Tries to parse a long flag of the form '--flag[=arg]' and returns a tuple
// with the flag atom and whether there is an argument or not.
// If '=arg' exists and 'arg' isn't a valid argument, an error is returned.
fn parse_long_equal(flag: &str) -> Result<(Atom, Argument), String> {
    let rarg = regex!("^(?P<name>[^=]+)=(?P<arg>.+)$");
    match rarg.captures(flag) {
        None => Ok((as_long(flag), Zero)),
        Some(cap) => {
            let arg = cap.name("arg").to_string();
            if !is_arg(arg.as_slice()) {
                err!("Argument '{}' for flag '{}' is not in the \
                      form ARG or <arg>.", flag, arg)
            }
            Ok((as_long(cap.name("name")), One))
        }
    }
}

fn as_short(s: &str) -> Atom {
    Short(s.as_slice().char_at(1))
}
fn as_long(s: &str) -> Atom {
    Long(s.as_slice().slice_from(2).to_string())
}
fn as_arg(s: &str) -> Atom {
    if s.starts_with("<") && s.ends_with(">") {
        Positional(s.slice(1, s.len()-1).to_string())
    } else {
        Positional(s.to_string())
    }
}
fn as_cmd(s: &str) -> Atom {
    Command(s.to_string())
}

fn is_short(s: &str) -> bool { return regex!(r"^-[^-]+$").is_match(s) }
fn is_long(s: &str) -> bool { return regex!(r"^--\S+$").is_match(s) }
fn is_arg(s: &str) -> bool { return regex!(r"^(\p{Lu}+|<[^>]+>)$").is_match(s) }
fn is_cmd(s: &str) -> bool { return regex!(r"^(-|--|[^-]\S+)$").is_match(s) }

impl fmt::Show for Docopt {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::FormatError> {
        try!(writeln!(f, "====="))
        try!(writeln!(f, "Program: {}", self.program))
        try!(writeln!(f, "Option descriptions:"))
        for (k, v) in self.descs.iter() {
            try!(writeln!(f, "  '{}' => {}", k, v.borrow()))
        }
        try!(writeln!(f, "Usages:"))
        for pat in self.usages.iter() {
            try!(writeln!(f, "  {}", pat))
        }
        writeln!(f, "=====")
    }
}
<|endoftext|>