<commit_before>//! This module implements the in-memory database
//!
//! A support folder with SDK debug symbols can be processed into a
//! in-memory database format which is a flat file on the file system
//! that gets mmaped into the process.
use std::str::from_utf8;
use std::mem;
use std::slice;
use std::path::Path;
use std::borrow::Cow;
use std::ffi::CStr;
use std::os::raw::c_char;

use std::fmt;
use uuid::Uuid;
use memmap::{Mmap, Protection};

use super::types::{IndexItem, StoredSlice, MemDbHeader, IndexedUuid};
use super::super::{Result, ErrorKind};
use super::super::sdk::SdkInfo;
use super::super::utils::binsearch_by_key;

enum Backing<'a> {
    Buf(Cow<'a, [u8]>),
    Mmap(Mmap),
}

/// Provides access to a memdb file
pub struct MemDb<'a> {
    info: SdkInfo,
    backing: Backing<'a>
}

/// Represents a symbol from a memdb file.
#[derive(Debug)]
pub struct Symbol<'a> {
    object_uuid: Uuid,
    object_name: Cow<'a, str>,
    symbol: Cow<'a, str>,
    addr: u64,
}

/// Represents a symbol iterator
pub struct SymbolIter<'a> {
    memdb: &'a MemDb<'a>,
    uuid: &'a Uuid,
    index: &'a [IndexItem],
    pos: usize,
}

impl<'a> Iterator for SymbolIter<'a> {
    type Item = Result<Symbol<'a>>;

    fn next(&mut self) -> Option<Result<Symbol<'a>>> {
        if self.pos < self.index.len() {
            let ii = &self.index[self.pos];
            self.pos += 1;
            Some(self.memdb.index_item_to_symbol(ii, self.uuid))
        } else {
            None
        }
    }
}

impl<'a> fmt::Display for Symbol<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:016x} {} ({})", self.addr(), self.symbol(), self.object_name())
    }
}

impl<'a> Backing<'a> {

    fn get_data(&self, start: usize, len: usize) -> Result<&[u8]> {
        let buffer = self.buffer();
        let end = start.wrapping_add(len);
        if end < start || end > buffer.len() {
            Err(ErrorKind::BadMemDb.into())
        } else {
            Ok(&buffer[start..end])
        }
    }

    fn get_slice<T>(&self, offset: usize, count: usize) -> Result<&[T]> {
        let size = mem::size_of::<T>();
        Ok(unsafe {
            slice::from_raw_parts(
                mem::transmute(self.get_data(offset, count * size)?.as_ptr()),
                count
            )
        })
    }

    #[inline(always)]
    fn header(&self) -> Result<&MemDbHeader> {
        unsafe {
            Ok(mem::transmute(self.get_data(0, mem::size_of::<MemDbHeader>())?.as_ptr()))
        }
    }

    #[inline(always)]
    fn buffer(&self) -> &[u8] {
        match *self {
            Backing::Buf(ref buf) => buf,
            Backing::Mmap(ref mmap) => unsafe { mmap.as_slice() }
        }
    }
}

impl<'a> Symbol<'a> {

    /// The uuid of the image
    pub fn object_uuid(&self) -> Uuid {
        self.object_uuid.clone()
    }

    /// The object name a string
    pub fn object_name(&self) -> &str {
        return &self.object_name
    }

    /// The symbol as string
    pub fn symbol(&self) -> &str {
        return &self.symbol
    }

    /// The symbol address as u64
    pub fn addr(&self) -> u64 {
        self.addr
    }
}

fn load_memdb<'a>(backing: Backing<'a>) -> Result<MemDb<'a>> {
    let info = {
        let header = backing.header()?;
        if header.version != 1 {
            return Err(ErrorKind::UnsupportedMemDbVersion.into());
        }
        header.sdk_info.to_sdk_info()
    };
    Ok(MemDb {
        backing: backing,
        info: info,
    })
}

impl<'a> MemDb<'a> {

    /// Constructs a memdb object from a byte slice cow.
    pub fn from_cow(cow: Cow<'a, [u8]>) -> Result<MemDb<'a>> {
        load_memdb(Backing::Buf(cow))
    }

    /// Constructs a memdb object from a byte slice.
    pub fn from_slice(buffer: &'a [u8]) -> Result<MemDb<'a>> {
        MemDb::from_cow(Cow::Borrowed(buffer))
    }

    /// Constructs a memdb object from a byte vector.
    pub fn from_vec(buffer: Vec<u8>) -> Result<MemDb<'a>> {
        MemDb::from_cow(Cow::Owned(buffer))
    }

    /// Constructs a memdb object by mmapping a file from the filesystem in.
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<MemDb<'a>> {
        let mmap = Mmap::open_path(path, Protection::Read)?;
        load_memdb(Backing::Mmap(mmap))
    }

    /// Return the SDK info.
    pub fn info(&self) -> &SdkInfo {
        &self.info
    }

    /// Finds a symbol by UUID and address.
    pub fn lookup_by_uuid(&'a self, uuid: &Uuid, addr: u64) -> Option<Symbol<'a>> {
        self.lookup_impl(uuid, addr).ok().and_then(|x| x)
    }

    /// Finds a symbol by object name and architecture
    pub fn lookup_by_object_name(&'a self, object_name: &str, arch: &str, addr: u64)
        -> Option<Symbol<'a>>
    {
        if let Ok(Some(uuid)) = self.find_uuid(object_name, arch) {
            self.lookup_impl(uuid, addr).ok().and_then(|x| x)
        } else {
            None
        }
    }

    /// Given an object namd and architecture this finds the image UUID in the file.
    pub fn find_uuid(&self, object_name: &str, arch: &str) -> Result<Option<&Uuid>> {
        let header = self.backing.header()?;
        let mut offset = header.tagged_object_names_start as usize;
        let refstr = format!("{}:{}", object_name, arch);
        let mut uuid_idx = 0;
        while offset < header.tagged_object_names_end as usize {
            let s = self.get_cstr(offset)?;
            if s == &refstr {
                return Ok(Some(&self.uuids()?[uuid_idx].uuid));
            }
            offset += s.len() + 1;
            uuid_idx += 1;
        }
        Ok(None)
    }

    /// Given object name and architecture or UUID as string, this finds the
    /// UUID in the file.
    pub fn find_uuid_fuzzy(&self, name_or_uuid: &str) -> Result<Option<&Uuid>> {
        if let Ok(parsed_uuid) = name_or_uuid.parse::<Uuid>() {
            let uuids = self.uuids()?;
            if let Some(item) = binsearch_by_key(uuids, parsed_uuid, |item| *item.uuid()) {
                return Ok(Some(item.uuid()));
            }
            return Ok(None)
        }
        let mut parts = name_or_uuid.rsplitn(2, ':');
        if_chain! {
            if let Some(arch) = parts.next();
            if let Some(name) = parts.next();
            if let Some(uuid) = self.find_uuid(name, arch)?;
            then {
                Ok(Some(uuid))
            } else {
                Ok(None)
            }
        }
    }

    /// Returns the symbols for an Uuid
    pub fn iter_symbols(&'a self, uuid: &'a Uuid) -> Result<SymbolIter<'a>> {
        let index = self.get_index(uuid)?.unwrap_or(&[][..]);
        Ok(SymbolIter {
            memdb: self,
            uuid: uuid,
            index: index,
            pos: 0,
        })
    }

    fn get_cstr(&self, offset: usize) -> Result<&str> {
        unsafe {
            Ok(from_utf8(CStr::from_ptr(self.backing.buffer().as_ptr().offset(
                offset as isize) as *const c_char).to_bytes())?)
        }
    }

    fn lookup_impl(&'a self, uuid: &Uuid, addr: u64) -> Result<Option<Symbol<'a>>>
    {
        if let Some(index) = self.get_index(uuid)? {
            if let Some(item) = binsearch_by_key(index, addr, |item| item.addr()) {
                return Ok(Some(self.index_item_to_symbol(item, uuid)?));
            }
        }
        Ok(None)
    }

    #[inline(always)]
    fn uuids(&self) -> Result<&[IndexedUuid]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.uuids_start as usize, head.uuids_count as usize)
    }

    #[inline(always)]
    fn variants(&self) -> Result<&[StoredSlice]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.variants_start as usize, head.variants_count as usize)
    }

    #[inline(always)]
    fn get_index(&self, uuid: &Uuid) -> Result<Option<&[IndexItem]>> {
        let uuids = self.uuids()?;
        if let Some(iuuid) = binsearch_by_key(uuids, *uuid, |item| *item.uuid()) {
            // only consider exact matches
            if iuuid.uuid() != uuid {
                return Ok(None);
            }
            let variant_slice = &self.variants()?[iuuid.idx()];
            unsafe {
                let data = self.backing.get_data(variant_slice.offset(),
                                                 variant_slice.len())?;
                let count = variant_slice.len() / mem::size_of::<IndexItem>();
                return Ok(Some(slice::from_raw_parts(
                    mem::transmute(data.as_ptr()),
                    count
                )));
            }
        }
        Ok(None)
    }

    #[inline(always)]
    fn symbols(&self) -> Result<&[StoredSlice]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.symbols_start as usize, head.symbols_count as usize)
    }

    #[inline(always)]
    fn object_names(&self) -> Result<&[StoredSlice]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.object_names_start as usize,
                               head.object_names_count as usize)
    }

    #[inline(always)]
    fn get_string(&'a self, slice: &StoredSlice) -> Result<Cow<'a, str>> {
        let bytes = self.backing.get_data(slice.offset(), slice.len())?;
        if slice.is_compressed() {
            panic!("We do not support compression");
        } else {
            Ok(Cow::Borrowed(from_utf8(bytes)?))
        }
    }

    fn get_object_name(&'a self, src_id: usize) -> Result<Cow<'a, str>> {
        self.get_string(&self.object_names()?[src_id])
    }

    fn get_symbol(&'a self, sym_id: usize) -> Result<Cow<'a, str>> {
        self.get_string(&self.symbols()?[sym_id])
    }

    fn index_item_to_symbol(&'a self, ii: &IndexItem, uuid: &Uuid) -> Result<Symbol<'a>> {
        Ok(Symbol {
            object_uuid: uuid.clone(),
            object_name: self.get_object_name(ii.src_id())?,
            symbol: self.get_symbol(ii.sym_id())?,
            addr: ii.addr(),
        })
    }
}
<commit_msg>Require exact match for uuid found from fuzzy match<commit_after>//! This module implements the in-memory database
//!
//! A support folder with SDK debug symbols can be processed into a
//! in-memory database format which is a flat file on the file system
//! that gets mmaped into the process.
use std::str::from_utf8;
use std::mem;
use std::slice;
use std::path::Path;
use std::borrow::Cow;
use std::ffi::CStr;
use std::os::raw::c_char;

use std::fmt;
use uuid::Uuid;
use memmap::{Mmap, Protection};

use super::types::{IndexItem, StoredSlice, MemDbHeader, IndexedUuid};
use super::super::{Result, ErrorKind};
use super::super::sdk::SdkInfo;
use super::super::utils::binsearch_by_key;

enum Backing<'a> {
    Buf(Cow<'a, [u8]>),
    Mmap(Mmap),
}

/// Provides access to a memdb file
pub struct MemDb<'a> {
    info: SdkInfo,
    backing: Backing<'a>
}

/// Represents a symbol from a memdb file.
#[derive(Debug)]
pub struct Symbol<'a> {
    object_uuid: Uuid,
    object_name: Cow<'a, str>,
    symbol: Cow<'a, str>,
    addr: u64,
}

/// Represents a symbol iterator
pub struct SymbolIter<'a> {
    memdb: &'a MemDb<'a>,
    uuid: &'a Uuid,
    index: &'a [IndexItem],
    pos: usize,
}

