<commit_before>#![crate_type = "lib"]
#![crate_name = "rs_es"]

#![feature(collections)]
#![feature(convert)]

#[macro_use] extern crate log;
extern crate hyper;
extern crate rustc_serialize;

use std::error::Error;
use std::io;
use std::fmt;

use hyper::client::response;
use hyper::status::StatusCode;

use rustc_serialize::json;
use rustc_serialize::json::{Json, ToJson};

// Error handling

#[derive(Debug)]
pub enum EsError {
    EsError(String),
    EsServerError(String),
    HttpError(hyper::error::HttpError),
    IoError(io::Error),
    JsonBuilderError(json::BuilderError)
}

impl From<io::Error> for EsError {
    fn from(err: io::Error) -> EsError {
        EsError::IoError(err)
    }
}

impl From<hyper::error::HttpError> for EsError {
    fn from(err: hyper::error::HttpError) -> EsError {
        EsError::HttpError(err)
    }
}

impl From<json::BuilderError> for EsError {
    fn from(err: json::BuilderError) -> EsError {
        EsError::JsonBuilderError(err)
    }
}

impl<'a> From<&'a mut response::Response> for EsError {
    fn from(err: &'a mut response::Response) -> EsError {
        EsError::EsServerError(format!("{} - {:?}", err.status, err))
    }
}

impl Error for EsError {
    fn description(&self) -> &str {
        match *self {
            EsError::EsError(ref err) => err.as_str(),
            EsError::EsServerError(ref err) => err.as_str(),
            EsError::HttpError(ref err) => err.description(),
            EsError::IoError(ref err) => err.description(),
            EsError::JsonBuilderError(ref err) => err.description()
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            EsError::EsError(_)                => None,
            EsError::EsServerError(_)          => None,
            EsError::HttpError(ref err)        => Some(err as &Error),
            EsError::IoError(ref err)          => Some(err as &Error),
            EsError::JsonBuilderError(ref err) => Some(err as &Error)
        }
    }
}

impl fmt::Display for EsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            EsError::EsError(ref s) => fmt::Display::fmt(s, f),
            EsError::EsServerError(ref s) => fmt::Display::fmt(s, f),
            EsError::HttpError(ref err) => fmt::Display::fmt(err, f),
            EsError::IoError(ref err) => fmt::Display::fmt(err, f),
            EsError::JsonBuilderError(ref err) => fmt::Display::fmt(err, f)
        }
    }
}

// Utilities

fn format_query_string(options: &mut Vec<(&'static str, String)>) -> String {
    let mut st = String::new();
    if options.is_empty() {
        return st;
    }
    st.push_str("?");
    for (k, v) in options.drain() {
        st.push_str(k);
        st.push_str("=");
        st.push_str(v.as_str());
        st.push_str("&");
    }
    st.pop();
    st
}

// The client

fn do_req<'a>(rb:   hyper::client::RequestBuilder<'a, &str>,
              body: Option<&'a str>) -> Result<Option<Json>, EsError> {
    info!("Params (body={:?})", body.unwrap());
    let mut result = match body {
        Some(json_str) => rb.body(json_str).send(),
        None           => rb.send()
    };
    info!("Result: {:?}", result);
    match result {
        Ok(ref mut r) => match r.status {
            StatusCode::Ok |
            StatusCode::Created  => match Json::from_reader(r) {
                Ok(json) => Ok(Some(json)),
                Err(e)   => Err(EsError::from(e))
            },
            StatusCode::NotFound => Ok(None),
            _                    => Err(EsError::from(r))
        },
        Err(e)        => Err(EsError::from(e))
    }
}

pub struct Client {
    host:        String,
    port:        u32,
    http_client: hyper::Client
}

macro_rules! es_op {
    ($n:ident) => {
        fn $n(&mut self, url: &str, body: Option<&Json>) -> Result<Option<Json>, EsError> {
            info!("Doing {} on {} with {:?}", stringify!($n), url, body);
            match body {
                Some(json) => {
                    let json_string = json::encode(json).unwrap();
                    do_req(self.http_client.$n(url), Some(json_string.as_str()))
                },
                None => {
                    do_req(self.http_client.$n(url), None)
                }
            }
        }
    }
}

impl Client {
    pub fn new(host: String, port: u32) -> Client {
        Client {
            host:        host,
            port:        port,
            http_client: hyper::Client::new()
        }
    }

    fn get_base_url(&self) -> String {
        format!("http://{}:{}/", self.host, self.port)
    }

    es_op!(get);
    es_op!(post);
    es_op!(put);

    pub fn version(&mut self) -> Result<String, EsError> {
        let url = self.get_base_url();
        let json = try!(self.get(url.as_str(), None)).unwrap();
        match json.find_path(&["version", "number"]) {
            Some(version) => match version.as_string() {
                Some(string) => Ok(string.to_string()),
                None         => Err(EsError::EsError(format!("Cannot find version number in: {:?}",
                                                             json)))
            },
            None          => Err(EsError::EsError(format!("Cannot find version number in {:?}",
                                                          json)))
        }
    }

    pub fn index<'a>(&'a mut self, index: &'a str, doc_type: &'a str) -> IndexOperation {
        IndexOperation::new(self, index, doc_type)
    }
}

// Specific operations

type Options = Vec<(&'static str, String)>;

macro_rules! add_option {
    ($n:ident, $e:expr, $t:ident) => (
        pub fn $n<T: ToString>(&'a mut self, val: &T) -> &'a mut $t {
            self.options.push(($e, val.to_string()));
            self
        }
    )
}

pub struct IndexOperation<'a> {
    client:   &'a mut Client,
    index:    &'a str,
    doc_type: &'a str,
    id:       Option<&'a str>,
    options:  Options,
    document: Option<Json>
}

impl<'a> IndexOperation<'a> {
    fn new(client: &'a mut Client, index: &'a str, doc_type: &'a str) -> IndexOperation<'a> {
        IndexOperation {
            client:   client,
            index:    index,
            doc_type: doc_type,
            id:       None,
            options:  Options::new(),
            document: None
        }
    }

    pub fn with_doc<T: ToJson>(&'a mut self, doc: &T) -> &'a mut IndexOperation {
        self.document = Some(doc.to_json());
        self
    }

    pub fn with_id(&'a mut self, id: &'a str) -> &'a mut IndexOperation {
        self.id = Some(id);
        self
    }

    add_option!(with_ttl, "ttl", IndexOperation);
    add_option!(with_version, "version", IndexOperation);
    add_option!(with_version_type, "version_type", IndexOperation);
    add_option!(with_op_type, "op_type", IndexOperation);
    add_option!(with_routing, "routing", IndexOperation);
    add_option!(with_parent, "parent", IndexOperation);
    add_option!(with_timestamp, "timestamp", IndexOperation);
    add_option!(with_refresh, "refresh", IndexOperation);
    add_option!(with_timeout, "timeout", IndexOperation);

    pub fn send(&'a mut self) -> Result<Json, EsError> {
        let result = try!(match self.id {
            Some(id) => {
                let url = format!("{}{}/{}/{}{}",
                                  self.client.get_base_url(),
                                  self.index,
                                  self.doc_type,
                                  id,
                                  format_query_string(&mut self.options));
                self.client.put(url.as_str(), match self.document {
                    Some(ref doc) => Some(doc),
                    None          => None
                })
            },
            None    => {
                let url = format!("{}{}/{}{}",
                                  self.client.get_base_url(),
                                  self.index,
                                  self.doc_type,
                                  format_query_string(&mut self.options));
                self.client.post(url.as_str(), match self.document {
                    Some(ref doc) => Some(doc),
                    None          => None
                })
            }
        });
        Ok(result.unwrap())
    }
}

#[cfg(test)]
mod tests {
    extern crate env_logger;
    extern crate regex;

    use super::Client;

    use std::collections::BTreeMap;

    use self::regex::Regex;

    use rustc_serialize::json;
    use rustc_serialize::json::{Json, ToJson};

    // test setup

    fn make_client() -> Client {
        Client::new("localhost".to_string(), 9200)
    }

    struct TestDocument {
        str_field: String
    }

    impl ToJson for TestDocument {
        fn to_json(&self) -> Json {
            let mut d = BTreeMap::new();
            d.insert("str_field".to_string(), self.str_field.to_json());

            Json::Object(d)
        }
    }

    fn make_doc() -> TestDocument {
        TestDocument {
            str_field: "I am a test".to_string()
        }
    }

    // tests

    #[test]
    fn it_works() {
        let mut client = make_client();
        let result = client.version().unwrap();

        let expected_regex = Regex::new(r"^\d\.\d\.\d$").unwrap();
        assert_eq!(expected_regex.is_match(result.as_str()), true);
    }

    #[test]
    fn test_indexing() {
        env_logger::init().unwrap();

        let mut client = make_client();
        let mut indexer = client.index("test_idx", "test_type");
        let doc = make_doc();
        let result = indexer.with_doc(&doc).with_ttl(&927500).send();
        info!("TEST RESULT: {:?}", result);
        assert_eq!(json::encode(&result.unwrap()).unwrap(), "");
    }
}
<commit_msg>Return a specific type as the result of a request to index a document.<commit_after>#![crate_type = "lib"]
#![crate_name = "rs_es"]

#![feature(collections)]
#![feature(convert)]

#[macro_use] extern crate log;
extern crate hyper;
extern crate rustc_serialize;

use std::error::Error;
use std::io;
use std::fmt;

use hyper::client::response;
use hyper::status::StatusCode;

use rustc_serialize::json;
use rustc_serialize::json::{Json, ToJson};

// Error handling

#[derive(Debug)]
pub enum EsError {
    EsError(String),
    EsServerError(String),
    HttpError(hyper::error::HttpError),
    IoError(io::Error),
    JsonBuilderError(json::BuilderError)
}

impl From<io::Error> for EsError {
    fn from(err: io::Error) -> EsError {
        EsError::IoError(err)
    }
}

impl From<hyper::error::HttpError> for EsError {
    fn from(err: hyper::error::HttpError) -> EsError {
        EsError::HttpError(err)
    }
}

impl From<json::BuilderError> for EsError {
    fn from(err: json::BuilderError) -> EsError {
        EsError::JsonBuilderError(err)
    }
}

impl<'a> From<&'a mut response::Response> for EsError {
    fn from(err: &'a mut response::Response) -> EsError {
        EsError::EsServerError(format!("{} - {:?}", err.status, err))
    }
}

impl Error for EsError {
    fn description(&self) -> &str {
        match *self {
            EsError::EsError(ref err) => err.as_str(),
            EsError::EsServerError(ref err) => err.as_str(),
            EsError::HttpError(ref err) => err.description(),
            EsError::IoError(ref err) => err.description(),
            EsError::JsonBuilderError(ref err) => err.description()
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            EsError::EsError(_)                => None,
            EsError::EsServerError(_)          => None,
            EsError::HttpError(ref err)        => Some(err as &Error),
            EsError::IoError(ref err)          => Some(err as &Error),
            EsError::JsonBuilderError(ref err) => Some(err as &Error)
        }
    }
}

impl fmt::Display for EsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            EsError::EsError(ref s) => fmt::Display::fmt(s, f),
            EsError::EsServerError(ref s) => fmt::Display::fmt(s, f),
            EsError::HttpError(ref err) => fmt::Display::fmt(err, f),
            EsError::IoError(ref err) => fmt::Display::fmt(err, f),
            EsError::JsonBuilderError(ref err) => fmt::Display::fmt(err, f)
        }
    }
}

// Utilities

