<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![deny(warnings)]

extern crate build_helper;
extern crate cc;

use build_helper::native_lib_boilerplate;
use std::env;
use std::fs::File;

fn main() {
    let target = env::var("TARGET").expect("TARGET was not set");
    if cfg!(feature = "backtrace") &&
        !target.contains("cloudabi") &&
        !target.contains("emscripten") &&
        !target.contains("fuchsia") &&
        !target.contains("msvc") &&
        !target.contains("wasm32")
    {
        let _ = build_libbacktrace(&target);
    }

    if target.contains("linux") {
        if target.contains("android") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=log");
            println!("cargo:rustc-link-lib=gcc");
        } else if !target.contains("musl") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=rt");
            println!("cargo:rustc-link-lib=pthread");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=execinfo");
        println!("cargo:rustc-link-lib=pthread");
    } else if target.contains("dragonfly") || target.contains("bitrig") ||
              target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=pthread");
    } else if target.contains("solaris") {
        println!("cargo:rustc-link-lib=socket");
        println!("cargo:rustc-link-lib=posix4");
        println!("cargo:rustc-link-lib=pthread");
        println!("cargo:rustc-link-lib=resolv");
    } else if target.contains("apple-darwin") {
        println!("cargo:rustc-link-lib=System");

        // res_init and friends require -lresolv on macOS/iOS.
        // See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
        println!("cargo:rustc-link-lib=resolv");
    } else if target.contains("apple-ios") {
        println!("cargo:rustc-link-lib=System");
        println!("cargo:rustc-link-lib=objc");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=Foundation");
        println!("cargo:rustc-link-lib=resolv");
    } else if target.contains("windows") {
        println!("cargo:rustc-link-lib=advapi32");
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=userenv");
        println!("cargo:rustc-link-lib=shell32");
    } else if target.contains("fuchsia") {
        // use system-provided libbacktrace
        if cfg!(feature = "backtrace") {
            println!("cargo:rustc-link-lib=backtrace");
        }
        println!("cargo:rustc-link-lib=zircon");
        println!("cargo:rustc-link-lib=fdio");
    } else if target.contains("cloudabi") {
        if cfg!(feature = "backtrace") {
            println!("cargo:rustc-link-lib=unwind");
        }
        println!("cargo:rustc-link-lib=c");
        println!("cargo:rustc-link-lib=compiler_rt");
    }
}

fn build_libbacktrace(target: &str) -> Result<(), ()> {
    let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", "")?;

    let mut build = cc::Build::new();
    build
        .flag("-fvisibility=hidden")
        .include("../libbacktrace")
        .include(&native.out_dir)
        .out_dir(&native.out_dir)
        .warnings(false)
        .file("../libbacktrace/alloc.c")
        .file("../libbacktrace/backtrace.c")
        .file("../libbacktrace/dwarf.c")
        .file("../libbacktrace/fileline.c")
        .file("../libbacktrace/posix.c")
        .file("../libbacktrace/read.c")
        .file("../libbacktrace/sort.c")
        .file("../libbacktrace/state.c");

    if target.contains("darwin") {
        build.file("../libbacktrace/macho.c");
    } else if target.contains("windows") {
        build.file("../libbacktrace/pecoff.c");
    } else {
        build.file("../libbacktrace/elf.c");

        if target.contains("64") {
            build.define("BACKTRACE_ELF_SIZE", "64");
        } else {
            build.define("BACKTRACE_ELF_SIZE", "32");
        }
    }

    File::create(native.out_dir.join("backtrace-supported.h")).unwrap();
    build.define("BACKTRACE_SUPPORTED", "1");
    build.define("BACKTRACE_USES_MALLOC", "1");
    build.define("BACKTRACE_SUPPORTS_THREADS", "0");
    build.define("BACKTRACE_SUPPORTS_DATA", "0");

    File::create(native.out_dir.join("config.h")).unwrap();
    if !target.contains("apple-ios") &&
       !target.contains("solaris") &&
       !target.contains("redox") &&
       !target.contains("android") {
        build.define("HAVE_DL_ITERATE_PHDR", "1");
    }
    build.define("_GNU_SOURCE", "1");
    build.define("_LARGE_FILES", "1");

    build.compile("backtrace");
    Ok(())
}
<commit_msg>Auto merge of #51931 - cramertj:rm-libbacktrace, r=alexcrichton<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![deny(warnings)]

extern crate build_helper;
extern crate cc;

use build_helper::native_lib_boilerplate;
use std::env;
use std::fs::File;

fn main() {
    let target = env::var("TARGET").expect("TARGET was not set");
    if cfg!(feature = "backtrace") &&
        !target.contains("cloudabi") &&
        !target.contains("emscripten") &&
        !target.contains("msvc") &&
        !target.contains("wasm32")
    {
        let _ = build_libbacktrace(&target);
    }

    if target.contains("linux") {
        if target.contains("android") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=log");
            println!("cargo:rustc-link-lib=gcc");
        } else if !target.contains("musl") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=rt");
            println!("cargo:rustc-link-lib=pthread");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=execinfo");
        println!("cargo:rustc-link-lib=pthread");
    } else if target.contains("dragonfly") || target.contains("bitrig") ||
              target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=pthread");
    } else if target.contains("solaris") {
        println!("cargo:rustc-link-lib=socket");
        println!("cargo:rustc-link-lib=posix4");
        println!("cargo:rustc-link-lib=pthread");
        println!("cargo:rustc-link-lib=resolv");
    } else if target.contains("apple-darwin") {
        println!("cargo:rustc-link-lib=System");

        // res_init and friends require -lresolv on macOS/iOS.
        // See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
        println!("cargo:rustc-link-lib=resolv");
    } else if target.contains("apple-ios") {
        println!("cargo:rustc-link-lib=System");
        println!("cargo:rustc-link-lib=objc");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=Foundation");
        println!("cargo:rustc-link-lib=resolv");
    } else if target.contains("windows") {
        println!("cargo:rustc-link-lib=advapi32");
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=userenv");
        println!("cargo:rustc-link-lib=shell32");
    } else if target.contains("fuchsia") {
        println!("cargo:rustc-link-lib=zircon");
        println!("cargo:rustc-link-lib=fdio");
    } else if target.contains("cloudabi") {
        if cfg!(feature = "backtrace") {
            println!("cargo:rustc-link-lib=unwind");
        }
        println!("cargo:rustc-link-lib=c");
        println!("cargo:rustc-link-lib=compiler_rt");
    }
}

fn build_libbacktrace(target: &str) -> Result<(), ()> {
    let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", "")?;

    let mut build = cc::Build::new();
    build
        .flag("-fvisibility=hidden")
        .include("../libbacktrace")
        .include(&native.out_dir)
        .out_dir(&native.out_dir)
        .warnings(false)
        .file("../libbacktrace/alloc.c")
        .file("../libbacktrace/backtrace.c")
        .file("../libbacktrace/dwarf.c")
        .file("../libbacktrace/fileline.c")
        .file("../libbacktrace/posix.c")
        .file("../libbacktrace/read.c")
        .file("../libbacktrace/sort.c")
        .file("../libbacktrace/state.c");

    if target.contains("darwin") {
        build.file("../libbacktrace/macho.c");
    } else if target.contains("windows") {
        build.file("../libbacktrace/pecoff.c");
    } else {
        build.file("../libbacktrace/elf.c");

        if target.contains("64") {
            build.define("BACKTRACE_ELF_SIZE", "64");
        } else {
            build.define("BACKTRACE_ELF_SIZE", "32");
        }
    }

    File::create(native.out_dir.join("backtrace-supported.h")).unwrap();
    build.define("BACKTRACE_SUPPORTED", "1");
    build.define("BACKTRACE_USES_MALLOC", "1");
    build.define("BACKTRACE_SUPPORTS_THREADS", "0");
    build.define("BACKTRACE_SUPPORTS_DATA", "0");

    File::create(native.out_dir.join("config.h")).unwrap();
    if !target.contains("apple-ios") &&
       !target.contains("solaris") &&
       !target.contains("redox") &&
       !target.contains("android") {
        build.define("HAVE_DL_ITERATE_PHDR", "1");
    }
    build.define("_GNU_SOURCE", "1");
    build.define("_LARGE_FILES", "1");

    build.compile("backtrace");
    Ok(())
}
<|endoftext|>


<commit_before>//!Handler context and request body reading extensions.

use std::collections::HashMap;
use std::io::{self, Read};
use std::net::SocketAddr;

#[cfg(feature = "rustc_json_body")]
use rustc_serialize::json;
#[cfg(feature = "rustc_json_body")]
use rustc_serialize::Decodable;

use hyper::http::HttpReader;
use hyper::net::NetworkStream;
use hyper::buffer::BufReader;

use utils;

use HttpVersion;
use Method;
use header::Headers;
use log::Log;

use Global;

///A container for things like request data and cache.
///
///A `Context` can be dereferenced to a `BodyReader`, allowing direct access to
///the underlying read methods.
pub struct Context<'a, 'b: 'a, 's> {
    ///Headers from the HTTP request.
    pub headers: Headers,

    ///The HTTP version used in the request.
    pub http_version: HttpVersion,

    ///The client address
    pub address: SocketAddr,

    ///The HTTP method.
    pub method: Method,

    ///The requested path.
    pub path: String,

    ///Hypermedia from the current endpoint.
    pub hypermedia: Hypermedia<'s>,

    ///Route variables.
    pub variables: HashMap<String, String>,

    ///Query variables from the path.
    pub query: HashMap<String, String>,

    ///The fragment part of the URL (after #), if provided.
    pub fragment: Option<String>,

    ///Log for notes, errors and warnings.
    pub log: &'s (Log + 's),

    ///Globally accessible data.
    pub global: &'s Global,

    ///A reader for the request body.
    pub body: BodyReader<'a, 'b>,
}

///A reader for a request body.
pub struct BodyReader<'a, 'b: 'a> {
    request: HttpReader<&'a mut BufReader<&'b mut NetworkStream>>
}

impl<'a, 'b> BodyReader<'a, 'b> {
    pub fn from_reader(request: HttpReader<&'a mut BufReader<&'b mut NetworkStream>>) -> BodyReader<'a, 'b> {
        BodyReader {
            request: request
        }
    }
}

impl<'a, 'b> Read for BodyReader<'a, 'b> {
    ///Read the request body.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.request.read(buf)
    }
}

///`BodyReader` extension for reading and parsing a query string.
pub trait ExtQueryBody {
    fn read_query_body(&mut self) -> io::Result<HashMap<String, String>>;
}

