<commit_before>#![feature(macro_rules)]
#![feature(globs)]

extern crate semver;
extern crate conduit;

use std::iter;
use std::io::net::ip::IpAddr;
use std::collections::hash_map::{HashMap, Entries};

use conduit::{Method, Scheme, Host, Extensions, Headers, Request};

pub trait RequestDelegator {
    fn request<'a>(&'a self) -> &'a Request;
    fn mut_request<'a>(&'a mut self) -> &'a mut Request;

    fn http_version(&self) -> semver::Version {
        self.request().http_version()
    }

    fn conduit_version(&self) -> semver::Version {
        self.request().conduit_version()
    }

    fn method(&self) -> Method {
        self.request().method()
    }

    fn scheme(&self) -> Scheme {
        self.request().scheme()
    }

    fn host<'a>(&'a self) -> Host<'a> {
        self.request().host()
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        self.request().virtual_root()
    }

    fn path<'a>(&'a self) -> &'a str {
        self.request().path()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request().query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        self.request().remote_ip()
    }

    fn content_length(&self) -> Option<uint> {
        self.request().content_length()
    }

    fn headers<'a>(&'a self) -> &'a Headers {
        self.request().headers()
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self.mut_request().body()
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        self.request().extensions()
    }

    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
        self.mut_request().mut_extensions()
    }
}

impl<'a> Request for &'a mut RequestDelegator + 'a {
    fn http_version(&self) -> semver::Version {
        self.http_version()
    }

    fn conduit_version(&self) -> semver::Version {
        self.conduit_version()
    }

    fn method(&self) -> Method {
        self.method()
    }

    fn scheme(&self) -> Scheme {
        self.scheme()
    }

    fn host<'a>(&'a self) -> Host<'a> {
        self.host()
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        self.virtual_root()
    }

    fn path<'a>(&'a self) -> &'a str {
        self.path()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        self.remote_ip()
    }

    fn content_length(&self) -> Option<uint> {
        self.content_length()
    }

    fn headers<'a>(&'a self) -> &'a Headers {
        self.headers()
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self.body()
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        self.extensions()
    }

    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
        self.mut_extensions()
    }
}

type RawHeaders = HashMap<String, Vec<String>>;
type InHeader<'a> = (&'a String, &'a Vec<String>);
type OutHeader<'a> = (String, &'a Vec<String>);

#[deriving(PartialEq, Clone, Show)]
pub struct HeaderMap(HashMap<String, Vec<String>>);

impl HeaderMap {
    fn normalize(headers: HashMap<String, Vec<String>>) -> HeaderMap {
        let headers = headers.into_iter().map(|(k,v)| (to_lower(&k), v)).collect();
        HeaderMap(headers)
    }

    fn iter<'a>(&'a self) -> iter::Map<'a, InHeader<'a>, OutHeader<'a>, Entries<'a, String, Vec<String>>> {
        self.as_ref().iter().map(|(k,v)| (to_lower(k), v))
    }

    fn as_ref<'a>(&'a self) -> &'a HashMap<String, Vec<String>> {
        match *self {
            HeaderMap(ref map) => map
        }
    }

    fn as_mut<'a>(&'a mut self) -> &'a mut HashMap<String, Vec<String>> {
        match *self {
            HeaderMap(ref mut map) => map
        }
    }

    pub fn len(&self) -> uint {
        self.as_ref().len()
    }
    pub fn clear(&mut self) {
        self.as_mut().clear()
    }
    pub fn find<'a, S: Str>(&'a self, key: &S) -> Option<&'a Vec<String>> {
        self.as_ref().get(&to_lower(key))
    }
    pub fn insert<S: Str>(&mut self, k: S, v: Vec<String>) -> Option<Vec<String>> {
        self.as_mut().insert(to_lower(&k), v)
    }
    pub fn remove<S: Str>(&mut self, k: &S) -> Option<Vec<String>> {
        self.as_mut().remove(&to_lower(k))
    }

    pub fn find_mut<'a, S: Str>(&'a mut self, k: &S) -> Option<&'a mut Vec<String>> {
        self.as_mut().get_mut(&to_lower(k))
    }
}

fn to_lower<S: Str>(string: &S) -> String {
    string.as_slice().chars().map(|c| c.to_lowercase()).collect()
}

#[cfg(test)]
mod tests {
    extern crate "conduit-test" as test;

    use {RequestDelegator, HeaderMap};

    use std::collections::HashMap;
    use conduit;
    use conduit::{Request, Method};

    struct OverrideRequest<'a> {
        request: &'a mut Request + 'a
    }

    impl<'a> RequestDelegator for OverrideRequest<'a> {
        fn request<'a>(&'a self) -> &'a Request {
            let req: &Request = self.request; req
        }

        fn mut_request<'a>(&'a mut self) -> &'a mut Request {
            let req: &mut Request = self.request; req
        }

        fn method(&self) -> Method {
            conduit::Get
        }
    }

    #[test]
    fn test_delegate() {
        let request = &mut test::MockRequest::new(conduit::Head, "/hello") as &mut Request;
        let new = OverrideRequest { request: request };

        assert_eq!(new.method(), conduit::Get);
        assert_eq!(new.path(), "/hello");
    }

    #[test]
    fn test_header_map() {
        let mut map = HeaderMap(HashMap::new());
        map.insert("Content-Type".to_string(), vec!("text/html".to_string()));
        map.insert("location".to_string(), vec!("http://example.com".to_string()));

        assert_eq!(map.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location".to_string()), Some(&vec!("http://example.com".to_string())))
        assert_eq!(map.find(&"content-type"), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location"), Some(&vec!("http://example.com".to_string())))
    }

    #[test]
    fn test_header_map_with_static_inserts() {
        let mut map = HeaderMap(HashMap::new());
        map.insert("Content-Type", vec!("text/html".to_string()));
        map.insert("location", vec!("http://example.com".to_string()));

        assert_eq!(map.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location".to_string()), Some(&vec!("http://example.com".to_string())))
        assert_eq!(map.find(&"content-type"), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location"), Some(&vec!("http://example.com".to_string())))
    }

    #[test]
    fn test_normalize() {
        let mut map = HashMap::new();
        map.insert("Content-Type".to_string(), vec!("text/html".to_string()));

        let headers = HeaderMap::normalize(map);
        assert_eq!(headers.find(&"Content-Type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(headers.find(&"Content-Type"), Some(&vec!("text/html".to_string())))
        assert_eq!(headers.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(headers.find(&"content-type"), Some(&vec!("text/html".to_string())))
    }

    #[test]
    fn test_iterate() {
        let mut headers = HeaderMap(HashMap::new());
        headers.insert("Content-Type", vec!("text/html".to_string()));
        headers.insert("location", vec!("http://example.com".to_string()));

        assert!(headers.iter().any(|t| {
            t.0.as_slice() == "content-type" &&
            t.1.as_slice() == &["text/html".to_string()]
        }));
        assert!(headers.iter().any(|t| {
            t.0.as_slice() == "location" &&
            t.1.as_slice() == &["http://example.com".to_string()]
        }));
        assert!(headers.iter().count() == 2);
    }
}
<commit_msg>Update to rust master<commit_after>#![feature(macro_rules)]
#![feature(globs)]

extern crate semver;
extern crate conduit;

use std::iter;
use std::io::net::ip::IpAddr;
use std::collections::hash_map::{HashMap, Entries};

use conduit::{Method, Scheme, Host, Extensions, Headers, Request};

pub trait RequestDelegator {
    fn request<'a>(&'a self) -> &'a Request;
    fn mut_request<'a>(&'a mut self) -> &'a mut Request;

    fn http_version(&self) -> semver::Version {
        self.request().http_version()
    }

    fn conduit_version(&self) -> semver::Version {
        self.request().conduit_version()
    }

    fn method(&self) -> Method {
        self.request().method()
    }

    fn scheme(&self) -> Scheme {
        self.request().scheme()
    }

    fn host<'a>(&'a self) -> Host<'a> {
        self.request().host()
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        self.request().virtual_root()
    }

    fn path<'a>(&'a self) -> &'a str {
        self.request().path()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request().query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        self.request().remote_ip()
    }

    fn content_length(&self) -> Option<uint> {
        self.request().content_length()
    }

    fn headers<'a>(&'a self) -> &'a Headers {
        self.request().headers()
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self.mut_request().body()
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        self.request().extensions()
    }

    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
        self.mut_request().mut_extensions()
    }
}

impl<'a> Request for &'a mut (RequestDelegator + 'a) {
    fn http_version(&self) -> semver::Version {
        self.http_version()
    }

    fn conduit_version(&self) -> semver::Version {
        self.conduit_version()
    }

    fn method(&self) -> Method {
        self.method()
    }

    fn scheme(&self) -> Scheme {
        self.scheme()
    }

    fn host<'a>(&'a self) -> Host<'a> {
        self.host()
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        self.virtual_root()
    }

    fn path<'a>(&'a self) -> &'a str {
        self.path()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        self.remote_ip()
    }

    fn content_length(&self) -> Option<uint> {
        self.content_length()
    }

    fn headers<'a>(&'a self) -> &'a Headers {
        self.headers()
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self.body()
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        self.extensions()
    }

    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
        self.mut_extensions()
    }
}