fn format_query_string(options: &mut Vec<(&'static str, String)>) -> String {
    let mut st = String::new();
    if options.is_empty() {
        return st;
    }
    st.push_str("?");
    for (k, v) in options.drain() {
        st.push_str(k);
        st.push_str("=");
        st.push_str(v.as_str());
        st.push_str("&");
    }
    st.pop();
    st
}

// The client

fn do_req<'a>(rb:   hyper::client::RequestBuilder<'a, &str>,
              body: Option<&'a str>) -> Result<Option<Json>, EsError> {
    info!("Params (body={:?})", body.unwrap());
    let mut result = match body {
        Some(json_str) => rb.body(json_str).send(),
        None           => rb.send()
    };
    info!("Result: {:?}", result);
    match result {
        Ok(ref mut r) => match r.status {
            StatusCode::Ok |
            StatusCode::Created  => match Json::from_reader(r) {
                Ok(json) => Ok(Some(json)),
                Err(e)   => Err(EsError::from(e))
            },
            StatusCode::NotFound => Ok(None),
            _                    => Err(EsError::from(r))
        },
        Err(e)        => Err(EsError::from(e))
    }
}

pub struct Client {
    host:        String,
    port:        u32,
    http_client: hyper::Client
}

macro_rules! es_op {
    ($n:ident) => {
        fn $n(&mut self, url: &str, body: Option<&Json>) -> Result<Option<Json>, EsError> {
            info!("Doing {} on {} with {:?}", stringify!($n), url, body);
            match body {
                Some(json) => {
                    let json_string = json::encode(json).unwrap();
                    do_req(self.http_client.$n(url), Some(json_string.as_str()))
                },
                None => {
                    do_req(self.http_client.$n(url), None)
                }
            }
        }
    }
}

impl Client {
    pub fn new(host: String, port: u32) -> Client {
        Client {
            host:        host,
            port:        port,
            http_client: hyper::Client::new()
        }
    }

    fn get_base_url(&self) -> String {
        format!("http://{}:{}/", self.host, self.port)
    }

    es_op!(get);
    es_op!(post);
    es_op!(put);

    pub fn version(&mut self) -> Result<String, EsError> {
        let url = self.get_base_url();
        let json = try!(self.get(url.as_str(), None)).unwrap();
        match json.find_path(&["version", "number"]) {
            Some(version) => match version.as_string() {
                Some(string) => Ok(string.to_string()),
                None         => Err(EsError::EsError(format!("Cannot find version number in: {:?}",
                                                             json)))
            },
            None          => Err(EsError::EsError(format!("Cannot find version number in {:?}",
                                                          json)))
        }
    }

    pub fn index<'a>(&'a mut self, index: &'a str, doc_type: &'a str) -> IndexOperation {
        IndexOperation::new(self, index, doc_type)
    }
}

// Specific operations