impl<'a, 'b> ExtQueryBody for BodyReader<'a, 'b> {
    ///Read and parse the request body as a query string.
    ///The body will be decoded as UTF-8 and plain '+' characters will be replaced with spaces.
    #[inline]
    fn read_query_body(&mut self) -> io::Result<HashMap<String, String>> {
        let mut buf = Vec::new();
        try!(self.read_to_end(&mut buf));
        Ok(utils::parse_parameters(&buf))
    }
}

///`BodyReader` extension for reading and parsing a JSON body.
///
///It is available by default and can be toggled using the `rustc_json_body`
///feature.
#[cfg(feature = "rustc_json_body")]
pub trait ExtJsonBody {
    ///Read the body into a JSON structure.
    fn read_json_body(&mut self) -> Result<json::Json, json::BuilderError>;

    ///Parse and decode the body as some type `T`.
    fn decode_json_body<T: Decodable>(&mut self) -> json::DecodeResult<T>;
}

#[cfg(feature = "rustc_json_body")]
impl<'a, 'b> ExtJsonBody for BodyReader<'a, 'b> {
    fn read_json_body(&mut self) -> Result<json::Json, json::BuilderError> {
        json::Json::from_reader(self)
    }

    fn decode_json_body<T: Decodable>(&mut self) -> json::DecodeResult<T> {
        let mut buf = String::new();
        try!(self.read_to_string(&mut buf).map_err(|e| {
            let parse_err = json::ParserError::IoError(e);
            json::DecoderError::ParseError(parse_err)
        }));
        json::decode(&buf)
    }
}

///Hypermedia connected to an API endpoint.
pub struct Hypermedia<'a> {
    ///Forward links from the current endpoint to other endpoints.
    pub links: Vec<Link<'a>>
}

impl<'a> Hypermedia<'a> {
    ///Create an empty `Hypermedia` structure.
    pub fn new() -> Hypermedia<'a> {
        Hypermedia {
            links: vec![]
        }
    }
}

///A hyperlink.
#[derive(PartialEq, Eq, Debug)]
pub struct Link<'a> {
    ///The HTTP method for which an endpoint is available. It can be left
    ///unspecified if the method doesn't matter.
    pub method: Option<Method>,
    ///A relative path from the current location.
    pub path: Vec<LinkSegment<'a>>
}

///A segment of a hyperlink path.
#[derive(PartialEq, Eq, Debug)]
pub enum LinkSegment<'a> {
    ///A static part of a path.
    Static(&'a str),
    ///A dynamic part of a path. Can be substituted with anything.
    Variable(&'a str),
    ///A recursive wildcard. Will recursively match anything.
    RecursiveWildcard
}
<commit_msg>Auto merge of #43 - Ogeon:docs, r=Ogeon<commit_after>//!Handler context and request body reading extensions.
//!
//!#Context
//!
//!The [`Context`][context] contains all the input data for the request
//!handlers, as well as some utilities. This is where request data, like
//!headers, client address and the request body can be retrieved from and it
//!can safely be picked apart, since its ownership is transferred to the
//!handler.
//!
//!##Accessing Headers
//!
//!The headers are stored in the `headers` field. See the [`Headers`][headers]
//!struct for more information about how to access them.
//!
//!```
//!use rustful::{Context, Response};
//!use rustful::header::UserAgent;
//!
//!fn my_handler(context: Context, response: Response) {
//!    if let Some(&UserAgent(ref user_agent)) = context.headers.get() {
//!        let res = format!("got user agent string \"{}\"", user_agent);
//!        response.into_writer().send(res);
//!    } else {
//!        response.into_writer().send("no user agent string provided");
//!    }
//!}
//!```
//!
//!##Path Variables
//!
//!A router may collect variable data from paths (for example `id` in
//!`/products/:id`). The values from these variables can be accessed through
//!the `variables` field.
//!
//!```
//!use rustful::{Context, Response};
//!
//!fn my_handler(context: Context, response: Response) {
//!    if let Some(id) = context.variables.get("id") {
//!        let res = format!("asking for product with id \"{}\"", id);
//!        response.into_writer().send(res);
//!    } else {
//!        //This will usually not happen, unless the handler is also
//!        //assigned to a path without the `id` variable
//!        response.into_writer().send("no id provided");
//!    }
//!}
//!```
//!
//!##Other URL Parts
//!
//! * Query variables (`http://example.com?a=b&c=d`) can be found in the
//!`query` field and they are accessed in exactly the same fashion as path
//!variables are used.
//!
//! * The fragment (`http://example.com#foo`) is also parsed and can be
//!accessed through `fragment` as an optional `String`.
//!
//!##Logging
//!
//!Rustful has a built in logging infrastructure and it is made available to
//!handlers through the `log` field. This provides logging and error reporting
//!in a unified and more controlled fashion than what panics and `println!`
//!gives. See the [`log`][log] module for more information about the standard
//!alternatives.
//!
//!```
//!# fn something_that_may_fail() -> Result<&'static str, &'static str> { Ok("yo") }
//!use rustful::{Context, Response};
//!use rustful::StatusCode::InternalServerError;
//!
//!fn my_handler(context: Context, mut response: Response) {
//!    match something_that_may_fail() {
//!        Ok(res) => response.into_writer().send(res),
//!        Err(e) => {
//!            context.log.error(&format!("it failed! {}", e));
//!            response.set_status(InternalServerError);
//!        }
//!    }
//!}
//!```
//!
//!##Global Data
//!
//!There is also infrastructure for globally accessible data, that can be
//!accessed through the `global` field. This is meant to provide a place for
//!things like database connections or cached data that should be available to
//!all handlers. The storage space itself is immutable when the server has
//!started, so the only way to change it is through some kind of inner
//!mutability.
//!
//!```
//!use rustful::{Context, Response};
//!use rustful::StatusCode::InternalServerError;
//!
//!fn my_handler(context: Context, mut response: Response) {
//!    if let Some(some_wise_words) = context.global.get::<&str>() {
//!        let res = format!("food for thought: {}", some_wise_words);
//!        response.into_writer().send(res);
//!    } else {
//!        context.log.error("there should be a string literal in `global`");
//!        response.set_status(InternalServerError);
//!    }
//!}
//!```
//!
//!##Request Body
//!
//!The body will not be read in advance, unlike the other parts of the
//!request. It is instead available as a `BodyReader` in the field `body`,
//!through which it can be read and parsed as various data formats, like JSON
//!and query strings. The documentation for [`BodyReader`][body_reader] gives
//!more examples.
//!
//!```
//!use std::io::{BufReader, BufRead};
//!use rustful::{Context, Response};
//!
//!fn my_handler(context: Context, response: Response) {
//!    let mut numbered_lines = BufReader::new(context.body).lines().enumerate();
//!    let mut writer = response.into_writer();
//!
//!    while let Some((line_no, Ok(line))) = numbered_lines.next() {
//!        writer.send(format!("{}: {}", line_no + 1, line));
//!    }
//!}
//!```
//!
//![context]: struct.Context.html
//![headers]: ../header/struct.Headers.html
//![log]: ../log/index.html
//![body_reader]: struct.BodyReader.html

use std::collections::HashMap;
use std::io::{self, Read};
use std::net::SocketAddr;

#[cfg(feature = "rustc_json_body")]
use rustc_serialize::json;
#[cfg(feature = "rustc_json_body")]
use rustc_serialize::Decodable;

use hyper::http::HttpReader;
use hyper::net::NetworkStream;
use hyper::buffer::BufReader;

use utils;

use HttpVersion;
use Method;
use header::Headers;
use log::Log;

use Global;

///A container for handler input, like request data and utilities.
pub struct Context<'a, 'b: 'a, 's> {
    ///Headers from the HTTP request.
    pub headers: Headers,

    ///The HTTP version used in the request.
    pub http_version: HttpVersion,

    ///The client address
    pub address: SocketAddr,

    ///The HTTP method.
    pub method: Method,

    ///The requested path.
    pub path: String,

    ///Hypermedia from the current endpoint.
    pub hypermedia: Hypermedia<'s>,

    ///Route variables.
    pub variables: HashMap<String, String>,

    ///Query variables from the path.
    pub query: HashMap<String, String>,

    ///The fragment part of the URL (after #), if provided.
    pub fragment: Option<String>,

    ///Log for notes, errors and warnings.
    pub log: &'s (Log + 's),

    ///Globally accessible data.
    pub global: &'s Global,

    ///A reader for the request body.
    pub body: BodyReader<'a, 'b>,
}

///A reader for a request body.
pub struct BodyReader<'a, 'b: 'a> {
    request: HttpReader<&'a mut BufReader<&'b mut NetworkStream>>
}

impl<'a, 'b> BodyReader<'a, 'b> {
    pub fn from_reader(request: HttpReader<&'a mut BufReader<&'b mut NetworkStream>>) -> BodyReader<'a, 'b> {
        BodyReader {
            request: request
        }
    }
}

///`BodyReader` extension for reading and parsing a query string.
///
///Examples and more information can be found in [the documentation for
///`BodyReader`][body_reader].
///
///[body_reader]: struct.BodyReader.html
pub trait ExtQueryBody {
    fn read_query_body(&mut self) -> io::Result<HashMap<String, String>>;
}

impl<'a, 'b> ExtQueryBody for BodyReader<'a, 'b> {
    ///Read and parse the request body as a query string. The body will be
    ///decoded as UTF-8 and plain '+' characters will be replaced with spaces.
    ///
    ///A simplified example of how to parse `a=number&b=number`:
    ///
    ///```
    ///use rustful::{Context, Response};
    ///use rustful::context::ExtQueryBody;
    ///
    ///fn my_handler(mut context: Context, response: Response) {
    ///    //Parse the request body as a query string
    ///    let query = context.body.read_query_body().unwrap();
    ///
    ///    //Find "a" and "b" and assume that they are numbers
    ///    let a: f64 = query.get("a").and_then(|number| number.parse().ok()).unwrap();
    ///    let b: f64 = query.get("b").and_then(|number| number.parse().ok()).unwrap();
    ///
    ///    response.into_writer().send(format!("{} + {} = {}", a, b, a + b));
    ///}
    ///```
    #[inline]
    fn read_query_body(&mut self) -> io::Result<HashMap<String, String>> {
        let mut buf = Vec::new();
        try!(self.read_to_end(&mut buf));
        Ok(utils::parse_parameters(&buf))
    }
}