type RawHeaders = HashMap<String, Vec<String>>;
type InHeader<'a> = (&'a String, &'a Vec<String>);
type OutHeader<'a> = (String, &'a Vec<String>);

#[deriving(PartialEq, Clone, Show)]
pub struct HeaderMap(HashMap<String, Vec<String>>);

impl HeaderMap {
    fn normalize(headers: HashMap<String, Vec<String>>) -> HeaderMap {
        let headers = headers.into_iter().map(|(k,v)| (to_lower(&k), v)).collect();
        HeaderMap(headers)
    }

    fn iter<'a>(&'a self) -> iter::Map<'a, InHeader<'a>, OutHeader<'a>, Entries<'a, String, Vec<String>>> {
        self.as_ref().iter().map(|(k,v)| (to_lower(k), v))
    }

    fn as_ref<'a>(&'a self) -> &'a HashMap<String, Vec<String>> {
        match *self {
            HeaderMap(ref map) => map
        }
    }

    fn as_mut<'a>(&'a mut self) -> &'a mut HashMap<String, Vec<String>> {
        match *self {
            HeaderMap(ref mut map) => map
        }
    }

    pub fn len(&self) -> uint {
        self.as_ref().len()
    }
    pub fn clear(&mut self) {
        self.as_mut().clear()
    }
    pub fn find<'a, S: Str>(&'a self, key: &S) -> Option<&'a Vec<String>> {
        self.as_ref().get(&to_lower(key))
    }
    pub fn insert<S: Str>(&mut self, k: S, v: Vec<String>) -> Option<Vec<String>> {
        self.as_mut().insert(to_lower(&k), v)
    }
    pub fn remove<S: Str>(&mut self, k: &S) -> Option<Vec<String>> {
        self.as_mut().remove(&to_lower(k))
    }

    pub fn find_mut<'a, S: Str>(&'a mut self, k: &S) -> Option<&'a mut Vec<String>> {
        self.as_mut().get_mut(&to_lower(k))
    }
}

fn to_lower<S: Str>(string: &S) -> String {
    string.as_slice().chars().map(|c| c.to_lowercase()).collect()
}

#[cfg(test)]
mod tests {
    extern crate "conduit-test" as test;

    use {RequestDelegator, HeaderMap};

    use std::collections::HashMap;
    use conduit::{Request, Method};

