<commit_before>// Copyright 2013 The rust-pcre authors.
//
// 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.

extern mod extra;
extern mod rustc;
extern mod rustpkg;

use extra::time;
use rustc::driver::driver::host_triple;
use rustpkg::api;
use std::from_str::{from_str};
use std::io;
use std::option::{Option};
use std::os;
use std::run;
use std::str;
use std::util;
use std::vec;

struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split_iter('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl ToStr for Version {
    fn to_str(&self) -> ~str {
        fmt!("%u.%u", self.major, self.minor)
    }
}

impl Ord for Version {
    fn lt(&self, other: &Version) -> bool {
        self.major < other.major || (self.major == other.major && self.minor < other.minor)
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail2!("Package script error: Failed to `cd` into `{}`", path.to_str());
    }
}

fn do_install(args: ~[~str]) {
    let sysroot_arg = args[1].clone();
    let sysroot_path = Path(sysroot_arg);

    let pcre_libs = match os::getenv("PCRE_LIBS") {
        None            => {
            let pcre_config_output = run::process_output("pcre-config", [~"--libs"]);
            if pcre_config_output.status != 0 {
                fail!("Package script error: `pcre-config` failed");
            }
            let output_ptr = vec::raw::to_ptr(pcre_config_output.output);
            let output_len = pcre_config_output.output.len();
            let libs_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            os::setenv("PCRE_LIBS", libs_str);
            libs_str
        },
        Some(pcre_libs) => pcre_libs
    };
    // `pcre-config` adds a newline to the end, which we need to trim away because newlines
    // in link_args cause build issues.
    let trimmed_pcre_libs = pcre_libs.trim();
    debug!("PCRE_LIBS=\"%s\"", trimmed_pcre_libs);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.push("build").push(host_triple());
    if !os::path_exists(&target_build_path) {
        if !os::make_dir(&target_build_path, 0x1FF) {
            fail2!("Package script error: Failed to create target build directory `{}`", target_build_path.to_str());
        }
    }
    let out_path = target_build_path.push("pcre");
    if !os::path_exists(&out_path) {
        if !os::make_dir(&out_path, 0x1FF) {
            fail2!("Package script error: Failed to create output directory `{}`", out_path.to_str());
        }
    }

    let versioncheck_rs_path = out_path.push("versioncheck.rs");
    {
        let w = match io::file_writer(&versioncheck_rs_path, [io::Create]) {
            Err(err_str) => fail2!("Package script error: Failed to open `{}` for writing: {}", versioncheck_rs_path.to_str(), err_str),
            Ok(w)        => w
        };
        w.write_str("\
use std::c_str::{CString};
use std::libc::*;
use std::ptr;
use std::vec;

type options = c_int;
struct pcre;
struct pcre_extra;

#[link_args = \"" + trimmed_pcre_libs + "\"]
extern {
    static pcre_free: extern \"C\" fn(ptr: *c_void);

    fn pcre_compile(pattern: *c_char, options: options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *pcre;
    fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *c_char;
}

#[fixed_stack_segment]
#[inline(never)]
fn main () {
    unsafe {
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_owned();

        let pattern = \"^\\\\d+\\\\.\\\\d+\";
        do pattern.with_c_str |pattern_c_str| {
            let mut err: *c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if ptr::is_null(code) {
                if ptr::is_null(code) {
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() {
                        None          => fail2!(\"pcre_compile() failed at offset {}\", erroffset as uint),
                        Some(err_str) => fail2!(\"pcre_compile() failed at offset {}: {}\", erroffset as uint, err_str)
                    }
                }
            }
            assert!(ptr::is_not_null(code));

            let ovecsize = 1 * 3;
            let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);
            do version_str.with_c_str_unchecked |version_c_str| {
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, vec::raw::to_mut_ptr(ovector), ovecsize as c_int);
                if rc < 0 {
                    fail!(\"pcre_exec() failed\");
                }

                print(version_str.slice_to(ovector[1] as uint));
            }

            pcre_free(code as *c_void);
        }
    }
}
");
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rust_run_output = run::process_output("rust", [~"run", ~"versioncheck.rs"]);
    cd(&workspace_path);
    if rust_run_output.status != 0 {
        fail!("Package script error: `rust run versioncheck.rs` failed");
    }
    let output_ptr = vec::raw::to_ptr(rust_run_output.output);
    let output_len = rust_run_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.rsplit_iter('\n');
    let version_str: ~str = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_owned()
    };

    debug!("libpcre version %s", version_str);

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str) {
        None               => fail2!("Package script error: Failed to parse version string '{}'", version_str),
        Some(pcre_version) => pcre_version
    };
    if pcre_version < min_required_version {
        fail2!("Package script error: Found libpcre version {}, but at least version {} is required", version_str, min_required_version.to_str());
    }

    let src_path = workspace_path.push("src");

    // Output `src/pcre/detail/native.rs`
    let detail_src_path = src_path.push("pcre").push("detail");
    if !os::path_exists(&detail_src_path) {
        fail2!("Package script error: Source directory `{}` does not exist.", detail_src_path.to_str());
    }
    let native_rs_path = detail_src_path.push("native.rs");
    let native_rs_in_path = detail_src_path.push("native.rs.in");
    if !os::path_exists(&native_rs_in_path) {
        fail2!("Package script error: Source file `{}` does not exist.", native_rs_in_path.to_str());
    }
    {
        let r = match io::file_reader(&native_rs_in_path) {
            Err(err_str) => fail2!("Package script error: Failed to open `{}` for reading: {}", native_rs_in_path.to_str(), err_str),
            Ok(r)        => r
        };
        let w = match io::file_writer(&native_rs_path, [io::Create]) {
            Err(err_str) => fail2!("Package script error: Failed to open `{}` for writing: {}", native_rs_path.to_str(), err_str),
            Ok(w)        => w
        };
        w.write_line("// -*- buffer-read-only: t -*-");
        w.write_line("// Generated by " + args[0] + " on " + time::now().rfc822());
        w.write_char('\n');

        do r.each_line |line| -> bool {
            let substituted_line = str::replace(line, "@PCRE_LIBS@", trimmed_pcre_libs);
            w.write_line(substituted_line);
            true
        };
    }

    api::build_lib(sysroot_path, workspace_path, ~"pcre", rustpkg::version::ExactRevision(~"0.1"), Path("mod.rs"));
}

fn do_configs(args: ~[~str]) {
    util::ignore(args);
}

fn main() {
    let args = os::args();
    let args_len = args.len();

    if args_len < 2 {
        fail!("Package script requires a directory where rustc libraries live as the first argument");
    } else if args_len < 3 {
        fail!("Package script requires a command as the second argument");
    }

    if args[2] == ~"install" {
        do_install(args);
    } else if args[2] == ~"configs" {
        do_configs(args);
    } else {
        fail2!("Package script error: Unsupported command `{}`", args[2]);
    }
}
<commit_msg>Pass the Truncate flag when outputting files<commit_after>// Copyright 2013 The rust-pcre authors.
//
// 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.

extern mod extra;
extern mod rustc;
extern mod rustpkg;

use extra::time;
use rustc::driver::driver::host_triple;
use rustpkg::api;
use std::from_str::{from_str};
use std::io;
use std::option::{Option};
use std::os;
use std::run;
use std::str;
use std::util;
use std::vec;

struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split_iter('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl ToStr for Version {
    fn to_str(&self) -> ~str {
        fmt!("%u.%u", self.major, self.minor)
    }
}

impl Ord for Version {
    fn lt(&self, other: &Version) -> bool {
        self.major < other.major || (self.major == other.major && self.minor < other.minor)
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail2!("Package script error: Failed to `cd` into `{}`", path.to_str());
    }
}

fn do_install(args: ~[~str]) {
    let sysroot_arg = args[1].clone();
    let sysroot_path = Path(sysroot_arg);

    let pcre_libs = match os::getenv("PCRE_LIBS") {
        None            => {
            let pcre_config_output = run::process_output("pcre-config", [~"--libs"]);
            if pcre_config_output.status != 0 {
                fail!("Package script error: `pcre-config` failed");
            }
            let output_ptr = vec::raw::to_ptr(pcre_config_output.output);
            let output_len = pcre_config_output.output.len();
            let libs_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            os::setenv("PCRE_LIBS", libs_str);
            libs_str
        },
        Some(pcre_libs) => pcre_libs
    };
    // `pcre-config` adds a newline to the end, which we need to trim away because newlines
    // in link_args cause build issues.
    let trimmed_pcre_libs = pcre_libs.trim();
    debug!("PCRE_LIBS=\"%s\"", trimmed_pcre_libs);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.push("build").push(host_triple());
    if !os::path_exists(&target_build_path) {
        if !os::make_dir(&target_build_path, 0x1FF) {
            fail2!("Package script error: Failed to create target build directory `{}`", target_build_path.to_str());
        }
    }
    let out_path = target_build_path.push("pcre");
    if !os::path_exists(&out_path) {
        if !os::make_dir(&out_path, 0x1FF) {
            fail2!("Package script error: Failed to create output directory `{}`", out_path.to_str());
        }
    }

    let versioncheck_rs_path = out_path.push("versioncheck.rs");
    {
        let w = match io::file_writer(&versioncheck_rs_path, [io::Create]) {
            Err(err_str) => fail2!("Package script error: Failed to open `{}` for writing: {}", versioncheck_rs_path.to_str(), err_str),
            Ok(w)        => w
        };
        w.write_str("\
use std::c_str::{CString};
use std::libc::*;
use std::ptr;
use std::vec;

type options = c_int;
struct pcre;
struct pcre_extra;

#[link_args = \"" + trimmed_pcre_libs + "\"]
extern {
    static pcre_free: extern \"C\" fn(ptr: *c_void);

    fn pcre_compile(pattern: *c_char, options: options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *pcre;
    fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *c_char;
}

#[fixed_stack_segment]
#[inline(never)]
fn main () {
    unsafe {
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_owned();

        let pattern = \"^\\\\d+\\\\.\\\\d+\";
        do pattern.with_c_str |pattern_c_str| {
            let mut err: *c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if ptr::is_null(code) {
                if ptr::is_null(code) {
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() {
                        None          => fail2!(\"pcre_compile() failed at offset {}\", erroffset as uint),
                        Some(err_str) => fail2!(\"pcre_compile() failed at offset {}: {}\", erroffset as uint, err_str)
                    }
                }
            }
            assert!(ptr::is_not_null(code));

            let ovecsize = 1 * 3;
            let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);
            do version_str.with_c_str_unchecked |version_c_str| {
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, vec::raw::to_mut_ptr(ovector), ovecsize as c_int);
                if rc < 0 {
                    fail!(\"pcre_exec() failed\");
                }

                print(version_str.slice_to(ovector[1] as uint));
            }

            pcre_free(code as *c_void);
        }
    }
}
");
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rust_run_output = run::process_output("rust", [~"run", ~"versioncheck.rs"]);
    cd(&workspace_path);
    if rust_run_output.status != 0 {
        fail!("Package script error: `rust run versioncheck.rs` failed");
    }
    let output_ptr = vec::raw::to_ptr(rust_run_output.output);
    let output_len = rust_run_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.rsplit_iter('\n');
    let version_str: ~str = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_owned()
    };

    debug!("libpcre version %s", version_str);

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str) {
        None               => fail2!("Package script error: Failed to parse version string '{}'", version_str),
        Some(pcre_version) => pcre_version
    };
    if pcre_version < min_required_version {
        fail2!("Package script error: Found libpcre version {}, but at least version {} is required", version_str, min_required_version.to_str());
    }

    let src_path = workspace_path.push("src");

    // Output `src/pcre/detail/native.rs`
    let detail_src_path = src_path.push("pcre").push("detail");
    if !os::path_exists(&detail_src_path) {
        fail2!("Package script error: Source directory `{}` does not exist.", detail_src_path.to_str());
    }
    let native_rs_path = detail_src_path.push("native.rs");
    let native_rs_in_path = detail_src_path.push("native.rs.in");
    if !os::path_exists(&native_rs_in_path) {
        fail2!("Package script error: Source file `{}` does not exist.", native_rs_in_path.to_str());
    }
    {
        let r = match io::file_reader(&native_rs_in_path) {
            Err(err_str) => fail2!("Package script error: Failed to open `{}` for reading: {}", native_rs_in_path.to_str(), err_str),
            Ok(r)        => r
        };
        let w = match io::file_writer(&native_rs_path, [io::Create, io::Truncate]) {
            Err(err_str) => fail2!("Package script error: Failed to open `{}` for writing: {}", native_rs_path.to_str(), err_str),
            Ok(w)        => w
        };
        w.write_line("// -*- buffer-read-only: t -*-");
        w.write_line("// Generated by " + args[0] + " on " + time::now().rfc822());
        w.write_char('\n');

        do r.each_line |line| -> bool {
            let substituted_line = str::replace(line, "@PCRE_LIBS@", trimmed_pcre_libs);
            w.write_line(substituted_line);
            true
        };
    }

    api::build_lib(sysroot_path, workspace_path, ~"pcre", rustpkg::version::ExactRevision(~"0.1"), Path("mod.rs"));
}

fn do_configs(args: ~[~str]) {
    util::ignore(args);
}

fn main() {
    let args = os::args();
    let args_len = args.len();

    if args_len < 2 {
        fail!("Package script requires a directory where rustc libraries live as the first argument");
    } else if args_len < 3 {
        fail!("Package script requires a command as the second argument");
    }

    if args[2] == ~"install" {
        do_install(args);
    } else if args[2] == ~"configs" {
        do_configs(args);
    } else {
        fail2!("Package script error: Unsupported command `{}`", args[2]);
    }
}
<|endoftext|>


<commit_before>#[feature(globs)];

use std::str;
use std::rt::io;
use std::rt::io::file;
use std::rt::io::{Reader,Writer};
use std::os;
use peg::{compile_grammar};
use codegen::RustWriter;

mod peg;
mod codegen;
mod grammar;

fn main() {
	let args = os::args();
	let source = str::from_utf8(file::open(&Path::new(args[1]), io::Open, io::Read).read_to_end());
	let grammar_def = grammar::grammar(source).unwrap();
	let w = RustWriter::new(io::stdout());
	compile_grammar(&w, grammar_def);
}
<commit_msg>Update for fs changes (again)<commit_after>#[feature(globs)];
#[feature(managed_boxes)];

use std::str;
use std::rt::io::stdout;
use std::rt::io::fs::File;
use std::os;
use peg::{compile_grammar};
use codegen::RustWriter;

mod peg;
mod codegen;
mod grammar;

fn main() {
	let args = os::args();
	let source = str::from_utf8(File::open(&Path::new(args[1])).read_to_end());
	let grammar_def = grammar::grammar(source).unwrap();
	let w = RustWriter::new(stdout());
	compile_grammar(&w, grammar_def);
}
<|endoftext|>


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

//! Module containing TaskPriority types and trait impls

use serde::Serialize;
use serde::ser::Serializer;
use serde::de::Deserialize;
use serde::de::Deserializer;
use serde::Error;
use serde::de::Visitor;

use std::fmt::Formatter;
use std::fmt::Result as FmtResult;

/// Enum for the priorities taskwarrior supports.
#[derive(Debug, Clone, PartialEq)]
pub enum TaskPriority {
    /// Low prio for a Task
    Low,

    /// Medium prio for a Task
    Medium,

    /// High prio for a Task
    High,
}

impl Serialize for TaskPriority {

    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        serializer.serialize_str(
            match self {
                &TaskPriority::Low    => "L",
                &TaskPriority::Medium => "M",
                &TaskPriority::High   => "H",
            }
        )
    }

}

impl Deserialize for TaskPriority {

    fn deserialize<D>(deserializer: D) -> Result<TaskPriority, D::Error>
        where D: Deserializer
    {
        struct TaskPriorityVisitor;

        impl Visitor for TaskPriorityVisitor {
            type Value = TaskPriority;

            fn expecting(&self, fmt: &mut Formatter) -> FmtResult {
                write!(fmt, "one of 'L', 'M', 'H'")
            }

            fn visit_str<E>(self, value: &str) -> Result<TaskPriority, E>
                where E: Error
            {
                match value {
                    "L" => Ok(TaskPriority::Low),
                    "M" => Ok(TaskPriority::Medium),
                    "H" => Ok(TaskPriority::High),
                    _ => Err(Error::custom("expected one of 'L', 'M', 'H'")),
                }
            }
        }

        deserializer.deserialize(TaskPriorityVisitor)
    }
}

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

//! Module containing TaskPriority types and trait impls

use serde::Serialize;
use serde::ser::Serializer;
use serde::de::Deserialize;
use serde::de::Deserializer;
use serde::de::Error as DeError;
use serde::de::Visitor;

use std::fmt::Formatter;
use std::fmt::Result as FmtResult;

/// Enum for the priorities taskwarrior supports.
#[derive(Debug, Clone, PartialEq)]
pub enum TaskPriority {
    /// Low prio for a Task
    Low,

    /// Medium prio for a Task
    Medium,

    /// High prio for a Task
    High,
}

impl Serialize for TaskPriority {

    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        serializer.serialize_str(
            match self {
                &TaskPriority::Low    => "L",
                &TaskPriority::Medium => "M",
                &TaskPriority::High   => "H",
            }
        )
    }

}

impl Deserialize for TaskPriority {

    fn deserialize<D>(deserializer: D) -> Result<TaskPriority, D::Error>
        where D: Deserializer
    {
        struct TaskPriorityVisitor;

        impl Visitor for TaskPriorityVisitor {
            type Value = TaskPriority;

            fn expecting(&self, fmt: &mut Formatter) -> FmtResult {
                write!(fmt, "one of 'L', 'M', 'H'")
            }

            fn visit_str<E>(self, value: &str) -> Result<TaskPriority, E>
                where E: DeError
            {
                match value {
                    "L" => Ok(TaskPriority::Low),
                    "M" => Ok(TaskPriority::Medium),
                    "H" => Ok(TaskPriority::High),
                    _ => Err(DeError::custom("expected one of 'L', 'M', 'H'")),
                }
            }
        }

        deserializer.deserialize(TaskPriorityVisitor)
    }
}

<|endoftext|>


<commit_before>mod secret;
mod config_map;
mod node;
mod deployment;
mod network_policy;
mod pod;

pub use self::secret::*;
pub use self::config_map::*;
pub use self::node::*;
pub use self::deployment::*;
pub use self::network_policy::*;
pub use self::pod::*;

use chrono::{DateTime, Utc};
use serde::Serialize;
use serde::de::DeserializeOwned;
use std::fmt;
use std::collections::BTreeMap;

#[derive(Serialize, Deserialize, Debug)]
pub enum Kind { Deployment, ConfigMap, NetworkPolicy, Node, Pod, Secret, Service }

impl Kind {
    pub fn route(&self) -> &'static str {
        match *self {
            Kind::ConfigMap => "configmaps",
            Kind::Deployment => "deployments",
            Kind::NetworkPolicy => "networkpolicies",
            Kind::Node => "nodes",
            Kind::Pod => "pods",
            Kind::Secret => "secrets",
            Kind::Service => "services",
        }
    }
}

// Debug output of Kind is exactly what we want for Display
impl fmt::Display for Kind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

pub trait Resource: Serialize + DeserializeOwned {
    fn kind() -> Kind;
    fn default_namespace() -> Option<&'static str> {
        Some("default")
    }
    fn api() -> &'static str {
        "/api/v1"
    }

}