///`BodyReader` extension for reading and parsing a JSON body.
///
///It is available by default and can be toggled using the `rustc_json_body`
///feature. Examples and more information can be found in [the documentation
///for `BodyReader`][body_reader].
///
///[body_reader]: struct.BodyReader.html
#[cfg(feature = "rustc_json_body")]
pub trait ExtJsonBody {
    ///Read the request body into a JSON structure.
    fn read_json_body(&mut self) -> Result<json::Json, json::BuilderError>;

    ///Parse and decode the request body as some type `T`.
    fn decode_json_body<T: Decodable>(&mut self) -> json::DecodeResult<T>;
}

#[cfg(feature = "rustc_json_body")]
impl<'a, 'b> ExtJsonBody for BodyReader<'a, 'b> {
    ///Read the request body into a generic JSON structure. This structure can
    ///then be navigated and parsed freely.
    ///
    ///A simplified example of how to parse `{ "a": number, "b": number }`:
    ///
    ///```
    ///use rustful::{Context, Response};
    ///use rustful::context::ExtJsonBody;
    ///
    ///fn my_handler(mut context: Context, response: Response) {
    ///    //Parse the request body as JSON
    ///    let json = context.body.read_json_body().unwrap();
    ///
    ///    //Find "a" and "b" in the root object and assume that they are numbers
    ///    let a = json.find("a").and_then(|number| number.as_f64()).unwrap();
    ///    let b = json.find("b").and_then(|number| number.as_f64()).unwrap();
    ///
    ///    response.into_writer().send(format!("{} + {} = {}", a, b, a + b));
    ///}
    ///```
    fn read_json_body(&mut self) -> Result<json::Json, json::BuilderError> {
        json::Json::from_reader(self)
    }

    ///Read and decode a request body as a type `T`. The target type must
    ///implement `rustc_serialize::Decodable`.
    ///
    ///A simplified example of how to parse `{ "a": number, "b": number }`:
    ///
    ///```
    ///extern crate rustful;
    ///extern crate rustc_serialize;
    ///
    ///use rustful::{Context, Response};
    ///use rustful::context::ExtJsonBody;
    ///
    ///#[derive(RustcDecodable)]
    ///struct Foo {
    ///    a: f64,
    ///    b: f64
    ///}
    ///
    ///fn my_handler(mut context: Context, response: Response) {
    ///    //Decode a JSON formatted request body into Foo
    ///    let foo: Foo = context.body.decode_json_body().unwrap();
    ///
    ///    let res = format!("{} + {} = {}", foo.a, foo.b, foo.a + foo.b);
    ///    response.into_writer().send(res);
    ///}
    ///# fn main() {}
    ///```
    fn decode_json_body<T: Decodable>(&mut self) -> json::DecodeResult<T> {
        let mut buf = String::new();
        try!(self.read_to_string(&mut buf).map_err(|e| {
            let parse_err = json::ParserError::IoError(e);
            json::DecoderError::ParseError(parse_err)
        }));
        json::decode(&buf)
    }
}

impl<'a, 'b> Read for BodyReader<'a, 'b> {
    ///Read the request body.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.request.read(buf)
    }
}

///Hypermedia connected to an API endpoint.
pub struct Hypermedia<'a> {
    ///Forward links from the current endpoint to other endpoints. These may
    ///include endpoints with the same path, but different method.
    pub links: Vec<Link<'a>>
}

impl<'a> Hypermedia<'a> {
    ///Create an empty `Hypermedia` structure.
    pub fn new() -> Hypermedia<'a> {
        Hypermedia {
            links: vec![]
        }
    }
}

///A hyperlink.
#[derive(PartialEq, Eq, Debug)]
pub struct Link<'a> {
    ///The HTTP method for which an endpoint is available. It can be left
    ///unspecified if the method doesn't matter.
    pub method: Option<Method>,
    ///A relative path from the current location.
    pub path: Vec<LinkSegment<'a>>
}

///A segment of a hyperlink path.
#[derive(PartialEq, Eq, Debug)]
pub enum LinkSegment<'a> {
    ///A static part of a path.
    Static(&'a str),
    ///A dynamic part of a path. Can be substituted with anything.
    Variable(&'a str),
    ///A recursive wildcard. Will recursively match anything.
    RecursiveWildcard
}
<|endoftext|>


<commit_before>use serialize::json::{Json, ToJson};
use std::iter::IteratorExt;
use std::collections::RingBuf;

pub struct Context {
    data: Json
}

static NULL_VALUE: Json = Json::Null;

impl Context {
    pub fn null() -> Context {
        Context {
            data: NULL_VALUE.clone()
        }
    }

    pub fn wraps<'a, T: ToJson>(e: &T) -> Context {
        Context {
            data: e.to_json()
        }
    }

    pub fn navigate(&self, path: &String, relative_path: &String) -> &Json {
        let mut path_stack :RingBuf<&str> = RingBuf::new();
        for p in (*path).split('/') {
            match p {
                "this" | "." => {
                    continue;
                }
                ".." => {
                    path_stack.pop_back();
                }
                _ => {
                    for dot_p in p.split('.') {
                        if p != "this" {
                            path_stack.push_back(p)
                        }
                    }
                }
            }
        }

        for p in (*relative_path).split('/') {
            match p {
                "this" | "." => {
                    continue;
                }
                ".." => {
                    path_stack.pop_back();
                }
                _ => {
                    for dot_p in p.split('.') {
                        if p != "this" {
                            path_stack.push_back(p)
                        }
                    }
                }
            }
        }

        let paths :Vec<&str> = path_stack.iter().map(|x| *x).collect();
        match self.data.find_path(paths.as_slice()){
            Some(j) => j,
            None => &NULL_VALUE
        }
    }
}

pub trait JsonRender {
    fn render(&self) -> String;
}

impl JsonRender for Json {
    fn render(&self) -> String {
        match *self {
            Json::String(_) => {
                let s = format!("{}", *self);
                s.slice_chars(1, s.char_len()-1).to_string()
            },
            _ => {
                format!("{}", *self)
            }
        }
    }
}

#[cfg(test)]
mod test {
    use context::{JsonRender, Context};
    use std::collections::TreeMap;
    use serialize::json::{Json, ToJson};

    struct Address {
        city: String,
        country: String
    }

    impl ToJson for Address {
        fn to_json(&self) -> Json {
            let mut m = TreeMap::new();
            m.insert("city".to_string(), self.city.to_json());
            m.insert("country".to_string(), self.country.to_json());
            Json::Object(m)
        }
    }

    struct Person {
        name: String,
        age: i16,
        addr: Address
    }

    impl ToJson for Person {
        fn to_json(&self) -> Json {
            let mut m = TreeMap::new();
            m.insert("name".to_string(), self.name.to_json());
            m.insert("age".to_string(), self.age.to_json());
            m.insert("addr".to_string(), self.addr.to_json());
            Json::Object(m)
        }
    }

    #[test]
    fn test_render() {
        let v = "hello";
        let ctx = Context::wraps(&v.to_string());
        let this = "this".to_string();
        assert_eq!(ctx.navigate(&this, &this).render(), v.to_string());
    }

    #[test]
    fn test_navigation() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string()
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr
        };

        let ctx = Context::wraps(&person);
        let this = "this".to_string();
        let that = "./name/../addr/country".to_string();

        assert_eq!(ctx.navigate(&this, &that).render(), "China".to_string());

        let v = true;
        let ctx2 = Context::wraps(&v);
        assert_eq!(ctx2.navigate(&"this".to_string(), &"this".to_string()).render(), "true".to_string());
    }
}
<commit_msg>rustup: TreeMap removed from std<commit_after>use serialize::json::{Json, ToJson};
use std::iter::IteratorExt;
use std::collections::RingBuf;

pub struct Context {
    data: Json
}

static NULL_VALUE: Json = Json::Null;

impl Context {
    pub fn null() -> Context {
        Context {
            data: NULL_VALUE.clone()
        }
    }

    pub fn wraps<'a, T: ToJson>(e: &T) -> Context {
        Context {
            data: e.to_json()
        }
    }

    pub fn navigate(&self, path: &String, relative_path: &String) -> &Json {
        let mut path_stack :RingBuf<&str> = RingBuf::new();
        for p in (*path).split('/') {
            match p {
                "this" | "." => {
                    continue;
                }
                ".." => {
                    path_stack.pop_back();
                }
                _ => {
                    for dot_p in p.split('.') {
                        if p != "this" {
                            path_stack.push_back(p)
                        }
                    }
                }
            }
        }

        for p in (*relative_path).split('/') {
            match p {
                "this" | "." => {
                    continue;
                }
                ".." => {
                    path_stack.pop_back();
                }
                _ => {
                    for dot_p in p.split('.') {
                        if p != "this" {
                            path_stack.push_back(p)
                        }
                    }
                }
            }
        }

        let paths :Vec<&str> = path_stack.iter().map(|x| *x).collect();
        match self.data.find_path(paths.as_slice()){
            Some(j) => j,
            None => &NULL_VALUE
        }
    }
}

pub trait JsonRender {
    fn render(&self) -> String;
}

impl JsonRender for Json {
    fn render(&self) -> String {
        match *self {
            Json::String(_) => {
                let s = format!("{}", *self);
                s.slice_chars(1, s.char_len()-1).to_string()
            },
            _ => {
                format!("{}", *self)
            }
        }
    }
}

#[cfg(test)]
mod test {
    use context::{JsonRender, Context};
    use std::collections::BTreeMap;
    use serialize::json::{Json, ToJson};

    struct Address {
        city: String,
        country: String
    }

    impl ToJson for Address {
        fn to_json(&self) -> Json {
            let mut m = BTreeMap::new();
            m.insert("city".to_string(), self.city.to_json());
            m.insert("country".to_string(), self.country.to_json());
            Json::Object(m)
        }
    }

    struct Person {
        name: String,
        age: i16,
        addr: Address
    }

    impl ToJson for Person {
        fn to_json(&self) -> Json {
            let mut m = BTreeMap::new();
            m.insert("name".to_string(), self.name.to_json());
            m.insert("age".to_string(), self.age.to_json());
            m.insert("addr".to_string(), self.addr.to_json());
            Json::Object(m)
        }
    }

    #[test]
    fn test_render() {
        let v = "hello";
        let ctx = Context::wraps(&v.to_string());
        let this = "this".to_string();
        assert_eq!(ctx.navigate(&this, &this).render(), v.to_string());
    }