    struct OverrideRequest<'a> {
        request: &'a mut (Request + 'a),
    }

    impl<'a> RequestDelegator for OverrideRequest<'a> {
        fn request<'a>(&'a self) -> &'a Request {
            let req: &Request = self.request; req
        }

        fn mut_request<'a>(&'a mut self) -> &'a mut Request {
            let req: &mut Request = self.request; req
        }

        fn method(&self) -> Method {
            Method::Get
        }
    }

    #[test]
    fn test_delegate() {
        let request = &mut test::MockRequest::new(Method::Head, "/hello") as &mut Request;
        let new = OverrideRequest { request: request };

        assert_eq!(new.method(), Method::Get);
        assert_eq!(new.path(), "/hello");
    }

    #[test]
    fn test_header_map() {
        let mut map = HeaderMap(HashMap::new());
        map.insert("Content-Type".to_string(), vec!("text/html".to_string()));
        map.insert("location".to_string(), vec!("http://example.com".to_string()));

        assert_eq!(map.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location".to_string()), Some(&vec!("http://example.com".to_string())))
        assert_eq!(map.find(&"content-type"), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location"), Some(&vec!("http://example.com".to_string())))
    }

    #[test]
    fn test_header_map_with_static_inserts() {
        let mut map = HeaderMap(HashMap::new());
        map.insert("Content-Type", vec!("text/html".to_string()));
        map.insert("location", vec!("http://example.com".to_string()));

        assert_eq!(map.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location".to_string()), Some(&vec!("http://example.com".to_string())))
        assert_eq!(map.find(&"content-type"), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location"), Some(&vec!("http://example.com".to_string())))
    }

    #[test]
    fn test_normalize() {
        let mut map = HashMap::new();
        map.insert("Content-Type".to_string(), vec!("text/html".to_string()));

        let headers = HeaderMap::normalize(map);
        assert_eq!(headers.find(&"Content-Type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(headers.find(&"Content-Type"), Some(&vec!("text/html".to_string())))
        assert_eq!(headers.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(headers.find(&"content-type"), Some(&vec!("text/html".to_string())))
    }

    #[test]
    fn test_iterate() {
        let mut headers = HeaderMap(HashMap::new());
        headers.insert("Content-Type", vec!("text/html".to_string()));
        headers.insert("location", vec!("http://example.com".to_string()));

        assert!(headers.iter().any(|t| {
            t.0.as_slice() == "content-type" &&
            t.1.as_slice() == &["text/html".to_string()]
        }));
        assert!(headers.iter().any(|t| {
            t.0.as_slice() == "location" &&
            t.1.as_slice() == &["http://example.com".to_string()]
        }));
        assert!(headers.iter().count() == 2);
    }
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! simple_bitfield_field {
   ($name:ident, $t:ty,) => {};
   ($name:ident, $t:ty, _, $setter:ident: $msb:expr, $lsb:expr, $($rest:tt)*) => {
       impl $name {
           pub fn $setter(&mut self, value: $t) {
               self.set_range_($msb, $lsb, value);
           }
       }
       simple_bitfield_field!{$name, $t, $($rest)*}
   };
   ($name:ident, $t:ty, _, $setter:ident: $msb:expr, $lsb:expr; $count:expr, $($rest:tt)*) => {
       impl $name {
           pub fn $setter(&mut self, index: usize, value: $t) {
               debug_assert!(index < $count);
               let width = $msb - $lsb + 1;
               let lsb = $lsb + index*width;
               let msb = lsb + width - 1;
               self.set_range_(msb, lsb, value);
           }
       }
       simple_bitfield_field!{$name, $t, $($rest)*}
   };
   ($name:ident, $t:ty, $getter:ident, _: $msb:expr, $lsb:expr, $($rest:tt)*) => {
       impl $name {
           pub fn $getter(&self) -> $t {
               self.get_range_($msb, $lsb)
           }
       }
       simple_bitfield_field!{$name, $t, $($rest)*}
   };
   ($name:ident, $t:ty, $getter:ident, _: $msb:expr, $lsb:expr; $count:expr, $($rest:tt)*) => {
       impl $name {
           pub fn $getter(&self, index: usize) -> $t {
               debug_assert!(index < $count);
               let width = $msb - $lsb + 1;
               let lsb = $lsb + index*width;
               let msb = lsb + width - 1;
               self.get_range_(msb, lsb)
           }
       }
       simple_bitfield_field!{$name, $t, $($rest)*}
   };
   ($name:ident, $t:ty, $getter:ident, $setter:ident: $msb:expr, $lsb:expr, $($rest:tt)*) => {
       simple_bitfield_field!{$name, $t, $getter, _: $msb, $lsb, }
       simple_bitfield_field!{$name, $t, _, $setter: $msb, $lsb, }
       simple_bitfield_field!{$name, $t, $($rest)*}
   };
   ($name:ident, $t:ty, $getter:ident, $setter:ident: $msb:expr, $lsb:expr; $count:expr, $($rest:tt)*) => {
         simple_bitfield_field!{$name, $t, $getter, _: $msb, $lsb; $count, }
         simple_bitfield_field!{$name, $t, _, $setter: $msb, $lsb; $count, }
         simple_bitfield_field!{$name, $t, $($rest)*}
   };
}

#[macro_export]
macro_rules! simple_bitfield {
    ($name:ident, $t:ty, $($rest:tt)*) => {
         #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
         #[repr(C)]
         pub struct $name(pub $t);
         impl $name {
             fn get_range_(&self, msb: usize, lsb: usize) -> $t {
                 let bit_len = mem::size_of::<$t>()*8;
                 (self.0 << (bit_len - msb - 1)) >> (bit_len - msb - 1 + lsb)
             }

             fn set_range_(&mut self, msb: usize, lsb: usize, value: $t) {
                 let bit_len = mem::size_of::<$t>()*8;
                 let mask: $t = !(0 as $t) << (bit_len - msb - 1) >> (bit_len - msb - 1 + lsb) << (lsb);
                 self.0 &= !mask;
                 self.0 |= (value << lsb) & mask;
             }
         }
         simple_bitfield_field!{$name, $t, $($rest)*}
    }
}
<commit_msg>Make the crate no_std<commit_after>#![no_std]
#[macro_export]
macro_rules! simple_bitfield_field {
   ($name:ident, $t:ty,) => {};
   ($name:ident, $t:ty, _, $setter:ident: $msb:expr, $lsb:expr, $($rest:tt)*) => {
       impl $name {
           pub fn $setter(&mut self, value: $t) {
               self.set_range_($msb, $lsb, value);
           }
       }
       simple_bitfield_field!{$name, $t, $($rest)*}
   };
   ($name:ident, $t:ty, _, $setter:ident: $msb:expr, $lsb:expr; $count:expr, $($rest:tt)*) => {
       impl $name {
           pub fn $setter(&mut self, index: usize, value: $t) {
               debug_assert!(index < $count);
               let width = $msb - $lsb + 1;
               let lsb = $lsb + index*width;
               let msb = lsb + width - 1;
               self.set_range_(msb, lsb, value);
           }
       }
       simple_bitfield_field!{$name, $t, $($rest)*}
   };
   ($name:ident, $t:ty, $getter:ident, _: $msb:expr, $lsb:expr, $($rest:tt)*) => {
       impl $name {
           pub fn $getter(&self) -> $t {
               self.get_range_($msb, $lsb)
           }
       }
       simple_bitfield_field!{$name, $t, $($rest)*}
   };
   ($name:ident, $t:ty, $getter:ident, _: $msb:expr, $lsb:expr; $count:expr, $($rest:tt)*) => {
       impl $name {
           pub fn $getter(&self, index: usize) -> $t {
               debug_assert!(index < $count);
               let width = $msb - $lsb + 1;
               let lsb = $lsb + index*width;
               let msb = lsb + width - 1;
               self.get_range_(msb, lsb)
           }
       }
       simple_bitfield_field!{$name, $t, $($rest)*}
   };
   ($name:ident, $t:ty, $getter:ident, $setter:ident: $msb:expr, $lsb:expr, $($rest:tt)*) => {
       simple_bitfield_field!{$name, $t, $getter, _: $msb, $lsb, }
       simple_bitfield_field!{$name, $t, _, $setter: $msb, $lsb, }
       simple_bitfield_field!{$name, $t, $($rest)*}
   };
   ($name:ident, $t:ty, $getter:ident, $setter:ident: $msb:expr, $lsb:expr; $count:expr, $($rest:tt)*) => {
         simple_bitfield_field!{$name, $t, $getter, _: $msb, $lsb; $count, }
         simple_bitfield_field!{$name, $t, _, $setter: $msb, $lsb; $count, }
         simple_bitfield_field!{$name, $t, $($rest)*}
   };
}

#[macro_export]
macro_rules! simple_bitfield {
    ($name:ident, $t:ty, $($rest:tt)*) => {
         #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
         #[repr(C)]
         pub struct $name(pub $t);
         impl $name {
             fn get_range_(&self, msb: usize, lsb: usize) -> $t {
                 let bit_len = mem::size_of::<$t>()*8;
                 (self.0 << (bit_len - msb - 1)) >> (bit_len - msb - 1 + lsb)
             }

             fn set_range_(&mut self, msb: usize, lsb: usize, value: $t) {
                 let bit_len = mem::size_of::<$t>()*8;
                 let mask: $t = !(0 as $t) << (bit_len - msb - 1) >> (bit_len - msb - 1 + lsb) << (lsb);
                 self.0 &= !mask;
                 self.0 |= (value << lsb) & mask;
             }
         }
         simple_bitfield_field!{$name, $t, $($rest)*}
    }
}
<|endoftext|>


<commit_before>//! The Liquid templating language for Rust
//!
//! __http://liquidmarkup.org/__
//!
//! ```toml
//! [dependencies]
//! liquid = "0.9"
//! ```
//!
//! ## Example
//! ```rust
//! use liquid::{Renderable, Context, Value};
//!
//! let template = liquid::parse("Liquid! {{num | minus: 2}}", Default::default()).unwrap();
//!
//! let mut context = Context::new();
//! context.set_val("num", Value::Num(4f32));
//!
//! let output = template.render(&mut context);
//! assert_eq!(output.unwrap(), Some("Liquid! 2".to_string()));
//! ```
#![crate_name = "liquid"]
#![doc(html_root_url = "https://cobalt-org.github.io/liquid-rust/")]

// Deny warnings, except in dev mode
#![deny(warnings)]
// #![deny(missing_docs)]
#![cfg_attr(feature="dev", warn(warnings))]

// Allow zero pointers for lazy_static. Otherwise clippy will complain.
#![allow(unknown_lints)]
#![allow(zero_ptr)]

extern crate regex;
extern crate chrono;
extern crate unicode_segmentation;
extern crate itertools;
extern crate url;

#[macro_use]
extern crate lazy_static;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

use std::collections::HashMap;
use lexer::Element;
use tags::{assign_tag, cycle_tag, include_tag, break_tag, continue_tag, comment_block, raw_block,
           for_block, if_block, unless_block, capture_block, case_block};
use std::default::Default;
use std::fs::File;
use std::io::prelude::Read;
use std::path::{PathBuf, Path};
use error::Result;

pub use value::Value;
pub use value::Object;
pub use value::Array;
pub use context::Context;
pub use template::Template;
pub use error::Error;
pub use filters::FilterError;
pub use token::Token;

pub mod lexer;
pub mod parser;

mod token;
mod error;
mod template;
mod output;
mod text;
mod tags;
mod filters;
mod value;
mod variable;
mod context;
mod path;

/// A trait for creating custom tags. This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a tag and returns
/// a new [Renderable](trait.Renderable.html) based on its parameters. The received parameters
/// specify the name of the tag, the argument [Tokens](lexer/enum.Token.html) passed to
/// the tag and the global [`LiquidOptions`](struct.LiquidOptions.html).
///
/// ## Minimal Example
/// ```
/// # use liquid::{Renderable, LiquidOptions, Context, Error, FnTagParser};
///
/// struct HelloWorld;
///
/// impl Renderable for HelloWorld {
///     fn render(&self, _context: &mut Context) -> Result<Option<String>, Error>{
///         Ok(Some("Hello World!".to_owned()))
///     }
/// }
///
/// let mut options : LiquidOptions = Default::default();
/// options.tags.insert(
///     "hello_world".to_owned(),
///     Box::new(FnTagParser::new(|_tag_name, _arguments, _options| {
///         Ok(Box::new(HelloWorld))
///     })),
/// );
///
/// let template = liquid::parse("{{hello_world}}", options).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Hello World!".to_owned()));
/// ```
pub trait ParseTag {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             options: &LiquidOptions)
             -> Result<Box<Renderable>>;
}

pub type FnParseTag = fn(&str, &[Token], &LiquidOptions) -> Result<Box<Renderable>>;

pub struct FnTagParser {
    pub parser: FnParseTag,
}

impl FnTagParser {
    pub fn new(parser: FnParseTag) -> Self {
        Self { parser }
    }
}

impl ParseTag for FnTagParser {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             options: &LiquidOptions)
             -> Result<Box<Renderable>> {
        (self.parser)(tag_name, arguments, options)
    }
}

/// A trait for creating custom custom block-size tags (`{% if something %}{% endif %}`).
/// This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a block and returns
/// a new `Renderable` based on its parameters. The received parameters specify the name
/// of the block, the argument [Tokens](lexer/enum.Token.html) passed to
/// the block, a Vec of all [Elements](lexer/enum.Element.html) inside the block and
/// the global [`LiquidOptions`](struct.LiquidOptions.html).
pub type Block = Fn(&str, &[Token], &[Element], &LiquidOptions) -> Result<Box<Renderable>>;

/// Any object (tag/block) that can be rendered by liquid must implement this trait.
pub trait Renderable: Send + Sync {
    /// Renders the Renderable instance given a Liquid context.
    /// The Result that is returned signals if there was an error rendering,
    /// the Option<String> that is wrapped by the Result will be None if
    /// the render has run successfully but there is no content to render.
    fn render(&self, context: &mut Context) -> Result<Option<String>>;
}

pub trait TemplateRepository {
    fn read_template(&self, path: &str) -> Result<String>;
}

/// `TemplateRepository` to load files relative to the root
pub struct LocalTemplateRepository {
    root: PathBuf,
}

impl LocalTemplateRepository {
    pub fn new(root: PathBuf) -> LocalTemplateRepository {
        LocalTemplateRepository { root: root }
    }
}

impl TemplateRepository for LocalTemplateRepository {
    fn read_template(&self, relative_path: &str) -> Result<String> {
        let path = self.root.clone().join(relative_path);

        if !path.exists() {
            return Err(Error::from(&*format!("{:?} does not exist", path)));
        }
        let mut file = try!(File::open(path));

        let mut content = String::new();
        file.read_to_string(&mut content)?;
        Ok(content)
    }
}

/// Options that `liquid::parse` takes
pub struct LiquidOptions {
    /// Holds all custom block-size tags
    pub blocks: HashMap<String, Box<Block>>,
    /// Holds all custom tags
    pub tags: HashMap<String, Box<ParseTag>>,
    /// The path to which paths in include tags should be relative to
    pub template_repository: Box<TemplateRepository>,
}

impl Default for LiquidOptions {
    fn default() -> LiquidOptions {
        LiquidOptions {
            blocks: Default::default(),
            tags: Default::default(),
            template_repository: Box::new(LocalTemplateRepository { root: PathBuf::new() }),
        }
    }
}

impl LiquidOptions {
    /// Creates a LiquidOptions instance, pre-seeded with all known
    /// tags and blocks.
    pub fn with_known_blocks() -> LiquidOptions {
        let mut options = LiquidOptions::default();
        options.register_known_blocks();
        options
    }

    /// Registers all known tags and blocks in an existing options
    /// struct
    pub fn register_known_blocks(&mut self) {
        self.register_tag("assign", Box::new(FnTagParser::new(assign_tag)));
        self.register_tag("break", Box::new(FnTagParser::new(break_tag)));
        self.register_tag("continue", Box::new(FnTagParser::new(continue_tag)));
        self.register_tag("cycle", Box::new(FnTagParser::new(cycle_tag)));
        self.register_tag("include", Box::new(FnTagParser::new(include_tag)));

        self.register_block("raw", Box::new(raw_block));
        self.register_block("if", Box::new(if_block));
        self.register_block("unless", Box::new(unless_block));
        self.register_block("for", Box::new(for_block));
        self.register_block("comment", Box::new(comment_block));
        self.register_block("capture", Box::new(capture_block));
        self.register_block("case", Box::new(case_block));
    }

    /// Inserts a new custom block into the options object
    pub fn register_block(&mut self, name: &str, block: Box<Block>) {
        self.blocks.insert(name.to_owned(), block);
    }

    /// Inserts a new custom tag into the options object
    pub fn register_tag(&mut self, name: &str, tag: Box<ParseTag>) {
        self.tags.insert(name.to_owned(), tag);
    }
}

/// Parses a liquid template, returning a Template object.
/// # Examples
///
/// ## Minimal Template
///
/// ```
/// use liquid::{Renderable, LiquidOptions, Context};
///
/// let template = liquid::parse("Liquid!", LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid!".to_owned()));
/// ```
///
pub fn parse(text: &str, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    options.register_known_blocks();

    let tokens = try!(lexer::tokenize(text));
    parser::parse(&tokens, &options).map(Template::new)
}

/// Parse a liquid template from a file, returning a `Result<Template, Error>`.
/// # Examples
///
/// ## Minimal Template
///
/// `template.txt`:
///
/// ```text
/// "Liquid {{data}}"
/// ```
///
/// Your rust code:
///
/// ```rust,no_run
/// use liquid::{Renderable, LiquidOptions, Context, Value};
///
/// let template = liquid::parse_file("path/to/template.txt",
///                                   LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// data.set_val("data", Value::Num(4f32));
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid 4\n".to_string()));
/// ```
///
pub fn parse_file<P: AsRef<Path>>(fp: P, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    options.register_known_blocks();

    let mut f = try!(File::open(fp));
    let mut buf = String::new();
    try!(f.read_to_string(&mut buf));

    let tokens = try!(lexer::tokenize(&buf));
    parser::parse(&tokens, &options).map(Template::new)
}
<commit_msg>feat: make ParseTag cloneable<commit_after>//! The Liquid templating language for Rust
//!
//! __http://liquidmarkup.org/__
//!
//! ```toml
//! [dependencies]
//! liquid = "0.9"
//! ```
//!
//! ## Example
//! ```rust
//! use liquid::{Renderable, Context, Value};
//!
//! let template = liquid::parse("Liquid! {{num | minus: 2}}", Default::default()).unwrap();
//!
//! let mut context = Context::new();
//! context.set_val("num", Value::Num(4f32));
//!
//! let output = template.render(&mut context);
//! assert_eq!(output.unwrap(), Some("Liquid! 2".to_string()));
//! ```
#![crate_name = "liquid"]
#![doc(html_root_url = "https://cobalt-org.github.io/liquid-rust/")]

// Deny warnings, except in dev mode
#![deny(warnings)]
// #![deny(missing_docs)]
#![cfg_attr(feature="dev", warn(warnings))]

// Allow zero pointers for lazy_static. Otherwise clippy will complain.
#![allow(unknown_lints)]
#![allow(zero_ptr)]

extern crate regex;
extern crate chrono;
extern crate unicode_segmentation;
extern crate itertools;
extern crate url;

#[macro_use]
extern crate lazy_static;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

use std::collections::HashMap;
use lexer::Element;
use tags::{assign_tag, cycle_tag, include_tag, break_tag, continue_tag, comment_block, raw_block,
           for_block, if_block, unless_block, capture_block, case_block};
use std::default::Default;
use std::fs::File;
use std::io::prelude::Read;
use std::path::{PathBuf, Path};
use error::Result;

pub use value::Value;
pub use value::Object;
pub use value::Array;
pub use context::Context;
pub use template::Template;
pub use error::Error;
pub use filters::FilterError;
pub use token::Token;

pub mod lexer;
pub mod parser;

mod token;
mod error;
mod template;
mod output;
mod text;
mod tags;
mod filters;
mod value;
mod variable;
mod context;
mod path;

/// A trait for creating custom tags. This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a tag and returns
/// a new [Renderable](trait.Renderable.html) based on its parameters. The received parameters
/// specify the name of the tag, the argument [Tokens](lexer/enum.Token.html) passed to
/// the tag and the global [`LiquidOptions`](struct.LiquidOptions.html).
///
/// ## Minimal Example
/// ```
/// # use liquid::{Renderable, LiquidOptions, Context, Error, FnTagParser};
///
/// struct HelloWorld;
///
/// impl Renderable for HelloWorld {
///     fn render(&self, _context: &mut Context) -> Result<Option<String>, Error>{
///         Ok(Some("Hello World!".to_owned()))
///     }
/// }
///
/// let mut options : LiquidOptions = Default::default();
/// options.tags.insert(
///     "hello_world".to_owned(),
///     Box::new(FnTagParser::new(|_tag_name, _arguments, _options| {
///         Ok(Box::new(HelloWorld))
///     })),
/// );
///
/// let template = liquid::parse("{{hello_world}}", options).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Hello World!".to_owned()));
/// ```
pub trait ParseTag: Send + Sync + ParseTagClone {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             options: &LiquidOptions)
             -> Result<Box<Renderable>>;
}

pub trait ParseTagClone {
    fn clone_box(&self) -> Box<ParseTag>;
}

impl<T> ParseTagClone for T
    where T: 'static + ParseTag + Clone
{
    fn clone_box(&self) -> Box<ParseTag> {
        Box::new(self.clone())
    }
}

impl Clone for Box<ParseTag> {
    fn clone(&self) -> Box<ParseTag> {
        self.clone_box()
    }
}

pub type FnParseTag = fn(&str, &[Token], &LiquidOptions) -> Result<Box<Renderable>>;

#[derive(Clone)]
pub struct FnTagParser {
    pub parser: FnParseTag,
}

impl FnTagParser {
    pub fn new(parser: FnParseTag) -> Self {
        Self { parser }
    }
}

impl ParseTag for FnTagParser {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             options: &LiquidOptions)
             -> Result<Box<Renderable>> {
        (self.parser)(tag_name, arguments, options)
    }
}

/// A trait for creating custom custom block-size tags (`{% if something %}{% endif %}`).
/// This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a block and returns
/// a new `Renderable` based on its parameters. The received parameters specify the name
/// of the block, the argument [Tokens](lexer/enum.Token.html) passed to
/// the block, a Vec of all [Elements](lexer/enum.Element.html) inside the block and
/// the global [`LiquidOptions`](struct.LiquidOptions.html).
pub type Block = Fn(&str, &[Token], &[Element], &LiquidOptions) -> Result<Box<Renderable>>;

/// Any object (tag/block) that can be rendered by liquid must implement this trait.
pub trait Renderable: Send + Sync {
    /// Renders the Renderable instance given a Liquid context.
    /// The Result that is returned signals if there was an error rendering,
    /// the Option<String> that is wrapped by the Result will be None if
    /// the render has run successfully but there is no content to render.
    fn render(&self, context: &mut Context) -> Result<Option<String>>;
}

pub trait TemplateRepository {
    fn read_template(&self, path: &str) -> Result<String>;
}

/// `TemplateRepository` to load files relative to the root
pub struct LocalTemplateRepository {
    root: PathBuf,
}

impl LocalTemplateRepository {
    pub fn new(root: PathBuf) -> LocalTemplateRepository {
        LocalTemplateRepository { root: root }
    }
}

impl TemplateRepository for LocalTemplateRepository {
    fn read_template(&self, relative_path: &str) -> Result<String> {
        let path = self.root.clone().join(relative_path);

        if !path.exists() {
            return Err(Error::from(&*format!("{:?} does not exist", path)));
        }
        let mut file = try!(File::open(path));

        let mut content = String::new();
        file.read_to_string(&mut content)?;
        Ok(content)
    }
}

/// Options that `liquid::parse` takes
pub struct LiquidOptions {
    /// Holds all custom block-size tags
    pub blocks: HashMap<String, Box<Block>>,
    /// Holds all custom tags
    pub tags: HashMap<String, Box<ParseTag>>,
    /// The path to which paths in include tags should be relative to
    pub template_repository: Box<TemplateRepository>,
}

impl Default for LiquidOptions {
    fn default() -> LiquidOptions {
        LiquidOptions {
            blocks: Default::default(),
            tags: Default::default(),
            template_repository: Box::new(LocalTemplateRepository { root: PathBuf::new() }),
        }
    }
}

impl LiquidOptions {
    /// Creates a LiquidOptions instance, pre-seeded with all known
    /// tags and blocks.
    pub fn with_known_blocks() -> LiquidOptions {
        let mut options = LiquidOptions::default();
        options.register_known_blocks();
        options
    }

    /// Registers all known tags and blocks in an existing options
    /// struct
    pub fn register_known_blocks(&mut self) {
        self.register_tag("assign", Box::new(FnTagParser::new(assign_tag)));
        self.register_tag("break", Box::new(FnTagParser::new(break_tag)));
        self.register_tag("continue", Box::new(FnTagParser::new(continue_tag)));
        self.register_tag("cycle", Box::new(FnTagParser::new(cycle_tag)));
        self.register_tag("include", Box::new(FnTagParser::new(include_tag)));

        self.register_block("raw", Box::new(raw_block));
        self.register_block("if", Box::new(if_block));
        self.register_block("unless", Box::new(unless_block));
        self.register_block("for", Box::new(for_block));
        self.register_block("comment", Box::new(comment_block));
        self.register_block("capture", Box::new(capture_block));
        self.register_block("case", Box::new(case_block));
    }

    /// Inserts a new custom block into the options object
    pub fn register_block(&mut self, name: &str, block: Box<Block>) {
        self.blocks.insert(name.to_owned(), block);
    }

    /// Inserts a new custom tag into the options object
    pub fn register_tag(&mut self, name: &str, tag: Box<ParseTag>) {
        self.tags.insert(name.to_owned(), tag);
    }
}

/// Parses a liquid template, returning a Template object.
/// # Examples
///
/// ## Minimal Template
///
/// ```
/// use liquid::{Renderable, LiquidOptions, Context};
///
/// let template = liquid::parse("Liquid!", LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid!".to_owned()));
/// ```
///
pub fn parse(text: &str, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    options.register_known_blocks();

    let tokens = try!(lexer::tokenize(text));
    parser::parse(&tokens, &options).map(Template::new)
}

/// Parse a liquid template from a file, returning a `Result<Template, Error>`.
/// # Examples
///
/// ## Minimal Template
///
/// `template.txt`:
///
/// ```text
/// "Liquid {{data}}"
/// ```
///
/// Your rust code:
///
/// ```rust,no_run
/// use liquid::{Renderable, LiquidOptions, Context, Value};
///
/// let template = liquid::parse_file("path/to/template.txt",
///                                   LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// data.set_val("data", Value::Num(4f32));
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid 4\n".to_string()));
/// ```
///
pub fn parse_file<P: AsRef<Path>>(fp: P, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    options.register_known_blocks();

    let mut f = try!(File::open(fp));
    let mut buf = String::new();
    try!(f.read_to_string(&mut buf));

    let tokens = try!(lexer::tokenize(&buf));
    parser::parse(&tokens, &options).map(Template::new)
}
<|endoftext|>


<commit_before>//! The `libopenreil` crate aims to provide an okay wrapper around openreil-sys.

extern crate openreil_sys;
extern crate libc;

use openreil_sys::root::{reil_addr_t, reil_inst_t, reil_t, reil_arch_t, reil_inst_print,
                            reil_inst_handler_t, reil_init, reil_close, reil_translate,
                            reil_translate_insn};
pub use openreil_sys::root::{reil_op_t, reil_type_t, reil_size_t, reil_arg_t, reil_raw_t};

use std::mem;
use std::ops::Drop;
use std::marker;

/// Specifies the architecture of the binary code.
///
/// As of now, supported architectures are `x86` and `ARM`.
#[derive(Clone, Copy, Debug)]
pub enum ReilArch {
    X86,
    ARM,
}

/// Callback handler type to further process the resulting REIL instructions.
/// Is a type alias for a C function.
///
/// Please take care to assert that neither argument is NULL.
pub type ReilInstHandler<T> = extern "C" fn(*mut ReilRawInst, *mut T) -> i32;

/// A raw REIL instruction, that is a simple autogenerated wrapper for the original C type.
pub type ReilRawInst = reil_inst_t;

/// A disassembler object.
///
/// The `Reil` type provides a simple interface to disassemble and translate single or multiple instructions
/// to the OpenREIL intermediate language.
///
/// A `handler` callback function can be provided during construction to further process the resulting REIL instructions.
pub struct Reil<'a, T: 'a> {
    reil_handle: reil_t,
    _marker: marker::PhantomData<&'a mut T>,
}

impl<'a, T: 'a> Reil<'a, T> {
    /// Construct a new disassembler object
    /// The handler function can be used to process the resulting REIL instructions
    /// The `context` gets handed to the callback function
    pub fn new(
        arch: ReilArch,
        handler: Option<ReilInstHandler<T>>,
        context: &'a mut T,
    ) -> Option<Self> {
        let arch = match arch {
            ReilArch::X86 => reil_arch_t::ARCH_X86,
            ReilArch::ARM => reil_arch_t::ARCH_ARM,
        };
        let handler: reil_inst_handler_t = unsafe { mem::transmute(handler) };

        let c_ptr = context as *mut _;

        let reil = unsafe { reil_init(arch, handler, c_ptr as *mut libc::c_void) };

        if reil.is_null() {
            return None;
        }

        let new_reil = Reil {
            reil_handle: reil,
            _marker: marker::PhantomData,
        };

        Some(new_reil)
    }

    /// Translate the binary data given in `data` to REIL instructions,
    /// `start_address` designates the starting address the decoded instructions get assigned.
    pub fn translate(&mut self, data: &mut [u8], start_address: u32) {
        unsafe {
            reil_translate(
                self.reil_handle,
                start_address as reil_addr_t,
                data.as_mut_ptr(),
                data.len() as libc::c_int,
            );
        }
    }

    /// Translate a single instruction from the binary data given in `data` and start addressing at the given address.
    pub fn translate_instruction(&mut self, data: &mut [u8], start_address: u32) {
        unsafe {
            reil_translate_insn(
                self.reil_handle,
                start_address as reil_addr_t,
                data.as_mut_ptr(),
                data.len() as libc::c_int,
            );
        }
    }
}

impl<'a, T: 'a> Drop for Reil<'a, T> {
    fn drop(&mut self) {
        unsafe {
            reil_close(self.reil_handle);
        }
    }
}

pub trait ReilInst {
    fn address(&self) -> u64;
    fn reil_offset(&self) -> u8;
    fn raw_address(&self) -> u64;
    fn print(&self);
    fn first_operand(&self) -> Option<reil_arg_t>;
    fn second_operand(&self) -> Option<reil_arg_t>;
    fn third_operand(&self) -> Option<reil_arg_t>;
    fn opcode(&self) -> reil_op_t;
}

impl ReilInst for reil_inst_t {
    fn address(&self) -> u64 {
        let raw_addr = self.raw_address() << 8;
        let reil_offset = self.reil_offset() as u64;
        raw_addr | reil_offset
    }

    fn reil_offset(&self) -> u8 {
        self.inum as u8
    }

    fn raw_address(&self) -> u64 {
        self.raw_info.addr as u64
    }

    fn print(&self) {
        let mut_ptr: *mut reil_inst_t = unsafe { mem::transmute(self) };
        unsafe { reil_inst_print(mut_ptr); }
    }

    fn first_operand(&self) -> Option<reil_arg_t> {
        match self.a.type_ {
            reil_type_t::A_NONE => None,
            _ => Some(self.a)
        }
    }

    fn second_operand(&self) -> Option<reil_arg_t> {
        match self.b.type_ {
            reil_type_t::A_NONE => None,
            _ => Some(self.b)
        }
    }

    fn third_operand(&self) -> Option<reil_arg_t> {
        match self.c.type_ {
            reil_type_t::A_NONE => None,
            _ => Some(self.c)
        }
    }

    fn opcode(&self) -> reil_op_t {
        self.op
    }
}

pub trait ReilArg {
    fn arg_type(&self) -> reil_type_t;
    fn size(&self) -> reil_size_t;
    fn val(&self) -> Option<u64>;
    fn name(&self) -> Option<String>;
}

impl ReilArg for reil_arg_t {
    fn arg_type(&self) -> reil_type_t {
        self.type_
    }

    fn size(&self) -> reil_size_t {
        self.size
    }

    fn val(&self) -> Option<u64> {
        match self.arg_type() {
            reil_type_t::A_CONST => Some(self.val as u64),
            _ => None,
        }
    }

    fn name(&self) -> Option<String> {
        if self.arg_type() == reil_type_t::A_NONE {
            return None;
        }
        let mut chars = vec![0u8; 15];
        for (src, dst) in self.name.iter().zip(chars.iter_mut()) {
            *dst = *src as u8;
        }
        String::from_utf8(chars).ok()
    }
}
<commit_msg>Small improvements<commit_after>//! The `libopenreil` crate aims to provide an okay wrapper around openreil-sys.

extern crate openreil_sys;
extern crate libc;

use openreil_sys::root::{reil_addr_t, reil_inst_t, reil_t, reil_arch_t, reil_inst_print,
                            reil_inst_handler_t, reil_init, reil_close, reil_translate,
                            reil_translate_insn};
pub use openreil_sys::root::{reil_op_t, reil_type_t, reil_size_t, reil_arg_t, reil_raw_t};

use std::mem;
use std::ops::Drop;
use std::marker;

/// Specifies the architecture of the binary code.
///
/// As of now, supported architectures are `x86` and `ARM`.
#[derive(Clone, Copy, Debug)]
pub enum ReilArch {
    X86,
    ARM,
}

/// Callback handler type to further process the resulting REIL instructions.
/// Is a type alias for a C function.
///
/// Please take care to assert that neither argument is NULL.
pub type ReilInstHandler<T> = extern "C" fn(*mut ReilRawInst, *mut T) -> i32;

/// A raw REIL instruction, that is a simple autogenerated wrapper for the original C type.
pub type ReilRawInst = reil_inst_t;

/// A disassembler object.
///
/// The `Reil` type provides a simple interface to disassemble and translate single or multiple instructions
/// to the OpenREIL intermediate language.
///
/// A `handler` callback function can be provided during construction to further process the resulting REIL instructions.
pub struct Reil<'a, T: 'a> {
    reil_handle: reil_t,
    _marker: marker::PhantomData<&'a mut T>,
}

impl<'a, T: 'a> Reil<'a, T> {
    /// Construct a new disassembler object
    /// The handler function can be used to process the resulting REIL instructions
    /// The `context` gets handed to the callback function
    pub fn new(
        arch: ReilArch,
        handler: Option<ReilInstHandler<T>>,
        context: &'a mut T,
    ) -> Option<Self> {
        let arch = match arch {
            ReilArch::X86 => reil_arch_t::ARCH_X86,
            ReilArch::ARM => reil_arch_t::ARCH_ARM,
        };
        let handler: reil_inst_handler_t = unsafe { mem::transmute(handler) };

        let c_ptr = context as *mut _;

        let reil = unsafe { reil_init(arch, handler, c_ptr as *mut libc::c_void) };

        if reil.is_null() {
            return None;
        }

        let new_reil = Reil {
            reil_handle: reil,
            _marker: marker::PhantomData,
        };

        Some(new_reil)
    }

    /// Translate the binary data given in `data` to REIL instructions,
    /// `start_address` designates the starting address the decoded instructions get assigned.
    pub fn translate(&mut self, data: &mut [u8], start_address: u32) {
        unsafe {
            reil_translate(
                self.reil_handle,
                start_address as reil_addr_t,
                data.as_mut_ptr(),
                data.len() as libc::c_int,
            );
        }
    }

    /// Translate a single instruction from the binary data given in `data` and start addressing at the given address.
    pub fn translate_instruction(&mut self, data: &mut [u8], start_address: u32) {
        unsafe {
            reil_translate_insn(
                self.reil_handle,
                start_address as reil_addr_t,
                data.as_mut_ptr(),
                data.len() as libc::c_int,
            );
        }
    }
}