pub trait ListableResource: Resource {
    type ListResponse: DeserializeOwned;
    fn list_items(response: Self::ListResponse) -> Vec<Self>;
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Status {
    pub kind: String,
    pub api_version: String,
    pub metadata: Metadata,
    pub status: String,
    pub message: String,
}

#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct Metadata {
    pub name: Option<String>,
    pub namespace: Option<String>,
    pub uid: Option<String>,
    pub creation_timestamp: Option<DateTime<Utc>>,
    pub annotations: Option<BTreeMap<String, String>>,
    pub labels: Option<BTreeMap<String, String>>,
}

#[derive(Clone, Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct ListQuery {
    #[serde(skip_serializing_if = "Option::is_none")]
    field_selector: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    label_selector: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    resource_version: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    timeout_seconds: Option<String>,
}

impl ListQuery {
    pub fn field_selector<S: Into<String>>(&self, field_selector: S) -> Self {
        let mut new = self.clone();
        new.field_selector = Some(field_selector.into());
        new
    }
    pub fn label_selector<S: Into<String>>(&self, label_selector: S) -> Self {
        let mut new = self.clone();
        new.label_selector = Some(label_selector.into());
        new
    }
    pub fn resource_version<S: Into<String>>(&self, resource_version: S) -> Self {
        let mut new = self.clone();
        new.resource_version = Some(resource_version.into());
        new
    }
    pub fn timeout_seconds(&self, timeout_seconds: u32) -> Self {
        let mut new = self.clone();
        new.timeout_seconds = Some(timeout_seconds.to_string());
        new
    }
}<commit_msg>fix field_selector<commit_after>mod secret;
mod config_map;
mod node;
mod deployment;
mod network_policy;
mod pod;