type Options = Vec<(&'static str, String)>;

macro_rules! add_option {
    ($n:ident, $e:expr, $t:ident) => (
        pub fn $n<T: ToString>(&'a mut self, val: &T) -> &'a mut $t {
            self.options.push(($e, val.to_string()));
            self
        }
    )
}

pub struct IndexOperation<'a> {
    client:   &'a mut Client,
    index:    &'a str,
    doc_type: &'a str,
    id:       Option<&'a str>,
    options:  Options,
    document: Option<Json>
}

impl<'a> IndexOperation<'a> {
    fn new(client: &'a mut Client, index: &'a str, doc_type: &'a str) -> IndexOperation<'a> {
        IndexOperation {
            client:   client,
            index:    index,
            doc_type: doc_type,
            id:       None,
            options:  Options::new(),
            document: None
        }
    }

    pub fn with_doc<T: ToJson>(&'a mut self, doc: &T) -> &'a mut IndexOperation {
        self.document = Some(doc.to_json());
        self
    }

    pub fn with_id(&'a mut self, id: &'a str) -> &'a mut IndexOperation {
        self.id = Some(id);
        self
    }

    add_option!(with_ttl, "ttl", IndexOperation);
    add_option!(with_version, "version", IndexOperation);
    add_option!(with_version_type, "version_type", IndexOperation);
    add_option!(with_op_type, "op_type", IndexOperation);
    add_option!(with_routing, "routing", IndexOperation);
    add_option!(with_parent, "parent", IndexOperation);
    add_option!(with_timestamp, "timestamp", IndexOperation);
    add_option!(with_refresh, "refresh", IndexOperation);
    add_option!(with_timeout, "timeout", IndexOperation);

    pub fn send(&'a mut self) -> Result<IndexResult, EsError> {
        let result = try!(match self.id {
            Some(id) => {
                let url = format!("{}{}/{}/{}{}",
                                  self.client.get_base_url(),
                                  self.index,
                                  self.doc_type,
                                  id,
                                  format_query_string(&mut self.options));
                self.client.put(url.as_str(), match self.document {
                    Some(ref doc) => Some(doc),
                    None          => None
                })
            },
            None    => {
                let url = format!("{}{}/{}{}",
                                  self.client.get_base_url(),
                                  self.index,
                                  self.doc_type,
                                  format_query_string(&mut self.options));
                self.client.post(url.as_str(), match self.document {
                    Some(ref doc) => Some(doc),
                    None          => None
                })
            }
        });
        Ok(IndexResult::from(result.unwrap()))
    }
}

macro_rules! get_json_thing {
    ($r:ident,$f:expr,$t:ident) => {
        $r.find($f).unwrap().$t().unwrap()
    }
}

macro_rules! get_json_string {
    ($r:ident,$f:expr) => {
        get_json_thing!($r,$f,as_string).to_string()
    }
}

macro_rules! get_json_i64 {
    ($r:ident,$f:expr) => {
        get_json_thing!($r,$f,as_i64)
    }
}

macro_rules! get_json_bool {
    ($r:ident,$f:expr) => {
        get_json_thing!($r,$f,as_boolean)
    }
}

#[derive(Debug)]
pub struct IndexResult {
    index:    String,
    doc_type: String,
    id:       String,
    version:  i64,
    created:  bool
}

impl From<Json> for IndexResult {
    fn from(r: Json) -> IndexResult {
        IndexResult {
            index:    get_json_string!(r, "_index"),
            doc_type: get_json_string!(r, "_type"),
            id:       get_json_string!(r, "_id"),
            version:  get_json_i64!(r, "_version"),
            created:  get_json_bool!(r, "created")
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate env_logger;
    extern crate regex;

    use super::Client;

    use std::collections::BTreeMap;

    use self::regex::Regex;

    use rustc_serialize::json::{Json, ToJson};

    // test setup

    fn make_client() -> Client {
        Client::new("localhost".to_string(), 9200)
    }

    struct TestDocument {
        str_field: String
    }

    impl ToJson for TestDocument {
        fn to_json(&self) -> Json {
            let mut d = BTreeMap::new();
            d.insert("str_field".to_string(), self.str_field.to_json());

            Json::Object(d)
        }
    }

    fn make_doc() -> TestDocument {
        TestDocument {
            str_field: "I am a test".to_string()
        }
    }

    // tests

    #[test]
    fn it_works() {
        let mut client = make_client();
        let result = client.version().unwrap();

        let expected_regex = Regex::new(r"^\d\.\d\.\d$").unwrap();
        assert_eq!(expected_regex.is_match(result.as_str()), true);
    }

    #[test]
    fn test_indexing() {
        env_logger::init().unwrap();

        let mut client = make_client();
        let mut indexer = client.index("test_idx", "test_type");
        let doc = make_doc();
        let result_wrapped = indexer.with_doc(&doc).with_ttl(&927500).send();
        info!("TEST RESULT: {:?}", result_wrapped);
        let result = result_wrapped.unwrap();
        assert_eq!(result.created, true);
        assert_eq!(result.index, "test_idx");
        assert_eq!(result.doc_type, "test_type");
        assert!(result.id.len() > 0);
        assert_eq!(result.version, 1);
    }
}
<|endoftext|>


<commit_before>//! # Handlebars
//! Handlebars is a modern and extensible templating solution originally created in the JavaScript world. It's used by many popular frameworks like [Ember.js](http://emberjs.com) and Chaplin. It's also ported to some other platforms such as [Java](https://github.com/jknack/handlebars.java).
//!
//! And this is handlebars Rust implementation, designed for server-side page generation. It's a general-purpose library so you use it for any kind of text generation.
//!
//! ## Handlebars spec
//!
//! ### Base
//!
//! You can go to [Handlebars.js](http://handlebarsjs.com/) website for its syntax. This implementation should be compatible with most parts of the spec, except:
//!
//! * configurable logging (hard-coded to rust native logging, with fixed level `INFO`)
//! * mustache iterators, block is not work in this implementation
//!
//! ### Extensions
//!
//! We have template reuse facilities supported via built-in helpers `>`, `partial` and `block`.
//!
//! There are two ways to reuse a template:
//!
//! * include (using `>`)
//! * inheritance (using `>` together with `block` and `partial`)
//!
//! Consult [Handlebar.java document about template inheritance](http://jknack.github.io/handlebars.java/reuse.html).
//!
//! ## Usage
//!
//! ### Template Creation and Registration
//!
//! Templates are created from String and registered to `Handlebars` with a name.
//!
//! ```
//!
//! extern crate handlebars;
//!
//! use handlebars::Handlebars;
//!
//! fn main() {
//!   let mut handlebars = Handlebars::new();
//!   let source = "hello {{world}}";
//!
//!   //compile returns an Option, we use unwrap() to deref it directly here
//!   handlebars.register_template_string("helloworld", source.to_string())
//!           .ok().unwrap();
//! }
//! ```
//!
//! ### Rendering Something
//!
//! I should say that rendering is a little tricky. Since handlebars is originally a JavaScript templating framework. It supports dynamic features like duck-typing, truthy/falsey values. But for a static language like Rust, this is a little difficult. As a solution, I'm using the `serialize::json::Json` internally for data rendering, which seems good by far.
//!
//! That means, if you want to render something, you have to ensure that it implements the `serialize::json::ToJson` trait. Luckily, most built-in types already have trait. However, if you want to render your custom struct, you need to implement this trait manually, or use [tojson_macros](https://github.com/sunng87/tojson_macros) to generate default `ToJson` implementation.
//!
//! You can use default `render` function to render a template into `String`. From 0.9, there's `renderw` to render text into anything of `std::io::Write`.
//!
//! ```ignore
//! extern crate rustc_serialize;
//! extern crate handlebars;
//!
//! use rustc_serialize::json::{Json, ToJson};
//! use std::collections::BTreeMap;
//!
//! use handlebars::Handlebars;
//!
//! struct Person {
//!   name: String,
//!   age: i16,
//! }
//!
//! impl ToJson for Person {
//!   fn to_json(&self) -> Json {
//!     let mut m: BTreeMap<String, Json> = BTreeMap::new();
//!     m.insert("name".to_string(), self.name.to_json());
//!     m.insert("age".to_string(), self.age.to_json());
//!     m.to_json()
//!   }
//! }
//!
//! fn main() {
//!   let source = "Hello, {{name}}";
//!
//!   let mut handlebars = Handlebars::new();
//!   handlebars.register_template_string("hello", source.to_string())
//!           .ok().unwrap();
//!
//!   let data = Person {
//!       name: "Ning Sun".to_string(),
//!       age: 27
//!   };
//!   let result = handlebars.render("hello", &data);
//! }
//! ```
//!
//! Or if you don't need the template to be cached or referenced by other ones, you can
//! simply render it without registering.
//!
//! ```ignore
//! fn main() {
//!   let source = "Hello, {{name}}";
//!
//!   let mut handlebars = Handlebars::new();
//!
//!   let data = Person {
//!       name: "Ning Sun".to_string(),
//!       age: 27
//!   };
//!   let result = handlebars.template_render("Hello, {{name}}", &data);
//! }
//! ```
//!
//!
//! #### Escaping
//!
//! As per the handlebars spec, output using `{{expression}}` is escaped by default (to be precise, the characters `&"<>` are replaced by their respective html / xml entities). However, since the use cases of a rust template engine are probably a bit more diverse than those of a JavaScript one, this implementation allows the user to supply a custom escape function to be used instead. For more information see the `EscapeFn` type and `Handlebars::register_escape_fn()` method.
//!
//! ### Custom Helper
//!
//! Handlebars is nothing without helpers. You can also create your own helpers with rust. Helpers in handlebars-rust are custom struct implements the `HelperDef` trait, concretely, the `call` function. For your convenience, most of stateless helpers can be implemented as bare functions.
//!
//! ```
//!
//! extern crate handlebars;
//!
//! use std::io::Write;
//! use handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context, JsonRender};
//!
//! // implement by a structure impls HelperDef
//! #[derive(Clone, Copy)]
//! struct SimpleHelper;
//!
//! impl HelperDef for SimpleHelper {
//!   fn call(&self, c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
//!     let param = h.params().get(0).unwrap();
//!
//!     // get value from context data
//!     // rc.get_path() is current json parent path, you should always use it like this
//!     // param is the key of value you want to display
//!     let value = c.navigate(rc.get_path(), param);
//!     try!(rc.writer.write("Ny helper dumps: ".as_bytes()));
//!     try!(rc.writer.write(value.render().into_bytes().as_ref()));
//!     Ok(())
//!   }
//! }
//!
//! // implement via bare function
//! fn another_simple_helper (c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
//!     let param = h.params().get(0).unwrap();
//!
//!     // get value from context data
//!     // rc.get_path() is current json parent path, you should always use it like this
//!     // param is the key of value you want to display
//!     let value = c.navigate(rc.get_path(), param);
//!     try!(rc.writer.write("My second helper dumps: ".as_bytes()));
//!     try!(rc.writer.write(value.render().into_bytes().as_ref()));
//!     Ok(())
//! }
//!
//!
//! fn main() {
//!   let mut handlebars = Handlebars::new();
//!   handlebars.register_helper("simple-helper", Box::new(SimpleHelper));
//!   handlebars.register_helper("another-simple-helper", Box::new(another_simple_helper));
//!   // via closure
//!   handlebars.register_helper("closure-helper",
//!       Box::new(|c: &Context, h: &Helper, r: &Handlebars, rc: &mut RenderContext| -> Result<(), RenderError>{
//!         try!(rc.writer.write("...".as_bytes()));
//!         Ok(())
//!       }));
//!
//!   //...
//! }
//! ```
//!
//! #### Arguments of HelpDef
//!
//! You can get data from the `Helper` argument about the template information:
//!
//! * `name()` for the helper name. This is known to you for most situation but if you are defining `helperMissing` or `blockHelperMissing`, this is important.
//! * `params()` is a vector of String as params in helper, like `{{#somehelper param1 param2 param3}}`.
//! * `hash()` is a map of String key and Json value, defined in helper as `{{@somehelper a=1 b="2" c=true}}`.
//! * `template()` gives you the nested template of block helper.
//! * `inverse()` gives you the inversed template of it, inversed template is the template behind `{{else}}`.
//!
//! You can learn more about helpers by looking into source code of built-in helpers.
//!
//! #### Built-in Helpers
//!
//! * `{{#raw}} ... {{/raw}}` escape handlebars expression within the block
//! * `{{#if ...}} ... {{else}} ... {{/if}}` if-else block
//! * `{{#unless ...}} ... {{else}} .. {{/unless}}` if-not-else block
//! * `{{#each ...}} ... {{/each}}` iterates over an array or object. Handlebar-rust doesn't support mustach iteration syntax so use this instead.
//! * `{{#with ...}} ... {{/with}}` change current context. Similar to {{#each}}, used for replace corresponding mustach syntax.
//! * `{{lookup ... ...}}` get value from array by `@index` or `@key`
//! * `{{#partial ...}} ... {{/partial}}` template reuse, used to replace block with same name
//! * `{{#block ...}} ... {{/block}}` template reuse, used to be replaced by partial with same name, with default content if partial not found.
//! * `{{> ...}}` include template with name
//! * `{{log ...}}` log value with rust logger, default level: INFO. Currently you cannot change the level.
//!

#[macro_use] extern crate log;
#[macro_use] extern crate quick_error;
#[macro_use] extern crate lazy_static;
#[cfg(test)] #[macro_use] extern crate maplit;

#[cfg(not(feature = "serde_type"))]
extern crate rustc_serialize as serialize;
extern crate regex;
extern crate num;
extern crate itertools;

#[cfg(feature = "serde_type")]
extern crate serde;
#[cfg(feature = "serde_type")]
extern crate serde_json;

pub use self::template::{Template};
pub use self::error::{TemplateError, TemplateFileError};
pub use self::registry::{EscapeFn, Registry as Handlebars};
pub use self::render::{Renderable, RenderError, RenderContext, Helper};
pub use self::helpers::{HelperDef};
pub use self::context::{Context, JsonRender, JsonTruthy};

mod template;
mod error;
mod registry;
mod render;
mod helpers;
mod context;
mod support;
<commit_msg>(feat) reexport TemplateRenderError<commit_after>//! # Handlebars
//! Handlebars is a modern and extensible templating solution originally created in the JavaScript world. It's used by many popular frameworks like [Ember.js](http://emberjs.com) and Chaplin. It's also ported to some other platforms such as [Java](https://github.com/jknack/handlebars.java).
//!
//! And this is handlebars Rust implementation, designed for server-side page generation. It's a general-purpose library so you use it for any kind of text generation.
//!
//! ## Handlebars spec
//!
//! ### Base
//!
//! You can go to [Handlebars.js](http://handlebarsjs.com/) website for its syntax. This implementation should be compatible with most parts of the spec, except:
//!
//! * configurable logging (hard-coded to rust native logging, with fixed level `INFO`)
//! * mustache iterators, block is not work in this implementation
//!
//! ### Extensions
//!
//! We have template reuse facilities supported via built-in helpers `>`, `partial` and `block`.
//!
//! There are two ways to reuse a template:
//!
//! * include (using `>`)
//! * inheritance (using `>` together with `block` and `partial`)
//!
//! Consult [Handlebar.java document about template inheritance](http://jknack.github.io/handlebars.java/reuse.html).
//!
//! ## Usage
//!
//! ### Template Creation and Registration
//!
//! Templates are created from String and registered to `Handlebars` with a name.
//!
//! ```
//!
//! extern crate handlebars;
//!
//! use handlebars::Handlebars;
//!
//! fn main() {
//!   let mut handlebars = Handlebars::new();
//!   let source = "hello {{world}}";
//!
//!   //compile returns an Option, we use unwrap() to deref it directly here
//!   handlebars.register_template_string("helloworld", source.to_string())
//!           .ok().unwrap();
//! }
//! ```
//!
//! ### Rendering Something
//!
//! I should say that rendering is a little tricky. Since handlebars is originally a JavaScript templating framework. It supports dynamic features like duck-typing, truthy/falsey values. But for a static language like Rust, this is a little difficult. As a solution, I'm using the `serialize::json::Json` internally for data rendering, which seems good by far.
//!
//! That means, if you want to render something, you have to ensure that it implements the `serialize::json::ToJson` trait. Luckily, most built-in types already have trait. However, if you want to render your custom struct, you need to implement this trait manually, or use [tojson_macros](https://github.com/sunng87/tojson_macros) to generate default `ToJson` implementation.
//!
//! You can use default `render` function to render a template into `String`. From 0.9, there's `renderw` to render text into anything of `std::io::Write`.
//!
//! ```ignore
//! extern crate rustc_serialize;
//! extern crate handlebars;
//!
//! use rustc_serialize::json::{Json, ToJson};
//! use std::collections::BTreeMap;
//!
//! use handlebars::Handlebars;
//!
//! struct Person {
//!   name: String,
//!   age: i16,
//! }
//!
//! impl ToJson for Person {
//!   fn to_json(&self) -> Json {
//!     let mut m: BTreeMap<String, Json> = BTreeMap::new();
//!     m.insert("name".to_string(), self.name.to_json());
//!     m.insert("age".to_string(), self.age.to_json());
//!     m.to_json()
//!   }
//! }
//!
//! fn main() {
//!   let source = "Hello, {{name}}";
//!
//!   let mut handlebars = Handlebars::new();
//!   handlebars.register_template_string("hello", source.to_string())
//!           .ok().unwrap();
//!
//!   let data = Person {
//!       name: "Ning Sun".to_string(),
//!       age: 27
//!   };
//!   let result = handlebars.render("hello", &data);
//! }
//! ```
//!
//! Or if you don't need the template to be cached or referenced by other ones, you can
//! simply render it without registering.
//!
//! ```ignore
//! fn main() {
//!   let source = "Hello, {{name}}";
//!
//!   let mut handlebars = Handlebars::new();
//!
//!   let data = Person {
//!       name: "Ning Sun".to_string(),
//!       age: 27
//!   };
//!   let result = handlebars.template_render("Hello, {{name}}", &data);
//! }
//! ```
//!
//!
//! #### Escaping
//!
//! As per the handlebars spec, output using `{{expression}}` is escaped by default (to be precise, the characters `&"<>` are replaced by their respective html / xml entities). However, since the use cases of a rust template engine are probably a bit more diverse than those of a JavaScript one, this implementation allows the user to supply a custom escape function to be used instead. For more information see the `EscapeFn` type and `Handlebars::register_escape_fn()` method.
//!
//! ### Custom Helper
//!
//! Handlebars is nothing without helpers. You can also create your own helpers with rust. Helpers in handlebars-rust are custom struct implements the `HelperDef` trait, concretely, the `call` function. For your convenience, most of stateless helpers can be implemented as bare functions.
//!
//! ```
//!
//! extern crate handlebars;
//!
//! use std::io::Write;
//! use handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context, JsonRender};
//!
//! // implement by a structure impls HelperDef
//! #[derive(Clone, Copy)]
//! struct SimpleHelper;
//!
//! impl HelperDef for SimpleHelper {
//!   fn call(&self, c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
//!     let param = h.params().get(0).unwrap();
//!
//!     // get value from context data
//!     // rc.get_path() is current json parent path, you should always use it like this
//!     // param is the key of value you want to display
//!     let value = c.navigate(rc.get_path(), param);
//!     try!(rc.writer.write("Ny helper dumps: ".as_bytes()));
//!     try!(rc.writer.write(value.render().into_bytes().as_ref()));
//!     Ok(())
//!   }
//! }
//!
//! // implement via bare function
//! fn another_simple_helper (c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
//!     let param = h.params().get(0).unwrap();
//!
//!     // get value from context data
//!     // rc.get_path() is current json parent path, you should always use it like this
//!     // param is the key of value you want to display
//!     let value = c.navigate(rc.get_path(), param);
//!     try!(rc.writer.write("My second helper dumps: ".as_bytes()));
//!     try!(rc.writer.write(value.render().into_bytes().as_ref()));
//!     Ok(())
//! }
//!
//!
//! fn main() {
//!   let mut handlebars = Handlebars::new();
//!   handlebars.register_helper("simple-helper", Box::new(SimpleHelper));
//!   handlebars.register_helper("another-simple-helper", Box::new(another_simple_helper));
//!   // via closure
//!   handlebars.register_helper("closure-helper",
//!       Box::new(|c: &Context, h: &Helper, r: &Handlebars, rc: &mut RenderContext| -> Result<(), RenderError>{
//!         try!(rc.writer.write("...".as_bytes()));
//!         Ok(())
//!       }));
//!
//!   //...
//! }
//! ```
//!
//! #### Arguments of HelpDef
//!
//! You can get data from the `Helper` argument about the template information:
//!
//! * `name()` for the helper name. This is known to you for most situation but if you are defining `helperMissing` or `blockHelperMissing`, this is important.
//! * `params()` is a vector of String as params in helper, like `{{#somehelper param1 param2 param3}}`.
//! * `hash()` is a map of String key and Json value, defined in helper as `{{@somehelper a=1 b="2" c=true}}`.
//! * `template()` gives you the nested template of block helper.
//! * `inverse()` gives you the inversed template of it, inversed template is the template behind `{{else}}`.
//!
//! You can learn more about helpers by looking into source code of built-in helpers.
//!
//! #### Built-in Helpers
//!
//! * `{{#raw}} ... {{/raw}}` escape handlebars expression within the block
//! * `{{#if ...}} ... {{else}} ... {{/if}}` if-else block
//! * `{{#unless ...}} ... {{else}} .. {{/unless}}` if-not-else block
//! * `{{#each ...}} ... {{/each}}` iterates over an array or object. Handlebar-rust doesn't support mustach iteration syntax so use this instead.
//! * `{{#with ...}} ... {{/with}}` change current context. Similar to {{#each}}, used for replace corresponding mustach syntax.
//! * `{{lookup ... ...}}` get value from array by `@index` or `@key`
//! * `{{#partial ...}} ... {{/partial}}` template reuse, used to replace block with same name
//! * `{{#block ...}} ... {{/block}}` template reuse, used to be replaced by partial with same name, with default content if partial not found.
//! * `{{> ...}}` include template with name
//! * `{{log ...}}` log value with rust logger, default level: INFO. Currently you cannot change the level.
//!

#[macro_use] extern crate log;
#[macro_use] extern crate quick_error;
#[macro_use] extern crate lazy_static;
#[cfg(test)] #[macro_use] extern crate maplit;

#[cfg(not(feature = "serde_type"))]
extern crate rustc_serialize as serialize;
extern crate regex;
extern crate num;
extern crate itertools;

#[cfg(feature = "serde_type")]
extern crate serde;
#[cfg(feature = "serde_type")]
extern crate serde_json;

pub use self::template::{Template};
pub use self::error::{TemplateError, TemplateFileError, TemplateRenderError};
pub use self::registry::{EscapeFn, Registry as Handlebars};
pub use self::render::{Renderable, RenderError, RenderContext, Helper};
pub use self::helpers::{HelperDef};
pub use self::context::{Context, JsonRender, JsonTruthy};

mod template;
mod error;
mod registry;
mod render;
mod helpers;
mod context;
mod support;
<|endoftext|>


<commit_before>
extern crate byteorder;
extern crate timecode;

#[macro_use] pub mod klv;
pub mod serializer;

#[cfg(test)]
mod test {
  // use serializer::decoder::*;
  use serializer::encoder::*;
  use klv::ul::ul::*;
  use klv::klv::*;
  use klv::klv_reader::*;
  use klv::value::value::*;
  use klv::value::value_data::*;
  use klv::value::partition::*;
  use klv::value::element::Element;

  #[test]
  fn read_empty_file() {
    use std::io::Cursor;

    let stream = Cursor::new(vec![0; 0]);
    let mut reader = KlvReader{
      stream: stream,
      elements: vec![]
    };

    let result = next_klv(&mut reader);

    assert!(result.is_ok());
    assert!(result.unwrap() == None);
  }

  #[test]
  fn read_first_key() {
    use std::io::Cursor;

    let data = vec![
      0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x00,
      0x83, 0x00, 0x00, 0x68,
      0x00, 0x01, 0x00, 0x02, // version major and minor
      0x00, 0x00, 0x02, 0x00, // kag size
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // this partition
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // previous partition
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // footer partition
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // header byte count
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // index byte count
      0x00, 0x00, 0x00, 0x00, // index sid
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // body byte count
      0x00, 0x00, 0x00, 0x00, // body sid
      0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09, 0x00, // operational pattern
      0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, // UL batch
      0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x02, 0x0d, 0x01, 0x03, 0x01, 0x02, 0x04, 0x97, 0x01, // Mpeg ES
      0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x0d, 0x01, 0x03, 0x01, 0x02, 0x06, 0x03, 0x00, // Mpeg ES Audio
      0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x02, 0x0d, 0x01, 0x03, 0x01, 0x02, 0x04, 0x60, 0x01, // Mpeg ES Video
    ];

    let stream = Cursor::new(data);
    let mut reader = KlvReader{
      stream: stream,
      elements: vec![]
    };

    let valid_klv = next_klv(&mut reader).unwrap().unwrap();

    assert_eq!(valid_klv, Klv {
      key: Ul::HeaderPartition {
        status: Some(PartitionStatus::ClosedAndComplete)
      },
      value: Value {
        elements: vec![
          build_element!(Ul::PartitionMajor, uint16 => 1),
          build_element!(Ul::PartitionMinor, uint16 => 2),
          build_element!(Ul::PartitionKagSize, uint32 => 512),
          build_element!(Ul::PartitionThisPartition, uint64 => 0),
          build_element!(Ul::PartitionPreviousPartition, uint64 => 0),
          build_element!(Ul::PartitionFooterPartition, uint64 => 0),
          build_element!(Ul::PartitionHeaderByteCount, uint64 => 0),
          build_element!(Ul::PartitionIndexByteCount, uint64 => 0),
          build_element!(Ul::PartitionIndexSid, uint32 => 0),
          build_element!(Ul::PartitionBodyOffset, uint64 => 0),
          build_element!(Ul::PartitionBodySid, uint32 => 0),
          Element {
            identifier: Ul::PartitionOperationalPattern,
            value: Some(ValueData::Ul {
              data: Ul::MxfOP1aSingleItemSinglePackageMultiTrackStreamInternal
            })
          },
          Element {
            identifier: Ul::PartitionEssenceContainers,
            value: Some(ValueData::ArrayUl {
              data: vec![
                Ul::Essence_MpegEsWithStreamIdFrameWrapped,
                Ul::Essence_AesFrameWrapped
              ]
            })
          }
        ]
      }
    });
  }

  #[test]
  fn generate_file() {
    use std::io::prelude::*;
    use std::io::Cursor;

    let mut stream = Cursor::new(vec![0; 0]);

    let header_value = Value {
      elements: vec![
        build_element!(Ul::PartitionMajor, uint16 => 1),
        build_element!(Ul::PartitionMinor, uint16 => 2),
        build_element!(Ul::PartitionKagSize, uint32 => 512),
        build_element!(Ul::PartitionThisPartition, uint64 => 0),
        build_element!(Ul::PartitionPreviousPartition, uint64 => 0),
        build_element!(Ul::PartitionFooterPartition, uint64 => 0),
        build_element!(Ul::PartitionHeaderByteCount, uint64 => 0),
        build_element!(Ul::PartitionIndexByteCount, uint64 => 0),
        build_element!(Ul::PartitionIndexSid, uint32 => 0),
        build_element!(Ul::PartitionBodyOffset, uint64 => 0),
        build_element!(Ul::PartitionBodySid, uint32 => 0),
        Element {
          identifier: Ul::PartitionOperationalPattern,
          value: Some(ValueData::Ul {
            data: Ul::MxfOP1aSingleItemSinglePackageMultiTrackStreamInternal
          })
        },
        Element {
          identifier: Ul::PartitionEssenceContainers,
          value: Some(ValueData::ArrayUl {
            data: vec![
              Ul::Essence_MpegEsWithStreamIdFrameWrapped,
              Ul::Essence_AesFrameWrapped
            ]
          })
        }
      ]
    };

    let header_klv = Klv {
      key: Ul::HeaderPartition {
        status: Some(PartitionStatus::ClosedAndComplete)
      },
      value: header_value
    };

    stream.write(Encoder::serialise(&header_klv).as_ref()).unwrap();

    // let frame_value = Value {
    //   elements: vec![
    //     Element{
    //       identifier: Ul::Unknown,
    //       value: None
    //     }
    //   ]
    // };

    // let frame_klv = Klv {
    //   key: Ul::PictureItemMpegFrameWrappedPictureElement,
    //   value: frame_value
    // };

    // stream.write(Encoder::serialise(&frame_klv).as_ref()).unwrap();

    println!("{:?}", stream.get_ref());
    assert_eq!(stream.get_ref().len(), 89);
  }
}
<commit_msg>fix inclusion for unit tests<commit_after>
extern crate byteorder;
extern crate timecode;

#[macro_use] pub mod klv;
pub mod serializer;

#[cfg(test)]
mod test {
  // use serializer::decoder::*;
  use serializer::encoder::*;
  use klv::ul::Ul;
  use klv::klv::*;
  use klv::klv_reader::*;
  use klv::value::value::*;
  use klv::value::value_data::*;
  use klv::value::partition::*;
  use klv::value::element::Element;

  #[test]
  fn read_empty_file() {
    use std::io::Cursor;

    let stream = Cursor::new(vec![0; 0]);
    let mut reader = KlvReader{
      stream: stream,
      elements: vec![]
    };

    let result = next_klv(&mut reader);

    assert!(result.is_ok());
    assert!(result.unwrap() == None);
  }

  #[test]
  fn read_first_key() {
    use std::io::Cursor;

    let data = vec![
      0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x00,
      0x83, 0x00, 0x00, 0x68,
      0x00, 0x01, 0x00, 0x02, // version major and minor
      0x00, 0x00, 0x02, 0x00, // kag size
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // this partition
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // previous partition
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // footer partition
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // header byte count
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // index byte count
      0x00, 0x00, 0x00, 0x00, // index sid
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // body byte count
      0x00, 0x00, 0x00, 0x00, // body sid
      0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09, 0x00, // operational pattern
      0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, // UL batch
      0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x02, 0x0d, 0x01, 0x03, 0x01, 0x02, 0x04, 0x97, 0x01, // Mpeg ES
      0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x0d, 0x01, 0x03, 0x01, 0x02, 0x06, 0x03, 0x00, // Mpeg ES Audio
      0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x02, 0x0d, 0x01, 0x03, 0x01, 0x02, 0x04, 0x60, 0x01, // Mpeg ES Video
    ];

    let stream = Cursor::new(data);
    let mut reader = KlvReader{
      stream: stream,
      elements: vec![]
    };

    let valid_klv = next_klv(&mut reader).unwrap().unwrap();

    assert_eq!(valid_klv, Klv {
      key: Ul::HeaderPartition {
        status: Some(PartitionStatus::ClosedAndComplete)
      },
      value: Value {
        elements: vec![
          build_element!(Ul::PartitionMajor, uint16 => 1),
          build_element!(Ul::PartitionMinor, uint16 => 2),
          build_element!(Ul::PartitionKagSize, uint32 => 512),
          build_element!(Ul::PartitionThisPartition, uint64 => 0),
          build_element!(Ul::PartitionPreviousPartition, uint64 => 0),
          build_element!(Ul::PartitionFooterPartition, uint64 => 0),
          build_element!(Ul::PartitionHeaderByteCount, uint64 => 0),
          build_element!(Ul::PartitionIndexByteCount, uint64 => 0),
          build_element!(Ul::PartitionIndexSid, uint32 => 0),
          build_element!(Ul::PartitionBodyOffset, uint64 => 0),
          build_element!(Ul::PartitionBodySid, uint32 => 0),
          Element {
            identifier: Ul::PartitionOperationalPattern,
            value: Some(ValueData::Ul {
              data: Ul::MxfOP1aSingleItemSinglePackageMultiTrackStreamInternal
            })
          },
          Element {
            identifier: Ul::PartitionEssenceContainers,
            value: Some(ValueData::ArrayUl {
              data: vec![
                Ul::Essence_MpegEsWithStreamIdFrameWrapped,
                Ul::Essence_AesFrameWrapped
              ]
            })
          }
        ]
      }
    });
  }

  #[test]
  fn generate_file() {
    use std::io::prelude::*;
    use std::io::Cursor;

    let mut stream = Cursor::new(vec![0; 0]);

    let header_value = Value {
      elements: vec![
        build_element!(Ul::PartitionMajor, uint16 => 1),
        build_element!(Ul::PartitionMinor, uint16 => 2),
        build_element!(Ul::PartitionKagSize, uint32 => 512),
        build_element!(Ul::PartitionThisPartition, uint64 => 0),
        build_element!(Ul::PartitionPreviousPartition, uint64 => 0),
        build_element!(Ul::PartitionFooterPartition, uint64 => 0),
        build_element!(Ul::PartitionHeaderByteCount, uint64 => 0),
        build_element!(Ul::PartitionIndexByteCount, uint64 => 0),
        build_element!(Ul::PartitionIndexSid, uint32 => 0),
        build_element!(Ul::PartitionBodyOffset, uint64 => 0),
        build_element!(Ul::PartitionBodySid, uint32 => 0),
        Element {
          identifier: Ul::PartitionOperationalPattern,
          value: Some(ValueData::Ul {
            data: Ul::MxfOP1aSingleItemSinglePackageMultiTrackStreamInternal
          })
        },
        Element {
          identifier: Ul::PartitionEssenceContainers,
          value: Some(ValueData::ArrayUl {
            data: vec![
              Ul::Essence_MpegEsWithStreamIdFrameWrapped,
              Ul::Essence_AesFrameWrapped
            ]
          })
        }
      ]
    };

    let header_klv = Klv {
      key: Ul::HeaderPartition {
        status: Some(PartitionStatus::ClosedAndComplete)
      },
      value: header_value
    };

    stream.write(Encoder::serialise(&header_klv).as_ref()).unwrap();

    // let frame_value = Value {
    //   elements: vec![
    //     Element{
    //       identifier: Ul::Unknown,
    //       value: None
    //     }
    //   ]
    // };

    // let frame_klv = Klv {
    //   key: Ul::PictureItemMpegFrameWrappedPictureElement,
    //   value: frame_value
    // };

    // stream.write(Encoder::serialise(&frame_klv).as_ref()).unwrap();

    println!("{:?}", stream.get_ref());
    assert_eq!(stream.get_ref().len(), 89);
  }
}
<|endoftext|>


<commit_before>// Temporary
#![allow(dead_code)]

trait DOMNode {}

trait DOMLevel {
    type NodeType: DOMNode;
    type ChildrenType: DOMChildren;
}

trait DOMChildrenProcessor {
    type State;
    fn get_processor<T: DOMLevel>() -> fn(&mut Self::State, T) -> ();
}

// Dummy type for testing
struct ChildCounter;
impl DOMChildrenProcessor for ChildCounter {
    type State = usize;

    fn get_processor<T: DOMLevel>() -> fn(&mut Self::State, T) -> () {
        fn incr<T: DOMLevel>(state: &mut usize, _level: T) {
            *state += 1;
        }
        incr
    }
}

trait DOMChildren {
    fn process_all<P: DOMChildrenProcessor>(&self, processor: &mut P::State) -> ();
}

// Credit to @shepmaster for structure of recursive tuple macro
macro_rules! tuple_impls {
    () => {};

    // Copywrite @shepmaster
    (($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
        /*
         * Invoke recursive reversal of list that ends in the macro expansion implementation
         * of the reversed list
        */
        tuple_impls!([($idx, $typ);] $( ($nidx => $ntyp), )*);
        tuple_impls!($( ($nidx => $ntyp), )*); // invoke macro on tail
    };

    /*
     * ([accumulatedList], listToReverse); recursively calls tuple_impls until the list to reverse
     + is empty (see next pattern)
    */
    ([$(($accIdx: tt, $accTyp: ident);)+]  ($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
      tuple_impls!([($idx, $typ); $(($accIdx, $accTyp); )*] $( ($nidx => $ntyp), ) *);
    };

    // Finally expand into the implementation
    ([($idx:tt, $typ:ident); $( ($nidx:tt, $ntyp:ident); )*]) => {
        impl<$typ, $( $ntyp ),*> DOMChildren for ($typ, $( $ntyp ),*)
            where $typ: DOMLevel + Copy,
                  $( $ntyp: DOMLevel + Copy ),*
        {
            fn process_all<P>(&self, state: &mut P::State) -> ()
                    where P: DOMChildrenProcessor {
                P::get_processor()(state, self.$idx);
                $(
                    P::get_processor()(state, self.$nidx);
                )*
            }
        }
    }
}

tuple_impls!(
    (9 => J),
    (8 => I),
    (7 => H),
    (6 => G),
    (5 => F),
    (4 => E),
    (3 => D),
    (2 => C),
    (1 => B),
    (0 => A),
);

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Add test of DOMChildrenProcessor<commit_after>trait DOMNode {}
impl<'a, T: DOMNode> DOMNode for &'a T {}

trait DOMLevel {
    type NodeType: DOMNode;
    type ChildrenType: DOMChildren;
}
impl<T: DOMNode> DOMLevel for T {
    type NodeType = T;
    type ChildrenType = ();
}

trait DOMChildrenProcessor {
    type State;
    fn get_processor<T: DOMLevel>() -> fn(&mut Self::State, T) -> ();
}

trait DOMChildren {
    fn process_all<P: DOMChildrenProcessor>(&self, processor: &mut P::State) -> ();
}
impl DOMChildren for () {
    fn process_all<P: DOMChildrenProcessor>(&self, _processor: &mut P::State) -> () {}
}

impl<'a, T: DOMChildren> DOMChildren for &'a T {
    fn process_all<P: DOMChildrenProcessor>(&self, processor: &mut P::State) -> () {
        (*self).process_all::<P>(processor);
    }
}

// Credit to @shepmaster for structure of recursive tuple macro
macro_rules! tuple_impls {
    () => {};

    // Copywrite @shepmaster
    (($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
        /*
         * Invoke recursive reversal of list that ends in the macro expansion implementation
         * of the reversed list
        */
        tuple_impls!([($idx, $typ);] $( ($nidx => $ntyp), )*);
        tuple_impls!($( ($nidx => $ntyp), )*); // invoke macro on tail
    };

    /*
     * ([accumulatedList], listToReverse); recursively calls tuple_impls until the list to reverse
     + is empty (see next pattern)
    */
    ([$(($accIdx: tt, $accTyp: ident);)+]  ($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
      tuple_impls!([($idx, $typ); $(($accIdx, $accTyp); )*] $( ($nidx => $ntyp), ) *);
    };

    // Finally expand into the implementation
    ([($idx:tt, $typ:ident); $( ($nidx:tt, $ntyp:ident); )*]) => {
        impl<$typ, $( $ntyp ),*> DOMChildren for ($typ, $( $ntyp ),*)
            where $typ: DOMLevel + Copy,
                  $( $ntyp: DOMLevel + Copy ),*
        {
            fn process_all<P>(&self, state: &mut P::State) -> ()
                    where P: DOMChildrenProcessor {
                P::get_processor()(state, self.$idx);
                $(
                    P::get_processor()(state, self.$nidx);
                )*
            }
        }
    }
}

tuple_impls!(
    (9 => J),
    (8 => I),
    (7 => H),
    (6 => G),
    (5 => F),
    (4 => E),
    (3 => D),
    (2 => C),
    (1 => B),
    (0 => A),
);

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

    #[derive(Copy, Clone)]
    struct BogusOne;
    impl DOMNode for BogusOne {}

    struct BogusTwo;
    impl DOMNode for BogusTwo {}

    struct ChildCounter;
    impl DOMChildrenProcessor for ChildCounter {
        type State = usize;

        fn get_processor<T: DOMLevel>() -> fn(&mut Self::State, T) -> () {
            fn incr<T: DOMLevel>(state: &mut usize, _level: T) {
                *state += 1;
            }
            incr
        }
    }

    #[test]
    fn counts_children() {
        let mut count = 0;
        (BogusOne, &BogusOne, &BogusTwo).process_all::<ChildCounter>(&mut count);
        assert_eq!(3, count);
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate futures;
extern crate tokio_core;

pub use futures::{Async, Poll};

#[macro_use] pub mod macros;
pub mod core;
pub mod ipaddr;
pub mod parse;
<commit_msg>Re-export EasyBuf.<commit_after>#[macro_use] extern crate futures;
extern crate tokio_core;

pub use futures::{Async, Poll};
pub use tokio_core::io::EasyBuf;

#[macro_use] pub mod macros;
pub mod core;
pub mod ipaddr;
pub mod parse;
<|endoftext|>


<commit_before>//! Temporal quantification using floating-point quantities.
//!
//! This crate provides quantification for spans of time. Unlike the standard
//! [`std::time`](https://doc.rust-lang.org/std/time/index.html) or the
//! [chrono](https://crates.io/crates/chrono) crate, this crate aims
//! to provide a fully featured Duration type which exposes and uses floating-point
//! values instead of integer ones.
//!
//! The existing solutions for time spans are high precision and good for displaying
//! and storing time values, but they are less than convenient to use in simulations or
//! mathematical contexts where a single fractional value in some unit is needed. Thus,
//! this crate was developed in order to fill that need while being maximally compatible
//! with the existing time libraries and not re-inventing the wheel. The interface aims to
//! be very similar to these libraries, just using floating point values so it may be
//! used as a near drop-in replacement for existing programs that
//! would benefit from floating point durations.
//!
//! The goal is to provide a type with the same set of features and flexibility as
//! `std::chrono::duration` in C++ while being "Rusty" in design.
//!
//! # Usage
//! Put this in your `Cargo.toml`:
//!
//! ```ignore
//! [dependencies]
//! float_duration = "0.2"
//! ```
//! # Overview
//!
//! This crate provides a single primary type:
//! [`FloatDuration`](duration/struct.FloatDuration.html) which represents an
//! arbitrary distance in time with no defined start or end point.
//! Internally, it stores a single `f64` holding the number of seconds the duration
//! represents, which can be negative for a "backward" duration. It provides accessors
//! methods to create and read the value in various units, as well as `impl`s for many
//! arithmetic operators in `std::ops`.
//!
//! ```rust
//! # use float_duration::*;
//! let timespan = FloatDuration::hours(2.5) + FloatDuration::seconds(30.0);
//! assert_eq!(timespan, FloatDuration::seconds(9030.0));
//! assert_eq!(timespan, FloatDuration::minutes(150.5));
//! ```
//! Additionally, a [`TimePoint`](duration/trait.TimePoint.html) trait is provided
//! for computing a `FloatDuration` between two objects representing a point in time.
//!
//! # Example Usage
//!
//! Compute the number of blocks in a larger interval:
//!
//! ```rust
//! use float_duration::FloatDuration;
//!
//! let time_block = FloatDuration::minutes(5.0);
//! let blocks_per_hour = FloatDuration::hours(1.0) / time_block;
//!
//! assert_eq!(blocks_per_hour, 12.0);
//! ```
//!
//! Perform a basic numerical integration of a mass on a spring:
//!
//! ```rust
//! use float_duration::FloatDuration;
//!
//! fn acceleration(m: f64, x: f64, t: FloatDuration) -> f64 {
//!     0.5*m*x*x
//! }
//!
//! fn main() {
//!     let mut sim_time = FloatDuration::zero();
//!     let end_time = FloatDuration::minutes(2.0);
//!     let dt = FloatDuration::milliseconds(50.0);
//!
//!     let mut x = 2.0;
//!     let mut v = 0.0;
//!     let m = 1.0;
//!
//!     while sim_time < end_time {
//!         let acc = acceleration(m, x, sim_time);
//!         v += acc*dt.as_seconds();
//!         x += v*dt.as_seconds();
//!         sim_time += dt;
//!     }
//! }
//! ```
//!
//! # Library Support
//!
//! Currently `float_duration` can be compiled without any dependencies, but it
//! provides optional features for interfacing with other libraries.
//!
//! ## std::time
//! The `std::time` module is supported and `FloatDuration`
//! can be used directly with `SystemTime` and `Instant`:
//!
//! ```rust
//! // TimePoint needed for `float_duration_since`.
//! use float_duration::{FloatDuration, TimePoint};
//! use std::time::{Instant, SystemTime};
//!
//!
//! let start_time = Instant::now();
//! //Do lengthy operation...
//! let end_time = Instant::now();
//!
//! println!("Took {}.", end_time.float_duration_since(start_time).unwrap());
//! ```
//!
//! `FloatDuration` may also be converted to/from `std::time::Duration` via the
//! `to_std` and `from_std` methods.
//!
//! ## [approx](https://crates.io/crates/approx)
//! `FloatDuration` provides an implementation of `approx::ApproxEq`
//! for near-equality comparisons of `FloatDuration` if the `approx` feature is enabled.
//! Since `FloatDuration` uses floating point values, this should be the
//! preferred way to establish equality between two duration objects.
//!
//! ## [chrono](https://crates.io/crates/chrono)
//!
//! Similar to `std::time`, computing a `FloatDuration` between any two of the same type of
//! date or time objects
//! is supported via `TimePoint` trait impls, assuming the feature
//! "chrono" is enabled.
//! Additionally, `FloatDuration` objects can be converted to/from
//! `chrono::Duration` objects via the `to_chrono` and `from_chrono` methods.
//!
//! Note: if the `chrono` feature is enabled, the `time` feature must also be enabled
//! as `chrono` directly relies on some types defined in `time`.
//!
//! ```rust,ignore
//! use chrono::{UTC, TimeZone};
//! use float_duration::{TimePoint, FloatDuration};
//!
//! let date1 = UTC.ymd(2017, 5, 25).and_hms(10, 0, 0);
//! let date2 = UTC.ymd(2017, 5, 26).and_hms(12, 0, 0);
//!
//! assert_eq!(date2.float_duration_since(date1).unwrap(), FloatDuration::days(1.0) +
//!     FloatDuration::hours(2.0));
//! ```
//!
//! ## [serde](https://crates.io/crates/serde)
//!
//! `FloatDuration` supports serialization with `serde`. Presently, a `FloatDuration`
//! is serialized to a single `f64` value representing the number of seconds in the
//! duration.

#[cfg(feature = "chrono")]
extern crate chrono;
#[cfg(feature = "time")]
extern crate time;
#[cfg(feature = "approx")]
extern crate approx;
#[cfg(feature = "serde")]
extern crate serde;
#[cfg(all(test, feature = "serde"))]
extern crate serde_test;

pub mod duration;
pub mod error;
pub mod iter;

pub use duration::{FloatDuration, TimePoint};
pub use error::OutOfRangeError;
<commit_msg>Reexport the two subdivide functions in iter.<commit_after>//! Temporal quantification using floating-point quantities.
//!
//! This crate provides quantification for spans of time. Unlike the standard
//! [`std::time`](https://doc.rust-lang.org/std/time/index.html) or the
//! [chrono](https://crates.io/crates/chrono) crate, this crate aims
//! to provide a fully featured Duration type which exposes and uses floating-point
//! values instead of integer ones.
//!
//! The existing solutions for time spans are high precision and good for displaying
//! and storing time values, but they are less than convenient to use in simulations or
//! mathematical contexts where a single fractional value in some unit is needed. Thus,
//! this crate was developed in order to fill that need while being maximally compatible
//! with the existing time libraries and not re-inventing the wheel. The interface aims to
//! be very similar to these libraries, just using floating point values so it may be
//! used as a near drop-in replacement for existing programs that
//! would benefit from floating point durations.
//!
//! The goal is to provide a type with the same set of features and flexibility as
//! `std::chrono::duration` in C++ while being "Rusty" in design.
//!
//! # Usage
//! Put this in your `Cargo.toml`:
//!
//! ```ignore
//! [dependencies]
//! float_duration = "0.2"
//! ```
//! # Overview
//!
//! This crate provides a single primary type:
//! [`FloatDuration`](duration/struct.FloatDuration.html) which represents an
//! arbitrary distance in time with no defined start or end point.
//! Internally, it stores a single `f64` holding the number of seconds the duration
//! represents, which can be negative for a "backward" duration. It provides accessors
//! methods to create and read the value in various units, as well as `impl`s for many
//! arithmetic operators in `std::ops`.
//!
//! ```rust
//! # use float_duration::*;
//! let timespan = FloatDuration::hours(2.5) + FloatDuration::seconds(30.0);
//! assert_eq!(timespan, FloatDuration::seconds(9030.0));
//! assert_eq!(timespan, FloatDuration::minutes(150.5));
//! ```
//! Additionally, a [`TimePoint`](duration/trait.TimePoint.html) trait is provided
//! for computing a `FloatDuration` between two objects representing a point in time.
//!
//! # Example Usage
//!
//! Compute the number of blocks in a larger interval:
//!
//! ```rust
//! use float_duration::FloatDuration;
//!
//! let time_block = FloatDuration::minutes(5.0);
//! let blocks_per_hour = FloatDuration::hours(1.0) / time_block;
//!
//! assert_eq!(blocks_per_hour, 12.0);
//! ```
//!
//! Perform a basic numerical integration of a mass on a spring:
//!
//! ```rust
//! use float_duration::FloatDuration;
//!
//! fn acceleration(m: f64, x: f64, t: FloatDuration) -> f64 {
//!     0.5*m*x*x
//! }
//!
//! fn main() {
//!     let mut sim_time = FloatDuration::zero();
//!     let end_time = FloatDuration::minutes(2.0);
//!     let dt = FloatDuration::milliseconds(50.0);
//!
//!     let mut x = 2.0;
//!     let mut v = 0.0;
//!     let m = 1.0;
//!
//!     while sim_time < end_time {
//!         let acc = acceleration(m, x, sim_time);
//!         v += acc*dt.as_seconds();
//!         x += v*dt.as_seconds();
//!         sim_time += dt;
//!     }
//! }
//! ```
//!
//! # Library Support
//!
//! Currently `float_duration` can be compiled without any dependencies, but it
//! provides optional features for interfacing with other libraries.
//!
//! ## std::time
//! The `std::time` module is supported and `FloatDuration`
//! can be used directly with `SystemTime` and `Instant`:
//!
//! ```rust
//! // TimePoint needed for `float_duration_since`.
//! use float_duration::{FloatDuration, TimePoint};
//! use std::time::{Instant, SystemTime};
//!
//!
//! let start_time = Instant::now();
//! //Do lengthy operation...
//! let end_time = Instant::now();
//!
//! println!("Took {}.", end_time.float_duration_since(start_time).unwrap());
//! ```
//!
//! `FloatDuration` may also be converted to/from `std::time::Duration` via the
//! `to_std` and `from_std` methods.
//!
//! ## [approx](https://crates.io/crates/approx)
//! `FloatDuration` provides an implementation of `approx::ApproxEq`
//! for near-equality comparisons of `FloatDuration` if the `approx` feature is enabled.
//! Since `FloatDuration` uses floating point values, this should be the
//! preferred way to establish equality between two duration objects.
//!
//! ## [chrono](https://crates.io/crates/chrono)
//!
//! Similar to `std::time`, computing a `FloatDuration` between any two of the same type of
//! date or time objects
//! is supported via `TimePoint` trait impls, assuming the feature
//! "chrono" is enabled.
//! Additionally, `FloatDuration` objects can be converted to/from
//! `chrono::Duration` objects via the `to_chrono` and `from_chrono` methods.
//!
//! Note: if the `chrono` feature is enabled, the `time` feature must also be enabled
//! as `chrono` directly relies on some types defined in `time`.
//!
//! ```rust,ignore
//! use chrono::{UTC, TimeZone};
//! use float_duration::{TimePoint, FloatDuration};
//!
//! let date1 = UTC.ymd(2017, 5, 25).and_hms(10, 0, 0);
//! let date2 = UTC.ymd(2017, 5, 26).and_hms(12, 0, 0);
//!
//! assert_eq!(date2.float_duration_since(date1).unwrap(), FloatDuration::days(1.0) +
//!     FloatDuration::hours(2.0));
//! ```
//!
//! ## [serde](https://crates.io/crates/serde)
//!
//! `FloatDuration` supports serialization with `serde`. Presently, a `FloatDuration`
//! is serialized to a single `f64` value representing the number of seconds in the
//! duration.

#[cfg(feature = "chrono")]
extern crate chrono;
#[cfg(feature = "time")]
extern crate time;
#[cfg(feature = "approx")]
extern crate approx;
#[cfg(feature = "serde")]
extern crate serde;
#[cfg(all(test, feature = "serde"))]
extern crate serde_test;

pub mod duration;
pub mod error;
pub mod iter;

pub use duration::{FloatDuration, TimePoint};
pub use error::OutOfRangeError;
pub use iter::{subdivide, subdivide_with_step};
<|endoftext|>


<commit_before>extern crate cslice;

#[doc(hidden)]
pub extern crate libc;

#[doc(hidden)]
pub extern crate libcruby_sys as sys;
// pub use rb;

use std::ffi::CStr;
use sys::VALUE;

mod macros;
mod class_definition;
mod coercions;

pub use coercions::*;

pub use class_definition::{ClassDefinition, MethodDefinition};

#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct Class(VALUE);

impl Class {
    pub fn inner(&self) -> VALUE {
        self.0
    }
}

pub trait RubyMethod {
    fn install(self, class: VALUE, name: &CStr);
}

impl RubyMethod for extern "C" fn(VALUE) -> VALUE {
    fn install(self, class: VALUE, name: &CStr) {
        unsafe {
            sys::rb_define_method(
                class,
                name.as_ptr(),
                self as *const libc::c_void,
                0
            );
        }
    }
}

impl RubyMethod for extern "C" fn(VALUE, VALUE) -> VALUE {
    fn install(self, class: VALUE, name: &CStr) {
        unsafe {
            sys::rb_define_method(
                class,
                name.as_ptr(),
                self as *const libc::c_void,
                1
            );
        }
    }
}

#[allow(non_snake_case)]
#[inline]
fn ObjectClass() -> Class {
    Class(unsafe { sys::rb_cObject })
}

impl Class {
    pub fn new(name: &CStr) -> Class {
        ObjectClass().subclass(name)
    }

    pub fn subclass(&self, name: &CStr) -> Class {
        unsafe {
            Class(sys::rb_define_class(name.as_ptr(), self.0))
        }
    }

    pub fn define_method<T: RubyMethod>(&self, name: &CStr, method: T) {
        method.install(self.0, name);
    }
}

pub fn inspect(val: VALUE) -> String {
    unsafe { CheckedValue::<String>::new(sys::rb_inspect(val)).to_rust() }
}

pub type Metadata = ::VALUE;

#[derive(Copy, Clone, Debug)]
pub struct ExceptionInfo {
    pub exception: Class,
    pub message: VALUE
}

impl ExceptionInfo {
    pub fn with_message<T: ToRuby>(string: T) -> ExceptionInfo {
        ExceptionInfo {
            exception: Class(unsafe { sys::rb_eRuntimeError }),
            message: string.to_ruby(),
        }
    }

    pub fn type_error<T: ToRuby>(string: T) -> ExceptionInfo {
        ExceptionInfo {
            exception: Class(unsafe { sys::rb_eTypeError }),
            message: string.to_ruby(),
        }
    }

    pub fn from_any(any: Box<std::any::Any>) -> ExceptionInfo {
        match any.downcast_ref::<ExceptionInfo>() {
            Some(e) => *e,
            None => {
                match any.downcast_ref::<&'static str>() {
                    Some(e) => ExceptionInfo::with_message(e.to_string()),
                    None => {
                        match any.downcast_ref::<String>() {
                            Some(e) => ExceptionInfo::with_message(e.as_str()),
                            None => ExceptionInfo::with_message(format!("Unknown Error; err={:?}", any)),
                        }
                    }
                }
            }
        }
    }

    pub fn message(&self) -> VALUE {
        self.message
    }

    pub fn raise(&self) -> ! {
        unsafe {
            sys::rb_raise(self.exception.0,
                          sys::SPRINTF_TO_S,
                          self.message);
        }
    }
}

unsafe impl Send for ExceptionInfo {}
unsafe impl Sync for ExceptionInfo {}
<commit_msg>Replace nested matching with `Option` combinators.<commit_after>extern crate cslice;

#[doc(hidden)]
pub extern crate libc;

#[doc(hidden)]
pub extern crate libcruby_sys as sys;
// pub use rb;

use std::ffi::CStr;
use sys::VALUE;

mod macros;
mod class_definition;
mod coercions;

pub use coercions::*;

pub use class_definition::{ClassDefinition, MethodDefinition};

#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct Class(VALUE);

impl Class {
    pub fn inner(&self) -> VALUE {
        self.0
    }
}

pub trait RubyMethod {
    fn install(self, class: VALUE, name: &CStr);
}

impl RubyMethod for extern "C" fn(VALUE) -> VALUE {
    fn install(self, class: VALUE, name: &CStr) {
        unsafe {
            sys::rb_define_method(
                class,
                name.as_ptr(),
                self as *const libc::c_void,
                0
            );
        }
    }
}

impl RubyMethod for extern "C" fn(VALUE, VALUE) -> VALUE {
    fn install(self, class: VALUE, name: &CStr) {
        unsafe {
            sys::rb_define_method(
                class,
                name.as_ptr(),
                self as *const libc::c_void,
                1
            );
        }
    }
}

#[allow(non_snake_case)]
#[inline]
fn ObjectClass() -> Class {
    Class(unsafe { sys::rb_cObject })
}

impl Class {
    pub fn new(name: &CStr) -> Class {
        ObjectClass().subclass(name)
    }

    pub fn subclass(&self, name: &CStr) -> Class {
        unsafe {
            Class(sys::rb_define_class(name.as_ptr(), self.0))
        }
    }

    pub fn define_method<T: RubyMethod>(&self, name: &CStr, method: T) {
        method.install(self.0, name);
    }
}

pub fn inspect(val: VALUE) -> String {
    unsafe { CheckedValue::<String>::new(sys::rb_inspect(val)).to_rust() }
}

pub type Metadata = ::VALUE;

#[derive(Copy, Clone, Debug)]
pub struct ExceptionInfo {
    pub exception: Class,
    pub message: VALUE
}

impl ExceptionInfo {
    pub fn with_message<T: ToRuby>(string: T) -> ExceptionInfo {
        ExceptionInfo {
            exception: Class(unsafe { sys::rb_eRuntimeError }),
            message: string.to_ruby(),
        }
    }

    pub fn type_error<T: ToRuby>(string: T) -> ExceptionInfo {
        ExceptionInfo {
            exception: Class(unsafe { sys::rb_eTypeError }),
            message: string.to_ruby(),
        }
    }

    pub fn from_any(any: Box<std::any::Any>) -> ExceptionInfo {
        any.downcast_ref::<ExceptionInfo>()
            .map(|e| *e)
            .or_else(||
                any.downcast_ref::<&'static str>()
                    .map(|e| e.to_string())
                    .map(ExceptionInfo::with_message)
            )
            .or_else(||
                any.downcast_ref::<String>()
                    .map(|e| e.as_str())
                    .map(ExceptionInfo::with_message)
            )
            .unwrap_or_else(||
                ExceptionInfo::with_message(format!("Unknown Error; err={:?}", any))
            )
    }

    pub fn message(&self) -> VALUE {
        self.message
    }

    pub fn raise(&self) -> ! {
        unsafe {
            sys::rb_raise(self.exception.0,
                          sys::SPRINTF_TO_S,
                          self.message);
        }
    }
}

unsafe impl Send for ExceptionInfo {}
unsafe impl Sync for ExceptionInfo {}
<|endoftext|>


<commit_before>extern crate num;
use self::num::Float;

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

use std::f64;
use std::collections::BinaryHeap;

/// A helper struct for `polylabel`
/// We're defining it out here because `#[derive]` doesn't work inside functions
#[derive(PartialOrd, PartialEq)]
struct Cell {
    x: f64, // cell centre x
    y: f64, // cell centre y
    h: f64, // half the cell size

    // pointToPolygonDist(x, y, polygon);
    d: f64, // distance from cell center to polygon
    // this.d + this.h * Math.SQRT2;
    max: f64, // max distance to polygon within a cell
}

impl Ord for Cell {
    fn cmp(&self, other: &Cell) -> std::cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}
impl Eq for Cell {}

// https://github.com/mapbox/polylabel/blob/master/index.js#L82-L101
fn point_to_polygon_dist<T>(point: &Point<T>, polygon: &Polygon<T>)
    where T: Float
{
    // pass
}

// perpendicular distance from a point to a line
fn point_line_distance<T>(point: &Point<T>, start: &Point<T>, end: &Point<T>) -> T
    where T: Float
{
    if start == end {
        point.distance(start)
    } else {
        let numerator = ((end.x() - start.x()) * (start.y() - point.y()) -
                         (start.x() - point.x()) * (end.y() - start.y()))
            .abs();
        let denominator = start.distance(end);
        numerator / denominator
    }
}

// https://github.com/mapbox/polylabel/blob/master/index.js#L7-L71
fn polylabel<T>(polygon: Polygon<T>, precision: &T)
    where T: Float
{
    // pass
}

#[cfg(test)]
mod tests {
}
<commit_msg>Implement Polygon distance for Cell<commit_after>extern crate num;
use self::num::Float;

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

use std::f64;
use std::collections::BinaryHeap;

/// A helper struct for `polylabel`
/// We're defining it out here because `#[derive]` doesn't work inside functions
#[derive(PartialOrd, PartialEq)]
struct Cell<T>
    where T: Float
{
    x: T, // cell centre x
    y: T, // cell centre y
    h: T, // half the cell size

    // pointToPolygonDist(x, y, polygon);
    d: T, // distance from cell center to polygon
    // this.d + this.h * Math.SQRT2;
    max: T, // max distance to polygon within a cell
}

// Signed distance from a Cell's centroid to a Polygon's outline
// Returned value is negative if the point is outside the polygon's exterior ring
impl<T> Cell<T>
    where T: Float
{
    fn distance(&self, polygon: &Polygon<T>) -> T {
        let ref ls = polygon.0;
        let ref points = ls.0;
        let inside = polygon.contains(&Point::new(self.x, self.y));
        let distance = pld(&Point::new(self.x, self.y),
                           &points[0],
                           &points.last().unwrap());
        match inside {
            true => distance,
            false => -distance,
        }
    }
}

impl<T> Ord for Cell<T>
    where T: Float
{
    fn cmp(&self, other: &Cell<T>) -> std::cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}
impl<T> Eq for Cell<T> where T: Float {}

// perpendicular distance from a point to a line
fn pld<T>(point: &Point<T>, start: &Point<T>, end: &Point<T>) -> T
    where T: Float
{
    if start == end {
        point.distance(start)
    } else {
        let numerator = ((end.x() - start.x()) * (start.y() - point.y()) -
                         (start.x() - point.x()) * (end.y() - start.y()))
            .abs();
        let denominator = start.distance(end);
        numerator / denominator
    }
}

// https://github.com/mapbox/polylabel/blob/master/index.js#L7-L71
fn polylabel<T>(polygon: Polygon<T>, precision: &T)
    where T: Float
{
    // pass
}

#[cfg(test)]
mod tests {}
<|endoftext|>


<commit_before>//! Numeric Rust provides a foundation for doing scientific computing with Rust. It aims to be for
//! Rust what Numpy is for Python.
//!
//! OpenBLAS/LAPACK is used to make things like matrix muliplications and solving linear equations
//! fast.
extern crate libc;
extern crate blas_sys;
extern crate lapack_sys;
extern crate num;
extern crate rand;

use num::traits::{Num, NumCast};

/// This is the basic trait that must be satisfied for basic elements used in `Tensor`.
pub trait TensorType: Copy {}
impl<T: Copy> TensorType for T {}

/// `Numeric` extends `TensorType` to all the numeric types supported by `Tensor`
/// (e.g. `u8` and `f32`).
pub trait Numeric: TensorType + Num + NumCast + PartialOrd {}
impl<T: TensorType + Num + NumCast + PartialOrd> Numeric for T {}

pub mod tensor;
pub mod math;
pub mod random;
pub mod linalg;

mod tests;

/// Many of the things in tensor is lifted into numeric since it is so common.
pub use tensor::{Tensor, AxisIndex};
pub use tensor::{SingleTensor, DoubleTensor};
<commit_msg>Added TODO note about TensorType<commit_after>//! Numeric Rust provides a foundation for doing scientific computing with Rust. It aims to be for
//! Rust what Numpy is for Python.
//!
//! OpenBLAS/LAPACK is used to make things like matrix muliplications and solving linear equations
//! fast.
extern crate libc;
extern crate blas_sys;
extern crate lapack_sys;
extern crate num;
extern crate rand;

use num::traits::{Num, NumCast};

// TODO: Sometimes TensorType is used, sometimes Copy. Make a decision and stick with it.
/// This is the basic trait that must be satisfied for basic elements used in `Tensor`.
pub trait TensorType: Copy {}
impl<T: Copy> TensorType for T {}

/// `Numeric` extends `TensorType` to all the numeric types supported by `Tensor`
/// (e.g. `u8` and `f32`).
pub trait Numeric: TensorType + Num + NumCast + PartialOrd {}
impl<T: TensorType + Num + NumCast + PartialOrd> Numeric for T {}

pub mod tensor;
pub mod math;
pub mod random;
pub mod linalg;

mod tests;

/// Many of the things in tensor is lifted into numeric since it is so common.
pub use tensor::{Tensor, AxisIndex};
pub use tensor::{SingleTensor, DoubleTensor};
<|endoftext|>


<commit_before>use std::ops::{Add, Sub, Mul, Div};

#[macro_use]
extern crate nalgebra;
use nalgebra::ApproxEq;

extern crate num;
use num::{Float};

#[inline]
pub fn magic_number_1<T>() -> T
    where T: std::convert::From<f32>
{
    <T as std::convert::From<f32>>::from(700.)
}

#[inline]
pub fn magic_number_2<T>() -> T
    where T: std::convert::From<f32>
{
    <T as std::convert::From<f32>>::from(2595.)
}

#[inline]
pub fn hertz_from_mel<T>(mel: T) -> T
    where T: std::convert::From<f32> + Float + Div<T, Output=T> + Sub<T, Output=T>
{
    magic_number_1::<T>() *
        (<T as std::convert::From<f32>>::from(10.)
         .powf(mel / magic_number_2::<T>()) -
         <T as std::convert::From<f32>>::from(1.))
}

#[inline]
pub fn mel_from_hertz<T>(hertz: T) -> T
    where T: std::convert::From<f32> + Float + Mul<T, Output=T> + Add<T, Output=T>
{
    magic_number_2::<T>() *
        (<T as std::convert::From<f32>>::from(1.) +
         hertz / magic_number_1::<T>()).log10()
}

macro_rules! test_mel {
    ($float:ty) => {{
        assert_approx_eq_eps!(
            549.64 as $float, mel_from_hertz(440 as $float), 0.01);
        assert_approx_eq_eps!(
            440 as $float, hertz_from_mel(549.64 as $float), 0.01);

        let mel: $float = 0.;
        assert_approx_eq!(mel, mel_from_hertz(hertz_from_mel(mel)));
        let mel: $float = 100.;
        assert_approx_eq_eps!(
            mel, mel_from_hertz(hertz_from_mel(mel)), 0.0001);

        let hertz: $float = 0.;
        assert_approx_eq!(hertz, hertz_from_mel(mel_from_hertz(hertz)));
        let hertz: $float = 44100. / 2.;
        assert_approx_eq!(hertz, hertz_from_mel(mel_from_hertz(hertz)));
    }}
}

#[test]
fn test_mel_f32() {
    test_mel!(f32);
}

#[test]
fn test_mel_f64() {
    test_mel!(f64);
}
<commit_msg>simplify code using macros<commit_after>use std::ops::{Add, Sub, Mul, Div};

#[macro_use]
extern crate nalgebra;
use nalgebra::ApproxEq;

extern crate num;
use num::{Float};

macro_rules! from {
    ($expr:expr, $src:ty, $dst:ty) => {
        <$dst as std::convert::From<$src>>::from($expr)
    }
}

#[inline]
pub fn hertz_from_mel<T>(mel: T) -> T
    where T: std::convert::From<f32> + Float + Div<T, Output=T> + Sub<T, Output=T>
{
    from!(700., f32, T) *
        (from!(10., f32, T).powf(
            mel / from!(2595., f32, T)) - from!(1., f32, T))
}

#[inline]
pub fn mel_from_hertz<T>(hertz: T) -> T
    where T: std::convert::From<f32> + Float + Mul<T, Output=T> + Add<T, Output=T>
{
    from!(2595., f32, T) *
        (from!(1., f32, T) + hertz / from!(700., f32, T)).log10()
}

macro_rules! test_mel {
    ($float:ty) => {{
        assert_approx_eq_eps!(
            549.64 as $float, mel_from_hertz(440 as $float), 0.01);
        assert_approx_eq_eps!(
            440 as $float, hertz_from_mel(549.64 as $float), 0.01);

        let mel: $float = 0.;
        assert_approx_eq!(mel, mel_from_hertz(hertz_from_mel(mel)));
        let mel: $float = 100.;
        assert_approx_eq_eps!(
            mel, mel_from_hertz(hertz_from_mel(mel)), 0.0001);

        let hertz: $float = 0.;
        assert_approx_eq!(hertz, hertz_from_mel(mel_from_hertz(hertz)));
        let hertz: $float = 44100. / 2.;
        assert_approx_eq!(hertz, hertz_from_mel(mel_from_hertz(hertz)));
    }}
}

#[test]
fn test_mel_f32() {
    test_mel!(f32);
}

#[test]
fn test_mel_f64() {
    test_mel!(f64);
}
<|endoftext|>


<commit_before>#![feature(libc)]

extern crate libc;
use std::ffi::CString;
use std::slice;
use std::ptr;

mod ffi;

#[derive(Debug, Copy, Clone)]
pub struct Env {
    env: ffi::Voidptr
}

#[derive(Debug, Copy, Clone)]
pub struct Db {
    db: ffi::Voidptr
}

// XXX: Use Arc
unsafe impl Sync for Db {}
unsafe impl Send for Db {}
unsafe impl Sync for Env {}
unsafe impl Send for Env {}

impl Env {
    pub fn new() -> Env {
        Env {env: unsafe{ffi::sp_env()}}
    }

    pub fn destroy(self) {
        unsafe{ffi::sp_destroy(self.env)};
    }

    pub fn db(&mut self, dbname: &str) {
        // XXX: is dbname copied?
        let dbname = CString::new(dbname).unwrap();
        unsafe {ffi::setstring(self.env, "db\0".as_bytes(), dbname.as_bytes(), 0) };
    }

    pub fn open(&mut self) {
        unsafe {ffi::sp_open(self.env)};
    }

    /*
    fn get_object(&mut self, attr: &str) -> Voidptr {
        let attr = CString::new(attr).unwrap();
        unsafe {ffi::sp_getobject(self.env, attr.as_ptr() as *const u8)}
    }
    */

    pub fn get_db(&self, dbname: &str) -> Option<Db> {
        let dbstr = "db.".to_string() + dbname;
        let attr = CString::new(&dbstr[..]).unwrap();
        unsafe {
            let obj = ffi::sp_getobject(self.env, attr.as_ptr() as *const u8);
            if obj.is_null() {
                None
            }
            else {
                Some(Db {db: obj})
            }
        }
    }

    pub fn setattr(&mut self, key: &str, val: &str) {
        let key = CString::new(key).unwrap();
        let val = CString::new(val).unwrap();
        unsafe {ffi::setstring(self.env, key.as_bytes(), val.as_bytes(), 0) };
    }

    pub fn setintattr(&mut self, key: &str, val: i64) {
        let key = CString::new(key).unwrap();
        unsafe {ffi::sp_setint(self.env, key.as_ptr(), val) };
    }
}

pub struct Object<'a> {
    obj: ffi::Voidptr,
    key: &'a [u8]
}

impl<'a> Object<'a> {
    pub fn get_value<'b>(&'b mut self) -> Option<&'b[u8]> {
        unsafe {
            let mut sz = 0;
            let valptr = ffi::sp_getstring(self.obj, "value\0".as_ptr(), &mut sz);

            // XXX: what if we stored an empty value?
            if valptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(valptr as *const u8, sz as usize);
            return Some(s);
        }
    }
}

impl<'a> Drop for Object<'a> {
    fn drop(&mut self) {
        unsafe {ffi::sp_destroy(self.obj);}
    }
}

pub struct Cursor {
    obj: ffi::Voidptr,
}

pub struct CursorObject<'a> {
    obj: ffi::Voidptr,
    cur: &'a Cursor
}

impl<'a> CursorObject<'a> {
    pub fn get_value<'b>(&'b mut self) -> Option<&'b[u8]> {
        unsafe {
            let mut sz = 0;
            let valptr = ffi::sp_getstring(self.obj, "value\0".as_ptr(), &mut sz);

            // XXX: what if we stored an empty value?
            if valptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(valptr as *const u8, sz as usize);
            return Some(s);
        }
    }
}

impl<'a> Drop for CursorObject<'a> {
    fn drop(&mut self) {
        unsafe {ffi::sp_destroy(self.obj);}
    }
}

impl Drop for Cursor {
    fn drop(&mut self) {
        unsafe {ffi::sp_destroy(self.obj);}
    }
}

impl Cursor {
    fn next<'a>(&'a self) -> Option<CursorObject<'a>> {
        let res = unsafe { ffi::sp_get(self.obj, ptr::null_mut()) };
        if res.is_null() {
            None
        }
        else {
            Some(CursorObject{obj: res, cur: &self})
        }
    }
}