impl<'a, T: 'a> Drop for Reil<'a, T> {
    fn drop(&mut self) {
        unsafe {
            reil_close(self.reil_handle);
        }
    }
}

pub trait ReilInst {
    fn address(&self) -> u64;
    fn reil_offset(&self) -> u8;
    fn raw_address(&self) -> u64;
    fn print(&self);
    fn first_operand(&self) -> Option<reil_arg_t>;
    fn second_operand(&self) -> Option<reil_arg_t>;
    fn third_operand(&self) -> Option<reil_arg_t>;
    fn opcode(&self) -> reil_op_t;
}

impl ReilInst for reil_inst_t {
    fn address(&self) -> u64 {
        let raw_addr = self.raw_address() << 8;
        let reil_offset = self.reil_offset() as u64;
        raw_addr | reil_offset
    }

    fn reil_offset(&self) -> u8 {
        self.inum as u8
    }

    fn raw_address(&self) -> u64 {
        self.raw_info.addr as u64
    }

    fn print(&self) {
        let mut_ptr: *mut reil_inst_t = unsafe { mem::transmute(self) };
        unsafe { reil_inst_print(mut_ptr); }
    }

    fn first_operand(&self) -> Option<reil_arg_t> {
        match self.a.type_ {
            reil_type_t::A_NONE => None,
            _ => Some(self.a)
        }
    }