impl<'a> Iterator for SymbolIter<'a> {
    type Item = Result<Symbol<'a>>;

    fn next(&mut self) -> Option<Result<Symbol<'a>>> {
        if self.pos < self.index.len() {
            let ii = &self.index[self.pos];
            self.pos += 1;
            Some(self.memdb.index_item_to_symbol(ii, self.uuid))
        } else {
            None
        }
    }
}

impl<'a> fmt::Display for Symbol<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:016x} {} ({})", self.addr(), self.symbol(), self.object_name())
    }
}

impl<'a> Backing<'a> {

    fn get_data(&self, start: usize, len: usize) -> Result<&[u8]> {
        let buffer = self.buffer();
        let end = start.wrapping_add(len);
        if end < start || end > buffer.len() {
            Err(ErrorKind::BadMemDb.into())
        } else {
            Ok(&buffer[start..end])
        }
    }

    fn get_slice<T>(&self, offset: usize, count: usize) -> Result<&[T]> {
        let size = mem::size_of::<T>();
        Ok(unsafe {
            slice::from_raw_parts(
                mem::transmute(self.get_data(offset, count * size)?.as_ptr()),
                count
            )
        })
    }

    #[inline(always)]
    fn header(&self) -> Result<&MemDbHeader> {
        unsafe {
            Ok(mem::transmute(self.get_data(0, mem::size_of::<MemDbHeader>())?.as_ptr()))
        }
    }

    #[inline(always)]
    fn buffer(&self) -> &[u8] {
        match *self {
            Backing::Buf(ref buf) => buf,
            Backing::Mmap(ref mmap) => unsafe { mmap.as_slice() }
        }
    }
}

impl<'a> Symbol<'a> {

    /// The uuid of the image
    pub fn object_uuid(&self) -> Uuid {
        self.object_uuid.clone()
    }

    /// The object name a string
    pub fn object_name(&self) -> &str {
        return &self.object_name
    }

    /// The symbol as string
    pub fn symbol(&self) -> &str {
        return &self.symbol
    }

    /// The symbol address as u64
    pub fn addr(&self) -> u64 {
        self.addr
    }
}

fn load_memdb<'a>(backing: Backing<'a>) -> Result<MemDb<'a>> {
    let info = {
        let header = backing.header()?;
        if header.version != 1 {
            return Err(ErrorKind::UnsupportedMemDbVersion.into());
        }
        header.sdk_info.to_sdk_info()
    };
    Ok(MemDb {
        backing: backing,
        info: info,
    })
}

impl<'a> MemDb<'a> {

    /// Constructs a memdb object from a byte slice cow.
    pub fn from_cow(cow: Cow<'a, [u8]>) -> Result<MemDb<'a>> {
        load_memdb(Backing::Buf(cow))
    }

    /// Constructs a memdb object from a byte slice.
    pub fn from_slice(buffer: &'a [u8]) -> Result<MemDb<'a>> {
        MemDb::from_cow(Cow::Borrowed(buffer))
    }

    /// Constructs a memdb object from a byte vector.
    pub fn from_vec(buffer: Vec<u8>) -> Result<MemDb<'a>> {
        MemDb::from_cow(Cow::Owned(buffer))
    }

    /// Constructs a memdb object by mmapping a file from the filesystem in.
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<MemDb<'a>> {
        let mmap = Mmap::open_path(path, Protection::Read)?;
        load_memdb(Backing::Mmap(mmap))
    }

    /// Return the SDK info.
    pub fn info(&self) -> &SdkInfo {
        &self.info
    }

    /// Finds a symbol by UUID and address.
    pub fn lookup_by_uuid(&'a self, uuid: &Uuid, addr: u64) -> Option<Symbol<'a>> {
        self.lookup_impl(uuid, addr).ok().and_then(|x| x)
    }

    /// Finds a symbol by object name and architecture
    pub fn lookup_by_object_name(&'a self, object_name: &str, arch: &str, addr: u64)
        -> Option<Symbol<'a>>
    {
        if let Ok(Some(uuid)) = self.find_uuid(object_name, arch) {
            self.lookup_impl(uuid, addr).ok().and_then(|x| x)
        } else {
            None
        }
    }

    /// Given an object namd and architecture this finds the image UUID in the file.
    pub fn find_uuid(&self, object_name: &str, arch: &str) -> Result<Option<&Uuid>> {
        let header = self.backing.header()?;
        let mut offset = header.tagged_object_names_start as usize;
        let refstr = format!("{}:{}", object_name, arch);
        let mut uuid_idx = 0;
        while offset < header.tagged_object_names_end as usize {
            let s = self.get_cstr(offset)?;
            if s == &refstr {
                return Ok(Some(&self.uuids()?[uuid_idx].uuid));
            }
            offset += s.len() + 1;
            uuid_idx += 1;
        }
        Ok(None)
    }

    /// Given object name and architecture or UUID as string, this finds the
    /// UUID in the file.
    pub fn find_uuid_fuzzy(&self, name_or_uuid: &str) -> Result<Option<&Uuid>> {
        if let Ok(parsed_uuid) = name_or_uuid.parse::<Uuid>() {
            let uuids = self.uuids()?;
            if let Some(item) = binsearch_by_key(uuids, parsed_uuid, |item| *item.uuid()) {
                if item.uuid() == &parsed_uuid {
                    return Ok(Some(item.uuid()));
                }
            }
            return Ok(None)
        }
        let mut parts = name_or_uuid.rsplitn(2, ':');
        if_chain! {
            if let Some(arch) = parts.next();
            if let Some(name) = parts.next();
            if let Some(uuid) = self.find_uuid(name, arch)?;
            then {
                Ok(Some(uuid))
            } else {
                Ok(None)
            }
        }
    }

    /// Returns the symbols for an Uuid
    pub fn iter_symbols(&'a self, uuid: &'a Uuid) -> Result<SymbolIter<'a>> {
        let index = self.get_index(uuid)?.unwrap_or(&[][..]);
        Ok(SymbolIter {
            memdb: self,
            uuid: uuid,
            index: index,
            pos: 0,
        })
    }

    fn get_cstr(&self, offset: usize) -> Result<&str> {
        unsafe {
            Ok(from_utf8(CStr::from_ptr(self.backing.buffer().as_ptr().offset(
                offset as isize) as *const c_char).to_bytes())?)
        }
    }

    fn lookup_impl(&'a self, uuid: &Uuid, addr: u64) -> Result<Option<Symbol<'a>>>
    {
        if let Some(index) = self.get_index(uuid)? {
            if let Some(item) = binsearch_by_key(index, addr, |item| item.addr()) {
                return Ok(Some(self.index_item_to_symbol(item, uuid)?));
            }
        }
        Ok(None)
    }

    #[inline(always)]
    fn uuids(&self) -> Result<&[IndexedUuid]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.uuids_start as usize, head.uuids_count as usize)
    }