    #[test]
    fn test_navigation() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string()
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr
        };

        let ctx = Context::wraps(&person);
        let this = "this".to_string();
        let that = "./name/../addr/country".to_string();

        assert_eq!(ctx.navigate(&this, &that).render(), "China".to_string());

        let v = true;
        let ctx2 = Context::wraps(&v);
        assert_eq!(ctx2.navigate(&"this".to_string(), &"this".to_string()).render(), "true".to_string());
    }
}
<|endoftext|>


<commit_before>use super::gl_lib as gl;
use super::gl_lib::types::*;
use super::types::{Color, Viewport, BufferBits, GLError};
use super::buffer::{ArrayBufferBinder, ElementArrayBufferBinder};
use super::program::{ProgramBinder, ProgramAttrib};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder,
    pub program: ProgramBinder
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder,
            program: ProgramBinder
        }
    }

    pub fn clear_color(&mut self, color: Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: BufferBits) {
        unsafe {
            gl::Clear(buffers.bits())
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
        }
    }

    pub fn viewport(&self, viewport: Viewport) {
        unsafe {
            gl::Viewport(viewport.x as GLint,
                         viewport.y as GLint,
                         viewport.width as GLsizei,
                         viewport.height as GLsizei);
        }
    }

    pub fn get_error() -> Option<GLError> {
        unsafe {
            match gl::GetError() {
                gl::INVALID_ENUM =>
                    Some(GLError::InvalidEnum),
                gl::INVALID_VALUE =>
                    Some(GLError::InvalidValue),
                gl::INVALID_OPERATION =>
                    Some(GLError::InvalidOperation),
                gl::INVALID_FRAMEBUFFER_OPERATION =>
                    Some(GLError::InvalidFramebufferOperation),
                gl::OUT_OF_MEMORY =>
                    Some(GLError::OutOfMemory),
                _ =>
                    None
            }
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! use_program {
    ($gl:expr, $program:expr) => {
        $gl.program.bind($program)
    }
}
<commit_msg>Add `dbg_gl_error!` and `dbg_gl_sanity_check!` for checking OpenGL errors<commit_after>use super::gl_lib as gl;
use super::gl_lib::types::*;
use super::types::{Color, Viewport, BufferBits, GLError};
use super::buffer::{ArrayBufferBinder, ElementArrayBufferBinder};
use super::program::{ProgramBinder, ProgramAttrib};

// Used to specify checks that shouldn't fail (but might in unsafe)
macro_rules! dbg_gl_error {
    ($($pat:pat => $msg:expr),*) => {
        if cfg!(debug_assertions) {
            let err = $crate::Context::get_error();
            match err {
                $(Some($pat) => {
                    panic!("OpenGL error {:?} - {}", err, $msg)
                }),*
                None => { }
            }
        }
    }
}

// Used to specify checks that should *never* be able to fail (even in unsafe!)
macro_rules! dbg_gl_sanity_check {
    ($($pat:pat => $msg:expr),*) => {
        dbg_gl_error! { $($pat => concat!("Sanity check failed: ", $msg)),* }
    }
}

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder,
    pub program: ProgramBinder
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder,
            program: ProgramBinder
        }
    }

    pub fn clear_color(&mut self, color: Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: BufferBits) {
        unsafe {
            gl::Clear(buffers.bits())
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
        }
    }

    pub fn viewport(&self, viewport: Viewport) {
        unsafe {
            gl::Viewport(viewport.x as GLint,
                         viewport.y as GLint,
                         viewport.width as GLsizei,
                         viewport.height as GLsizei);
        }
    }

    pub fn get_error() -> Option<GLError> {
        unsafe {
            match gl::GetError() {
                gl::INVALID_ENUM =>
                    Some(GLError::InvalidEnum),
                gl::INVALID_VALUE =>
                    Some(GLError::InvalidValue),
                gl::INVALID_OPERATION =>
                    Some(GLError::InvalidOperation),
                gl::INVALID_FRAMEBUFFER_OPERATION =>
                    Some(GLError::InvalidFramebufferOperation),
                gl::OUT_OF_MEMORY =>
                    Some(GLError::OutOfMemory),
                _ =>
                    None
            }
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! use_program {
    ($gl:expr, $program:expr) => {
        $gl.program.bind($program)
    }
}
<|endoftext|>


<commit_before>/* Copyright 2017 David Li.

 * This file is part of BigRedRPG.

 * BigRedRPG is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.

 * BigRedRPG is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU Affero General Public License
 * along with BigRedRPG.  If not, see <http://www.gnu.org/licenses/>.
 */

use std::ops;

use rand::{self, Rng};

use interactiondb::InteractionDb;
use location::{Location, LocationId, Map};
use student::Student;
use util::rng;

/// Time represents the current game time, stored as the number of
/// minutes since game start.
#[derive(Clone,Copy,Debug,Eq,PartialEq)]
pub struct Time(u32);

pub const TIME_STEP: Time = Time(15);

impl ops::Add for Time {
    type Output = Time;

    fn add(self, rhs: Time) -> Time {
        Time(self.0 + rhs.0)
    }
}

impl ops::AddAssign for Time {
    fn add_assign(&mut self, rhs: Time) {
        self.0 += rhs.0;
    }
}

pub struct Cornell {
    map: Map,

    time: Time,
}

impl Cornell {
    pub fn new() -> Cornell {
        Cornell {
            map: Map::new(),

            time: Time(0),
        }
    }

    pub fn add_location(&mut self, location: Location) -> LocationId {
        self.map.add(location)
    }

    pub fn add_student(&mut self, student: Student, location: LocationId) {
        if let Some(loc) = self.map.get_mut(location) {
            loc.add_student(student);
        }
        else {
            panic!("LocationId not found: {:?}", location);
        }
    }

    pub fn get_map(&self) -> &Map {
        &self.map
    }

    pub fn step(&mut self, interactions: &InteractionDb) {
        self.time += TIME_STEP;

        let mut rng = rand::thread_rng();

        let mut side_effects = Vec::new();

        for (location_id, location) in self.map.iter_mut() {
            for student in location.students.iter_mut() {
                student.check_goals(*location_id);

                let possible_interactions = interactions.search(&student, *location_id);

                if let Some(interaction) = rng.choose(&possible_interactions) {
                    let choices = rng::convert_disposition_list(&interaction.choices, student);

                    let rand_choice = rng::weighted_random(choices.iter().cloned(), &mut rng);
                    if let Some((_choice_index, choice)) = rand_choice {
                        for effect in choice.effects.iter() {
                            effect.apply(*location_id, student, &mut side_effects);
                        }
                    }
                }
            }
        }

        for side_effect in side_effects {
            side_effect.apply(&mut self.map);
        }
    }
}
<commit_msg>feat(Simulation): only process interactions sometimes<commit_after>/* Copyright 2017 David Li.

 * This file is part of BigRedRPG.

 * BigRedRPG is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.

 * BigRedRPG is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU Affero General Public License
 * along with BigRedRPG.  If not, see <http://www.gnu.org/licenses/>.
 */

use std::ops;

use rand::{self, Rng};

use interactiondb::InteractionDb;
use location::{Location, LocationId, Map};
use student::Student;
use util::rng;

/// Time represents the current game time, stored as the number of
/// minutes since game start.
#[derive(Clone,Copy,Debug,Eq,PartialEq)]
pub struct Time(u32);

pub const TIME_STEP: Time = Time(15);

impl ops::Add for Time {
    type Output = Time;

    fn add(self, rhs: Time) -> Time {
        Time(self.0 + rhs.0)
    }
}

impl ops::AddAssign for Time {
    fn add_assign(&mut self, rhs: Time) {
        self.0 += rhs.0;
    }
}

pub struct Cornell {
    map: Map,

    time: Time,
}

impl Cornell {
    pub fn new() -> Cornell {
        Cornell {
            map: Map::new(),

            time: Time(0),
        }
    }

    pub fn add_location(&mut self, location: Location) -> LocationId {
        self.map.add(location)
    }

    pub fn add_student(&mut self, student: Student, location: LocationId) {
        if let Some(loc) = self.map.get_mut(location) {
            loc.add_student(student);
        }
        else {
            panic!("LocationId not found: {:?}", location);
        }
    }

    pub fn get_map(&self) -> &Map {
        &self.map
    }

    pub fn step(&mut self, interactions: &InteractionDb) {
        self.time += TIME_STEP;

        let mut rng = rand::thread_rng();

        let mut side_effects = Vec::new();

        for (location_id, location) in self.map.iter_mut() {
            for student in location.students.iter_mut() {
                student.check_goals(*location_id);

                let roll = rng::d20(&mut rng);

                if roll > 15 {
                    let possible_interactions = interactions.search(&student, *location_id);

                    if let Some(interaction) = rng.choose(&possible_interactions) {
                        let choices = rng::convert_disposition_list(&interaction.choices, student);

                        let rand_choice = rng::weighted_random(choices.iter().cloned(), &mut rng);
                        if let Some((_choice_index, choice)) = rand_choice {
                            for effect in choice.effects.iter() {
                                effect.apply(*location_id, student, &mut side_effects);
                            }
                        }
                    }
                }
                else {
                    let effects = {
                        student.with_weighted_goals(|goals| {
                            let choice = rng::weighted_random(goals.iter().cloned(), &mut rng);

                            if let Some((_, goal)) = choice {
                                Some(goal.apply())
                            }
                            else {
                                None
                            }
                        })
                    };

                    if let Some(effects) = effects {
                        for effect in effects {
                            effect.apply(*location_id, student, &mut side_effects);
                        }
                    }
                }
            }
        }

        for side_effect in side_effects {
            side_effect.apply(&mut self.map);
        }
    }
}
<|endoftext|>


<commit_before>#![allow(experimental)]

use std::io::{File,fs};
use std::io::process::Command;
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;
use std::finally::Finally;

static TEMPLATE: &'static str = include_str!("creator/template.yml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = if muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
      Path::new(format!("{}/.{}/", homedir_string(), &DEFAULT_MUXED_DIR.to_string()))
    } else {
      create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}", muxed_dir.display(), name));
    if !path.exists() {
      create_project_file(path)
    } else {
      println!("Project already exists.");
    }
}

fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to create project {}", path.filename()),
    }
//    Command::new("vim").arg(format!("{}", path.display())).detached();
}

fn create_muxed_dir(name: &String) -> Path {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}

fn muxed_dir_exists(name: &String) -> bool {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    path.exists()
}

fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

#[test]
fn muxed_dir_exists_returns_false() {
  let dir = format!("test_dir_{}", random::<f64>());
  assert!(!muxed_dir_exists(&dir));
}