pub use self::secret::*;
pub use self::config_map::*;
pub use self::node::*;
pub use self::deployment::*;
pub use self::network_policy::*;
pub use self::pod::*;

use chrono::{DateTime, Utc};
use serde::Serialize;
use serde::de::DeserializeOwned;
use std::fmt;
use std::collections::BTreeMap;
use std::borrow::Borrow;

#[derive(Serialize, Deserialize, Debug)]
pub enum Kind { Deployment, ConfigMap, NetworkPolicy, Node, Pod, Secret, Service }

impl Kind {
    pub fn route(&self) -> &'static str {
        match *self {
            Kind::ConfigMap => "configmaps",
            Kind::Deployment => "deployments",
            Kind::NetworkPolicy => "networkpolicies",
            Kind::Node => "nodes",
            Kind::Pod => "pods",
            Kind::Secret => "secrets",
            Kind::Service => "services",
        }
    }
}

// Debug output of Kind is exactly what we want for Display
impl fmt::Display for Kind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

pub trait Resource: Serialize + DeserializeOwned {
    fn kind() -> Kind;
    fn default_namespace() -> Option<&'static str> {
        Some("default")
    }
    fn api() -> &'static str {
        "/api/v1"
    }

}

pub trait ListableResource: Resource {
    type ListResponse: DeserializeOwned;
    fn list_items(response: Self::ListResponse) -> Vec<Self>;
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Status {
    pub kind: String,
    pub api_version: String,
    pub metadata: Metadata,
    pub status: String,
    pub message: String,
}

#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct Metadata {
    pub name: Option<String>,
    pub namespace: Option<String>,
    pub uid: Option<String>,
    pub creation_timestamp: Option<DateTime<Utc>>,
    pub annotations: Option<BTreeMap<String, String>>,
    pub labels: Option<BTreeMap<String, String>>,
}

#[derive(Clone, Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct ListQuery {
    #[serde(skip_serializing_if = "Option::is_none")]
    field_selector: Option<BTreeMap<String, String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    label_selector: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    resource_version: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    timeout_seconds: Option<String>,
}

impl ListQuery {
    pub fn field_selector<B, K, V>(mut self, field_selector: B) -> Self
    where
        B: Borrow<(K, V)>,
        K: AsRef<str>,
        V: AsRef<str>,
    {
        let f = field_selector.borrow();
        let (k, v) = (f.0.as_ref(), f.1.as_ref());
        match self.field_selector {
            Some(ref mut m) => {
                m.insert(k.to_owned(), v.to_owned());
            }
            None => {
                let mut m = BTreeMap::new();
                m.insert(k.to_owned(), v.to_owned());
                self.field_selector = Some(m);
            }
        }
        self
    }
    pub fn label_selector<S: Into<String>>(&self, label_selector: S) -> Self {
        let mut new = self.clone();
        new.label_selector = Some(label_selector.into());
        new
    }
    pub fn resource_version<S: Into<String>>(&self, resource_version: S) -> Self {
        let mut new = self.clone();
        new.resource_version = Some(resource_version.into());
        new
    }
    pub fn timeout_seconds(&self, timeout_seconds: u32) -> Self {
        let mut new = self.clone();
        new.timeout_seconds = Some(timeout_seconds.to_string());
        new
    }
}<|endoftext|>


<commit_before>use middleware::{Middleware, Continue, MiddlewareResult};
use hyper::uri::RequestUri::AbsolutePath;
use request::Request;
use response::Response;
use router::HttpRouter;
use hyper::method::Method;
use hyper::status::StatusCode;
use router::{Matcher, FORMAT_PARAM};

/// A Route is the basic data structure that stores both the path
/// and the handler that gets executed for the route.
/// The path can contain variable pattern such as `user/:userid/invoices`
pub struct Route {
    pub method: Method,
    pub handler: Box<Middleware + Send + Sync + 'static>,
    matcher: Matcher
}

/// A RouteResult is what the router returns when `match_route` is called.
/// It contains the matched `route` and also a `params` property holding
/// a HashMap with the keys being the variable names and the value being the
/// evaluated string
pub struct RouteResult<'a> {
    pub route: &'a Route,
    params: Vec<(String, String)>
}

impl<'a> RouteResult<'a> {
    pub fn param(&self, key: &str) -> &str {
        for &(ref k, ref v) in &self.params {
            if k == &key {
                return &v[..]
            }
        }

        // FIXME: should have a default format
        if key == FORMAT_PARAM { return "" }
        panic!("unknown param: {}", key)
    }
}

/// The Router's job is it to hold routes and to resolve them later against
/// concrete URLs. The router is also a regular middleware and needs to be
/// added to the middleware stack with `server.utilize(router)`.
pub struct Router {
    routes: Vec<Route>,
}

impl Router {
    pub fn new () -> Router {
        Router {
            routes: Vec::new()
        }
    }

    pub fn match_route<'a>(&'a self, method: &Method, path: &str) -> Option<RouteResult<'a>> {
        // Strip off the querystring when matching a route
        let path = path.splitn(2, '?').next().unwrap();

        self.routes
            .iter()
            .find(|item| item.method == *method && item.matcher.is_match(path))
            .map(|route|
                RouteResult {
                    params: extract_params(route, path),
                    route: route
                }
            )
    }
}

fn extract_params(route: &Route, path: &str) -> Vec<(String, String)> {
    match route.matcher.captures(path) {
        Some(captures) => {
            captures.iter_named()
                    .filter_map(|(name, subcap)| {
                        subcap.map(|cap| (name.to_string(), cap.to_string()))
                    })
                    .collect()
        }
        None => vec![]
    }
}

impl HttpRouter for Router {
    fn add_route<M: Into<Matcher>, H: Middleware>(&mut self, method: Method, matcher: M, handler: H) {
        let route = Route {
            matcher: matcher.into(),
            method: method,
            handler: Box::new(handler),
        };

        self.routes.push(route);
    }
}

impl Middleware for Router {
    fn invoke<'a, 'b>(&'a self, req: &mut Request<'b, 'a, 'b>, mut res: Response<'a>)
                        -> MiddlewareResult<'a> {
        debug!("Router::invoke for '{:?}'", req.origin.uri);
        let route_result = match req.origin.uri {
            AbsolutePath(ref url) => self.match_route(&req.origin.method, &**url),
            _ => None
        };
        debug!("route_result.route.path: {:?}", route_result.as_ref().map(|r| r.route.matcher.path()));

        match route_result {
            Some(route_result) => {
                res.set_status(StatusCode::Ok);
                let handler = &route_result.route.handler;
                req.route_result = Some(route_result);
                handler.invoke(req, res)
            },
            None => Ok(Continue(res))
        }
    }
}

#[test]
fn creates_regex_with_captures () {
    let matcher: Matcher = "foo/:uid/bar/:groupid".into();
    let caps = matcher.captures("foo/4711/bar/5490").unwrap();

    assert_eq!(matcher.path(), "foo/:uid/bar/:groupid(\\.:format)?");
    assert_eq!(caps.at(1).unwrap(), "4711");
    assert_eq!(caps.at(2).unwrap(), "5490");

    let matcher: Matcher = "foo/*/:uid/bar/:groupid".into();
    let caps = matcher.captures("foo/test/4711/bar/5490").unwrap();

    assert_eq!(matcher.path(), "foo/*/:uid/bar/:groupid(\\.:format)?");
    assert_eq!(caps.at(1).unwrap(), "4711");
    assert_eq!(caps.at(2).unwrap(), "5490");

    let matcher: Matcher = "foo/**/:uid/bar/:groupid".into();
    let caps = matcher.captures("foo/test/another/4711/bar/5490").unwrap();

    assert_eq!(matcher.path(), "foo/**/:uid/bar/:groupid(\\.:format)?");
    assert_eq!(caps.at(1).unwrap(), "4711");
    assert_eq!(caps.at(2).unwrap(), "5490");

    let matcher: Matcher = "foo/**/:format/bar/:groupid".into();
    let caps = matcher.captures("foo/test/another/4711/bar/5490").unwrap();

    assert_eq!(matcher.path(), "foo/**/:format/bar/:groupid");
    assert_eq!(caps.name("format").unwrap(), "4711");
    assert_eq!(caps.name("groupid").unwrap(), "5490");
}

#[test]
fn creates_valid_regex_for_routes () {
    let regex1: Matcher = "foo/:uid/bar/:groupid".into();
    let regex2: Matcher = "foo/*/bar".into();
    let regex3: Matcher = "foo/**/bar".into();

    assert_eq!(regex1.is_match("foo/4711/bar/5490"), true);
    assert_eq!(regex1.is_match("foo/4711/bar/5490?foo=true&bar=false"), true);
    assert_eq!(regex1.is_match("foo/4711/bar"), false);
    assert_eq!(regex1.is_match("foo/4711/bar?foo=true&bar=false"), false);
    assert_eq!(regex1.is_match("foo/4711/bar/test%20spacing"), true);
    assert_eq!(regex1.is_match("foo/4711/bar/5281?foo=test%20spacing&bar=false"), true);

    assert_eq!(regex2.is_match("foo/4711/bar"), true);
    assert_eq!(regex2.is_match("foo/4711/barr"), false);
    assert_eq!(regex2.is_match("foo/4711/bar?foo=true&bar=false"), true);
    assert_eq!(regex2.is_match("foo/4711/4712/bar"), false);
    assert_eq!(regex2.is_match("foo/4711/4712/bar?foo=true&bar=false"), false);

    assert_eq!(regex3.is_match("foo/4711/bar"), true);
    assert_eq!(regex3.is_match("foo/4711/bar?foo=true&bar=false"), true);
    assert_eq!(regex3.is_match("foo/4711/4712/bar"), true);
    assert_eq!(regex3.is_match("foo/4711/4712/bar?foo=true&bar=false"), true);

    //ensure that this works with commas too
    assert_eq!(regex1.is_match("foo/4711/bar/5490,1234"), true);
    assert_eq!(regex1.is_match("foo/4711/bar/5490,1234?foo=true&bar=false"), true);
    assert_eq!(regex1.is_match("foo/4711/bar"), false);
    assert_eq!(regex1.is_match("foo/4711/bar?foo=1,2,3&bar=false"), false);
}