impl Db {
    pub fn set(&mut self, key: &[u8], value: &[u8]) {
        unsafe {
            //ffi::sp_set_kv(self.db, key.as_ptr(), key.len() as i32, value.as_ptr(), value.len() as i32);
            let obj = ffi::sp_object(self.db);
            assert!(!obj.is_null());
            ffi::setkey(obj, key);
            ffi::setvalue(obj, value);
            ffi::sp_set(self.db, obj);
            ffi::sp_destroy(obj);
        }
    }

    pub fn iter_all(&mut self) -> Cursor {
        unsafe {
            let obj = ffi::sp_object(self.db);
            assert!(!obj.is_null());
            ffi::setstring(obj, "order\0".as_bytes(), ">=\0".as_bytes(), 0);
            let cursor = ffi::sp_cursor(self.db, obj);
            assert!(!cursor.is_null());
            Cursor {obj: cursor}
        }
    }

    pub fn get<'a>(&self, key: &'a [u8]) -> Option<Object<'a>> {
        assert!(key.len() > 0);
        unsafe {
            let pattern = ffi::sp_object(self.db);
            if pattern.is_null() {
                // XXX: Return Err
                return None;
            }
            ffi::setkey(pattern, key);
            let res = ffi::sp_get(self.db, pattern);
            if res.is_null() {
                ffi::sp_destroy(pattern);
                return None;
            }
            return Some(Object{obj: res, key: key});
        }
    }
}
<commit_msg>Add get_key() for retrieving the key<commit_after>#![feature(libc)]