#[test]
fn muxed_dir_exists_returns_true() {
  let dir = format!("test_dir_{}", random::<f64>());
  create_muxed_dir(&dir);
  assert!(muxed_dir_exists(&dir));

  let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir.as_slice()));
  fs::rmdir_recursive(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}

#[test]
// TODO: Fix this test so it verifies something better.
fn new_doesnt_overwrite_existing_file() {
    let name = format!("test_project_{}", random::<f64>());
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        fs::unlink(path);
    })
}
<commit_msg>Not currently using Command.<commit_after>#![allow(experimental)]

use std::io::{File,fs};
//use std::io::process::Command;
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;
use std::finally::Finally;

static TEMPLATE: &'static str = include_str!("creator/template.yml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = if muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
      Path::new(format!("{}/.{}/", homedir_string(), &DEFAULT_MUXED_DIR.to_string()))
    } else {
      create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}", muxed_dir.display(), name));
    if !path.exists() {
      create_project_file(path)
    } else {
      println!("Project already exists.");
    }
}

fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to create project {}", path.filename()),
    }
//    Command::new("vim").arg(format!("{}", path.display())).detached();
}

fn create_muxed_dir(name: &String) -> Path {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}

fn muxed_dir_exists(name: &String) -> bool {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    path.exists()
}

fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

#[test]
fn muxed_dir_exists_returns_false() {
  let dir = format!("test_dir_{}", random::<f64>());
  assert!(!muxed_dir_exists(&dir));
}

#[test]
fn muxed_dir_exists_returns_true() {
  let dir = format!("test_dir_{}", random::<f64>());
  create_muxed_dir(&dir);
  assert!(muxed_dir_exists(&dir));

  let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir.as_slice()));
  fs::rmdir_recursive(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}

#[test]
// TODO: Fix this test so it verifies something better.
fn new_doesnt_overwrite_existing_file() {
    let name = format!("test_project_{}", random::<f64>());
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        fs::unlink(path);
    })
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::io::Result;
use std::ptr;
use super::liblz4::*;
use liblz4::libc::size_t;

const BUFFER_SIZE: usize = 32 * 1024;

struct DecoderContext {
	c: LZ4FDecompressionContext,
}

pub struct Decoder<R> {
	c: DecoderContext,
	r: R,
	buf: [u8; BUFFER_SIZE],
	pos: usize,
	len: usize,
	eof: bool,
}

impl<R: Read> Decoder<R> {
	/// Creates a new encoder which will have its output written to the given
	/// output stream. The output stream can be re-acquired by calling
	/// `finish()`
	pub fn new(r: R) -> Result<Decoder<R>> {
		Ok (Decoder {
			r: r,
			c: try! (DecoderContext::new()),
			buf: [0; BUFFER_SIZE],
			pos: BUFFER_SIZE,
			len: BUFFER_SIZE,
			eof: false,
		})
	}
}

impl<R: Read> Read for Decoder<R> {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize>
	{
		if self.eof || buf.len() == 0
		{
			return Ok(0);
		}
		let mut dst_offset: usize = 0;
		while dst_offset == 0
		{
			if self.pos >= self.len
			{
				self.pos = 0;
				self.len = try! (self.r.read(&mut self.buf));
				if self.len <= 0
				{
					break;
				}
			}
			while (dst_offset < buf.len()) && (self.pos < self.len)
			{
				let mut src_size = (self.len - self.pos) as size_t;
				let mut dst_size = (buf.len() - dst_offset) as size_t;
				let len = try! (check_error(unsafe {LZ4F_decompress(self.c.c, buf[dst_offset..].as_mut_ptr(), &mut dst_size, self.buf[self.pos..].as_ptr(), &mut src_size, ptr::null())}));
				self.pos += src_size as usize;
				dst_offset += dst_size as usize;
				if len == 0 {
					self.eof = true;
					return Ok(dst_offset);
				}
			}
		}
		Ok(dst_offset)
	}
}

impl DecoderContext {
	fn new() -> Result<DecoderContext>
	{
		let mut context: LZ4FDecompressionContext = ptr::null_mut();
		try! (check_error(unsafe {
			LZ4F_createDecompressionContext(&mut context, LZ4F_VERSION)
		}));
		Ok(DecoderContext {
			c: context
		})
	}
}

impl Drop for DecoderContext {
	fn drop(&mut self) {
		unsafe
		{
			LZ4F_freeDecompressionContext(self.c)
		};
	}
}

#[cfg(test)]
mod test {
	use std::io::{Cursor, Read, Write};
	use super::super::encoder::EncoderBuilder;
	use super::Decoder;

	const BUFFER_SIZE: usize = 64 * 1024;

	#[test]
	fn test_decoder_smoke() {
		let mut encoder = EncoderBuilder::new().level(1).build(Vec::new()).unwrap();
		let expected = b"Some data";
		encoder.write(&expected[..4]).unwrap();
		encoder.write(&expected[4..]).unwrap();
		let (buffer, result) = encoder.finish();
		result.unwrap();

		let mut decoder = Decoder::new(Cursor::new(buffer)).unwrap();
		let mut actual = [0; BUFFER_SIZE];

		let size = decoder.read(&mut actual).unwrap();
		assert_eq!(expected, &actual[0..size]);
	}

	#[test]
	fn test_decoder_random() {
		let mut encoder = EncoderBuilder::new().level(1).build(Vec::new()).unwrap();
		let mut expected = Vec::new();
		let mut rnd: u32 = 42;
		for _ in 0..1027 * 1023 * 7 {
			expected.push((rnd & 0xFF) as u8);
			rnd = ((1664525 as u64) * (rnd as u64) + (1013904223 as u64)) as u32;
		}
		encoder.write(&expected).unwrap();
		let (encoded, result) = encoder.finish();
		result.unwrap();

		let mut decoder = Decoder::new(Cursor::new(encoded)).unwrap();
		let mut actual = Vec::new();
		loop {
			let mut buffer = [0; BUFFER_SIZE];
			let size = decoder.read(&mut buffer).unwrap();
			if size == 0 {
				break;
			}
			actual.write(&buffer[0..size]).unwrap();
		}
		assert_eq!(expected, actual);
	}
}
<commit_msg>More correct smoke test<commit_after>use std::io::Read;
use std::io::Result;
use std::ptr;
use super::liblz4::*;
use liblz4::libc::size_t;

const BUFFER_SIZE: usize = 32 * 1024;

struct DecoderContext {
	c: LZ4FDecompressionContext,
}

pub struct Decoder<R> {
	c: DecoderContext,
	r: R,
	buf: [u8; BUFFER_SIZE],
	pos: usize,
	len: usize,
	eof: bool,
}

impl<R: Read> Decoder<R> {
	/// Creates a new encoder which will have its output written to the given
	/// output stream. The output stream can be re-acquired by calling
	/// `finish()`
	pub fn new(r: R) -> Result<Decoder<R>> {
		Ok (Decoder {
			r: r,
			c: try! (DecoderContext::new()),
			buf: [0; BUFFER_SIZE],
			pos: BUFFER_SIZE,
			len: BUFFER_SIZE,
			eof: false,
		})
	}
}

impl<R: Read> Read for Decoder<R> {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize>
	{
		if self.eof || buf.len() == 0
		{
			return Ok(0);
		}
		let mut dst_offset: usize = 0;
		while dst_offset == 0
		{
			if self.pos >= self.len
			{
				self.pos = 0;
				self.len = try! (self.r.read(&mut self.buf));
				if self.len <= 0
				{
					break;
				}
			}
			while (dst_offset < buf.len()) && (self.pos < self.len)
			{
				let mut src_size = (self.len - self.pos) as size_t;
				let mut dst_size = (buf.len() - dst_offset) as size_t;
				let len = try! (check_error(unsafe {LZ4F_decompress(self.c.c, buf[dst_offset..].as_mut_ptr(), &mut dst_size, self.buf[self.pos..].as_ptr(), &mut src_size, ptr::null())}));
				self.pos += src_size as usize;
				dst_offset += dst_size as usize;
				if len == 0 {
					self.eof = true;
					return Ok(dst_offset);
				}
			}
		}
		Ok(dst_offset)
	}
}

impl DecoderContext {
	fn new() -> Result<DecoderContext>
	{
		let mut context: LZ4FDecompressionContext = ptr::null_mut();
		try! (check_error(unsafe {
			LZ4F_createDecompressionContext(&mut context, LZ4F_VERSION)
		}));
		Ok(DecoderContext {
			c: context
		})
	}
}

impl Drop for DecoderContext {
	fn drop(&mut self) {
		unsafe
		{
			LZ4F_freeDecompressionContext(self.c)
		};
	}
}

#[cfg(test)]
mod test {
	use std::io::{Cursor, Read, Write};
	use super::super::encoder::EncoderBuilder;
	use super::Decoder;

	const BUFFER_SIZE: usize = 64 * 1024;

	#[test]
	fn test_decoder_smoke() {
		let mut encoder = EncoderBuilder::new().level(1).build(Vec::new()).unwrap();
		let mut expected = Vec::new();
		expected.write(b"Some data").unwrap();
		encoder.write(&expected[..4]).unwrap();
		encoder.write(&expected[4..]).unwrap();
		let (buffer, result) = encoder.finish();
		result.unwrap();

		let mut decoder = Decoder::new(Cursor::new(buffer)).unwrap();
		let mut actual = Vec::new();

		decoder.read_to_end(&mut actual).unwrap();
		assert_eq!(expected, actual);
	}