#[test]
fn can_match_var_routes () {
    let route_store = &mut Router::new();

    route_store.add_route(Method::Get, "/foo/:userid", middleware! { "hello from foo" });
    route_store.add_route(Method::Get, "/bar", middleware! { "hello from foo" });
    route_store.add_route(Method::Get, "/file/:format/:file", middleware! { "hello from foo" });

    let route_result = route_store.match_route(&Method::Get, "/foo/4711").unwrap();
    assert_eq!(route_result.param("userid"), "4711");

    let route_result = route_store.match_route(&Method::Get, "/bar/4711");
    assert!(route_result.is_none());

    let route_result = route_store.match_route(&Method::Get, "/foo");
    assert!(route_result.is_none());

    // ensure that this will work with commas too
    let route_result = route_store.match_route(&Method::Get, "/foo/123,456");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("userid"), "123,456");

    // ensure that this will work with spacing too
    let route_result = route_store.match_route(&Method::Get, "/foo/John%20Doe");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("userid"), "John%20Doe");

    // check for optional format param
    let route_result = route_store.match_route(&Method::Get, "/foo/John%20Doe.json");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("userid"), "John%20Doe");
    assert_eq!(route_result.param("format"), "json");

    // ensure format works with queries
    let route_result = route_store.match_route(&Method::Get,
    "/foo/5490,1234.csv?foo=true&bar=false");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    // NOTE: `.param` doesn't cover query params currently
    assert_eq!(route_result.param("userid"), "5490,1234");
    assert_eq!(route_result.param("format"), "csv");

    // ensure format works with no format
    let route_result = route_store.match_route(&Method::Get,
                                               "/foo/5490,1234?foo=true&bar=false").unwrap();

    assert_eq!(route_result.param("format"), "");

    // ensure format works if defined by user
    let route_result = route_store.match_route(&Method::Get, "/file/markdown/something?foo=true");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    // NOTE: `.param` doesn't cover query params currently
    assert_eq!(route_result.param("file"), "something");
    assert_eq!(route_result.param("format"), "markdown");
}

#[test]
fn params_lifetime() {
    let route_store = &mut Router::new();
    let handler = middleware! { "hello from foo" };

    route_store.add_route(Method::Get, "/file/:format/:file", handler);

    let route_result = route_store.match_route(&Method::Get, "/file/txt/manual");
    assert!(route_result.is_some());

    // Ensure two params can live without borrowck problems
    let route_result = route_result.unwrap();
    let format = route_result.param("format");
    let file = route_result.param("file");
    assert_eq!(format, "txt");
    assert_eq!(file, "manual");
}

#[test]
fn regex_path() {
    use regex::Regex;

    let route_store = &mut Router::new();

    let regex = Regex::new("/(foo|bar)").unwrap();
    route_store.add_route(Method::Get, regex, middleware! { "hello from foo" });

    let route_result = route_store.match_route(&Method::Get, "/foo");
    assert!(route_result.is_some());

    let route_result = route_store.match_route(&Method::Get, "/bar");
    assert!(route_result.is_some());

    let route_result = route_store.match_route(&Method::Get, "/bar?foo");
    assert!(route_result.is_some());

    let route_result = route_store.match_route(&Method::Get, "/baz");
    assert!(route_result.is_none());
}

#[test]
fn regex_path_named() {
    use regex::Regex;

    let route_store = &mut Router::new();

    let regex = Regex::new("/(?Pfoo|bar)/b").unwrap();
    route_store.add_route(Method::Get, regex, middleware! { "hello from foo" });

    let route_result = route_store.match_route(&Method::Get, "/foo/b");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("a"), "foo");

    let route_result = route_store.match_route(&Method::Get, "/bar/b");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("a"), "bar");

    let route_result = route_store.match_route(&Method::Get, "/baz/b");
    assert!(route_result.is_none());
}

#[test]
fn ignores_querystring() {
    use regex::Regex;

    let route_store = &mut Router::new();

    let regex = Regex::new("/(?Pfoo|bar)/b").unwrap();
    route_store.add_route(Method::Get, regex, middleware! { "hello from foo" });
    route_store.add_route(Method::Get, "/:foo", middleware! { "hello from foo" });

    // Should ignore the querystring
    let route_result = route_store.match_route(&Method::Get, "/moo?foo");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("foo"), "moo");

    let route_result = route_store.match_route(&Method::Get, "/bar/b?foo");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("a"), "bar");
}
<commit_msg>test(router): enhance matcher tests<commit_after>use middleware::{Middleware, Continue, MiddlewareResult};
use hyper::uri::RequestUri::AbsolutePath;
use request::Request;
use response::Response;
use router::HttpRouter;
use hyper::method::Method;
use hyper::status::StatusCode;
use router::{Matcher, FORMAT_PARAM};

/// A Route is the basic data structure that stores both the path
/// and the handler that gets executed for the route.
/// The path can contain variable pattern such as `user/:userid/invoices`
pub struct Route {
    pub method: Method,
    pub handler: Box<Middleware + Send + Sync + 'static>,
    matcher: Matcher
}

/// A RouteResult is what the router returns when `match_route` is called.
/// It contains the matched `route` and also a `params` property holding
/// a HashMap with the keys being the variable names and the value being the
/// evaluated string
pub struct RouteResult<'a> {
    pub route: &'a Route,
    params: Vec<(String, String)>
}

impl<'a> RouteResult<'a> {
    pub fn param(&self, key: &str) -> &str {
        for &(ref k, ref v) in &self.params {
            if k == &key {
                return &v[..]
            }
        }

        // FIXME: should have a default format
        if key == FORMAT_PARAM { return "" }
        panic!("unknown param: {}", key)
    }
}

/// The Router's job is it to hold routes and to resolve them later against
/// concrete URLs. The router is also a regular middleware and needs to be
/// added to the middleware stack with `server.utilize(router)`.
pub struct Router {
    routes: Vec<Route>,
}

impl Router {
    pub fn new () -> Router {
        Router {
            routes: Vec::new()
        }
    }

    pub fn match_route<'a>(&'a self, method: &Method, path: &str) -> Option<RouteResult<'a>> {
        // Strip off the querystring when matching a route
        let path = path.splitn(2, '?').next().unwrap();

        self.routes
            .iter()
            .find(|item| item.method == *method && item.matcher.is_match(path))
            .map(|route|
                RouteResult {
                    params: extract_params(route, path),
                    route: route
                }
            )
    }
}

fn extract_params(route: &Route, path: &str) -> Vec<(String, String)> {
    match route.matcher.captures(path) {
        Some(captures) => {
            captures.iter_named()
                    .filter_map(|(name, subcap)| {
                        subcap.map(|cap| (name.to_string(), cap.to_string()))
                    })
                    .collect()
        }
        None => vec![]
    }
}

impl HttpRouter for Router {
    fn add_route<M: Into<Matcher>, H: Middleware>(&mut self, method: Method, matcher: M, handler: H) {
        let route = Route {
            matcher: matcher.into(),
            method: method,
            handler: Box::new(handler),
        };

        self.routes.push(route);
    }
}

impl Middleware for Router {
    fn invoke<'a, 'b>(&'a self, req: &mut Request<'b, 'a, 'b>, mut res: Response<'a>)
                        -> MiddlewareResult<'a> {
        debug!("Router::invoke for '{:?}'", req.origin.uri);
        let route_result = match req.origin.uri {
            AbsolutePath(ref url) => self.match_route(&req.origin.method, &**url),
            _ => None
        };
        debug!("route_result.route.path: {:?}", route_result.as_ref().map(|r| r.route.matcher.path()));

        match route_result {
            Some(route_result) => {
                res.set_status(StatusCode::Ok);
                let handler = &route_result.route.handler;
                req.route_result = Some(route_result);
                handler.invoke(req, res)
            },
            None => Ok(Continue(res))
        }
    }
}

#[test]
fn creates_regex_with_captures () {
    let matcher: Matcher = "foo/:uid/bar/:groupid".into();
    let caps = matcher.captures("foo/4711/bar/5490").unwrap();

    assert_eq!(matcher.path(), "foo/:uid/bar/:groupid(\\.:format)?");
    assert_eq!(caps.at(1).unwrap(), "4711");
    assert_eq!(caps.at(2).unwrap(), "5490");

    let matcher: Matcher = "foo/*/:uid/bar/:groupid".into();
    let caps = matcher.captures("foo/test/4711/bar/5490").unwrap();

    assert_eq!(matcher.path(), "foo/*/:uid/bar/:groupid(\\.:format)?");
    assert_eq!(caps.at(1).unwrap(), "4711");
    assert_eq!(caps.at(2).unwrap(), "5490");

    let matcher: Matcher = "foo/**/:uid/bar/:groupid".into();
    let caps = matcher.captures("foo/test/another/4711/bar/5490").unwrap();

    assert_eq!(matcher.path(), "foo/**/:uid/bar/:groupid(\\.:format)?");
    assert_eq!(caps.at(1).unwrap(), "4711");
    assert_eq!(caps.at(2).unwrap(), "5490");

    let matcher: Matcher = "foo/**/:format/bar/:groupid".into();
    let caps = matcher.captures("foo/test/another/4711/bar/5490").unwrap();

    assert_eq!(matcher.path(), "foo/**/:format/bar/:groupid");
    assert_eq!(caps.name("format").unwrap(), "4711");
    assert_eq!(caps.name("groupid").unwrap(), "5490");
}