extern crate libc;
use std::ffi::CString;
use std::slice;
use std::ptr;

mod ffi;

#[derive(Debug, Copy, Clone)]
pub struct Env {
    env: ffi::Voidptr
}

#[derive(Debug, Copy, Clone)]
pub struct Db {
    db: ffi::Voidptr
}

// XXX: Use Arc
unsafe impl Sync for Db {}
unsafe impl Send for Db {}
unsafe impl Sync for Env {}
unsafe impl Send for Env {}

impl Env {
    pub fn new() -> Env {
        Env {env: unsafe{ffi::sp_env()}}
    }

    pub fn destroy(self) {
        unsafe{ffi::sp_destroy(self.env)};
    }

    pub fn db(&mut self, dbname: &str) {
        // XXX: is dbname copied?
        let dbname = CString::new(dbname).unwrap();
        unsafe {ffi::setstring(self.env, "db\0".as_bytes(), dbname.as_bytes(), 0) };
    }

    pub fn open(&mut self) {
        unsafe {ffi::sp_open(self.env)};
    }

    /*
    fn get_object(&mut self, attr: &str) -> Voidptr {
        let attr = CString::new(attr).unwrap();
        unsafe {ffi::sp_getobject(self.env, attr.as_ptr() as *const u8)}
    }
    */