	#[test]
	fn test_decoder_random() {
		let mut encoder = EncoderBuilder::new().level(1).build(Vec::new()).unwrap();
		let mut expected = Vec::new();
		let mut rnd: u32 = 42;
		for _ in 0..1027 * 1023 * 7 {
			expected.push((rnd & 0xFF) as u8);
			rnd = ((1664525 as u64) * (rnd as u64) + (1013904223 as u64)) as u32;
		}
		encoder.write(&expected).unwrap();
		let (encoded, result) = encoder.finish();
		result.unwrap();

		let mut decoder = Decoder::new(Cursor::new(encoded)).unwrap();
		let mut actual = Vec::new();
		loop {
			let mut buffer = [0; BUFFER_SIZE];
			let size = decoder.read(&mut buffer).unwrap();
			if size == 0 {
				break;
			}
			actual.write(&buffer[0..size]).unwrap();
		}
		assert_eq!(expected, actual);
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use num::complex::Complex;

pub trait Default {
    fn one() -> Self;
    fn zero() -> Self;
}

macro_rules! default_impl(
    ($t:ty, $ov:expr, $zv:expr) => {
        impl Default for $t {
            #[inline]
            fn one() -> $t { $ov }
            #[inline]
            fn zero() -> $t { $zv }
        }

        impl Default for Complex<$t> {
            #[inline]
            fn one() -> Complex<$t> { Complex::new($ov, $zv) }
            #[inline]
            fn zero() -> Complex<$t> { Complex::new($zv, $zv) }
        }
    }
);

default_impl!(f32, 1f32, 0f32);
default_impl!(f64, 1f64, 0f64);
<commit_msg>Add negative one to Default<commit_after>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use num::complex::Complex;

pub trait Default {
    fn one() -> Self;
    fn zero() -> Self;
    fn neg_one() -> Self;
}

macro_rules! default_impl(
    ($t:ty, $ov:expr, $zv:expr) => {
        impl Default for $t {
            #[inline]
            fn one() -> $t { $ov }
            #[inline]
            fn zero() -> $t { $zv }
            #[inline]
            fn neg_one() -> $t { -$ov }
        }

        impl Default for Complex<$t> {
            #[inline]
            fn one() -> Complex<$t> { Complex::new($ov, $zv) }
            #[inline]
            fn zero() -> Complex<$t> { Complex::new($zv, $zv) }
            #[inline]
            fn neg_one() -> Complex<$t> { Complex::new(-$ov, $zv) }
        }
    }
);

default_impl!(f32, 1f32, 0f32);
default_impl!(f64, 1f64, 0f64);
<|endoftext|>


<commit_before>use av_format::error::*;
use std::io::SeekFrom;
use av_data::packet::Packet;
use av_data::timeinfo::TimeInfo;
use av_data::params::*;
use av_format::stream::Stream;
use av_format::buffer::Buffered;
use av_format::demuxer::{Demuxer, Event};
use av_format::demuxer::{Descr, Descriptor};
use av_format::common::GlobalInfo;
use std::collections::VecDeque;
use rational::Rational64;

use ebml::{ebml_header, EBMLHeader};
use elements::{segment, segment_element, Cluster, SeekHead, Info, Tracks, TrackEntry,
               SegmentElement, simple_block};
use nom::{self, Err, IResult, Offset};

#[derive(Debug, Clone, PartialEq)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            queue: VecDeque::new(),
            blockstream: Vec::new(),
        }
    }

    pub fn parse_until_tracks<'a>(&mut self, original_input: &'a [u8]) -> IResult<&'a [u8], ()> {
        let (i1, header) = try_parse!(original_input, ebml_header);

        self.header = Some(header);

        let (mut input, _) = try_parse!(i1, segment);

        self.seek_head = None;
        self.info = None;
        self.tracks = None;

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return Ok((input, ()));
            }

            // println!("offset: {}", original_input.offset(input));

            let (i3, element) = try_parse!(input, segment_element);

            match element {
                SegmentElement::SeekHead(s) => {
                    // println!("got seek head: {:#?}", s);
                    if self.seek_head.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    // println!("got info: {:#?}", i);
                    if self.info.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    // println!("got tracks: {:#?}", t);
                    if self.tracks.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.tracks = Some(t);
                    }
                }
                el => {
                    println!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

use nom::Needed;

impl Demuxer for MkvDemuxer {
    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            Ok((i, _)) => {
                info.duration = self.info.as_ref().and_then(|info| info.duration).map(|d| d as u64);
                if let Some(ref t) = self.tracks {
                    info.streams = t.tracks.iter().map(|tr| {
                        track_to_stream(self.info.as_ref().unwrap(), tr)
                    }).collect();
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            },
            Err(Err::Incomplete(needed)) => {
                let sz = match needed {
                    Needed::Size(size) => buf.data().len() + size,
                    _ => 1024,
                };
                Err(Error::MoreDataNeeded(sz))
            },
            e => {
                println!("error reading headers: {:?}", e);
                Err(Error::InvalidData)
            }
        }
    }

    fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
        if let Some(event) = self.queue.pop_front() {
            Ok((SeekFrom::Current(0), event))
        } else {
            // println!("no more stored packet, parsing a new one");
            match segment_element(buf.data()) {
                Ok((i, element)) => {
                    let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                    match element {
                        SegmentElement::Cluster(c) => {
                            //self.clusters.push(c);
                            // println!("got cluster element at timecode: {}", c.timecode);
                            let mut packets = c.generate_packets();
                            self.queue.extend(packets.drain(..));
                            if let Some(event) = self.queue.pop_front() {
                                return Ok((seek, event));
                            }
                        }
                        _el => {
                            // println!("got element: {:#?}", el);
                        }
                    }
                    Ok((seek, Event::MoreDataNeeded(0)))
                },
                Err(Err::Incomplete(Needed::Size(size))) => {
                    Err(Error::MoreDataNeeded(size))
                },
                e => {
                    println!("parsing issue: {:?}", e);
                    Err(Error::InvalidData)
                }
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<String> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS"   => Some("opus".to_owned()),
        "A_VORBIS" => Some("vorbis".to_owned()),
        "V_AV1"    => Some("av1".to_owned()),
        "V_VP8"    => Some("vp8".to_owned()),
        "V_VP9"    => Some("vp9".to_owned()),
        _ => None,
    }
}

fn track_entry_video_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref video) = t.video {
        let v = VideoInfo {
            width: video.pixel_width as usize,
            height: video.pixel_height as usize,
            // TODO parse Colour and/or CodecPrivate to extract the format
            format: None,
        };
        Some(MediaKind::Video(v))
    } else {
        None
    }
}

fn track_entry_audio_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref audio) = t.audio {
        let rate = if let Some(r) = audio.output_sampling_frequency {
            r
        } else {
            audio.sampling_frequency
        };
        // TODO: complete it
        let a = AudioInfo {
            rate: rate as usize,
            map: None,
            format: None,
        };
        Some(MediaKind::Audio(a))
    } else {
        None
    }
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => track_entry_video_kind(t),
        0x2 => track_entry_audio_kind(t),
        _ => None,
    }
}

// TODO: make sure the timecode_scale isn't 0
pub fn track_to_stream(info: &Info, t: &TrackEntry) -> Stream {
    let num = if let Some(ts) = t.track_timecode_scale  {
        (ts * info.timecode_scale as f64) as i64
    } else {
        info.timecode_scale as i64
    };

    Stream {
        id: t.track_uid as isize,
        index: t.track_number as usize,
        start: None,
        duration: t.default_duration,
        timebase: Rational64::new(num, 1000 * 1000 * 1000),
        // TODO: Extend CodecParams and fill it with the remaining information
        params: CodecParams {
            extradata: t.codec_private.clone(),
            bit_rate: 0,
            delay: t.codec_delay.unwrap_or(0) as usize,
            convergence_window: t.seek_pre_roll.unwrap_or(0) as usize,
            codec_id: track_entry_codec_id(t),
            kind: track_entry_media_kind(t),
        },
    }
}

impl<'a> Cluster<'a> {
    pub fn generate_packets(&self) -> Vec<Event> {
        let mut v = Vec::new();

        for block_data in self.simple_block.iter() {
            if let Ok((i, block)) = simple_block(block_data) {
                //println!("parsing simple block: {:?}", block);
                let packet = Packet {
                    data: i.into(),
                    t: TimeInfo {
                        pts: Some(block.timecode as i64),
                        dts: None,
                        duration: None,
                        timebase: None,
                    },
                    pos: None,
                    stream_index: block.track_number as isize,
                    is_key: block.keyframe,
                    is_corrupted: false,
                };

                v.push(Event::NewPacket(packet));
            } else {
                println!("error parsing simple block");
            }
        }

        v
    }
}

struct Des {
    d: Descr,
}

impl Descriptor for Des {
    fn create(&self) -> Box<Demuxer> {
        Box::new(MkvDemuxer::new())
    }
    fn describe<'a>(&'a self) -> &'a Descr {
        &self.d
    }
    fn probe(&self, data: &[u8]) -> u8 {
        match ebml_header(&data[..100]) {
            Ok(_) => 100,
            _ => 0,
        }
    }
}

pub const MKV_DESC: &Descriptor = &Des {
    d: Descr {
        name: "matroska",
        demuxer: "mkv",
        description: "Nom-based Matroska demuxer",
        extensions: &["mkv", "webm", "mka"],
        mime: &["video/x-matroska", "audio/x-matroska"],
    }
};

#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
    use super::*;
    use std::io::Cursor;
    use nom::Offset;
    use av_format::demuxer::Context;
    use av_format::buffer::*;

    const webm: &'static [u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        println!("got parsing res: {:?}", res);
        match res {
            Ok((i, _)) => {
                println!("offset: {} bytes", webm.offset(i));
            }
            e => {
                println!("could not parse: {:?}", e);
            }
        }

        println!("demuxer: {:#?}", demuxer);
    }

    #[test]
    fn parse_headers_incremental_buffer() {
        let mut demuxer = MkvDemuxer::new();

        for n in 100..2000 {
            let res = demuxer.parse_until_tracks(&webm[0..n]);
            match res {
                Ok(_) => println!("Size {} ok", n),
                Err(Err::Incomplete(needed)) => println!("Incomplete {} needs {:?}", n, needed),
                Err(e) => {
                    panic!("Error at size {}: {:?}", n, e);
                }
            }
        }
    }

    #[test]
    fn context() {
        let mut context = Context::new(Box::new(MkvDemuxer::new()),
                                       Box::new(AccReader::new(Cursor::new(webm))));
        println!("DEMUXER CONTEXT read headers: {:?}", context.read_headers().unwrap());
        println!("DEMUXER CONTEXT streams: {:?}", context.info.streams);
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
    }
}
<commit_msg>Initial channelmap support<commit_after>use av_format::error::*;
use std::io::SeekFrom;
use av_data::packet::Packet;
use av_data::timeinfo::TimeInfo;
use av_data::params::*;
use av_format::stream::Stream;
use av_format::buffer::Buffered;
use av_format::demuxer::{Demuxer, Event};
use av_format::demuxer::{Descr, Descriptor};
use av_format::common::GlobalInfo;
use std::collections::VecDeque;
use rational::Rational64;

use ebml::{ebml_header, EBMLHeader};
use elements::{segment, segment_element, Cluster, SeekHead, Info, Tracks, TrackEntry,
               SegmentElement, simple_block};
use nom::{self, Err, IResult, Offset};