    fn second_operand(&self) -> Option<reil_arg_t> {
        match self.b.type_ {
            reil_type_t::A_NONE => None,
            _ => Some(self.b)
        }
    }

    fn third_operand(&self) -> Option<reil_arg_t> {
        match self.c.type_ {
            reil_type_t::A_NONE => None,
            _ => Some(self.c)
        }
    }

    fn opcode(&self) -> reil_op_t {
        self.op
    }
}

pub trait ReilArg {
    fn arg_type(&self) -> reil_type_t;
    fn size(&self) -> reil_size_t;
    fn val(&self) -> Option<u64>;
    fn name(&self) -> Option<String>;
}

impl ReilArg for reil_arg_t {
    fn arg_type(&self) -> reil_type_t {
        self.type_
    }

    fn size(&self) -> reil_size_t {
        self.size
    }

    fn val(&self) -> Option<u64> {
        match self.arg_type() {
            reil_type_t::A_CONST | reil_type_t::A_LOC => Some(self.val as u64),
            _ => None,
        }
    }

    fn name(&self) -> Option<String> {
        if self.arg_type() == reil_type_t::A_NONE {
            return None;
        }
        let chars = self.name.iter()
            .take_while(|&b| b as u8 != 0)
            .map(|&b| b as u8)
            .collect();

        String::from_utf8(chars).ok()
    }
}
<|endoftext|>