#[test]
fn creates_valid_regex_for_routes () {
    let regex1: Matcher = "foo/:uid/bar/:groupid".into();
    let regex2: Matcher = "foo/*/bar".into();
    let regex3: Matcher = "foo/**/bar".into();

    assert_eq!(regex1.is_match("foo/4711/bar/5490"), true);
    assert_eq!(regex1.is_match("foo/4711/bar/5490?foo=true&bar=false"), true);
    assert_eq!(regex1.is_match("foo/4711/bar"), false);
    assert_eq!(regex1.is_match("foo/4711/bar?foo=true&bar=false"), false);
    assert_eq!(regex1.is_match("foo/4711/bar/test%20spacing"), true);
    assert_eq!(regex1.is_match("foo/4711/bar/5281?foo=test%20spacing&bar=false"), true);
    assert_eq!(regex1.is_match("foo/alice/bar/bob"), true);

    assert_eq!(regex2.is_match("foo/4711/bar"), true);
    assert_eq!(regex2.is_match("foo/4711/barr"), false);
    assert_eq!(regex2.is_match("foo/4711/bar?foo=true&bar=false"), true);
    assert_eq!(regex2.is_match("foo/4711/4712/bar"), false);
    assert_eq!(regex2.is_match("foo/4711/4712/bar?foo=true&bar=false"), false);
    assert_eq!(regex2.is_match("foo/alice/bar/bob"), false);
    assert_eq!(regex2.is_match("foo/alice/bar"), true);

    assert_eq!(regex3.is_match("foo/4711/bar"), true);
    assert_eq!(regex3.is_match("foo/4711/bar?foo=true&bar=false"), true);
    assert_eq!(regex3.is_match("foo/4711/4712/bar"), true);
    assert_eq!(regex3.is_match("foo/4711/4712/bar?foo=true&bar=false"), true);
    assert_eq!(regex3.is_match("foo/alice/bar/bob"), false);

    //ensure that this works with commas too
    assert_eq!(regex1.is_match("foo/4711/bar/5490,1234"), true);
    assert_eq!(regex1.is_match("foo/4711/bar/5490,1234?foo=true&bar=false"), true);
    assert_eq!(regex1.is_match("foo/4711/bar"), false);
    assert_eq!(regex1.is_match("foo/4711/bar?foo=1,2,3&bar=false"), false);

    //ensure that this works with hyphens too
    assert_eq!(regex1.is_match("foo/alice-anne/bar/bob-gates"), true);

}

#[test]
fn can_match_var_routes () {
    let route_store = &mut Router::new();

    route_store.add_route(Method::Get, "/foo/:userid", middleware! { "hello from foo" });
    route_store.add_route(Method::Get, "/bar", middleware! { "hello from foo" });
    route_store.add_route(Method::Get, "/file/:format/:file", middleware! { "hello from foo" });

    let route_result = route_store.match_route(&Method::Get, "/foo/4711").unwrap();
    assert_eq!(route_result.param("userid"), "4711");

    let route_result = route_store.match_route(&Method::Get, "/bar/4711");
    assert!(route_result.is_none());

    let route_result = route_store.match_route(&Method::Get, "/foo");
    assert!(route_result.is_none());

    // ensure that this will work with commas too
    let route_result = route_store.match_route(&Method::Get, "/foo/123,456");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("userid"), "123,456");

    // ensure that this will work with spacing too
    let route_result = route_store.match_route(&Method::Get, "/foo/John%20Doe");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("userid"), "John%20Doe");

    // check for optional format param
    let route_result = route_store.match_route(&Method::Get, "/foo/John%20Doe.json");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("userid"), "John%20Doe");
    assert_eq!(route_result.param("format"), "json");

    // ensure format works with queries
    let route_result = route_store.match_route(&Method::Get,
    "/foo/5490,1234.csv?foo=true&bar=false");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    // NOTE: `.param` doesn't cover query params currently
    assert_eq!(route_result.param("userid"), "5490,1234");
    assert_eq!(route_result.param("format"), "csv");

    // ensure format works with no format
    let route_result = route_store.match_route(&Method::Get,
                                               "/foo/5490,1234?foo=true&bar=false").unwrap();

    assert_eq!(route_result.param("format"), "");

    // ensure format works if defined by user
    let route_result = route_store.match_route(&Method::Get, "/file/markdown/something?foo=true");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    // NOTE: `.param` doesn't cover query params currently
    assert_eq!(route_result.param("file"), "something");
    assert_eq!(route_result.param("format"), "markdown");
}

#[test]
fn params_lifetime() {
    let route_store = &mut Router::new();
    let handler = middleware! { "hello from foo" };

    route_store.add_route(Method::Get, "/file/:format/:file", handler);

    let route_result = route_store.match_route(&Method::Get, "/file/txt/manual");
    assert!(route_result.is_some());

    // Ensure two params can live without borrowck problems
    let route_result = route_result.unwrap();
    let format = route_result.param("format");
    let file = route_result.param("file");
    assert_eq!(format, "txt");
    assert_eq!(file, "manual");
}

#[test]
fn regex_path() {
    use regex::Regex;

    let route_store = &mut Router::new();

    let regex = Regex::new("/(foo|bar)").unwrap();
    route_store.add_route(Method::Get, regex, middleware! { "hello from foo" });

    let route_result = route_store.match_route(&Method::Get, "/foo");
    assert!(route_result.is_some());

    let route_result = route_store.match_route(&Method::Get, "/bar");
    assert!(route_result.is_some());

    let route_result = route_store.match_route(&Method::Get, "/bar?foo");
    assert!(route_result.is_some());

    let route_result = route_store.match_route(&Method::Get, "/baz");
    assert!(route_result.is_none());
}

#[test]
fn regex_path_named() {
    use regex::Regex;

    let route_store = &mut Router::new();

    let regex = Regex::new("/(?Pfoo|bar)/b").unwrap();
    route_store.add_route(Method::Get, regex, middleware! { "hello from foo" });

    let route_result = route_store.match_route(&Method::Get, "/foo/b");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("a"), "foo");

    let route_result = route_store.match_route(&Method::Get, "/bar/b");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("a"), "bar");

    let route_result = route_store.match_route(&Method::Get, "/baz/b");
    assert!(route_result.is_none());
}

#[test]
fn ignores_querystring() {
    use regex::Regex;

    let route_store = &mut Router::new();

    let regex = Regex::new("/(?Pfoo|bar)/b").unwrap();
    route_store.add_route(Method::Get, regex, middleware! { "hello from foo" });
    route_store.add_route(Method::Get, "/:foo", middleware! { "hello from foo" });

    // Should ignore the querystring
    let route_result = route_store.match_route(&Method::Get, "/moo?foo");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("foo"), "moo");

    let route_result = route_store.match_route(&Method::Get, "/bar/b?foo");
    assert!(route_result.is_some());

    let route_result = route_result.unwrap();
    assert_eq!(route_result.param("a"), "bar");
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};

/// Class of types that can be loaded from
pub trait Load: Sized {
  type Args;

  fn load<P>(path: P, args: Self::Args) -> Result<Self, LoadError> where P: AsRef<Path>;
  fn reload<P>(&self, path :P) -> Result<Self, LoadError> where P: AsRef<Path>;
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LoadError {
  FileNotFound(PathBuf, String),
  ParseFailed(String),
  ConversionFailed(String)
}

#[cfg(feature = "hot-resource")]
mod hot {
  use notify::{self, RecommendedWatcher, Watcher};
  use std::collections::BTreeMap;
  use std::path::{Path, PathBuf};
  use std::sync::{Arc, Mutex};
  use std::sync::mpsc;
  use std::thread;

  /// Time to await after a resource update to establish that it should be reloaded.
  pub const UPDATE_AWAIT_TIME: f64 = 0.1; // 100ms

  pub struct ResourceManager {
    senders: Arc<Mutex<BTreeMap<PathBuf, mpsc::Sender<()>>>>
  }

  impl ResourceManager {
    pub fn new<P>(root: P) -> Self where P: AsRef<Path> {
      let (wsx, wrx) = mpsc::channel();
      let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();
      let senders: Arc<Mutex<BTreeMap<PathBuf, mpsc::Sender<()>>>> = Arc::new(Mutex::new(BTreeMap::new()));
      let senders_ = senders.clone();
      let root = root.as_ref().to_path_buf();

      let _ = thread::spawn(move || {
        let _ = watcher.watch(root);

        for event in wrx.iter() {
          match event {
            notify::Event { path: Some(path), op: Ok(notify::op::WRITE) } => {
              if let Some(sx) = senders_.lock().unwrap().get(&path) {
                sx.send(()).unwrap();
              }
            },
            _ => {}
          }
        }
      });

      ResourceManager {
        senders: senders
      }
    }

    pub fn monitor<P>(&mut self, path: P, sx: mpsc::Sender<()>) where P: AsRef<Path> {
      let mut senders = self.senders.lock().unwrap();

      senders.insert(path.as_ref().to_path_buf(), sx);
    }
  }
}

#[cfg(not(feature = "hot-resource"))]
mod cold {
  use std::path::Path;
  use std::sync::mpsc;

  pub struct ResourceManager {}

  impl ResourceManager {
    pub fn new<P>(_: P) -> Self where P: AsRef<Path> {
      ResourceManager {}
    }

    pub fn monitor<P>(&mut self, _: P, _: mpsc::Sender<()>) where P: AsRef<Path> {}
  }
}

#[cfg(feature = "hot-resource")]
pub use self::hot::*;
#[cfg(not(feature = "hot-resource"))]
pub use self::cold::*;

/// Sync all the resources passed in as arguments.
#[macro_export]
macro_rules! sync {
  ($( $r:expr ),*) => {
    $( $r.sync(); )*
  }
}

/// A helper macro to declare a `sync` public method for a resource. The resource must
/// have a `last_update_time: Option<f64>` and a `reload(&mut self)` function.
#[cfg(feature = "hot-resource")]
#[macro_export]
macro_rules! decl_sync_hot {
  () => {
    pub fn sync(&mut self) {
      if self.rx.try_recv().is_ok() {
        self.last_update_time = Some(::time::precise_time_s());
      }

      match self.last_update_time {
        Some(last_update_time) if ::time::precise_time_s() - last_update_time >= ::resource::UPDATE_AWAIT_TIME => {
          self.reload();
          self.last_update_time = None;
        },
        _ => {}
      }
    }
  }
}
<commit_msg>Ended a comment.<commit_after>use std::path::{Path, PathBuf};

/// Class of types that can be loaded and reloaded.
pub trait Load: Sized {
  type Args;