#[derive(Debug, Clone, PartialEq)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            queue: VecDeque::new(),
            blockstream: Vec::new(),
        }
    }

    pub fn parse_until_tracks<'a>(&mut self, original_input: &'a [u8]) -> IResult<&'a [u8], ()> {
        let (i1, header) = try_parse!(original_input, ebml_header);

        self.header = Some(header);

        let (mut input, _) = try_parse!(i1, segment);

        self.seek_head = None;
        self.info = None;
        self.tracks = None;

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return Ok((input, ()));
            }

            // println!("offset: {}", original_input.offset(input));

            let (i3, element) = try_parse!(input, segment_element);

            match element {
                SegmentElement::SeekHead(s) => {
                    // println!("got seek head: {:#?}", s);
                    if self.seek_head.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    // println!("got info: {:#?}", i);
                    if self.info.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    // println!("got tracks: {:#?}", t);
                    if self.tracks.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.tracks = Some(t);
                    }
                }
                el => {
                    println!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

use nom::Needed;

impl Demuxer for MkvDemuxer {
    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            Ok((i, _)) => {
                info.duration = self.info.as_ref().and_then(|info| info.duration).map(|d| d as u64);
                if let Some(ref t) = self.tracks {
                    info.streams = t.tracks.iter().map(|tr| {
                        track_to_stream(self.info.as_ref().unwrap(), tr)
                    }).collect();
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            },
            Err(Err::Incomplete(needed)) => {
                let sz = match needed {
                    Needed::Size(size) => buf.data().len() + size,
                    _ => 1024,
                };
                Err(Error::MoreDataNeeded(sz))
            },
            e => {
                println!("error reading headers: {:?}", e);
                Err(Error::InvalidData)
            }
        }
    }

    fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
        if let Some(event) = self.queue.pop_front() {
            Ok((SeekFrom::Current(0), event))
        } else {
            // println!("no more stored packet, parsing a new one");
            match segment_element(buf.data()) {
                Ok((i, element)) => {
                    let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                    match element {
                        SegmentElement::Cluster(c) => {
                            //self.clusters.push(c);
                            // println!("got cluster element at timecode: {}", c.timecode);
                            let mut packets = c.generate_packets();
                            self.queue.extend(packets.drain(..));
                            if let Some(event) = self.queue.pop_front() {
                                return Ok((seek, event));
                            }
                        }
                        _el => {
                            // println!("got element: {:#?}", el);
                        }
                    }
                    Ok((seek, Event::MoreDataNeeded(0)))
                },
                Err(Err::Incomplete(Needed::Size(size))) => {
                    Err(Error::MoreDataNeeded(size))
                },
                e => {
                    println!("parsing issue: {:?}", e);
                    Err(Error::InvalidData)
                }
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<String> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS"   => Some("opus".to_owned()),
        "A_VORBIS" => Some("vorbis".to_owned()),
        "V_AV1"    => Some("av1".to_owned()),
        "V_VP8"    => Some("vp8".to_owned()),
        "V_VP9"    => Some("vp9".to_owned()),
        _ => None,
    }
}

fn track_entry_video_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref video) = t.video {
        let v = VideoInfo {
            width: video.pixel_width as usize,
            height: video.pixel_height as usize,
            // TODO parse Colour and/or CodecPrivate to extract the format
            format: None,
        };
        Some(MediaKind::Video(v))
    } else {
        None
    }
}

fn track_entry_audio_kind(t: &TrackEntry) -> Option<MediaKind> {
    use av_data::audiosample::*;
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref audio) = t.audio {
        let rate = if let Some(r) = audio.output_sampling_frequency {
            r
        } else {
            audio.sampling_frequency
        };
        // TODO: complete it
        let map = if audio.channel_positions.is_none() {
            Some(ChannelMap::default_map(audio.channels as usize))
        } else {
            unimplemented!("Convert matroska map to rust-av map")
        };
        let a = AudioInfo {
            rate: rate as usize,
            map: map,
            format: None,
        };
        Some(MediaKind::Audio(a))
    } else {
        None
    }
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => track_entry_video_kind(t),
        0x2 => track_entry_audio_kind(t),
        _ => None,
    }
}

// TODO: make sure the timecode_scale isn't 0
pub fn track_to_stream(info: &Info, t: &TrackEntry) -> Stream {
    let num = if let Some(ts) = t.track_timecode_scale  {
        (ts * info.timecode_scale as f64) as i64
    } else {
        info.timecode_scale as i64
    };

    Stream {
        id: t.track_uid as isize,
        index: t.track_number as usize,
        start: None,
        duration: t.default_duration,
        timebase: Rational64::new(num, 1000 * 1000 * 1000),
        // TODO: Extend CodecParams and fill it with the remaining information
        params: CodecParams {
            extradata: t.codec_private.clone(),
            bit_rate: 0,
            delay: t.codec_delay.unwrap_or(0) as usize,
            convergence_window: t.seek_pre_roll.unwrap_or(0) as usize,
            codec_id: track_entry_codec_id(t),
            kind: track_entry_media_kind(t),
        },
    }
}

impl<'a> Cluster<'a> {
    pub fn generate_packets(&self) -> Vec<Event> {
        let mut v = Vec::new();

        for block_data in self.simple_block.iter() {
            if let Ok((i, block)) = simple_block(block_data) {
                //println!("parsing simple block: {:?}", block);
                let packet = Packet {
                    data: i.into(),
                    t: TimeInfo {
                        pts: Some(block.timecode as i64),
                        dts: None,
                        duration: None,
                        timebase: None,
                    },
                    pos: None,
                    stream_index: block.track_number as isize,
                    is_key: block.keyframe,
                    is_corrupted: false,
                };

                v.push(Event::NewPacket(packet));
            } else {
                println!("error parsing simple block");
            }
        }

        v
    }
}

struct Des {
    d: Descr,
}

impl Descriptor for Des {
    fn create(&self) -> Box<Demuxer> {
        Box::new(MkvDemuxer::new())
    }
    fn describe<'a>(&'a self) -> &'a Descr {
        &self.d
    }
    fn probe(&self, data: &[u8]) -> u8 {
        match ebml_header(&data[..100]) {
            Ok(_) => 100,
            _ => 0,
        }
    }
}

pub const MKV_DESC: &Descriptor = &Des {
    d: Descr {
        name: "matroska",
        demuxer: "mkv",
        description: "Nom-based Matroska demuxer",
        extensions: &["mkv", "webm", "mka"],
        mime: &["video/x-matroska", "audio/x-matroska"],
    }
};

#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
    use super::*;
    use std::io::Cursor;
    use nom::Offset;
    use av_format::demuxer::Context;
    use av_format::buffer::*;

    const webm: &'static [u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        println!("got parsing res: {:?}", res);
        match res {
            Ok((i, _)) => {
                println!("offset: {} bytes", webm.offset(i));
            }
            e => {
                println!("could not parse: {:?}", e);
            }
        }

        println!("demuxer: {:#?}", demuxer);
    }

    #[test]
    fn parse_headers_incremental_buffer() {
        let mut demuxer = MkvDemuxer::new();

        for n in 100..2000 {
            let res = demuxer.parse_until_tracks(&webm[0..n]);
            match res {
                Ok(_) => println!("Size {} ok", n),
                Err(Err::Incomplete(needed)) => println!("Incomplete {} needs {:?}", n, needed),
                Err(e) => {
                    panic!("Error at size {}: {:?}", n, e);
                }
            }
        }
    }

    #[test]
    fn context() {
        let mut context = Context::new(Box::new(MkvDemuxer::new()),
                                       Box::new(AccReader::new(Cursor::new(webm))));
        println!("DEMUXER CONTEXT read headers: {:?}", context.read_headers().unwrap());
        println!("DEMUXER CONTEXT streams: {:?}", context.info.streams);
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
    }
}
<|endoftext|>


<commit_before>use std::time::Duration;

pub mod env_reader;
pub mod sleeper;

pub struct Config {
    pub hosts: String,
    pub global_timeout: u64,
    pub tcp_connection_timeout: u64,
    pub wait_before: u64,
    pub wait_after: u64,
    pub wait_sleep_interval: u64,
}

const LINE_SEPARATOR: &str = "--------------------------------------------------------";

pub fn wait(
    sleep: &mut dyn crate::sleeper::Sleeper,
    config: &Config,
    on_timeout: &mut dyn FnMut(),
) {
    println!("{}", LINE_SEPARATOR);
    println!("docker-compose-wait - starting with configuration:");
    println!(" - Hosts to be waiting for: [{}]", config.hosts);
    println!(" - Timeout before failure: {} seconds ", config.global_timeout);
    println!(" - TCP connection timeout before retry: {} seconds ", config.tcp_connection_timeout);
    println!(
        " - Sleeping time before checking for hosts availability: {} seconds",
        config.wait_before
    );
    println!(
        " - Sleeping time once all hosts are available: {} seconds",
        config.wait_after
    );
    println!("{}", LINE_SEPARATOR);

    if config.wait_before > 0 {
        println!(
            "Waiting {} seconds before checking for hosts availability",
            config.wait_before
        );
        println!("{}", LINE_SEPARATOR);
        sleep.sleep(config.wait_before);
    }

    if !config.hosts.trim().is_empty() {
        sleep.reset();
        for host in config.hosts.trim().split(',') {
            println!("Checking availability of {}", host);
            while !port_check::is_port_reachable_with_timeout(&host.trim().to_string().parse().expect("The host IP should be valid"), Duration::from_secs(config.tcp_connection_timeout)) {
                println!("Host {} not yet available...", host);
                if sleep.elapsed(config.global_timeout) {
                    println!(
                        "Timeout! After {} seconds some hosts are still not reachable",
                        config.global_timeout
                    );
                    on_timeout();
                    return;
                }
                sleep.sleep(config.wait_sleep_interval);
            }
            println!("Host {} is now available!", host);
            println!("{}", LINE_SEPARATOR);
        }
    }

    if config.wait_after > 0 {
        println!(
            "Waiting {} seconds after hosts availability",
            config.wait_after
        );
        println!("{}", LINE_SEPARATOR);
        sleep.sleep(config.wait_after);
    }

    println!("docker-compose-wait - Everything's fine, the application can now start!");
    println!("{}", LINE_SEPARATOR);
}