    pub fn get_db(&self, dbname: &str) -> Option<Db> {
        let dbstr = "db.".to_string() + dbname;
        let attr = CString::new(&dbstr[..]).unwrap();
        unsafe {
            let obj = ffi::sp_getobject(self.env, attr.as_ptr() as *const u8);
            if obj.is_null() {
                None
            }
            else {
                Some(Db {db: obj})
            }
        }
    }

    pub fn setattr(&mut self, key: &str, val: &str) {
        let key = CString::new(key).unwrap();
        let val = CString::new(val).unwrap();
        unsafe {ffi::setstring(self.env, key.as_bytes(), val.as_bytes(), 0) };
    }

    pub fn setintattr(&mut self, key: &str, val: i64) {
        let key = CString::new(key).unwrap();
        unsafe {ffi::sp_setint(self.env, key.as_ptr(), val) };
    }
}

pub struct Object<'a> {
    obj: ffi::Voidptr,
    key: &'a [u8]
}

impl<'a> Object<'a> {
    pub fn get_value<'b>(&'b mut self) -> Option<&'b[u8]> {
        unsafe {
            let mut sz = 0;
            let valptr = ffi::sp_getstring(self.obj, "value\0".as_ptr(), &mut sz);

            // XXX: what if we stored an empty value?
            if valptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(valptr as *const u8, sz as usize);
            return Some(s);
        }
    }
}