  fn load<P>(path: P, args: Self::Args) -> Result<Self, LoadError> where P: AsRef<Path>;
  fn reload<P>(&self, path :P) -> Result<Self, LoadError> where P: AsRef<Path>;
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LoadError {
  FileNotFound(PathBuf, String),
  ParseFailed(String),
  ConversionFailed(String)
}

#[cfg(feature = "hot-resource")]
mod hot {
  use notify::{self, RecommendedWatcher, Watcher};
  use std::collections::BTreeMap;
  use std::path::{Path, PathBuf};
  use std::sync::{Arc, Mutex};
  use std::sync::mpsc;
  use std::thread;

  /// Time to await after a resource update to establish that it should be reloaded.
  pub const UPDATE_AWAIT_TIME: f64 = 0.1; // 100ms

  pub struct ResourceManager {
    senders: Arc<Mutex<BTreeMap<PathBuf, mpsc::Sender<()>>>>
  }

  impl ResourceManager {
    pub fn new<P>(root: P) -> Self where P: AsRef<Path> {
      let (wsx, wrx) = mpsc::channel();
      let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();
      let senders: Arc<Mutex<BTreeMap<PathBuf, mpsc::Sender<()>>>> = Arc::new(Mutex::new(BTreeMap::new()));
      let senders_ = senders.clone();
      let root = root.as_ref().to_path_buf();

      let _ = thread::spawn(move || {
        let _ = watcher.watch(root);

        for event in wrx.iter() {
          match event {
            notify::Event { path: Some(path), op: Ok(notify::op::WRITE) } => {
              if let Some(sx) = senders_.lock().unwrap().get(&path) {
                sx.send(()).unwrap();
              }
            },
            _ => {}
          }
        }
      });

      ResourceManager {
        senders: senders
      }
    }

    pub fn monitor<P>(&mut self, path: P, sx: mpsc::Sender<()>) where P: AsRef<Path> {
      let mut senders = self.senders.lock().unwrap();

      senders.insert(path.as_ref().to_path_buf(), sx);
    }
  }
}

#[cfg(not(feature = "hot-resource"))]
mod cold {
  use std::path::Path;
  use std::sync::mpsc;

  pub struct ResourceManager {}

  impl ResourceManager {
    pub fn new<P>(_: P) -> Self where P: AsRef<Path> {
      ResourceManager {}
    }

    pub fn monitor<P>(&mut self, _: P, _: mpsc::Sender<()>) where P: AsRef<Path> {}
  }
}

#[cfg(feature = "hot-resource")]
pub use self::hot::*;
#[cfg(not(feature = "hot-resource"))]
pub use self::cold::*;

/// Sync all the resources passed in as arguments.
#[macro_export]
macro_rules! sync {
  ($( $r:expr ),*) => {
    $( $r.sync(); )*
  }
}

/// A helper macro to declare a `sync` public method for a resource. The resource must
/// have a `last_update_time: Option<f64>` and a `reload(&mut self)` function.
#[cfg(feature = "hot-resource")]
#[macro_export]
macro_rules! decl_sync_hot {
  () => {
    pub fn sync(&mut self) {
      if self.rx.try_recv().is_ok() {
        self.last_update_time = Some(::time::precise_time_s());
      }

      match self.last_update_time {
        Some(last_update_time) if ::time::precise_time_s() - last_update_time >= ::resource::UPDATE_AWAIT_TIME => {
          self.reload();
          self.last_update_time = None;
        },
        _ => {}
      }
    }
  }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_id="http://olsonjeffery.github.io#schemers:0.0.1"]
#![desc = "Simple Scheme Interpreter"]
#![license = "3-Clause BSD"]

use std::from_str::FromStr;

// this is starting out as a straight port of Peter Norvig's
// lis.py (the first iteration) to Rust

#[cfg(not(test))]
fn main() {
    use std::os::args;
    let args: Vec<~str> = args().move_iter().skip(1).collect();
    if args.len() == 0 {
        fail!("no program provided");
    }
    let program: ~str = args.move_iter()
        .fold(~"", |memo, arg| memo + arg + " ").trim().to_owned();
    let tokens = &mut tokenize(program);
    let parsed_items = parse(tokens);
    println!("{}", parsed_items.print());
}

// parser impl
fn pad_input(input: ~str) -> ~str {
    input.replace("(", " ( ").replace(")", " ) ")
}

fn tokenize(input: ~str) -> Vec<~str> {
    pad_input(input).split_str(" ")
        .filter(|i| *i != "").map(|i| i.to_owned()).collect()
}

#[deriving(Eq, Show)]
pub enum Expression {
    Atom(AtomType),
    List(Vec<~Expression>)
}
impl Expression {
    pub fn new_atom(input: ~str) -> Expression {
        let first_char = input.char_at(0);
        match first_char {
            '0' | '1' | '2' | '3' | '4' | '5' |
            '6' | '7' | '8' | '9' => {
                match input.contains(".") {
                    true => {
                        match FromStr::from_str(input) {
                            Some(val) => Atom(Float(val)),
                            None => fail!("Cannot parse number-like input of: {}", input)
                        }
                    },
                    false => {
                        match FromStr::from_str(input) {
                            Some(val) => Atom(Integer(val)),
                            None => fail!("Cannot parse number-like input of: {}", input)
                        }
                    }
                }
            },
            _ => Atom(Symbol(input))
        }
    }

    pub fn is_atom(&self) -> bool {
        match *self {
            Atom(_) => true,
            _ => false
        }
    }

    pub fn print(&self) -> ~str {
        match self {
            &List(ref items) => {
                let out = items.iter().map(|i| i.print())
                    .fold(~"(", |m, v| m + v + " ");
                out.trim() + ")"
            },
            &Atom(ref v) => v.print()
        }
    }
}

#[deriving(Eq, Show)]
pub enum AtomType {
    Symbol(~str),
    Integer(i64),
    Float(f64)
}

impl AtomType {
    pub fn print(&self) -> ~str {
        match self {
            &Symbol(ref v) => v.to_owned(),
            &Integer(ref v) => v.to_str(),
            &Float(ref v) => v.to_str()
        }
    }
}

fn parse(tokens: &mut Vec<~str>) -> Expression {
    let current_token =
        tokens.shift().expect("calling parse() w/ empty token list; shouldn't happen");
    match current_token {
        ref x if *x == ~"(" => {
            let mut list = Vec::new();
            while *tokens.get(0) != ~")" {
                list.push(box parse(tokens));
            }
            tokens.shift();
            List(list)
        },
        ref x if *x == ~")" => fail!("hit ) token; shouldn't happen"),
        x => Expression::new_atom(x)
    }
}

#[cfg(test)]
mod parser_test {
    use super::{pad_input, tokenize, parse, Atom, List, Symbol, Integer, Float};

    #[test]
    fn pad_input_should_insert_spaces_before_and_after_parens() {
        assert_eq!(pad_input(~"(x 1 2 3)"), ~" ( x 1 2 3 ) ");
    }

    #[test]
    fn tokenize_string_into_tokens() {
        let tokens = tokenize(~"(foo 12 3)");
        assert_eq!(tokens.len(), 5);
        assert_eq!(tokens.get(0).to_owned(), ~"(");
        assert_eq!(tokens.get(1).to_owned(), ~"foo");
        assert_eq!(tokens.get(2).to_owned(), ~"12");
        assert_eq!(tokens.get(3).to_owned(), ~"3");
        assert_eq!(tokens.get(4).to_owned(), ~")");
    }

    #[test]
    fn should_parse_tokens_consisting_of_a_str_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"bar");
        let parsed_item = parse(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(Symbol(val)) => {
                assert_eq!(val, ~"bar")
            },
            _ => assert!(false)
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_an_int_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"42");
        let parsed_item = parse(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(Integer(val)) => {
                assert_eq!(val, 42)
            },
            _ => assert!(false)
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_a_float_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"1.1");
        let parsed_item = parse(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(Float(val)) => {
                assert_eq!(val, 1.1)
            },
            _ => assert!(false)
        }
    }