pub fn config_from_env() -> Config {
    Config {
        hosts: crate::env_reader::env_var(&"WAIT_HOSTS".to_string(), "".to_string()),
        global_timeout: to_int(
            &crate::env_reader::env_var(&"WAIT_HOSTS_TIMEOUT".to_string(), "".to_string()),
            30,
        ),
        tcp_connection_timeout: to_int(
            &crate::env_reader::env_var(&"WAIT_HOST_CONNECT_TIMEOUT".to_string(), "".to_string()),
            5,
        ),
        wait_before: to_int(
            &crate::env_reader::env_var(&"WAIT_BEFORE_HOSTS".to_string(), "".to_string()),
            0,
        ),
        wait_after: to_int(
            &crate::env_reader::env_var(&"WAIT_AFTER_HOSTS".to_string(), "".to_string()),
            0,
        ),
        wait_sleep_interval: to_int(
            &crate::env_reader::env_var(&"WAIT_SLEEP_INTERVAL".to_string(), "".to_string()),
            1,
        ),
    }
}

fn to_int(number: &str, default: u64) -> u64 {
    match number.parse::<u64>() {
        Ok(value) => value,
        Err(_e) => default,
    }
}

#[cfg(test)]
mod test {

    use super::*;
    use lazy_static::*;
    use std::env;
    use std::sync::Mutex;

    lazy_static! {
        static ref TEST_MUTEX: Mutex<()> = Mutex::new(());
    }

    #[test]
    fn should_return_int_value() {
        let value = to_int("32", 0);
        assert_eq!(32, value)
    }

    #[test]
    fn should_return_zero_when_negative_value() {
        let value = to_int("-32", 10);
        assert_eq!(10, value)
    }

    #[test]
    fn should_return_zero_when_invalid_value() {
        let value = to_int("hello", 0);
        assert_eq!(0, value)
    }

    #[test]
    fn should_return_zero_when_empty_value() {
        let value = to_int("", 11);
        assert_eq!(11, value)
    }

    #[test]
    fn config_should_use_default_values() {
        let _guard = TEST_MUTEX.lock().unwrap();
        set_env("", "", "10o", "10", "", "abc");
        let config = config_from_env();
        assert_eq!("".to_string(), config.hosts);
        assert_eq!(30, config.global_timeout);
        assert_eq!(5, config.tcp_connection_timeout);
        assert_eq!(0, config.wait_before);
        assert_eq!(10, config.wait_after);
    }

    #[test]
    fn should_get_config_values_from_env() {
        let _guard = TEST_MUTEX.lock().unwrap();
        set_env("localhost:1234", "20", "2", "3", "4", "23");
        let config = config_from_env();
        assert_eq!("localhost:1234".to_string(), config.hosts);
        assert_eq!(20, config.global_timeout);
        assert_eq!(23, config.tcp_connection_timeout);
        assert_eq!(2, config.wait_before);
        assert_eq!(3, config.wait_after);
        assert_eq!(4, config.wait_sleep_interval);
    }

    #[test]
    fn should_get_default_config_values() {
        let _guard = TEST_MUTEX.lock().unwrap();
        set_env("localhost:1234", "", "", "", "", "");
        let config = config_from_env();
        assert_eq!("localhost:1234".to_string(), config.hosts);
        assert_eq!(30, config.global_timeout);
        assert_eq!(5, config.tcp_connection_timeout);
        assert_eq!(0, config.wait_before);
        assert_eq!(0, config.wait_after);
        assert_eq!(1, config.wait_sleep_interval);
    }

    fn set_env(hosts: &str, timeout: &str, before: &str, after: &str, sleep: &str, tcp_timeout: &str) {
        env::set_var("WAIT_BEFORE_HOSTS", before.to_string());
        env::set_var("WAIT_AFTER_HOSTS", after.to_string());
        env::set_var("WAIT_HOSTS_TIMEOUT", timeout.to_string());
        env::set_var("WAIT_HOST_CONNECT_TIMEOUT", tcp_timeout.to_string());
        env::set_var("WAIT_HOSTS", hosts.to_string());
        env::set_var("WAIT_SLEEP_INTERVAL", sleep.to_string());
    }
}
<commit_msg>Print sleeping time between retries<commit_after>use std::time::Duration;

pub mod env_reader;
pub mod sleeper;

pub struct Config {
    pub hosts: String,
    pub global_timeout: u64,
    pub tcp_connection_timeout: u64,
    pub wait_before: u64,
    pub wait_after: u64,
    pub wait_sleep_interval: u64,
}

const LINE_SEPARATOR: &str = "--------------------------------------------------------";

pub fn wait(
    sleep: &mut dyn crate::sleeper::Sleeper,
    config: &Config,
    on_timeout: &mut dyn FnMut(),
) {
    println!("{}", LINE_SEPARATOR);
    println!("docker-compose-wait - starting with configuration:");
    println!(" - Hosts to be waiting for: [{}]", config.hosts);
    println!(" - Timeout before failure: {} seconds ", config.global_timeout);
    println!(" - TCP connection timeout before retry: {} seconds ", config.tcp_connection_timeout);
    println!(
        " - Sleeping time before checking for hosts availability: {} seconds",
        config.wait_before
    );
    println!(
        " - Sleeping time once all hosts are available: {} seconds",
        config.wait_after
    );
    println!(
        " - Sleeping time between retries: {} seconds",
        config.wait_sleep_interval
    );
    println!("{}", LINE_SEPARATOR);

    if config.wait_before > 0 {
        println!(
            "Waiting {} seconds before checking for hosts availability",
            config.wait_before
        );
        println!("{}", LINE_SEPARATOR);
        sleep.sleep(config.wait_before);
    }

    if !config.hosts.trim().is_empty() {
        sleep.reset();
        for host in config.hosts.trim().split(',') {
            println!("Checking availability of {}", host);
            while !port_check::is_port_reachable_with_timeout(&host.trim().to_string().parse().expect("The host IP should be valid"), Duration::from_secs(config.tcp_connection_timeout)) {
                println!("Host {} not yet available...", host);
                if sleep.elapsed(config.global_timeout) {
                    println!(
                        "Timeout! After {} seconds some hosts are still not reachable",
                        config.global_timeout
                    );
                    on_timeout();
                    return;
                }
                sleep.sleep(config.wait_sleep_interval);
            }
            println!("Host {} is now available!", host);
            println!("{}", LINE_SEPARATOR);
        }
    }

    if config.wait_after > 0 {
        println!(
            "Waiting {} seconds after hosts availability",
            config.wait_after
        );
        println!("{}", LINE_SEPARATOR);
        sleep.sleep(config.wait_after);
    }

    println!("docker-compose-wait - Everything's fine, the application can now start!");
    println!("{}", LINE_SEPARATOR);
}

pub fn config_from_env() -> Config {
    Config {
        hosts: crate::env_reader::env_var(&"WAIT_HOSTS".to_string(), "".to_string()),
        global_timeout: to_int(
            &crate::env_reader::env_var(&"WAIT_HOSTS_TIMEOUT".to_string(), "".to_string()),
            30,
        ),
        tcp_connection_timeout: to_int(
            &crate::env_reader::env_var(&"WAIT_HOST_CONNECT_TIMEOUT".to_string(), "".to_string()),
            5,
        ),
        wait_before: to_int(
            &crate::env_reader::env_var(&"WAIT_BEFORE_HOSTS".to_string(), "".to_string()),
            0,
        ),
        wait_after: to_int(
            &crate::env_reader::env_var(&"WAIT_AFTER_HOSTS".to_string(), "".to_string()),
            0,
        ),
        wait_sleep_interval: to_int(
            &crate::env_reader::env_var(&"WAIT_SLEEP_INTERVAL".to_string(), "".to_string()),
            1,
        ),
    }
}

fn to_int(number: &str, default: u64) -> u64 {
    match number.parse::<u64>() {
        Ok(value) => value,
        Err(_e) => default,
    }
}

#[cfg(test)]
mod test {

    use super::*;
    use lazy_static::*;
    use std::env;
    use std::sync::Mutex;

    lazy_static! {
        static ref TEST_MUTEX: Mutex<()> = Mutex::new(());
    }

    #[test]
    fn should_return_int_value() {
        let value = to_int("32", 0);
        assert_eq!(32, value)
    }

    #[test]
    fn should_return_zero_when_negative_value() {
        let value = to_int("-32", 10);
        assert_eq!(10, value)
    }

    #[test]
    fn should_return_zero_when_invalid_value() {
        let value = to_int("hello", 0);
        assert_eq!(0, value)
    }

    #[test]
    fn should_return_zero_when_empty_value() {
        let value = to_int("", 11);
        assert_eq!(11, value)
    }

    #[test]
    fn config_should_use_default_values() {
        let _guard = TEST_MUTEX.lock().unwrap();
        set_env("", "", "10o", "10", "", "abc");
        let config = config_from_env();
        assert_eq!("".to_string(), config.hosts);
        assert_eq!(30, config.global_timeout);
        assert_eq!(5, config.tcp_connection_timeout);
        assert_eq!(0, config.wait_before);
        assert_eq!(10, config.wait_after);
    }

    #[test]
    fn should_get_config_values_from_env() {
        let _guard = TEST_MUTEX.lock().unwrap();
        set_env("localhost:1234", "20", "2", "3", "4", "23");
        let config = config_from_env();
        assert_eq!("localhost:1234".to_string(), config.hosts);
        assert_eq!(20, config.global_timeout);
        assert_eq!(23, config.tcp_connection_timeout);
        assert_eq!(2, config.wait_before);
        assert_eq!(3, config.wait_after);
        assert_eq!(4, config.wait_sleep_interval);
    }

    #[test]
    fn should_get_default_config_values() {
        let _guard = TEST_MUTEX.lock().unwrap();
        set_env("localhost:1234", "", "", "", "", "");
        let config = config_from_env();
        assert_eq!("localhost:1234".to_string(), config.hosts);
        assert_eq!(30, config.global_timeout);
        assert_eq!(5, config.tcp_connection_timeout);
        assert_eq!(0, config.wait_before);
        assert_eq!(0, config.wait_after);
        assert_eq!(1, config.wait_sleep_interval);
    }

    fn set_env(hosts: &str, timeout: &str, before: &str, after: &str, sleep: &str, tcp_timeout: &str) {
        env::set_var("WAIT_BEFORE_HOSTS", before.to_string());
        env::set_var("WAIT_AFTER_HOSTS", after.to_string());
        env::set_var("WAIT_HOSTS_TIMEOUT", timeout.to_string());
        env::set_var("WAIT_HOST_CONNECT_TIMEOUT", tcp_timeout.to_string());
        env::set_var("WAIT_HOSTS", hosts.to_string());
        env::set_var("WAIT_SLEEP_INTERVAL", sleep.to_string());
    }
}
<|endoftext|>