impl<'a> Drop for Object<'a> {
    fn drop(&mut self) {
        unsafe {ffi::sp_destroy(self.obj);}
    }
}

pub struct Cursor {
    obj: ffi::Voidptr,
}

pub struct CursorObject<'a> {
    obj: ffi::Voidptr,
    cur: &'a Cursor
}

impl<'a> CursorObject<'a> {
    pub fn get_key<'b>(&'b mut self) -> Option<&'b[u8]> {
        unsafe {
            let mut sz = 0;
            let keyptr = ffi::sp_getstring(self.obj, "key\0".as_ptr(), &mut sz);

            if keyptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(keyptr as *const u8, sz as usize);
            return Some(s);
        }
    }

    pub fn get_value<'b>(&'b mut self) -> Option<&'b[u8]> {
        unsafe {
            let mut sz = 0;
            let valptr = ffi::sp_getstring(self.obj, "value\0".as_ptr(), &mut sz);

            // XXX: what if we stored an empty value?
            if valptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(valptr as *const u8, sz as usize);
            return Some(s);
        }
    }
}

impl<'a> Drop for CursorObject<'a> {
    fn drop(&mut self) {
        unsafe {ffi::sp_destroy(self.obj);}
    }
}

impl Drop for Cursor {
    fn drop(&mut self) {
        unsafe {ffi::sp_destroy(self.obj);}
    }
}