<commit_before>#![feature(core, core_prelude, core_slice_ext, custom_derive)]
#![no_std]
#![crate_name = "elfloader"]
#![crate_type = "lib"]
#![deny(warnings)]

#[cfg(test)]
#[macro_use]
extern crate std;

pub mod elf;
use core::fmt;
use core::mem::{size_of, transmute};

pub type PAddr = u64;
pub type VAddr = usize;

/// Abstract representation of a loadable ELF binary.
pub struct ElfBinary<'s> {
    name: &'s str,
    region: &'s [u8],
    header: &'s elf::FileHeader,
}

impl<'s> fmt::Debug for ElfBinary<'s> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ElfBinary{{ {} {} [", self.name, self.header)?;
        for p in self.program_headers() {
            write!(f, " pheader = {}", p)?;
        }
        write!(f, "] }}")
    }
}

/// Implement this for ELF loading.
pub trait ElfLoader {
    /// Allocates a virtual region of size amount of bytes.
    fn allocate(&mut self, base: VAddr, size: usize, flags: elf::ProgFlag);

    /// Copies the region into the base.
    fn load(&mut self, base: VAddr, region: &'static [u8]);
}

// T must be a POD for this to be safe
unsafe fn slice_pod<T>(region: &[u8], offset: usize, count: usize) -> &[T] {
    assert!(region.len() - offset >= count * size_of::<T>());
    core::slice::from_raw_parts(region[offset..].as_ptr() as *const T, count)
}

impl<'s> ElfBinary<'s> {
    /// Create a new ElfBinary.
    /// Makes sure that the provided region has valid ELF magic byte sequence
    /// and is big enough to contain at least the ELF file header
    /// otherwise it will return None.
    pub fn new(name: &'s str, region: &'s [u8]) -> Option<ElfBinary<'s>> {
        if region.len() >= size_of::<elf::FileHeader>() && region.starts_with(elf::ELF_MAGIC) {
            let header: &elf::FileHeader = unsafe { &slice_pod(region, 0, 1)[0] };
            return Some(ElfBinary {
                name: name,
                region: region,
                header: header,
            });
        }

        None
    }