    #[test]
    fn should_parse_tokens_consisting_of_a_list_of_atoms_and_parse_it() {
        let tokens = &mut tokenize(~"(bar 12 45)");
        let parsed_item = parse(tokens);
        assert_eq!(parsed_item.is_atom(), false);
        match parsed_item {
            List(items) => {
                let items_len = items.len();
                assert!(3 == items_len);
                assert_eq!(items.get(0).is_atom(), true);
                assert_eq!(*items.get(0), ~Atom(Symbol(~"bar")));
                assert_eq!(items.get(1).is_atom(), true);
                assert_eq!(*items.get(1), ~Atom(Integer(12)));
                assert_eq!(items.get(2).is_atom(), true);
                assert_eq!(*items.get(2), ~Atom(Integer(45)));
            },
            _ => fail!("got back an atom, it seems")
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_a_list_of_atoms_and_a_nested_list() {
        let tokens = &mut tokenize(~"((2 3) bar 12 (hee (hah)))");
        let parsed_item = parse(tokens);
        assert_eq!(parsed_item.is_atom(), false);
        match parsed_item {
            List(items) => {
                let items_len = items.len();
                assert!(4 == items_len);
                match *items.get(0) {
                    ~List(ref items) => {
                        assert_eq!(items.len(), 2);
                        assert_eq!(*items.get(0), ~Atom(Integer(2)));
                        assert_eq!(*items.get(1), ~Atom(Integer(3)));
                    },
                    _ => fail!("shoulda got a list")
                }
                assert_eq!(*items.get(1), ~Atom(Symbol(~"bar")));
                assert_eq!(*items.get(2), ~Atom(Integer(12)));
                match *items.get(3) {
                    ~List(ref items) => {
                        assert_eq!(items.len(), 2);
                        assert_eq!(*items.get(0), ~Atom(Symbol(~"hee")));
                        match *items.get(1) {
                            ~List(ref items) => {
                                assert_eq!(items.len(), 1);
                                assert_eq!(*items.get(0), ~Atom(Symbol(~"hah")));
                            },
                            _ => fail!("shoulda got a list")
                        }
                    },
                    _ => fail!("shoulda got a list")
                }
            },
            _ => fail!("got back an atom, it seems")
        }
    }
    #[test]
    fn parsed_tokens_of_a_list_of_atoms_and_a_nested_list_should_to_str_correctly() {
        let input = ~"((2 3) bar 12 (hee (hah)))";
        let tokens = &mut tokenize(input.to_owned());
        let parsed_item = parse(tokens);
        let output = parsed_item.print();
        assert_eq!(input, output);
    }
}
<commit_msg>ok nevermind, rename Expression->Expr.. too much typing<commit_after>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_id="http://olsonjeffery.github.io#schemers:0.0.1"]
#![desc = "Simple Scheme Interpreter"]
#![license = "3-Clause BSD"]

use std::from_str::FromStr;

// this is starting out as a straight port of Peter Norvig's
// lis.py (the first iteration) to Rust

#[cfg(not(test))]
fn main() {
    use std::os::args;
    let args: Vec<~str> = args().move_iter().skip(1).collect();
    if args.len() == 0 {
        fail!("no program provided");
    }
    let program: ~str = args.move_iter()
        .fold(~"", |memo, arg| memo + arg + " ").trim().to_owned();
    let tokens = &mut tokenize(program);
    let parsed_items = parse(tokens);
    println!("{}", parsed_items.print());
}

// parser impl
fn pad_input(input: ~str) -> ~str {
    input.replace("(", " ( ").replace(")", " ) ")
}

fn tokenize(input: ~str) -> Vec<~str> {
    pad_input(input).split_str(" ")
        .filter(|i| *i != "").map(|i| i.to_owned()).collect()
}

#[deriving(Eq, Show)]
pub enum Expr {
    Atom(AtomType),
    List(Vec<~Expr>)
}
impl Expr {
    pub fn new_atom(input: ~str) -> Expr {
        let first_char = input.char_at(0);
        match first_char {
            '0' | '1' | '2' | '3' | '4' | '5' |
            '6' | '7' | '8' | '9' => {
                match input.contains(".") {
                    true => {
                        match FromStr::from_str(input) {
                            Some(val) => Atom(Float(val)),
                            None => fail!("Cannot parse number-like input of: {}", input)
                        }
                    },
                    false => {
                        match FromStr::from_str(input) {
                            Some(val) => Atom(Integer(val)),
                            None => fail!("Cannot parse number-like input of: {}", input)
                        }
                    }
                }
            },
            _ => Atom(Symbol(input))
        }
    }

    pub fn is_atom(&self) -> bool {
        match *self {
            Atom(_) => true,
            _ => false
        }
    }

    pub fn print(&self) -> ~str {
        match self {
            &List(ref items) => {
                let out = items.iter().map(|i| i.print())
                    .fold(~"(", |m, v| m + v + " ");
                out.trim() + ")"
            },
            &Atom(ref v) => v.print()
        }
    }
}

#[deriving(Eq, Show)]
pub enum AtomType {
    Symbol(~str),
    Integer(i64),
    Float(f64)
}

impl AtomType {
    pub fn print(&self) -> ~str {
        match self {
            &Symbol(ref v) => v.to_owned(),
            &Integer(ref v) => v.to_str(),
            &Float(ref v) => v.to_str()
        }
    }
}

fn parse(tokens: &mut Vec<~str>) -> Expr {
    let current_token =
        tokens.shift().expect("calling parse() w/ empty token list; shouldn't happen");
    match current_token {
        ref x if *x == ~"(" => {
            let mut list = Vec::new();
            while *tokens.get(0) != ~")" {
                list.push(box parse(tokens));
            }
            tokens.shift();
            List(list)
        },
        ref x if *x == ~")" => fail!("hit ) token; shouldn't happen"),
        x => Expr::new_atom(x)
    }
}

#[cfg(test)]
mod parser_test {
    use super::{pad_input, tokenize, parse, Atom, List, Symbol, Integer, Float};

    #[test]
    fn pad_input_should_insert_spaces_before_and_after_parens() {
        assert_eq!(pad_input(~"(x 1 2 3)"), ~" ( x 1 2 3 ) ");
    }

    #[test]
    fn tokenize_string_into_tokens() {
        let tokens = tokenize(~"(foo 12 3)");
        assert_eq!(tokens.len(), 5);
        assert_eq!(tokens.get(0).to_owned(), ~"(");
        assert_eq!(tokens.get(1).to_owned(), ~"foo");
        assert_eq!(tokens.get(2).to_owned(), ~"12");
        assert_eq!(tokens.get(3).to_owned(), ~"3");
        assert_eq!(tokens.get(4).to_owned(), ~")");
    }

    #[test]
    fn should_parse_tokens_consisting_of_a_str_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"bar");
        let parsed_item = parse(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(Symbol(val)) => {
                assert_eq!(val, ~"bar")
            },
            _ => assert!(false)
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_an_int_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"42");
        let parsed_item = parse(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(Integer(val)) => {
                assert_eq!(val, 42)
            },
            _ => assert!(false)
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_a_float_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"1.1");
        let parsed_item = parse(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(Float(val)) => {
                assert_eq!(val, 1.1)
            },
            _ => assert!(false)
        }
    }

    #[test]
    fn should_parse_tokens_consisting_of_a_list_of_atoms_and_parse_it() {
        let tokens = &mut tokenize(~"(bar 12 45)");
        let parsed_item = parse(tokens);
        assert_eq!(parsed_item.is_atom(), false);
        match parsed_item {
            List(items) => {
                let items_len = items.len();
                assert!(3 == items_len);
                assert_eq!(items.get(0).is_atom(), true);
                assert_eq!(*items.get(0), ~Atom(Symbol(~"bar")));
                assert_eq!(items.get(1).is_atom(), true);
                assert_eq!(*items.get(1), ~Atom(Integer(12)));
                assert_eq!(items.get(2).is_atom(), true);
                assert_eq!(*items.get(2), ~Atom(Integer(45)));
            },
            _ => fail!("got back an atom, it seems")
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_a_list_of_atoms_and_a_nested_list() {
        let tokens = &mut tokenize(~"((2 3) bar 12 (hee (hah)))");
        let parsed_item = parse(tokens);
        assert_eq!(parsed_item.is_atom(), false);
        match parsed_item {
            List(items) => {
                let items_len = items.len();
                assert!(4 == items_len);
                match *items.get(0) {
                    ~List(ref items) => {
                        assert_eq!(items.len(), 2);
                        assert_eq!(*items.get(0), ~Atom(Integer(2)));
                        assert_eq!(*items.get(1), ~Atom(Integer(3)));
                    },
                    _ => fail!("shoulda got a list")
                }
                assert_eq!(*items.get(1), ~Atom(Symbol(~"bar")));
                assert_eq!(*items.get(2), ~Atom(Integer(12)));
                match *items.get(3) {
                    ~List(ref items) => {
                        assert_eq!(items.len(), 2);
                        assert_eq!(*items.get(0), ~Atom(Symbol(~"hee")));
                        match *items.get(1) {
                            ~List(ref items) => {
                                assert_eq!(items.len(), 1);
                                assert_eq!(*items.get(0), ~Atom(Symbol(~"hah")));
                            },
                            _ => fail!("shoulda got a list")
                        }
                    },
                    _ => fail!("shoulda got a list")
                }
            },
            _ => fail!("got back an atom, it seems")
        }
    }
    #[test]
    fn parsed_tokens_of_a_list_of_atoms_and_a_nested_list_should_to_str_correctly() {
        let input = ~"((2 3) bar 12 (hee (hah)))";
        let tokens = &mut tokenize(input.to_owned());
        let parsed_item = parse(tokens);
        let output = parsed_item.print();
        assert_eq!(input, output);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

use core::fmt;
use prelude::*;
use serde::de::{self, Error, SeqAccess};
use serde::ser::SerializeTuple;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

#[cfg(all(feature = "serde", not(feature = "dense_serde")))]
impl Serialize for Uuid {
    fn serialize<S: Serializer>(
        &self,
        serializer: S,
    ) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            serializer
                .serialize_str(&self.to_hyphenated().encode_lower(&mut [0; 36]))
        } else {
            serializer.serialize_bytes(self.as_bytes())
        }
    }
}

#[cfg(feature = "dense_serde")]
impl Serialize for Uuid {
    fn serialize<S: Serializer>(
        &self,
        serializer: S,
    ) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            serializer
                .serialize_str(&self.to_hyphenated().encode_lower(&mut [0; 36]))
        } else {
            let mut seq = serializer.serialize_tuple(16)?;

            for byte in self.as_bytes() {
                seq.serialize_element(byte)?;
            }

            seq.end()
        }
    }
}

struct UuidStringVisitor;

impl<'vi> de::Visitor<'vi> for UuidStringVisitor {
    type Value = Uuid;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "a UUID string")
    }

    fn visit_str<E: de::Error>(self, value: &str) -> Result<Uuid, E> {
        value.parse::<Uuid>().map_err(E::custom)
    }

    fn visit_bytes<E: de::Error>(self, value: &[u8]) -> Result<Uuid, E> {
        Uuid::from_slice(value).map_err(E::custom)
    }
}

#[cfg(feature = "dense_serde")]
impl<'de> Deserialize<'de> for Uuid {
    fn deserialize<D: Deserializer<'de>>(
        deserializer: D,
    ) -> Result<Self, D::Error> {
        if deserializer.is_human_readable() {
            deserializer.deserialize_str(UuidStringVisitor)
        } else {
            struct DenseUuidBytesVisitor;

            impl<'vi> de::Visitor<'vi> for DenseUuidBytesVisitor {
                type Value = Uuid;

                fn expecting(
                    &self,
                    formatter: &mut fmt::Formatter,
                ) -> fmt::Result {
                    write!(formatter, "tuple")
                }

                fn visit_seq<A: SeqAccess<'vi>>(
                    self,
                    mut seq: A,
                ) -> Result<Self::Value, A::Error> {
                    if seq.size_hint() == Some(16) {
                        let mut buf = [0; 16];

                        for i in 0..16 {
                            buf[i] = seq.next_element().unwrap().unwrap()
                        }

                        Ok(Uuid::from_bytes(buf))
                    } else {
                        Err(Error::custom("Uuid must be 16 bytes long"))
                    }
                }
            }

            deserializer.deserialize_tuple(16, DenseUuidBytesVisitor)
        }
    }
}