    #[inline(always)]
    fn variants(&self) -> Result<&[StoredSlice]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.variants_start as usize, head.variants_count as usize)
    }

    #[inline(always)]
    fn get_index(&self, uuid: &Uuid) -> Result<Option<&[IndexItem]>> {
        let uuids = self.uuids()?;
        if let Some(iuuid) = binsearch_by_key(uuids, *uuid, |item| *item.uuid()) {
            // only consider exact matches
            if iuuid.uuid() != uuid {
                return Ok(None);
            }
            let variant_slice = &self.variants()?[iuuid.idx()];
            unsafe {
                let data = self.backing.get_data(variant_slice.offset(),
                                                 variant_slice.len())?;
                let count = variant_slice.len() / mem::size_of::<IndexItem>();
                return Ok(Some(slice::from_raw_parts(
                    mem::transmute(data.as_ptr()),
                    count
                )));
            }
        }
        Ok(None)
    }

    #[inline(always)]
    fn symbols(&self) -> Result<&[StoredSlice]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.symbols_start as usize, head.symbols_count as usize)
    }

    #[inline(always)]
    fn object_names(&self) -> Result<&[StoredSlice]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.object_names_start as usize,
                               head.object_names_count as usize)
    }

    #[inline(always)]
    fn get_string(&'a self, slice: &StoredSlice) -> Result<Cow<'a, str>> {
        let bytes = self.backing.get_data(slice.offset(), slice.len())?;
        if slice.is_compressed() {
            panic!("We do not support compression");
        } else {
            Ok(Cow::Borrowed(from_utf8(bytes)?))
        }
    }

    fn get_object_name(&'a self, src_id: usize) -> Result<Cow<'a, str>> {
        self.get_string(&self.object_names()?[src_id])
    }

    fn get_symbol(&'a self, sym_id: usize) -> Result<Cow<'a, str>> {
        self.get_string(&self.symbols()?[sym_id])
    }

    fn index_item_to_symbol(&'a self, ii: &IndexItem, uuid: &Uuid) -> Result<Symbol<'a>> {
        Ok(Symbol {
            object_uuid: uuid.clone(),
            object_name: self.get_object_name(ii.src_id())?,
            symbol: self.get_symbol(ii.sym_id())?,
            addr: ii.addr(),
        })
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::fs::{File, walk_dir};
use std::path::Path;
use std::io::prelude::*;
use std::result::Result;

use iron::prelude::*;
use iron::{AfterMiddleware, typemap};
use iron::modifier::Modifier;
use plugin::Plugin as PluginFor;
use iron::headers;

use hyper::header::ContentType;

use handlebars::Handlebars;
use serialize::json::{ToJson, Json};

pub struct HandlebarsEngine {
    registry: Box<Handlebars>
}

#[derive(Clone)]
pub struct Template {
    name: String,
    value: Json
}

impl Template {
    pub fn new<T: ToJson>(name: &str, value: T) -> Template {
        Template {
            name: name.to_string(),
            value: value.to_json()
        }
    }
}

impl typemap::Key for HandlebarsEngine {
    type Value = Template;
}

impl Modifier<Response> for Template {
    fn modify(self, resp: &mut Response) {
        resp.extensions.insert::<HandlebarsEngine>(self);
    }
}

impl PluginFor<Response> for HandlebarsEngine {
    type Error = ();

    fn eval(resp: &mut Response) -> Result<Template, ()> {
        match resp.extensions.get::<HandlebarsEngine>(){
            Some(t) => Ok(t.clone()),
            None => Err(())
        }
    }
}

impl HandlebarsEngine {
    pub fn new(prefix: &str, suffix: &str) -> HandlebarsEngine {
        let mut r = Handlebars::new();

        let mut prefix_slash = prefix.to_string();
        let normalized_prefix = if prefix.ends_with("/") {
            prefix_slash
        } else {
            prefix_slash.push('/');
            prefix_slash
        };
        let prefix_path = Path::new(&normalized_prefix);
        if ! prefix_path.exists() {
            panic!("Prefix path doesn't exist.");
        }

        let walker = walk_dir(prefix_path);
        if !walker.is_ok() {
            panic!("Failed to list directory.");
        }
        for p in walker.ok().unwrap().filter_map(Result::ok) {
            let path = p.path();
            let disp = path.to_str().unwrap();
            if disp.ends_with(suffix) {
                let mut file = File::open(&path).ok()
                    .expect(format!("Failed to open file {}", disp).as_slice());
                let mut buf = String::new();
                file.read_to_string(&mut buf).ok()
                    .expect(format!("Failed to read file {}", disp).as_slice());

                let t = r.register_template_string(
                    &disp[normalized_prefix.len() .. disp.len()-suffix.len()], buf);
                if t.is_err() {
                    panic!("Failed to create template.");
                }
            }
        }

        HandlebarsEngine {
            registry: Box::new(r)
        }
    }
}

impl AfterMiddleware for HandlebarsEngine {
    fn after(&self, _: &mut Request, r: Response) -> IronResult<Response> {
        let mut resp = r;
        // internally we still extensions.get to avoid clone
        let page = match resp.extensions.get::<HandlebarsEngine>() {
            Some(ref h) => {
                let name = &h.name;
                let value = &h.value;
                let rendered = self.registry.render(name.as_slice(), value);
                match rendered {
                    Ok(r) => Some(r),
                    Err(_) => None
                }
            },
            None => {
                None
            }
        };

        if page.is_some() {
            if !resp.headers.has::<ContentType>() {
                resp.headers.set(headers::ContentType(FromStr::from_str("text/html;charset=utf-8").unwrap()));
            }
            resp.set_mut(page.unwrap());
        }

        Ok(resp)
    }
}

#[cfg(test)]
mod test {
    use serialize::json::ToJson;
    use std::collections::BTreeMap;
    use iron::prelude::*;
    use middleware::*;

    fn hello_world() -> IronResult<Response> {
        let resp = Response::new();

        let mut data = BTreeMap::new();
        data.insert("title".to_string(), "Handlebars on Iron".to_json());

        Ok(resp.set(Template::new("index", data)))
    }

    #[test]
    fn test_resp_set() {
        let mut resp = hello_world().ok().expect("response expected");

        // use response plugin to retrieve a cloned template for testing
        match resp.get::<HandlebarsEngine>() {
            Ok(h) => {
                assert_eq!(h.name, "index".to_string());
                assert_eq!(h.value.as_object().unwrap()
                           .get(&"title".to_string()).unwrap()
                           .as_string().unwrap(),
                           "Handlebars on Iron");
            },
            _ => panic!("template expected")
        }
    }
}
<commit_msg>Improve the 'prefix path doesn't exist' panic message to include the tried absolute path for clearer error message.<commit_after>use std::str::FromStr;
use std::fs::{File, walk_dir};
use std::path::Path;
use std::io::prelude::*;
use std::result::Result;
use std::env;

use iron::prelude::*;
use iron::{AfterMiddleware, typemap};
use iron::modifier::Modifier;
use plugin::Plugin as PluginFor;
use iron::headers;

use hyper::header::ContentType;

use handlebars::Handlebars;
use serialize::json::{ToJson, Json};

pub struct HandlebarsEngine {
    registry: Box<Handlebars>
}

#[derive(Clone)]
pub struct Template {
    name: String,
    value: Json
}

impl Template {
    pub fn new<T: ToJson>(name: &str, value: T) -> Template {
        Template {
            name: name.to_string(),
            value: value.to_json()
        }
    }
}

impl typemap::Key for HandlebarsEngine {
    type Value = Template;
}

impl Modifier<Response> for Template {
    fn modify(self, resp: &mut Response) {
        resp.extensions.insert::<HandlebarsEngine>(self);
    }
}

impl PluginFor<Response> for HandlebarsEngine {
    type Error = ();

    fn eval(resp: &mut Response) -> Result<Template, ()> {
        match resp.extensions.get::<HandlebarsEngine>(){
            Some(t) => Ok(t.clone()),
            None => Err(())
        }
    }
}

impl HandlebarsEngine {
    pub fn new(prefix: &str, suffix: &str) -> HandlebarsEngine {
        let mut r = Handlebars::new();

        let mut prefix_slash = prefix.to_string();
        let normalized_prefix = if prefix.ends_with("/") {
            prefix_slash
        } else {
            prefix_slash.push('/');
            prefix_slash
        };
        let prefix_path = Path::new(&normalized_prefix);
        if ! prefix_path.exists() {
            let abs_prefix_path = if prefix_path.is_relative() {
                 let mut p = env::current_dir().ok().unwrap();
                 p.push(prefix_path);
                 p.iter().collect() // normalization
            } else { prefix_path.to_path_buf() };
            panic!("Prefix path '{}' doesn't exist.", abs_prefix_path.display());
        }

        let walker = walk_dir(prefix_path);
        if !walker.is_ok() {
            panic!("Failed to list directory.");
        }
        for p in walker.ok().unwrap().filter_map(Result::ok) {
            let path = p.path();
            let disp = path.to_str().unwrap();
            if disp.ends_with(suffix) {
                let mut file = File::open(&path).ok()
                    .expect(format!("Failed to open file {}", disp).as_slice());
                let mut buf = String::new();
                file.read_to_string(&mut buf).ok()
                    .expect(format!("Failed to read file {}", disp).as_slice());

                let t = r.register_template_string(
                    &disp[normalized_prefix.len() .. disp.len()-suffix.len()], buf);
                if t.is_err() {
                    panic!("Failed to create template.");
                }
            }
        }

        HandlebarsEngine {
            registry: Box::new(r)
        }
    }
}

impl AfterMiddleware for HandlebarsEngine {
    fn after(&self, _: &mut Request, r: Response) -> IronResult<Response> {
        let mut resp = r;
        // internally we still extensions.get to avoid clone
        let page = match resp.extensions.get::<HandlebarsEngine>() {
            Some(ref h) => {
                let name = &h.name;
                let value = &h.value;
                let rendered = self.registry.render(name.as_slice(), value);
                match rendered {
                    Ok(r) => Some(r),
                    Err(_) => None
                }
            },
            None => {
                None
            }
        };

        if page.is_some() {
            if !resp.headers.has::<ContentType>() {
                resp.headers.set(headers::ContentType(FromStr::from_str("text/html;charset=utf-8").unwrap()));
            }
            resp.set_mut(page.unwrap());
        }

        Ok(resp)
    }
}

#[cfg(test)]
mod test {
    use serialize::json::ToJson;
    use std::collections::BTreeMap;
    use iron::prelude::*;
    use middleware::*;

    fn hello_world() -> IronResult<Response> {
        let resp = Response::new();

        let mut data = BTreeMap::new();
        data.insert("title".to_string(), "Handlebars on Iron".to_json());

        Ok(resp.set(Template::new("index", data)))
    }

    #[test]
    fn test_resp_set() {
        let mut resp = hello_world().ok().expect("response expected");

        // use response plugin to retrieve a cloned template for testing
        match resp.get::<HandlebarsEngine>() {
            Ok(h) => {
                assert_eq!(h.name, "index".to_string());
                assert_eq!(h.value.as_object().unwrap()
                           .get(&"title".to_string()).unwrap()
                           .as_string().unwrap(),
                           "Handlebars on Iron");
            },
            _ => panic!("template expected")
        }
    }
}
<|endoftext|>


<commit_before>use super::*;
use internal::RwLockExt;

#[cfg(all(feature = "model", feature = "utils"))]
use std::result::Result as StdResult;
#[cfg(all(feature = "model", feature = "utils"))]
use std::error::Error as StdError;
#[cfg(all(feature = "model", feature = "utils"))]
use std::str::FromStr;
#[cfg(all(feature = "model", feature = "utils"))]
use std::fmt;
#[cfg(all(feature = "model", feature = "utils"))]
use std::error::Error;
#[cfg(all(feature = "model", any(feature = "cache", feature = "utils")))]
use utils;

/// Allows something - such as a channel or role - to be mentioned in a message.
pub trait Mentionable {
    /// Creates a mentionable string, that will be able to notify and/or create
    /// a link to the item.
    fn mention(&self) -> String;
}

impl Mentionable for ChannelId {
    fn mention(&self) -> String { format!("<#{}>", self.0) }
}

impl Mentionable for Channel {
    fn mention(&self) -> String {
        match *self {
            Channel::Guild(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
            Channel::Private(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
            Channel::Group(ref x) => format!("<#{}>", x.with(|x| x.channel_id.0)),
            Channel::Category(_) => panic!("Categories can't be mentioned"),
        }
    }
}

impl Mentionable for Emoji {
    fn mention(&self) -> String { format!("<:{}:{}>", self.name, self.id.0) }
}

impl Mentionable for Member {
    fn mention(&self) -> String { format!("<@{}>", self.user.with(|u| u.id.0)) }
}

impl Mentionable for RoleId {
    fn mention(&self) -> String { format!("<@&{}>", self.0) }
}

impl Mentionable for Role {
    fn mention(&self) -> String { format!("<@&{}>", self.id.0) }
}

impl Mentionable for UserId {
    fn mention(&self) -> String { format!("<@{}>", self.0) }
}

impl Mentionable for User {
    fn mention(&self) -> String { format!("<@{}>", self.id.0) }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum UserParseError {
    InvalidUsername,
    Rest(Box<Error>),
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for UserParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for UserParseError {
    fn description(&self) -> &str {
        use self::UserParseError::*;

        match *self {
            InvalidUsername => "invalid username",
            Rest(_) => "could not fetch",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for User {
    type Err = UserParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        match utils::parse_username(s) {
            Some(x) => UserId(x as u64)
                .get()
                .map_err(|e| UserParseError::Rest(Box::new(e))),
            _ => Err(UserParseError::InvalidUsername),
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum UserIdParseError {
    InvalidFormat,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for UserIdParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for UserIdParseError {
    fn description(&self) -> &str {
        use self::UserIdParseError::*;

        match *self {
            InvalidFormat => "invalid user id format",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for UserId {
    type Err = UserIdParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        utils::parse_username(s)
            .ok_or_else(|| UserIdParseError::InvalidFormat)
            .map(UserId)
    }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum RoleParseError {
    NotPresentInCache,
    InvalidRole,
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl fmt::Display for RoleParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl StdError for RoleParseError {
    fn description(&self) -> &str {
        use self::RoleParseError::*;

        match *self {
            NotPresentInCache => "not present in cache",
            InvalidRole => "invalid role",
        }
    }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl FromStr for Role {
    type Err = RoleParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        match utils::parse_role(s) {
            Some(x) => match RoleId(x).find() {
                Some(user) => Ok(user),
                _ => Err(RoleParseError::NotPresentInCache),
            },
            _ => Err(RoleParseError::InvalidRole),
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum RoleIdParseError {
    NotPresentInCache,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for RoleIdParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for RoleIdParseError {
    fn description(&self) -> &str {
        use self::RoleIdParseError::*;

        match *self {
            NotPresentInCache => "not present in cache",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for RoleId {
    type Err = RoleIdParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        utils::parse_role(s)
            .ok_or_else(|| RoleIdParseError::NotPresentInCache)
            .map(RoleId)
    }
}

/// A version of an emoji used only when solely the Id and name are known.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct EmojiIdentifier {
    /// The Id of the emoji.
    pub id: EmojiId,
    /// The name of the emoji. It must be at least 2 characters long and can
    /// only contain alphanumeric characters and underscores.
    pub name: String,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl EmojiIdentifier {
    /// Generates a URL to the emoji's image.
    #[inline]
    pub fn url(&self) -> String { format!(cdn!("/emojis/{}.png"), self.id) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for EmojiIdentifier {
    type Err = ();

    fn from_str(s: &str) -> StdResult<Self, ()> { utils::parse_emoji(s).ok_or_else(|| ()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for ChannelId {
    type Err = ();

    fn from_str(s: &str) -> StdResult<Self, ()> {
        utils::parse_channel(s).ok_or_else(|| ()).map(ChannelId)
    }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl FromStr for Channel {
    type Err = ();

    fn from_str(s: &str) -> StdResult<Self, ()> {
        match utils::parse_channel(s) {
            Some(x) => match ChannelId(x).find() {
                Some(channel) => Ok(channel),
                _ => Err(()),
            },
            _ => Err(()),
        }
    }
}

/// A component that was affected during a service incident.
///
/// This is pulled from the Discord status page.
#[derive(Clone, Debug, Deserialize)]
pub struct AffectedComponent {
    pub name: String,
}

/// An incident retrieved from the Discord status page.
///
/// This is not necessarily a representation of an ongoing incident.
#[derive(Clone, Debug, Deserialize)]
pub struct Incident {
    pub created_at: String,
    pub id: String,
    pub impact: String,
    pub incident_updates: Vec<IncidentUpdate>,
    pub monitoring_at: Option<String>,
    pub name: String,
    pub page_id: String,
    pub resolved_at: Option<String>,
    pub short_link: String,
    pub status: String,
    pub updated_at: String,
}

/// An update to an incident from the Discord status page.
///
/// This will typically state what new information has been discovered about an
/// incident.
#[derive(Clone, Debug, Deserialize)]
pub struct IncidentUpdate {
    pub affected_components: Vec<AffectedComponent>,
    pub body: String,
    pub created_at: String,
    pub display_at: String,
    pub id: String,
    pub incident_id: String,
    pub status: IncidentStatus,
    pub updated_at: String,
}

/// The type of status update during a service incident.
#[derive(Copy, Clone, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum IncidentStatus {
    Identified,
    Investigating,
    Monitoring,
    Postmortem,
    Resolved,
}

/// A Discord status maintenance message. This can be either for active
/// maintenances or for scheduled maintenances.
#[derive(Clone, Debug, Deserialize)]
pub struct Maintenance {
    pub description: String,
    pub id: String,
    pub name: String,
    pub start: String,
    pub stop: String,
}
<commit_msg>Fall back to `str::parse` if `parse_username` fails<commit_after>use super::*;
use internal::RwLockExt;

#[cfg(all(feature = "model", feature = "utils"))]
use std::result::Result as StdResult;
#[cfg(all(feature = "model", feature = "utils"))]
use std::error::Error as StdError;
#[cfg(all(feature = "model", feature = "utils"))]
use std::str::FromStr;
#[cfg(all(feature = "model", feature = "utils"))]
use std::fmt;
#[cfg(all(feature = "model", feature = "utils"))]
use std::error::Error;
#[cfg(all(feature = "model", any(feature = "cache", feature = "utils")))]
use utils;

/// Allows something - such as a channel or role - to be mentioned in a message.
pub trait Mentionable {
    /// Creates a mentionable string, that will be able to notify and/or create
    /// a link to the item.
    fn mention(&self) -> String;
}

impl Mentionable for ChannelId {
    fn mention(&self) -> String { format!("<#{}>", self.0) }
}

impl Mentionable for Channel {
    fn mention(&self) -> String {
        match *self {
            Channel::Guild(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
            Channel::Private(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
            Channel::Group(ref x) => format!("<#{}>", x.with(|x| x.channel_id.0)),
            Channel::Category(_) => panic!("Categories can't be mentioned"),
        }
    }
}

impl Mentionable for Emoji {
    fn mention(&self) -> String { format!("<:{}:{}>", self.name, self.id.0) }
}

impl Mentionable for Member {
    fn mention(&self) -> String { format!("<@{}>", self.user.with(|u| u.id.0)) }
}

impl Mentionable for RoleId {
    fn mention(&self) -> String { format!("<@&{}>", self.0) }
}

impl Mentionable for Role {
    fn mention(&self) -> String { format!("<@&{}>", self.id.0) }
}

impl Mentionable for UserId {
    fn mention(&self) -> String { format!("<@{}>", self.0) }
}

impl Mentionable for User {
    fn mention(&self) -> String { format!("<@{}>", self.id.0) }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum UserParseError {
    InvalidUsername,
    Rest(Box<Error>),
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for UserParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for UserParseError {
    fn description(&self) -> &str {
        use self::UserParseError::*;

        match *self {
            InvalidUsername => "invalid username",
            Rest(_) => "could not fetch",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for User {
    type Err = UserParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        match utils::parse_username(s) {
            Some(x) => UserId(x as u64)
                .get()
                .map_err(|e| UserParseError::Rest(Box::new(e))),
            _ => Err(UserParseError::InvalidUsername),
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum UserIdParseError {
    InvalidFormat,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for UserIdParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for UserIdParseError {
    fn description(&self) -> &str {
        use self::UserIdParseError::*;

        match *self {
            InvalidFormat => "invalid user id format",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for UserId {
    type Err = UserIdParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        Ok(match utils::parse_username(s)
            Some(id) => UserId(id),
            None => s.parse::<u64>().map(UserId).map_err(|_| UserIdParseError::InvalidFormat)
        })
    }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum RoleParseError {
    NotPresentInCache,
    InvalidRole,
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl fmt::Display for RoleParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl StdError for RoleParseError {
    fn description(&self) -> &str {
        use self::RoleParseError::*;

        match *self {
            NotPresentInCache => "not present in cache",
            InvalidRole => "invalid role",
        }
    }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl FromStr for Role {
    type Err = RoleParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        match utils::parse_role(s) {
            Some(x) => match RoleId(x).find() {
                Some(user) => Ok(user),
                _ => Err(RoleParseError::NotPresentInCache),
            },
            _ => Err(RoleParseError::InvalidRole),
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum RoleIdParseError {
    NotPresentInCache,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for RoleIdParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for RoleIdParseError {
    fn description(&self) -> &str {
        use self::RoleIdParseError::*;

        match *self {
            NotPresentInCache => "not present in cache",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for RoleId {
    type Err = RoleIdParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        utils::parse_role(s)
            .ok_or_else(|| RoleIdParseError::NotPresentInCache)
            .map(RoleId)
    }
}

/// A version of an emoji used only when solely the Id and name are known.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct EmojiIdentifier {
    /// The Id of the emoji.
    pub id: EmojiId,
    /// The name of the emoji. It must be at least 2 characters long and can
    /// only contain alphanumeric characters and underscores.
    pub name: String,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl EmojiIdentifier {
    /// Generates a URL to the emoji's image.
    #[inline]
    pub fn url(&self) -> String { format!(cdn!("/emojis/{}.png"), self.id) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for EmojiIdentifier {
    type Err = ();

    fn from_str(s: &str) -> StdResult<Self, ()> { utils::parse_emoji(s).ok_or_else(|| ()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for ChannelId {
    type Err = ();

    fn from_str(s: &str) -> StdResult<Self, ()> {
        utils::parse_channel(s).ok_or_else(|| ()).map(ChannelId)
    }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl FromStr for Channel {
    type Err = ();

    fn from_str(s: &str) -> StdResult<Self, ()> {
        match utils::parse_channel(s) {
            Some(x) => match ChannelId(x).find() {
                Some(channel) => Ok(channel),
                _ => Err(()),
            },
            _ => Err(()),
        }
    }
}

/// A component that was affected during a service incident.
///
/// This is pulled from the Discord status page.
#[derive(Clone, Debug, Deserialize)]
pub struct AffectedComponent {
    pub name: String,
}

/// An incident retrieved from the Discord status page.
///
/// This is not necessarily a representation of an ongoing incident.
#[derive(Clone, Debug, Deserialize)]
pub struct Incident {
    pub created_at: String,
    pub id: String,
    pub impact: String,
    pub incident_updates: Vec<IncidentUpdate>,
    pub monitoring_at: Option<String>,
    pub name: String,
    pub page_id: String,
    pub resolved_at: Option<String>,
    pub short_link: String,
    pub status: String,
    pub updated_at: String,
}

/// An update to an incident from the Discord status page.
///
/// This will typically state what new information has been discovered about an
/// incident.
#[derive(Clone, Debug, Deserialize)]
pub struct IncidentUpdate {
    pub affected_components: Vec<AffectedComponent>,
    pub body: String,
    pub created_at: String,
    pub display_at: String,
    pub id: String,
    pub incident_id: String,
    pub status: IncidentStatus,
    pub updated_at: String,
}

/// The type of status update during a service incident.
#[derive(Copy, Clone, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum IncidentStatus {
    Identified,
    Investigating,
    Monitoring,
    Postmortem,
    Resolved,
}

/// A Discord status maintenance message. This can be either for active
/// maintenances or for scheduled maintenances.
#[derive(Clone, Debug, Deserialize)]
pub struct Maintenance {
    pub description: String,
    pub id: String,
    pub name: String,
    pub start: String,
    pub stop: String,
}
<|endoftext|>


<commit_before>use {osc_types, errors};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn destruct(message: &mut [u8], size: usize) -> Result<osc_types::OscPacket, errors::OscError> {
    Ok(osc_types::OscPacket::OscMessage)
}<commit_msg>Add destruct and helper methods<commit_after>use {osc_types, errors};

use std::{io, str};
use std::io::BufRead; // trait

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn destruct(msg: &[u8], size: usize) -> Result<osc_types::OscPacket, errors::OscError> {
    match msg[0] as char {
        '/' => {
            destruct_message(msg, size);
            Ok(osc_types::OscPacket::OscMessage)
        }
        '#' => {
            destruct_bundle(msg);
            Ok(osc_types::OscPacket::OscBundle)
        }
        _ => Err(errors::OscError::BadOscPacket("Unknown message format.".to_string())),
    }
}

fn destruct_message(msg: &[u8], size: usize) -> Result<osc_types::OscPacket, errors::OscError> {
    let buffer: &mut Vec<u8> = &mut Vec::new();
    let mut reader = io::BufReader::with_capacity(size, msg);
    let mut pos: usize = 0;
    match reader.read_until(0u8, buffer) {
        Ok(pos) => {
            match read_as_utf8(&msg[0..pos]) {
                Ok(s) => {
                    println!("address: {}, pad: {}", s, pad_four(pos));
                    Ok(osc_types::OscPacket::OscMessage)
                },
                Err(e) => Err(errors::OscError::BadOscAddress("Could not interpret address.".to_string()))
            }
        }
        Err(e) => Err(errors::OscError::BadOscPacket("Broken message.".to_string())),
    }
}

fn destruct_bundle(msg: &[u8]) -> Result<osc_types::OscPacket, errors::OscError> {
    Err(errors::OscError::BadOscBundle)
}

fn read_as_utf8(msg: &[u8]) -> Result<&str, str::Utf8Error> {
    match str::from_utf8(&msg) {
        Ok(s) => Ok(s),
        Err(e) => Err(e)
    }
}

fn pad_four(pos: usize) -> usize {
    let d: usize = pos % 4;
    match d {
        0 => pos,
        _ => pos + (4 - d)
    }
}<|endoftext|>


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

use pest::prelude::*;

use super::{Rdp, ParseError};
use operations::{self, OperationsResult};
use operations::scope::ScopeStack;

#[derive(Debug, PartialEq, Clone)]
pub struct Program {
    pub root_mod: Module,
}

impl Program {
    pub fn new() -> Program {
        Program {
            root_mod: Module::new(),
        }
    }

    pub fn into_operations(self, global_scope: &mut ScopeStack) -> OperationsResult {
        operations::from_ast(global_scope, self)
    }
}

impl FromStr for Program {
    type Err = ParseError;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = Rdp::new(StringInput::new(input));

        if parser.module() {
            Ok(Program {
                root_mod: parser.module_ast(),
            })
        }
        else {
            let (expected, pos) = parser.expected();
            let (line, col) = parser.input().line_col(pos);
            Err(ParseError {
                line: line,
                col: col,
                expected: expected,
            })
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Module {
    pub body: Block,
}

impl Module {
    pub fn new() -> Module {
        Module {
            body: Block::new(),
        }
    }
}

impl From<Block> for Module {
    fn from(block: Block) -> Self {
        Module {
            body: block
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Statement {
    Comment(String),
    Declaration {
        pattern: Pattern,
        type_def: TypeDefinition,
        expr: Option<Expression>,
    },
    Assignment {
        lhs: Identifier,
        expr: Expression,
    },
    WhileLoop {
        condition: Expression,
        body: Block,
    },
    Expression {
        expr: Expression,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Pattern {
    Identifier(Identifier),
}

#[derive(Debug, PartialEq, Clone)]
pub enum TypeDefinition {
    Name {
        name: Identifier,
    },
    Array {
        type_def: Box<TypeDefinition>,
        size: Option<Expression>,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    ByteLiteral(String),
    Identifier(Identifier),
    Number(Number),
    Call {
        method: Box<Expression>,
        args: FuncArgs,
    },
    Access {
        target: Box<Expression>,
        field: Box<Expression>,
    },
    Branch {
        /// Condition to be executed to determine which block
        /// is run
        condition: Box<Expression>,
        /// executed if the condition is non-zero
        body: Block,
        /// (optional) executed if the condition is zero
        otherwise: Option<Block>,
    },
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Identifier(Vec<String>);

impl FromStr for Identifier {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Identifier(s.split("::").map(|s| s.to_owned()).collect()))
    }
}

impl<'a> From<&'a str> for Identifier {
    fn from(s: &'a str) -> Identifier {
        s.parse().unwrap()
    }
}

pub type Block = Vec<Statement>;
pub type Number = i32;
pub type FuncArgs = Vec<FuncArg>;
pub type FuncArg = Expression;
<commit_msg>Making it possible to concat two identifiers<commit_after>use std::iter::FromIterator;
use std::convert::From;
use std::str::FromStr;

use pest::prelude::*;

use super::{Rdp, ParseError};
use operations::{self, OperationsResult};
use operations::scope::ScopeStack;

#[derive(Debug, PartialEq, Clone)]
pub struct Program {
    pub root_mod: Module,
}

impl Program {
    pub fn new() -> Program {
        Program {
            root_mod: Module::new(),
        }
    }

    pub fn into_operations(self, global_scope: &mut ScopeStack) -> OperationsResult {
        operations::from_ast(global_scope, self)
    }
}

impl FromStr for Program {
    type Err = ParseError;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = Rdp::new(StringInput::new(input));

        if parser.module() {
            Ok(Program {
                root_mod: parser.module_ast(),
            })
        }
        else {
            let (expected, pos) = parser.expected();
            let (line, col) = parser.input().line_col(pos);
            Err(ParseError {
                line: line,
                col: col,
                expected: expected,
            })
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Module {
    pub body: Block,
}

impl Module {
    pub fn new() -> Module {
        Module {
            body: Block::new(),
        }
    }
}

impl From<Block> for Module {
    fn from(block: Block) -> Self {
        Module {
            body: block
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Statement {
    Comment(String),
    Declaration {
        pattern: Pattern,
        type_def: TypeDefinition,
        expr: Option<Expression>,
    },
    Assignment {
        lhs: Identifier,
        expr: Expression,
    },
    WhileLoop {
        condition: Expression,
        body: Block,
    },
    Expression {
        expr: Expression,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Pattern {
    Identifier(Identifier),
}

#[derive(Debug, PartialEq, Clone)]
pub enum TypeDefinition {
    Name {
        name: Identifier,
    },
    Array {
        type_def: Box<TypeDefinition>,
        size: Option<Expression>,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    ByteLiteral(String),
    Identifier(Identifier),
    Number(Number),
    Call {
        method: Box<Expression>,
        args: FuncArgs,
    },
    Access {
        target: Box<Expression>,
        field: Box<Expression>,
    },
    Branch {
        /// Condition to be executed to determine which block
        /// is run
        condition: Box<Expression>,
        /// executed if the condition is non-zero
        body: Block,
        /// (optional) executed if the condition is zero
        otherwise: Option<Block>,
    },
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Identifier(Vec<String>);

impl Identifier {
    // NOTE: Do not implement ::new() for Identifier
    // Having an empty Identifier does not make any sense!

    // Concatenates this identifier with another identifier and returns
    // a new identifier
    pub fn concat<T>(self, other: T) -> Identifier where T: IntoIterator<Item=String> {
        self.into_iter().chain(other).collect()
    }
}

impl FromStr for Identifier {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Identifier(s.split("::").map(|s| s.to_owned()).collect()))
    }
}

impl<'a> From<&'a str> for Identifier {
    fn from(s: &'a str) -> Identifier {
        s.parse().unwrap()
    }
}

impl IntoIterator for Identifier {
    type Item = String;
    type IntoIter = ::std::vec::IntoIter<String>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromIterator<String> for Identifier {
    fn from_iter<I: IntoIterator<Item=String>>(iter: I) -> Self {
        Identifier(iter.into_iter().collect())
    }
}

pub type Block = Vec<Statement>;
pub type Number = i32;
pub type FuncArgs = Vec<FuncArg>;
pub type FuncArg = Expression;

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

    #[test]
    fn concat_identifiers() {
        let mut ident = Identifier::from("foo::bar::Bar::spam")
            .concat(Identifier::from("car::bar::star"));

        let concated = Identifier::from("foo::bar::Bar::spam::car::bar::star");

        assert_eq!(ident, concated);
    }
}
<|endoftext|>


<commit_before>macro_rules! push {
    ($s:ident, $t:expr) => {{
        // println!("parser push: {:?}", $t);
        Ok($s.vm.borrow_mut().alloc($t))
    }}
}

mod error;

use std::rc::Rc;
use std::cell::RefCell;
use core::*;
use lexer::*;
use self::error::Error;

const UNIT_INDX: usize = 5;

pub struct Parser<'a> {
    lexer: Lexer<'a, 'a>,
    vm: Rc<RefCell<Heliqs>>,
    // state: State,
    current_token: RefCell<CurrentToken>,
    // aexp_tokens: Vec<Vec<Tokn>>,
}

#[derive(Eq, PartialEq, Clone, Debug)]
enum CurrentToken {
    SOT, // Start Of Tokens
    Has(Tokn),
    EOT, // End Of Tokens
}

impl<'a> Parser<'a> {
    pub fn new(lexer: Lexer<'a, 'a>, vm: Rc<RefCell<Heliqs>>) -> Self {
        Parser {
            lexer: lexer,
            vm: vm,
            // state: State::Aexp,
            current_token: RefCell::new(CurrentToken::SOT),
            // aexp_tokens: vec![vec![]],
        }
    }

    // Unitは常に1つにする(index=0)
    fn add_unit(&mut self) {
        let _unit = self.vm.borrow_mut().alloc(Epiq::Unit);
    }

    fn add_prim(&mut self, name: &str) {
        let prim = self.vm.borrow_mut().alloc(Epiq::Prim(name.to_string()));
        self.vm.borrow_mut().define(name, prim);
    }

    pub fn parse(&mut self) {

        self.add_prim("decr");
        self.add_prim("ltoreq");
        self.add_prim("eq");
        self.add_prim("plus");
        self.add_prim("minus");

        self.add_unit();

        self.consume_token();

        let _ = self.parse_aexp();
    }

    fn consume_token(&mut self) {
        let res = self.lexer.tokenize();
        match res {
            TokenizeResult::Ok(t) => {
                let mut token = self.current_token.borrow_mut();
                *token = CurrentToken::Has(t);
            },
            TokenizeResult::Err(_e) => {},
            TokenizeResult::EOF => {
                let mut token = self.current_token.borrow_mut();
                *token = CurrentToken::EOT;
            },
        }
    }

    fn parse_aexp(&mut self) -> Result<usize, Error> {
        let res = self.current_token.borrow().clone();

        match res {
            CurrentToken::Has(Tokn::Atsm) => {
                self.consume_token();
                self.parse_resolve()
            },

            CurrentToken::Has(Tokn::Sgqt) => {
                self.consume_token();
                self.parse_otag(Tokn::Sgqt)
            },

            CurrentToken::Has(Tokn::Pipe) => {
                self.consume_token();
                self.parse_otag(Tokn::Pipe)
            },
            CurrentToken::Has(Tokn::Crrt) => {
                self.consume_token();
                self.parse_otag(Tokn::Crrt)
            },
            CurrentToken::Has(Tokn::Smcl) => {
                self.consume_token();
                Ok(UNIT_INDX)
            }
            CurrentToken::Has(Tokn::Lbkt) => {
                self.consume_token();
                self.parse_list()
            },
            CurrentToken::Has(Tokn::Dbqt) => {
                self.consume_token();
                self.parse_text()
            },
            _ => self.parse_literal(),
        }
    }

    fn parse_resolve(&mut self) -> Result<usize, Error> {
        // let pidx = (self.parse_aexp())?;
        let qidx = (self.parse_aexp())?;
        let id = self.vm.borrow_mut().alloc(Epiq::Rslv(UNIT_INDX, qidx));
        push!(self, Epiq::Eval(UNIT_INDX, id))
    }

    // Pipe QTag Pval QVal
    fn parse_otag(&mut self, tokn: Tokn) -> Result<usize, Error> {
        let current_token = self.current_token.borrow().clone();
        match current_token {
            CurrentToken::Has(Tokn::Otag(ref otag)) => {
                self.consume_token();

                match tokn {
                    Tokn::Pipe => {
                        let pidx = (self.parse_aexp())?;
                        let qidx = (self.parse_aexp())?;
                        self.match_otag(pidx, qidx, otag)
                    },
                    Tokn::Crrt => {
                        match otag.as_ref() {
                            // ^Tと^Fは特別扱い
                            "T" => push!(self, Epiq::Tval),
                            "F" => push!(self, Epiq::Fval),
                            _ =>  {
                                // 現在は^Tか^Fしか認めていないが、将来のため
                                let pidx = (self.parse_aexp())?;
                                let qidx = (self.parse_aexp())?;
                                push!(self, Epiq::Mpiq{o: otag.clone(), p: pidx, q: qidx})
                            },
                        }
                    },
                    Tokn::Sgqt => {
                        // 引数は一つ、それをqとみなす
                        let qidx = (self.parse_aexp())?;
                        self.match_otag(UNIT_INDX, qidx, otag)
                    },
                    _ => Err(Error::UnknownError(255)),
                }
            },

            CurrentToken::Has(ref t) => Err(Error::TokenError(t.clone())),
            _ => Err(Error::UnknownError(1)),
        }
    }

    fn match_otag(&mut self, pidx: NodeId, qidx: NodeId, otag: &str) -> Result<usize, Error> {
        match otag {
            ">" => push!(self, Epiq::Eval(pidx, qidx)),
            ":" => push!(self, Epiq::Lpiq(pidx, qidx)),
            "!" => push!(self, Epiq::Appl(pidx, qidx)),
            "@" => push!(self, Epiq::Rslv(pidx, qidx)),
            "?" => push!(self, Epiq::Cond(pidx, qidx)),
            "%" => push!(self, Epiq::Envn(pidx, qidx)),
            "#" => push!(self, Epiq::Bind(pidx, qidx)),
            "." => push!(self, Epiq::Accs(pidx, qidx)),
            r"\" => push!(self, Epiq::Lmbd(pidx, qidx)),

            _ => {
                push!(self, Epiq::Tpiq{o: otag.to_string(), p: pidx, q: qidx})
            },
        }
    }

    fn parse_list(&mut self) -> Result<usize, Error> {
        let current_token = self.current_token.borrow().clone();
        // 閉じbracketが出るまで再帰呼出
        match current_token {
            CurrentToken::Has(Tokn::Rbkt) => {
                self.consume_token();
                push!(self, Epiq::Unit)
            },
            _ => {
                let pidx = (self.parse_aexp())?;
                let qidx = (self.parse_list())?;
                push!(self, Epiq::Lpiq(pidx, qidx))
            }
        }
    }

    fn parse_text(&mut self) -> Result<usize, Error> {
        let current_token1 = self.current_token.borrow().clone();
        match current_token1 {
            CurrentToken::Has(Tokn::Chvc(ref s)) => {
                self.consume_token();
                let current_token2 = self.current_token.borrow().clone();
                match current_token2 {
                    CurrentToken::Has(Tokn::Dbqt) => {
                        self.consume_token();
                        push!(self, Epiq::Text(s.clone()))
                    },
                    _ => Err(Error::UnknownError(13)),
                }
            },
            _ => Err(Error::UnknownError(12)),
        }
    }

    fn parse_literal(&mut self) -> Result<usize, Error> {
        let current_token = self.current_token.borrow().clone();
        match current_token {
            CurrentToken::Has(Tokn::Chvc(ref s)) => {
                self.consume_token();
                push!(self, Epiq::Name(s.clone()))
            },
            CurrentToken::Has(Tokn::Nmbr(ref s)) => {
                self.consume_token();
                push!(self, Epiq::Uit8(s.parse::<i64>().unwrap()))
            },
            _ => Err(Error::UnknownError(10)),
        }
    }
}
<commit_msg>prepare "lookahead" and "p" for LL(2) parser<commit_after>macro_rules! push {
    ($s:ident, $t:expr) => {{
        // println!("parser push: {:?}", $t);
        Ok($s.vm.borrow_mut().alloc($t))
    }}
}

mod error;

use std::rc::Rc;
use std::cell::RefCell;
use core::*;
use lexer::*;
use self::error::Error;

const UNIT_INDX: usize = 5;

pub struct Parser<'a> {
    lexer: Lexer<'a, 'a>,
    vm: Rc<RefCell<Heliqs>>,
    // state: State,
    current_token: RefCell<CurrentToken>,
    // aexp_tokens: Vec<Vec<Tokn>>,

    lookahead: [CurrentToken; 2],
    p: usize,
}

#[derive(Eq, PartialEq, Clone, Debug)]
enum CurrentToken {
    SOT, // Start Of Tokens
    Has(Tokn),
    EOT, // End Of Tokens
}

impl<'a> Parser<'a> {
    pub fn new(lexer: Lexer<'a, 'a>, vm: Rc<RefCell<Heliqs>>) -> Self {
        let mut parser = Parser {
            lexer: lexer,
            vm: vm,
            // state: State::Aexp,
            current_token: RefCell::new(CurrentToken::SOT),
            // aexp_tokens: vec![vec![]],
            lookahead: [CurrentToken::SOT, CurrentToken::SOT],
            p: 1, // 0にはCurrentToken::SOTを入れることが固定で決まっているので、consumeを開始するのは1から
        };

        parser.consume_token();

        parser
    }

    // Unitは常に1つにする(index固定)
    fn add_unit(&mut self) {
        let _unit = self.vm.borrow_mut().alloc(Epiq::Unit);
    }

    fn add_prim(&mut self, name: &str) {
        let prim = self.vm.borrow_mut().alloc(Epiq::Prim(name.to_string()));
        self.vm.borrow_mut().define(name, prim);
    }

    pub fn parse(&mut self) {

        self.add_prim("decr");
        self.add_prim("ltoreq");
        self.add_prim("eq");
        self.add_prim("plus");
        self.add_prim("minus");

        self.add_unit();

        self.consume_token();

        let _ = self.parse_aexp();
    }

    fn set_current_token(&mut self, t: CurrentToken) {
        // let mut token = self.current_token.borrow_mut();
        // *token = t;

        self.lookahead[self.p] = t;
        self.p = 1 - self.p;
    }

    fn get_current_token(&self) -> CurrentToken {
        // self.current_token.borrow().clone()

        self.lookahead[self.p].clone()
    }

    fn consume_token(&mut self) {
        let res = self.lexer.tokenize();
        match res {
            TokenizeResult::Ok(t) => self.set_current_token(CurrentToken::Has(t)),
            TokenizeResult::Err(_e) => {},
            TokenizeResult::EOF => self.set_current_token(CurrentToken::EOT),
        }
    }

    fn parse_aexp(&mut self) -> Result<usize, Error> {
        let res = self.get_current_token();

        match res {
            CurrentToken::Has(Tokn::Atsm) => {
                self.consume_token();
                self.parse_resolve()
            },

            CurrentToken::Has(Tokn::Sgqt) => {
                self.consume_token();
                self.parse_otag(Tokn::Sgqt)
            },

            CurrentToken::Has(Tokn::Pipe) => {
                self.consume_token();
                self.parse_otag(Tokn::Pipe)
            },
            CurrentToken::Has(Tokn::Crrt) => {
                self.consume_token();
                self.parse_otag(Tokn::Crrt)
            },
            CurrentToken::Has(Tokn::Smcl) => {
                self.consume_token();
                Ok(UNIT_INDX)
            }
            CurrentToken::Has(Tokn::Lbkt) => {
                self.consume_token();
                self.parse_list()
            },
            CurrentToken::Has(Tokn::Dbqt) => {
                self.consume_token();
                self.parse_text()
            },

            _ => self.parse_literal(),
        }
    }

    fn parse_resolve(&mut self) -> Result<usize, Error> {
        // let pidx = (self.parse_aexp())?;
        let qidx = (self.parse_aexp())?;
        let id = self.vm.borrow_mut().alloc(Epiq::Rslv(UNIT_INDX, qidx));
        push!(self, Epiq::Eval(UNIT_INDX, id))
    }

    // Pipe QTag Pval QVal
    fn parse_otag(&mut self, tokn: Tokn) -> Result<usize, Error> {
        let current_token = self.get_current_token();
        match current_token {
            CurrentToken::Has(Tokn::Otag(ref otag)) => {
                self.consume_token();

                match tokn {
                    Tokn::Pipe => {
                        let pidx = (self.parse_aexp())?;
                        let qidx = (self.parse_aexp())?;
                        self.match_otag(pidx, qidx, otag)
                    },
                    Tokn::Crrt => {
                        match otag.as_ref() {
                            // ^Tと^Fは特別扱い
                            "T" => push!(self, Epiq::Tval),
                            "F" => push!(self, Epiq::Fval),
                            _ =>  {
                                // 現在は^Tか^Fしか認めていないが、将来のため
                                let pidx = (self.parse_aexp())?;
                                let qidx = (self.parse_aexp())?;
                                push!(self, Epiq::Mpiq{o: otag.clone(), p: pidx, q: qidx})
                            },
                        }
                    },
                    Tokn::Sgqt => {
                        // 引数は一つ、それをqとみなす
                        let qidx = (self.parse_aexp())?;
                        self.match_otag(UNIT_INDX, qidx, otag)
                    },
                    _ => Err(Error::UnknownError(255)),
                }
            },

            CurrentToken::Has(ref t) => Err(Error::TokenError(t.clone())),
            _ => Err(Error::UnknownError(1)),
        }
    }

    fn match_otag(&mut self, pidx: NodeId, qidx: NodeId, otag: &str) -> Result<usize, Error> {
        match otag {
            ">" => push!(self, Epiq::Eval(pidx, qidx)),
            ":" => push!(self, Epiq::Lpiq(pidx, qidx)),
            "!" => push!(self, Epiq::Appl(pidx, qidx)),
            "@" => push!(self, Epiq::Rslv(pidx, qidx)),
            "?" => push!(self, Epiq::Cond(pidx, qidx)),
            "%" => push!(self, Epiq::Envn(pidx, qidx)),
            "#" => push!(self, Epiq::Bind(pidx, qidx)),
            "." => push!(self, Epiq::Accs(pidx, qidx)),
            r"\" => push!(self, Epiq::Lmbd(pidx, qidx)),

            _ => {
                push!(self, Epiq::Tpiq{o: otag.to_string(), p: pidx, q: qidx})
            },
        }
    }

    fn parse_list(&mut self) -> Result<usize, Error> {
        let current_token = self.get_current_token();
        // 閉じbracketが出るまで再帰呼出
        match current_token {
            CurrentToken::Has(Tokn::Rbkt) => {
                self.consume_token();
                push!(self, Epiq::Unit)
            },
            _ => {
                let pidx = (self.parse_aexp())?;
                let qidx = (self.parse_list())?;
                push!(self, Epiq::Lpiq(pidx, qidx))
            }
        }
    }

    fn parse_text(&mut self) -> Result<usize, Error> {
        let current_token1 = self.get_current_token();
        match current_token1 {
            CurrentToken::Has(Tokn::Chvc(ref s)) => {
                self.consume_token();
                let current_token2 = self.get_current_token();
                match current_token2 {
                    CurrentToken::Has(Tokn::Dbqt) => {
                        self.consume_token();
                        push!(self, Epiq::Text(s.clone()))
                    },
                    _ => Err(Error::UnknownError(13)),
                }
            },
            _ => Err(Error::UnknownError(12)),
        }
    }

    fn parse_literal(&mut self) -> Result<usize, Error> {
        let current_token = self.get_current_token();
        match current_token {
            CurrentToken::Has(Tokn::Chvc(ref s)) => {
                self.consume_token();
                push!(self, Epiq::Name(s.clone()))
            },
            CurrentToken::Has(Tokn::Nmbr(ref s)) => {
                self.consume_token();
                push!(self, Epiq::Uit8(s.parse::<i64>().unwrap()))
            },
            _ => Err(Error::UnknownError(10)),
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::error::Error;

use rotor::{Machine, EventSet, PollOpt, Scope, Response, Time};
use rotor::void::{unreachable, Void};
use rotor::{GenericScope};

use {ActiveStream, Protocol, Stream, ProtocolStop, Transport};
use extensions::{ResponseExt, ScopeExt};

/// Reconnect timeout in milliseconds.
///
/// TODO(tailhook) should be overridable at runtime
pub const RECONNECT_TIMEOUT: u64 = 200;

/// Time for establishing a connection
///
/// TODO(tailhook) should be overridable at runtime
pub const CONNECT_TIMEOUT: u64 = 1_000;

/// Persistent client connection
///
/// TODO(tailhook) this should include name resolution
pub struct Persistent
(
::Address,
                         P::Seed, Fsm
)
    where P: Protocol, P::Socket: ActiveStream;

#[derive(Debug)]
pub enum Fsm
 {
    Idle,
    Connecting(P::Socket, Time),
    Established(Stream
),
    Sleeping(Time),
}

fn response
(addr:
::Address,
    seed: P::Seed, fsm: Fsm
)
    -> Response<Persistent
, Void>
    where P: Protocol, P::Socket: ActiveStream
{
    use self::Fsm::*;
    let timeo = match *&fsm {
        Idle => None,
        Connecting(_, tm) => Some(tm),
        // Can't find out a timeout for established connection
        // some other way should be used for this case
        Established(..) => unreachable!(),
        Sleeping(tm) => Some(tm),
    };
    println!("Deadline {:?}", timeo);
    Response::ok(Persistent(addr, seed, fsm))
        .deadline_opt(timeo)
}

impl
 Persistent

    where P: Protocol,
          P::Socket: ActiveStream,

::Address: Debug
{
    pub fn new<S: GenericScope>(_scope: &mut S,
            address:
::Address, seed: P::Seed)
        -> Response<Persistent
, Void>
    {
        Response::ok(Persistent(address, seed, Fsm::Idle))
    }

    pub fn connect<S: GenericScope>(scope: &mut S,
            address:
::Address, seed: P::Seed)
        -> Response<Persistent
, Void>
    {
        let fsm = match P::Socket::connect(&address) {
            Ok(sock) => {
                scope.register(&sock, EventSet::writable(), PollOpt::level())
                    .expect("Can't register socket");
                Fsm::Connecting(sock, scope.after(CONNECT_TIMEOUT))
            }
            Err(e) => {
                info!("Failed to connect to {:?}: {}", address, e);
                Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
            }
        };
        response(address, seed, fsm)
    }
}

impl
 Persistent

    where P: Protocol, P::Socket: ActiveStream
{
    /// Get a `Transport` object of the underlying stream
    ///
    /// This method is only useful if you want to manipulate buffers
    /// externally (like pushing to the buffer from another thread). Just be
    /// sure to **wake up** state machine after manipulating buffers.
    ///
    /// Returns `None` if stream is not currently connected
    pub fn transport(&mut self) -> Option<Transport
> {
        match self.2 {
            Fsm::Established(ref mut s) => Some(s.transport()),
            _ => None,
        }
    }
}

impl
 Fsm

    where P: Protocol,
          P::Seed: Clone,
          P::Socket: ActiveStream,

::Address: Debug
{
    fn action<S: GenericScope>(resp: Response<Stream
, Void>,
        addr:
::Address,
        seed: P::Seed, scope: &mut S)
        -> Response<Persistent
, Void>
    {
        if resp.is_stopped() {
            if let Some(err) = resp.cause() {
                warn!("Connection is failed: {}", err);
            } else {
                warn!("Connection is stopped by protocol");
            }
            response(addr, seed,
                Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT)))
        } else {
            resp
                .wrap(Fsm::Established)
                .wrap(|x| Persistent(addr, seed, x))
        }
    }
}

impl
 Machine for Persistent

    where P: Protocol,
          P::Seed: Clone,
          P::Socket: ActiveStream,

::Address: Debug
{
    type Context = P::Context;
    type Seed = Void;
    fn create(seed: Self::Seed, _scope: &mut Scope
)
        -> Response<Self, Void>
    {
        unreachable(seed)
    }
    fn ready(self, events: EventSet, scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        use self::Fsm::*;
        let Persistent(addr, seed, state) = self;
        let state = match state {
            Idle => Idle,  // spurious event
            Connecting(sock, dline) => {
                if events.is_writable() {
                    let resp =  Stream::connected(sock, seed.clone(), scope);
                    if resp.is_stopped() {
                        error!("Error creating stream FSM: {}",
                            resp.cause().unwrap_or(&ProtocolStop));
                        Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
                    } else {
                        return resp
                            .wrap(Established)
                            .wrap(|x| Persistent(addr, seed, x))
                    }
                } else if events.is_hup() {
                    error!("Connection closed immediately");
                    Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
                } else {
                    Connecting(sock, dline) // spurious event
                }
            }
            Established(x) => {
                return Fsm::action(x.ready(events, scope), addr, seed, scope);
            }
            Sleeping(dline) => Sleeping(dline), // spurious event
        };
        response(addr, seed, state)
    }
    fn spawned(self, _scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        unreachable!();
    }
    fn timeout(self, scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        use self::Fsm::*;
        let Persistent(addr, seed, state) = self;
        let state = match state {
            Idle => Idle,  // spurious timeout
            Connecting(sock, dline) => {
                if scope.now() >= dline {
                    warn!("Timeout while establishing connection");
                    Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
                } else {  // spurious timeout
                    Connecting(sock, dline)
                }
            }
            Established(x) => {
                return Fsm::action(x.timeout(scope), addr, seed, scope);
            }
            Sleeping(dline) => {
                if scope.now() >= dline {
                    return Self::connect(scope, addr, seed);
                } else {
                    Sleeping(dline)  // spurious timeout
                }
            }
        };
        response(addr, seed, state)
    }
    fn wakeup(self, scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        use self::Fsm::*;
        let Persistent(addr, seed, state) = self;
        let state = match state {
            Established(x) => {
                return Fsm::action(x.wakeup(scope), addr, seed, scope);
            }
            x => x, // spurious wakeup
        };
        response(addr, seed, state)
    }
}

#[cfg(feature="replaceable")]
mod replaceable {

    use std::fmt::Debug;

    use {ActiveStream, Protocol, Persistent};
    use rotor_tools::sync::Replaceable;

    use super::Fsm;

    impl
 Replaceable for Persistent

        where P: Protocol,
              P::Seed: Clone,

::Address: Clone + Debug,
              P::Socket: ActiveStream
    {
        fn empty(&self) -> Self {
            // We assume that cloning is cheap enough. Probably just Copy
            Persistent(self.0.clone(), self.1.clone(), Fsm::Idle)
        }
    }
}
<commit_msg>Remove debugging print<commit_after>use std::fmt::Debug;
use std::error::Error;

use rotor::{Machine, EventSet, PollOpt, Scope, Response, Time};
use rotor::void::{unreachable, Void};
use rotor::{GenericScope};

use {ActiveStream, Protocol, Stream, ProtocolStop, Transport};
use extensions::{ResponseExt, ScopeExt};

/// Reconnect timeout in milliseconds.
///
/// TODO(tailhook) should be overridable at runtime
pub const RECONNECT_TIMEOUT: u64 = 200;

/// Time for establishing a connection
///
/// TODO(tailhook) should be overridable at runtime
pub const CONNECT_TIMEOUT: u64 = 1_000;

/// Persistent client connection
///
/// TODO(tailhook) this should include name resolution
pub struct Persistent
(
::Address,
                         P::Seed, Fsm
)
    where P: Protocol, P::Socket: ActiveStream;

#[derive(Debug)]
pub enum Fsm
 {
    Idle,
    Connecting(P::Socket, Time),
    Established(Stream
),
    Sleeping(Time),
}

fn response
(addr:
::Address,
    seed: P::Seed, fsm: Fsm
)
    -> Response<Persistent
, Void>
    where P: Protocol, P::Socket: ActiveStream
{
    use self::Fsm::*;
    let timeo = match *&fsm {
        Idle => None,
        Connecting(_, tm) => Some(tm),
        // Can't find out a timeout for established connection
        // some other way should be used for this case
        Established(..) => unreachable!(),
        Sleeping(tm) => Some(tm),
    };
    Response::ok(Persistent(addr, seed, fsm))
        .deadline_opt(timeo)
}

impl
 Persistent

    where P: Protocol,
          P::Socket: ActiveStream,

::Address: Debug
{
    pub fn new<S: GenericScope>(_scope: &mut S,
            address:
::Address, seed: P::Seed)
        -> Response<Persistent
, Void>
    {
        Response::ok(Persistent(address, seed, Fsm::Idle))
    }

    pub fn connect<S: GenericScope>(scope: &mut S,
            address:
::Address, seed: P::Seed)
        -> Response<Persistent
, Void>
    {
        let fsm = match P::Socket::connect(&address) {
            Ok(sock) => {
                scope.register(&sock, EventSet::writable(), PollOpt::level())
                    .expect("Can't register socket");
                Fsm::Connecting(sock, scope.after(CONNECT_TIMEOUT))
            }
            Err(e) => {
                info!("Failed to connect to {:?}: {}", address, e);
                Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
            }
        };
        response(address, seed, fsm)
    }
}

impl
 Persistent

    where P: Protocol, P::Socket: ActiveStream
{
    /// Get a `Transport` object of the underlying stream
    ///
    /// This method is only useful if you want to manipulate buffers
    /// externally (like pushing to the buffer from another thread). Just be
    /// sure to **wake up** state machine after manipulating buffers.
    ///
    /// Returns `None` if stream is not currently connected
    pub fn transport(&mut self) -> Option<Transport
> {
        match self.2 {
            Fsm::Established(ref mut s) => Some(s.transport()),
            _ => None,
        }
    }
}

impl
 Fsm

    where P: Protocol,
          P::Seed: Clone,
          P::Socket: ActiveStream,

::Address: Debug
{
    fn action<S: GenericScope>(resp: Response<Stream
, Void>,
        addr:
::Address,
        seed: P::Seed, scope: &mut S)
        -> Response<Persistent
, Void>
    {
        if resp.is_stopped() {
            if let Some(err) = resp.cause() {
                warn!("Connection is failed: {}", err);
            } else {
                warn!("Connection is stopped by protocol");
            }
            response(addr, seed,
                Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT)))
        } else {
            resp
                .wrap(Fsm::Established)
                .wrap(|x| Persistent(addr, seed, x))
        }
    }
}

impl
 Machine for Persistent

    where P: Protocol,
          P::Seed: Clone,
          P::Socket: ActiveStream,

::Address: Debug
{
    type Context = P::Context;
    type Seed = Void;
    fn create(seed: Self::Seed, _scope: &mut Scope
)
        -> Response<Self, Void>
    {
        unreachable(seed)
    }
    fn ready(self, events: EventSet, scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        use self::Fsm::*;
        let Persistent(addr, seed, state) = self;
        let state = match state {
            Idle => Idle,  // spurious event
            Connecting(sock, dline) => {
                if events.is_writable() {
                    let resp =  Stream::connected(sock, seed.clone(), scope);
                    if resp.is_stopped() {
                        error!("Error creating stream FSM: {}",
                            resp.cause().unwrap_or(&ProtocolStop));
                        Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
                    } else {
                        return resp
                            .wrap(Established)
                            .wrap(|x| Persistent(addr, seed, x))
                    }
                } else if events.is_hup() {
                    error!("Connection closed immediately");
                    Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
                } else {
                    Connecting(sock, dline) // spurious event
                }
            }
            Established(x) => {
                return Fsm::action(x.ready(events, scope), addr, seed, scope);
            }
            Sleeping(dline) => Sleeping(dline), // spurious event
        };
        response(addr, seed, state)
    }
    fn spawned(self, _scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        unreachable!();
    }
    fn timeout(self, scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        use self::Fsm::*;
        let Persistent(addr, seed, state) = self;
        let state = match state {
            Idle => Idle,  // spurious timeout
            Connecting(sock, dline) => {
                if scope.now() >= dline {
                    warn!("Timeout while establishing connection");
                    Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
                } else {  // spurious timeout
                    Connecting(sock, dline)
                }
            }
            Established(x) => {
                return Fsm::action(x.timeout(scope), addr, seed, scope);
            }
            Sleeping(dline) => {
                if scope.now() >= dline {
                    return Self::connect(scope, addr, seed);
                } else {
                    Sleeping(dline)  // spurious timeout
                }
            }
        };
        response(addr, seed, state)
    }
    fn wakeup(self, scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        use self::Fsm::*;
        let Persistent(addr, seed, state) = self;
        let state = match state {
            Established(x) => {
                return Fsm::action(x.wakeup(scope), addr, seed, scope);
            }
            x => x, // spurious wakeup
        };
        response(addr, seed, state)
    }
}

#[cfg(feature="replaceable")]
mod replaceable {

    use std::fmt::Debug;

    use {ActiveStream, Protocol, Persistent};
    use rotor_tools::sync::Replaceable;

    use super::Fsm;

    impl
 Replaceable for Persistent

        where P: Protocol,
              P::Seed: Clone,

::Address: Clone + Debug,
              P::Socket: ActiveStream
    {
        fn empty(&self) -> Self {
            // We assume that cloning is cheap enough. Probably just Copy
            Persistent(self.0.clone(), self.1.clone(), Fsm::Idle)
        }
    }
}
<|endoftext|>