    /// Create a slice of the program headers.
    pub fn program_headers(&self) -> &'s [elf::ProgramHeader] {
        let correct_header_size = self.header.phentsize as usize == size_of::<elf::ProgramHeader>();
        let pheader_region_size = self.header.phoff as usize
            + self.header.phnum as usize * self.header.phentsize as usize;
        let big_enough_region = self.region.len() >= pheader_region_size;

        if self.header.phoff == 0 || !correct_header_size || !big_enough_region {
            return &[];
        }

        unsafe {
            slice_pod(
                self.region,
                self.header.phoff as usize,
                self.header.phnum as usize,
            )
        }
    }

    // Get the string at offset str_offset in the string table strtab
    fn strtab_str(&self, strtab: &'s elf::SectionHeader, str_offset: elf::StrOffset) -> &'s str {
        assert!(strtab.shtype == elf::SHT_STRTAB);
        let data = self.section_data(strtab);
        let offset = str_offset.0 as usize;
        let mut end = offset;
        while data[end] != 0 {
            end += 1;
        }
        core::str::from_utf8(&data[offset..end]).unwrap()
    }

    // Get the name of the section
    pub fn symbol_name(&self, symbol: &'s elf::Symbol) -> &'s str {
        let strtab = self
            .section_headers()
            .iter()
            .find(|s| s.shtype == elf::SHT_STRTAB && self.section_name(s) == ".strtab")
            .unwrap();
        self.strtab_str(strtab, symbol.name)
    }

    // Get the data of the section
    pub fn section_data(&self, section: &'s elf::SectionHeader) -> &'s [u8] {
        &self.region[(section.offset as usize)..(section.offset as usize + section.size as usize)]
    }

    // Get the name of the section
    pub fn section_name(&self, section: &'s elf::SectionHeader) -> &'s str {
        self.strtab_str(
            &self.section_headers()[self.header.shstrndx as usize],
            section.name,
        )
    }

    // Get the symbols of the section
    fn section_symbols(&self, section: &'s elf::SectionHeader) -> &'s [elf::Symbol] {
        assert!(section.shtype == elf::SHT_SYMTAB);
        unsafe {
            slice_pod(
                self.section_data(section),
                0,
                section.size as usize / size_of::<elf::Symbol>(),
            )
        }
    }

    // Enumerate all the symbols in the file
    pub fn for_each_symbol<F: FnMut(&'s elf::Symbol)>(&self, mut func: F) {
        for sym in self
            .section_headers()
            .iter()
            .filter(|s| s.shtype == elf::SHT_SYMTAB)
            .flat_map(|s| self.section_symbols(s).iter())
        {
            func(sym);
        }
    }

    /// Create a slice of the section headers.
    pub fn section_headers(&self) -> &'s [elf::SectionHeader] {
        let correct_header_size = self.header.shentsize as usize == size_of::<elf::SectionHeader>();
        let sheader_region_size = self.header.shoff as usize
            + self.header.shnum as usize * self.header.shentsize as usize;
        let big_enough_region = self.region.len() >= sheader_region_size;

        if self.header.shoff == 0 || !correct_header_size || !big_enough_region {
            return &[];
        }

        unsafe {
            slice_pod(
                self.region,
                self.header.shoff as usize,
                self.header.shnum as usize,
            )
        }
    }

    /// Can we load the binary on our platform?
    fn _can_load(&self) -> bool {
        let correct_class = self.header.ident.class == elf::ELFCLASS64;
        let correct_elfversion = self.header.ident.version == elf::EV_CURRENT;
        let correct_data = self.header.ident.data == elf::ELFDATA2LSB;
        let correct_osabi = self.header.ident.osabi == elf::ELFOSABI_SYSV
            || self.header.ident.osabi == elf::ELFOSABI_LINUX;
        let correct_type =
            unsafe { self.header.elftype == elf::ET_EXEC || self.header.elftype == elf::ET_DYN };
        let correct_machine = unsafe { self.header.machine == elf::EM_X86_64 };

        correct_class
            && correct_data
            && correct_elfversion
            && correct_machine
            && correct_osabi
            && correct_type
    }

    fn load_header(&self, p: &elf::ProgramHeader, loader: &mut ElfLoader) {
        let big_enough_region = self.region.len() >= (p.offset + p.filesz) as usize;
        if !big_enough_region {
            //log!("Unable to load {}", p);
            return;
        }

        loader.allocate(p.vaddr, p.memsz as usize, p.flags);
        let segment: &'static [u8] = unsafe {
            core::slice::from_raw_parts(
                transmute(&self.region[p.offset as usize]),
                p.filesz as usize,
            )
        };
        loader.load(p.vaddr, segment);
    }

    pub fn load(&self, loader: &mut ElfLoader) {
        for p in self.program_headers() {
            let _ = match p.progtype {
                elf::PT_LOAD => self.load_header(p, loader),
                _ => (),
            };
        }
    }
}
<commit_msg>Remove warnings.<commit_after>#![feature(core, core_prelude, core_slice_ext, custom_derive)]
#![no_std]
#![crate_name = "elfloader"]
#![crate_type = "lib"]

#[cfg(test)]
#[macro_use]
extern crate std;

pub mod elf;
use core::fmt;
use core::mem::{size_of, transmute};

pub type PAddr = u64;
pub type VAddr = usize;

/// Abstract representation of a loadable ELF binary.
pub struct ElfBinary<'s> {
    name: &'s str,
    region: &'s [u8],
    header: &'s elf::FileHeader,
}

impl<'s> fmt::Debug for ElfBinary<'s> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ElfBinary{{ {} {} [", self.name, self.header)?;
        for p in self.program_headers() {
            write!(f, " pheader = {}", p)?;
        }
        write!(f, "] }}")
    }
}

/// Implement this for ELF loading.
pub trait ElfLoader {
    /// Allocates a virtual region of size amount of bytes.
    fn allocate(&mut self, base: VAddr, size: usize, flags: elf::ProgFlag);

    /// Copies the region into the base.
    fn load(&mut self, base: VAddr, region: &'static [u8]);
}

// T must be a POD for this to be safe
unsafe fn slice_pod<T>(region: &[u8], offset: usize, count: usize) -> &[T] {
    assert!(region.len() - offset >= count * size_of::<T>());
    core::slice::from_raw_parts(region[offset..].as_ptr() as *const T, count)
}

impl<'s> ElfBinary<'s> {
    /// Create a new ElfBinary.
    /// Makes sure that the provided region has valid ELF magic byte sequence
    /// and is big enough to contain at least the ELF file header
    /// otherwise it will return None.
    pub fn new(name: &'s str, region: &'s [u8]) -> Option<ElfBinary<'s>> {
        if region.len() >= size_of::<elf::FileHeader>() && region.starts_with(elf::ELF_MAGIC) {
            let header: &elf::FileHeader = unsafe { &slice_pod(region, 0, 1)[0] };
            return Some(ElfBinary {
                name: name,
                region: region,
                header: header,
            });
        }

        None
    }

    /// Create a slice of the program headers.
    pub fn program_headers(&self) -> &'s [elf::ProgramHeader] {
        let correct_header_size = self.header.phentsize as usize == size_of::<elf::ProgramHeader>();
        let pheader_region_size = self.header.phoff as usize
            + self.header.phnum as usize * self.header.phentsize as usize;
        let big_enough_region = self.region.len() >= pheader_region_size;

        if self.header.phoff == 0 || !correct_header_size || !big_enough_region {
            return &[];
        }

        unsafe {
            slice_pod(
                self.region,
                self.header.phoff as usize,
                self.header.phnum as usize,
            )
        }
    }

    // Get the string at offset str_offset in the string table strtab
    fn strtab_str(&self, strtab: &'s elf::SectionHeader, str_offset: elf::StrOffset) -> &'s str {
        assert!(strtab.shtype == elf::SHT_STRTAB);
        let data = self.section_data(strtab);
        let offset = str_offset.0 as usize;
        let mut end = offset;
        while data[end] != 0 {
            end += 1;
        }
        core::str::from_utf8(&data[offset..end]).unwrap()
    }

    // Get the name of the section
    pub fn symbol_name(&self, symbol: &'s elf::Symbol) -> &'s str {
        let strtab = self
            .section_headers()
            .iter()
            .find(|s| s.shtype == elf::SHT_STRTAB && self.section_name(s) == ".strtab")
            .unwrap();
        self.strtab_str(strtab, symbol.name)
    }

    // Get the data of the section
    pub fn section_data(&self, section: &'s elf::SectionHeader) -> &'s [u8] {
        &self.region[(section.offset as usize)..(section.offset as usize + section.size as usize)]
    }

    // Get the name of the section
    pub fn section_name(&self, section: &'s elf::SectionHeader) -> &'s str {
        self.strtab_str(
            &self.section_headers()[self.header.shstrndx as usize],
            section.name,
        )
    }

    // Get the symbols of the section
    fn section_symbols(&self, section: &'s elf::SectionHeader) -> &'s [elf::Symbol] {
        assert!(section.shtype == elf::SHT_SYMTAB);
        unsafe {
            slice_pod(
                self.section_data(section),
                0,
                section.size as usize / size_of::<elf::Symbol>(),
            )
        }
    }

    // Enumerate all the symbols in the file
    pub fn for_each_symbol<F: FnMut(&'s elf::Symbol)>(&self, mut func: F) {
        for sym in self
            .section_headers()
            .iter()
            .filter(|s| s.shtype == elf::SHT_SYMTAB)
            .flat_map(|s| self.section_symbols(s).iter())
        {
            func(sym);
        }
    }

    /// Create a slice of the section headers.
    pub fn section_headers(&self) -> &'s [elf::SectionHeader] {
        let correct_header_size = self.header.shentsize as usize == size_of::<elf::SectionHeader>();
        let sheader_region_size = self.header.shoff as usize
            + self.header.shnum as usize * self.header.shentsize as usize;
        let big_enough_region = self.region.len() >= sheader_region_size;

        if self.header.shoff == 0 || !correct_header_size || !big_enough_region {
            return &[];
        }

        unsafe {
            slice_pod(
                self.region,
                self.header.shoff as usize,
                self.header.shnum as usize,
            )
        }
    }

    /// Can we load the binary on our platform?
    fn _can_load(&self) -> bool {
        let correct_class = self.header.ident.class == elf::ELFCLASS64;
        let correct_elfversion = self.header.ident.version == elf::EV_CURRENT;
        let correct_data = self.header.ident.data == elf::ELFDATA2LSB;
        let correct_osabi = self.header.ident.osabi == elf::ELFOSABI_SYSV
            || self.header.ident.osabi == elf::ELFOSABI_LINUX;
        let correct_type =
            unsafe { self.header.elftype == elf::ET_EXEC || self.header.elftype == elf::ET_DYN };
        let correct_machine = unsafe { self.header.machine == elf::EM_X86_64 };

        correct_class
            && correct_data
            && correct_elfversion
            && correct_machine
            && correct_osabi
            && correct_type
    }

    fn load_header(&self, p: &elf::ProgramHeader, loader: &mut ElfLoader) {
        let big_enough_region = self.region.len() >= (p.offset + p.filesz) as usize;
        if !big_enough_region {
            //log!("Unable to load {}", p);
            return;
        }

        loader.allocate(p.vaddr, p.memsz as usize, p.flags);
        let segment: &'static [u8] = unsafe {
            core::slice::from_raw_parts(
                transmute(&self.region[p.offset as usize]),
                p.filesz as usize,
            )
        };
        loader.load(p.vaddr, segment);
    }

    pub fn load(&self, loader: &mut ElfLoader) {
        for p in self.program_headers() {
            let _ = match p.progtype {
                elf::PT_LOAD => self.load_header(p, loader),
                _ => (),
            };
        }
    }
}
<|endoftext|>


<commit_before>extern crate conduit;
extern crate route_recognizer as router;

use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fmt;

use conduit::{Handler, Method, Request, Response};
use router::{Match, Router};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<dyn Handler>>>,
}

#[derive(Debug)]
pub struct RouterError(String);

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder {
            routers: HashMap::new(),
        }
    }

    pub fn recognize<'a>(
        &'a self,
        method: &Method,
        path: &str,
    ) -> Result<Match<&'a Box<dyn Handler>>, RouterError> {
        match self.routers.get(method) {
            Some(router) => router.recognize(path),
            None => Err(format!("No router found for {:?}", method)),
        }
        .map_err(RouterError)
    }