#[cfg(all(feature = "serde", not(feature = "dense_serde")))]
impl<'de> Deserialize<'de> for Uuid {
    fn deserialize<D: Deserializer<'de>>(
        deserializer: D
    ) -> Result<Self, D::Error> {
        if deserializer.is_human_readable() {
            deserializer.deserialize_str(UuidStringVisitor)
        } else {
            struct UuidBytesVisitor;

            impl<'vi> de::Visitor<'vi> for UuidBytesVisitor {
                type Value = Uuid;

                fn expecting(
                    &self,
                    formatter: &mut fmt::Formatter,
                ) -> fmt::Result {
                    write!(formatter, "bytes")
                }

                fn visit_bytes<E: de::Error>(
                    self,
                    value: &[u8],
                ) -> Result<Uuid, E> {
                    Uuid::from_slice(value).map_err(E::custom)
                }
            }

            deserializer.deserialize_bytes(UuidBytesVisitor)
        }
    }
}

#[cfg(all(test, feature = "serde", not(feature = "dense_serde")))]
mod serde_tests {
    use serde_test;

    use prelude::*;

    #[test]
    fn test_serialize_readable() {
        use serde_test::Configure;

        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
        let u = Uuid::parse_str(uuid_str).unwrap();
        serde_test::assert_tokens(
            &u.readable(),
            &[serde_test::Token::Str(uuid_str)],
        );
    }

    #[test]
    fn test_serialize_compact() {
        use serde_test::Configure;

        let uuid_bytes = b"F9168C5E-CEB2-4F";
        let u = Uuid::from_slice(uuid_bytes).unwrap();
        serde_test::assert_tokens(
            &u.compact(),
            &[serde_test::Token::Bytes(uuid_bytes)],
        );
    }
}

#[cfg(all(test, feature = "dense_serde"))]
mod dense_serde_tests {
    use serde_test;

    use prelude::*;

    #[test]
    fn test_serialize_readable() {
        use serde_test::Configure;

        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
        let u = Uuid::parse_str(uuid_str).unwrap();
        serde_test::assert_tokens(
            &u.readable(),
            &[serde_test::Token::Str(uuid_str)],
        );
    }

    #[test]
    fn test_serialize_compact() {
        use serde_test::Configure;

        let uuid_bytes = b"F9168C5E-CEB2-4F";
        let u = Uuid::from_slice(uuid_bytes).unwrap();
        serde_test::assert_tokens(
            &u.compact(),
            &[
                serde_test::Token::Tuple { len: 16 },
                serde_test::Token::U8(uuid_bytes[0]),
                serde_test::Token::U8(uuid_bytes[1]),
                serde_test::Token::U8(uuid_bytes[2]),
                serde_test::Token::U8(uuid_bytes[3]),
                serde_test::Token::U8(uuid_bytes[4]),
                serde_test::Token::U8(uuid_bytes[5]),
                serde_test::Token::U8(uuid_bytes[6]),
                serde_test::Token::U8(uuid_bytes[7]),
                serde_test::Token::U8(uuid_bytes[8]),
                serde_test::Token::U8(uuid_bytes[9]),
                serde_test::Token::U8(uuid_bytes[10]),
                serde_test::Token::U8(uuid_bytes[11]),
                serde_test::Token::U8(uuid_bytes[12]),
                serde_test::Token::U8(uuid_bytes[13]),
                serde_test::Token::U8(uuid_bytes[14]),
                serde_test::Token::U8(uuid_bytes[15]),
                serde_test::Token::TupleEnd,
            ],
        )
    }
}
<commit_msg>That should actually finally fix it.<commit_after>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

use core::fmt;
use prelude::*;
use serde::de::{self, Error, SeqAccess};
use serde::ser::SerializeTuple;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

#[cfg(all(feature = "serde", not(feature = "dense_serde")))]
impl Serialize for Uuid {
    fn serialize<S: Serializer>(
        &self,
        serializer: S,
    ) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            serializer
                .serialize_str(&self.to_hyphenated().encode_lower(&mut [0; 36]))
        } else {
            serializer.serialize_bytes(self.as_bytes())
        }
    }
}

#[cfg(feature = "dense_serde")]
impl Serialize for Uuid {
    fn serialize<S: Serializer>(
        &self,
        serializer: S,
    ) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            serializer
                .serialize_str(&self.to_hyphenated().encode_lower(&mut [0; 36]))
        } else {
            let mut seq = serializer.serialize_tuple(16)?;

            for byte in self.as_bytes() {
                seq.serialize_element(byte)?;
            }

            seq.end()
        }
    }
}

struct UuidStringVisitor;

impl<'vi> de::Visitor<'vi> for UuidStringVisitor {
    type Value = Uuid;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "a UUID string")
    }

    fn visit_str<E: de::Error>(self, value: &str) -> Result<Uuid, E> {
        value.parse::<Uuid>().map_err(E::custom)
    }

    fn visit_bytes<E: de::Error>(self, value: &[u8]) -> Result<Uuid, E> {
        Uuid::from_slice(value).map_err(E::custom)
    }
}

#[cfg(feature = "dense_serde")]
impl<'de> Deserialize<'de> for Uuid {
    fn deserialize<D: Deserializer<'de>>(
        deserializer: D,
    ) -> Result<Self, D::Error> {
        if deserializer.is_human_readable() {
            deserializer.deserialize_str(UuidStringVisitor)
        } else {
            struct DenseUuidBytesVisitor;

            impl<'vi> de::Visitor<'vi> for DenseUuidBytesVisitor {
                type Value = Uuid;

                fn expecting(
                    &self,
                    formatter: &mut fmt::Formatter,
                ) -> fmt::Result {
                    write!(formatter, "tuple")
                }

                fn visit_seq<A: SeqAccess<'vi>>(
                    self,
                    mut seq: A,
                ) -> Result<Self::Value, A::Error> {
                    if seq.size_hint() == Some(16) {
                        let mut buf = [0; 16];

                        for i in 0..16 {
                            buf[i] = seq.next_element().unwrap().unwrap()
                        }

                        Ok(Uuid::from_bytes(buf))
                    } else {
                        Err(Error::custom("Uuid must be 16 bytes long"))
                    }
                }
            }

            deserializer.deserialize_tuple(16, DenseUuidBytesVisitor)
        }
    }
}

#[cfg(all(feature = "serde", not(feature = "dense_serde")))]
impl<'de> Deserialize<'de> for Uuid {
    fn deserialize<D: Deserializer<'de>>(
        deserializer: D,
    ) -> Result<Self, D::Error> {
        if deserializer.is_human_readable() {
            deserializer.deserialize_str(UuidStringVisitor)
        } else {
            struct UuidBytesVisitor;

            impl<'vi> de::Visitor<'vi> for UuidBytesVisitor {
                type Value = Uuid;

                fn expecting(
                    &self,
                    formatter: &mut fmt::Formatter,
                ) -> fmt::Result {
                    write!(formatter, "bytes")
                }

                fn visit_bytes<E: de::Error>(
                    self,
                    value: &[u8],
                ) -> Result<Uuid, E> {
                    Uuid::from_slice(value).map_err(E::custom)
                }
            }

            deserializer.deserialize_bytes(UuidBytesVisitor)
        }
    }
}

#[cfg(all(test, feature = "serde", not(feature = "dense_serde")))]
mod serde_tests {
    use serde_test;

    use prelude::*;

    #[test]
    fn test_serialize_readable() {
        use serde_test::Configure;

        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
        let u = Uuid::parse_str(uuid_str).unwrap();
        serde_test::assert_tokens(
            &u.readable(),
            &[serde_test::Token::Str(uuid_str)],
        );
    }

    #[test]
    fn test_serialize_compact() {
        use serde_test::Configure;

        let uuid_bytes = b"F9168C5E-CEB2-4F";
        let u = Uuid::from_slice(uuid_bytes).unwrap();
        serde_test::assert_tokens(
            &u.compact(),
            &[serde_test::Token::Bytes(uuid_bytes)],
        );
    }
}

#[cfg(all(test, feature = "dense_serde"))]
mod dense_serde_tests {
    use serde_test;

    use prelude::*;

    #[test]
    fn test_serialize_readable() {
        use serde_test::Configure;

        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
        let u = Uuid::parse_str(uuid_str).unwrap();
        serde_test::assert_tokens(
            &u.readable(),
            &[serde_test::Token::Str(uuid_str)],
        );
    }

    #[test]
    fn test_serialize_compact() {
        use serde_test::Configure;

        let uuid_bytes = b"F9168C5E-CEB2-4F";
        let u = Uuid::from_slice(uuid_bytes).unwrap();
        serde_test::assert_tokens(
            &u.compact(),
            &[
                serde_test::Token::Tuple { len: 16 },
                serde_test::Token::U8(uuid_bytes[0]),
                serde_test::Token::U8(uuid_bytes[1]),
                serde_test::Token::U8(uuid_bytes[2]),
                serde_test::Token::U8(uuid_bytes[3]),
                serde_test::Token::U8(uuid_bytes[4]),
                serde_test::Token::U8(uuid_bytes[5]),
                serde_test::Token::U8(uuid_bytes[6]),
                serde_test::Token::U8(uuid_bytes[7]),
                serde_test::Token::U8(uuid_bytes[8]),
                serde_test::Token::U8(uuid_bytes[9]),
                serde_test::Token::U8(uuid_bytes[10]),
                serde_test::Token::U8(uuid_bytes[11]),
                serde_test::Token::U8(uuid_bytes[12]),
                serde_test::Token::U8(uuid_bytes[13]),
                serde_test::Token::U8(uuid_bytes[14]),
                serde_test::Token::U8(uuid_bytes[15]),
                serde_test::Token::TupleEnd,
            ],
        )
    }
}
<|endoftext|>