impl Cursor {
    fn next<'a>(&'a self) -> Option<CursorObject<'a>> {
        let res = unsafe { ffi::sp_get(self.obj, ptr::null_mut()) };
        if res.is_null() {
            None
        }
        else {
            Some(CursorObject{obj: res, cur: &self})
        }
    }
}

impl Db {
    pub fn set(&mut self, key: &[u8], value: &[u8]) {
        unsafe {
            //ffi::sp_set_kv(self.db, key.as_ptr(), key.len() as i32, value.as_ptr(), value.len() as i32);
            let obj = ffi::sp_object(self.db);
            assert!(!obj.is_null());
            ffi::setkey(obj, key);
            ffi::setvalue(obj, value);
            ffi::sp_set(self.db, obj);
            ffi::sp_destroy(obj);
        }
    }

    pub fn iter_all(&mut self) -> Cursor {
        unsafe {
            let obj = ffi::sp_object(self.db);
            assert!(!obj.is_null());
            ffi::setstring(obj, "order\0".as_bytes(), ">=\0".as_bytes(), 0);
            let cursor = ffi::sp_cursor(self.db, obj);
            assert!(!cursor.is_null());
            Cursor {obj: cursor}
        }
    }

    pub fn get<'a>(&self, key: &'a [u8]) -> Option<Object<'a>> {
        assert!(key.len() > 0);
        unsafe {
            let pattern = ffi::sp_object(self.db);
            if pattern.is_null() {
                // XXX: Return Err
                return None;
            }
            ffi::setkey(pattern, key);
            let res = ffi::sp_get(self.db, pattern);
            if res.is_null() {
                ffi::sp_destroy(pattern);
                return None;
            }
            return Some(Object{obj: res, key: key});
        }
    }
}
<|endoftext|>