    pub fn map<'a, H: Handler>(
        &'a mut self,
        method: Method,
        pattern: &str,
        handler: H,
    ) -> &'a mut RouteBuilder {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            router.add(pattern, Box::new(handler));
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::Get, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::Post, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::Put, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::Delete, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut dyn Request) -> Result<Response, Box<dyn Error + Send>> {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(Box::new(e) as Box<dyn Error + Send>),
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert(m.params.clone());
        }

        (*m.handler).call(request)
    }
}

impl Error for RouterError {
    fn description(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for RouterError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a dyn Request) -> &'a router::Params {
    req.extensions()
        .find::<router::Params>()
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a (dyn Request + 'a) {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::collections::HashMap;
    use std::io;
    use std::net::SocketAddr;

    use {RequestParams, RouteBuilder};

    use conduit;
    use conduit::{Extensions, Handler, Headers, Host, Method, Scheme, TypeMap};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions,
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method: method,
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version {
            unimplemented!()
        }
        fn conduit_version(&self) -> semver::Version {
            unimplemented!()
        }
        fn method(&self) -> Method {
            self.method.clone()
        }
        fn scheme(&self) -> Scheme {
            unimplemented!()
        }
        fn host<'a>(&'a self) -> Host<'a> {
            unimplemented!()
        }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> {
            unimplemented!()
        }
        fn path<'a>(&'a self) -> &'a str {
            &self.path
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> {
            unimplemented!()
        }
        fn remote_addr(&self) -> SocketAddr {
            unimplemented!()
        }
        fn content_length(&self) -> Option<u64> {
            unimplemented!()
        }
        fn headers<'a>(&'a self) -> &'a dyn Headers {
            unimplemented!()
        }
        fn body<'a>(&'a mut self) -> &'a mut dyn io::Read {
            unimplemented!()
        }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"1, Get");
    }

    #[test]
    fn basic_post() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"10, Post");
    }

    #[test]
    fn nonexistent_route() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Post, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::Request) -> io::Result<conduit::Response> {
        let mut res = vec![];
        res.push(req.params()["id"].clone());
        res.push(format!("{:?}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: Box::new(io::Cursor::new(res.join(", ").into_bytes())),
        })
    }
}
<commit_msg>Enable warnings for 2018 idioms<commit_after>#![warn(rust_2018_idioms)]
extern crate conduit;
extern crate route_recognizer as router;

use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fmt;

use conduit::{Handler, Method, Request, Response};
use router::{Match, Router};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<dyn Handler>>>,
}

#[derive(Debug)]
pub struct RouterError(String);

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder {
            routers: HashMap::new(),
        }
    }

    pub fn recognize<'a>(
        &'a self,
        method: &Method,
        path: &str,
    ) -> Result<Match<&'a Box<dyn Handler>>, RouterError> {
        match self.routers.get(method) {
            Some(router) => router.recognize(path),
            None => Err(format!("No router found for {:?}", method)),
        }
        .map_err(RouterError)
    }

    pub fn map<'a, H: Handler>(
        &'a mut self,
        method: Method,
        pattern: &str,
        handler: H,
    ) -> &'a mut RouteBuilder {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            router.add(pattern, Box::new(handler));
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::Get, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::Post, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::Put, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::Delete, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &str, handler: H) -> &'a mut RouteBuilder {
        self.map(Method::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut dyn Request) -> Result<Response, Box<dyn Error + Send>> {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(Box::new(e) as Box<dyn Error + Send>),
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert(m.params.clone());
        }

        (*m.handler).call(request)
    }
}

impl Error for RouterError {
    fn description(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for RouterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a dyn Request) -> &'a router::Params {
    req.extensions()
        .find::<router::Params>()
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a (dyn Request + 'a) {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::collections::HashMap;
    use std::io;
    use std::net::SocketAddr;

    use {RequestParams, RouteBuilder};

    use conduit;
    use conduit::{Extensions, Handler, Headers, Host, Method, Scheme, TypeMap};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions,
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method: method,
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version {
            unimplemented!()
        }
        fn conduit_version(&self) -> semver::Version {
            unimplemented!()
        }
        fn method(&self) -> Method {
            self.method.clone()
        }
        fn scheme(&self) -> Scheme {
            unimplemented!()
        }
        fn host<'a>(&'a self) -> Host<'a> {
            unimplemented!()
        }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> {
            unimplemented!()
        }
        fn path<'a>(&'a self) -> &'a str {
            &self.path
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> {
            unimplemented!()
        }
        fn remote_addr(&self) -> SocketAddr {
            unimplemented!()
        }
        fn content_length(&self) -> Option<u64> {
            unimplemented!()
        }
        fn headers<'a>(&'a self) -> &'a dyn Headers {
            unimplemented!()
        }
        fn body<'a>(&'a mut self) -> &'a mut dyn io::Read {
            unimplemented!()
        }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"1, Get");
    }

    #[test]
    fn basic_post() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"10, Post");
    }

    #[test]
    fn nonexistent_route() {
        let router = test_router();
        let mut req = RequestSentinel::new(Method::Post, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::Request) -> io::Result<conduit::Response> {
        let mut res = vec![];
        res.push(req.params()["id"].clone());
        res.push(format!("{:?}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: Box::new(io::Cursor::new(res.join(", ").into_bytes())),
        })
    }
}
<|endoftext|>