<commit_before>#[macro_use]
extern crate error_chain;

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

mod errors;
mod container;

use std::sync::Arc;
use std::cell::RefCell;
use errors::*;
use container::{Container, ContainerType};

/// The contents of a Node
#[derive(Clone, Debug)]
pub enum Content {
    Directory(Vec<Edge>),
    Leaf(Container)
}

impl Content {
    pub fn new(ty: NodeType) -> Content {
        match ty {
            NodeType::Directory => Content::Directory(vec![]),
            NodeType::Blob => Content::Leaf(Container::new(ContainerType::Blob)),
            NodeType::Queue => Content::Leaf(Container::new(ContainerType::Queue)),
            NodeType::Set => Content::Leaf(Container::new(ContainerType::Set))
        }
    }

    pub fn is_dir(&self) -> bool {
        if let Content::Directory(_) = *self {
            return true;
        }
        false
    }
}

/// A single entry in the contents of an interior node
#[derive(Clone, Debug)]
pub struct Edge {
    pub label: String,
    pub node: Arc<RefCell<Node>>
}

impl Edge {
    pub fn new(label: &str, node: Node) -> Edge {
        Edge {
            label: label.to_string(),
            node: Arc::new(RefCell::new(node))
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub enum NodeType {
    Directory,
    Blob,
    Queue,
    Set
}

/// A node in a hierarchical version tree
#[derive(Clone, Debug)]
pub struct Node {
    pub path: String,
    pub version: usize,
    pub content: Content
}

impl Node {
    pub fn new<S>(path: S, content: Content) -> Node
        where S: Into<String>
    {
        Node {
            path: path.into(),
            version: 0,
            content: content
        }
    }
}

/// A hierarchical version tree.
///
/// This tree is persistent, and every update to a node both path copies the parent until it gets
/// to the root and increments the parent's version number. Only a single thread can write to the
/// tree at one time.
#[derive(Debug, Clone)]
pub struct Tree {
    root: Arc<RefCell<Node>>
}

impl Tree {
    pub fn new() -> Tree {
        Tree {
            root: Arc::new(RefCell::new(Node::new("/", Content::Directory(vec![]))))
        }
    }

    /// Create a new node of a given type
    ///
    /// This function creates all intermediate directories that don't exist. It returns the
    /// new tree on success. Creation will fail if a directory component of the path matches an
    /// already existing leaf node or the leaf node component of path already exists.
    ///
    /// This function is optimized for the successful case. It walks the tree from the root,
    /// copying on write or creating intermediate directory nodes as required until it gets to the
    /// leaf where it creates and inserts the new leaf node of the proper type. If there is an
    /// error, the new, partially path-copied tree is discarded as the root goes out of scope.
    /// This is an optimization on the successful path because it doesn't require traversing down
    /// the tree and then back upwards. It also doesn't require the use of parent pointers. Finally
    /// it doesn't rely on recursion, since Rust does not have tail recursion and we don't want to
    /// limit the depth of the tree arbitrarily.
    pub fn create<S>(&self, path: S, ty: NodeType) -> Result<Tree>
        where S: Into<String>
    {
        let path = try!(validate_path(path));
        let root = cow_node(&self.root);
        let mut node = root.clone();
        let mut iter = path.split('/').peekable();
        while let Some(s) = iter.next() {
            if iter.peek().is_none() {
                // This is the last component in the path
                try!(insert_leaf(node.clone(), &s, ty));
                break;
            }
            node = try!(insert_dir(node.clone(), &s));
        }
        return Ok(Tree {root: root})
    }

    pub fn iter(&self) -> Iter {
        Iter {
            stack: vec![self.root.clone()]
        }
    }

}

/// An iterator that performs a depth first walk of the entire tree.
///
/// This iterator returns Arc pointers to RefCell<Node>. The tree being iterated over is logically
/// immutable and it is not safe to modify the contents of the RefCell.
//
// It would be awesome to get rid of the atomic pointer clones in this implementation. But using
// RefCells makes this difficult to do without unsafe code AFAICT because borrowing on the refcell
// limits the scope of the inner value to within the call to next().
pub struct Iter {
    stack: Vec<Arc<RefCell<Node>>>,
}

impl Iterator for Iter {
    type Item = Arc<RefCell<Node>>;
    fn next(&mut self) -> Option<Arc<RefCell<Node>>> {
        if self.stack.len() == 0 {
            return None;
        }
        let node = self.stack.pop().unwrap();
        if let Content::Directory(ref edges) = node.borrow().content {
            self.stack.extend(edges.iter().cloned().rev().map(|edge| edge.node));
        }
        Some(node)
    }
}

/// Check for a leading slash and at least one level of depth in path.
///
/// Strip leading and trailing slashes and return normalized path as String
fn validate_path<S>(path: S) -> Result<String>
    where S: Into<String>
{
    let path = path.into();
    if !path.starts_with("/") {
        return Err(ErrorKind::BadPath(format!("{} does not start with a '/'", path)).into())
    }
    let path = path.trim_matches('/').to_string();
    if path.len() == 0 {
        return Err(ErrorKind::BadPath("Path must contain at least one component".to_string())
                   .into());
    }
    Ok(path)
}

fn insert_dir(parent: Arc<RefCell<Node>>, label: &str) -> Result<Arc<RefCell<Node>>>
{
    let mut path = parent.borrow().path.clone();
    if path.len() != 1 {
        // We aren't at the root.
        path.push_str("/");
    }
    path.push_str(label);
    let mut parent = parent.borrow_mut();
    if let Content::Directory(ref mut edges) = parent.content {
        match edges.binary_search_by_key(&label, |e| &e.label) {
            Ok(index) => {
                // Unsafe block needed because of the call to edges.get_unchecked_mut(index).
                // We know it's safe though because we just got the index in our binary search.
                unsafe {
                    let ref mut child = edges.get_unchecked_mut(index);
                    if !child.node.borrow().content.is_dir() {
                        let ref child_path = child.node.borrow().path;
                        let msg = format!("{} is a leaf node", child_path);
                        return Err(ErrorKind::InvalidPathContent(msg).into());
                    }
                    // Create a copy of child node and replace the old node
                    let node = cow_node(&child.node);
                    child.node = node.clone();
                    return Ok(node);
                }
            },
            Err(index) => {
                let content = Content::new(NodeType::Directory);
                // Edge doesn't exist, let's create it in the proper sort position
                let edge = Edge::new(label, Node::new(path, content));
                let node = edge.node.clone();
                edges.insert(index, edge);
                return Ok(node);
            }
        }
    }
    Err(ErrorKind::InvalidPathContent(parent.path.clone()).into())
}

fn insert_leaf(parent: Arc<RefCell<Node>>, label: &str, ty: NodeType) -> Result<()> {
    let mut path = parent.borrow().path.clone();
    if path.len() != 1 {
        // We aren't at the root.
        path.push_str("/");
    }
    path.push_str(label);
    if let Content::Directory(ref mut edges) = parent.borrow_mut().content {
        // Assume sorted vec
        if let Err(index) = edges.binary_search_by_key(&label, |e| &e.label) {
            // Edge doesn't exist, let's create it in proper sort position
            let edge = Edge::new(label, Node::new(path, Content::new(ty)));
            edges.insert(index, edge);
            return Ok(());
        }
        return Err(ErrorKind::AlreadyExists(path).into());
    }
    Err(ErrorKind::InvalidPathContent(parent.borrow().path.clone()).into())
}

/// Deep clone a node and bump it's version
fn cow_node(node: &Arc<RefCell<Node>>) -> Arc<RefCell<Node>> {
    // Create a shallow copy of the node (inc ref count on Arc)
    let mut new_node = node.clone();

    // Force a deep copy on write copy and increment the version number
    Arc::make_mut(&mut new_node).borrow_mut().version += 1;
    new_node
}

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

    #[test]
    fn create_nodes() {
        let original_tree = Tree::new();
        assert_eq!(original_tree.root.borrow().version, 0);
        let tree = original_tree.create("/somenode", NodeType::Directory).unwrap();
        assert_eq!(tree.root.borrow().version, 1);
        let tree = tree.create("/somenode/somechildnode", NodeType::Set).unwrap();
        assert_eq!(tree.root.borrow().version, 2);
        let tree = tree.create("/somedir1/somedir2/leaf", NodeType::Queue).unwrap();
        assert_eq!(tree.root.borrow().version, 3);
        assert_eq!(original_tree.root.borrow().version, 0);
        if let Content::Directory(ref edges) = tree.root.borrow().content {
            assert_eq!(edges.len(), 2);
            assert_eq!(edges[0].label, "somedir1".to_string());
            assert_eq!(edges[1].label, "somenode".to_string());
            assert_eq!(edges[1].node.borrow().version, 1);
            assert_eq!(edges[0].node.borrow().version, 0);
            if let Content::Directory(ref edges) = edges[1].node.borrow().content {
                assert_eq!(edges.len(), 1);
                assert_eq!(edges[0].label, "somechildnode".to_string());
                assert_eq!(edges[0].node.borrow().version, 0);
                assert_eq!(edges[0].node.borrow().path, "/somenode/somechildnode".to_string());
                assert_matches!(edges[0].node.borrow().content, Content::Leaf(Container::Set(_)));
            } else {
                assert!(false);
            }
            if let Content::Directory(ref edges) = edges[0].node.borrow().content {
                assert_eq!(edges.len(), 1);
                assert_eq!(edges[0].label, "somedir2".to_string());
                assert_eq!(edges[0].node.borrow().version, 0);
                assert_eq!(edges[0].node.borrow().path, "/somedir1/somedir2".to_string());
                if let Content::Directory(ref edges) = edges[0].node.borrow().content {
                    assert_eq!(edges.len(), 1);
                    assert_eq!(edges[0].label, "leaf");
                    assert_eq!(edges[0].node.borrow().version, 0);
                    assert_eq!(edges[0].node.borrow().path, "/somedir1/somedir2/leaf".to_string());
                    assert_matches!(edges[0].node.borrow().content,
                                    Content::Leaf(Container::Queue(_)));
                }
            } else {
                assert!(false)
            }
        } else {
            assert!(false);
        }
        let err = tree.create("/somenode/somechildnode", NodeType::Set).unwrap_err();
        assert_matches!(*err.kind(), ErrorKind::AlreadyExists(_));
        let err = tree.create("blahblah", NodeType::Set).unwrap_err();
        assert_matches!(*err.kind(), ErrorKind::BadPath(_));
        let err = tree.create("/somenode/somechildnode/leaf", NodeType::Set).unwrap_err();
        assert_matches!(*err.kind(), ErrorKind::InvalidPathContent(_));
    }

    #[test]
    fn create_nodes_iter_check() {
        let tree = Tree::new();
        let tree = tree.create("/somenode", NodeType::Directory).unwrap();
        let tree = tree.create("/somenode/somechildnode", NodeType::Set).unwrap();
        let tree = tree.create("/somedir1/somedir2/leaf", NodeType::Queue).unwrap();

        // Tuples are (path, num_edges, version)
        // Num edges is  None if not a directory
        // Note the sorted order
        let expected = [("/", Some(2), 3),
                        ("/somedir1", Some(1), 0),
                        ("/somedir1/somedir2", Some(1), 0),
                        ("/somedir1/somedir2/leaf", None, 0),
                        ("/somenode", Some(1), 1),
                        ("/somenode/somechildnode", None, 0)];

        // All the directories and leaves including "/"
        assert_eq!(tree.iter().count(), expected.len());
        for (i, node) in tree.iter().enumerate() {
            let (path, num_edges, version) = expected[i];
            assert_eq!(node.borrow().path, path);
            assert_eq!(node.borrow().version, version);
            if let Some(num_edges) = num_edges {
                if let Content::Directory(ref edges) = node.borrow().content {
                    assert_eq!(edges.len(), num_edges);
                } else {
                    assert!(false);
                }
            }
        }
    }
}
<commit_msg>Make tree iterator incapable of mutating tree.<commit_after>#[macro_use]
extern crate error_chain;

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

mod errors;
mod container;

use std::sync::Arc;
use std::cell::RefCell;
use errors::*;
use container::{Container, ContainerType};

/// The contents of a Node
#[derive(Clone, Debug)]
pub enum Content {
    Directory(Vec<Edge>),
    Leaf(Container)
}

impl Content {
    pub fn new(ty: NodeType) -> Content {
        match ty {
            NodeType::Directory => Content::Directory(vec![]),
            NodeType::Blob => Content::Leaf(Container::new(ContainerType::Blob)),
            NodeType::Queue => Content::Leaf(Container::new(ContainerType::Queue)),
            NodeType::Set => Content::Leaf(Container::new(ContainerType::Set))
        }
    }

    pub fn is_dir(&self) -> bool {
        if let Content::Directory(_) = *self {
            return true;
        }
        false
    }
}

/// A single entry in the contents of an interior node
#[derive(Clone, Debug)]
pub struct Edge {
    label: String,
    node: Arc<RefCell<Node>>
}

impl Edge {
    pub fn new(label: &str, node: Node) -> Edge {
        Edge {
            label: label.to_string(),
            node: Arc::new(RefCell::new(node))
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub enum NodeType {
    Directory,
    Blob,
    Queue,
    Set
}

/// A node in a hierarchical version tree
#[derive(Clone, Debug)]
pub struct Node {
    path: String,
    version: usize,
    content: Content
}

impl Node {
    pub fn new<S>(path: S, content: Content) -> Node
        where S: Into<String>
    {
        Node {
            path: path.into(),
            version: 0,
            content: content
        }
    }
}

/// A hierarchical version tree.
///
/// This tree is persistent, and every update to a node both path copies the parent until it gets
/// to the root and increments the parent's version number. Only a single thread can write to the
/// tree at one time.
#[derive(Debug, Clone)]
pub struct Tree {
    root: Arc<RefCell<Node>>
}

impl Tree {
    pub fn new() -> Tree {
        Tree {
            root: Arc::new(RefCell::new(Node::new("/", Content::Directory(vec![]))))
        }
    }

    /// Create a new node of a given type
    ///
    /// This function creates all intermediate directories that don't exist. It returns the
    /// new tree on success. Creation will fail if a directory component of the path matches an
    /// already existing leaf node or the leaf node component of path already exists.
    ///
    /// This function is optimized for the successful case. It walks the tree from the root,
    /// copying on write or creating intermediate directory nodes as required until it gets to the
    /// leaf where it creates and inserts the new leaf node of the proper type. If there is an
    /// error, the new, partially path-copied tree is discarded as the root goes out of scope.
    /// This is an optimization on the successful path because it doesn't require traversing down
    /// the tree and then back upwards. It also doesn't require the use of parent pointers. Finally
    /// it doesn't rely on recursion, since Rust does not have tail recursion and we don't want to
    /// limit the depth of the tree arbitrarily.
    pub fn create<S>(&self, path: S, ty: NodeType) -> Result<Tree>
        where S: Into<String>
    {
        let path = try!(validate_path(path));
        let root = cow_node(&self.root);
        let mut node = root.clone();
        let mut iter = path.split('/').peekable();
        while let Some(s) = iter.next() {
            if iter.peek().is_none() {
                // This is the last component in the path
                try!(insert_leaf(node.clone(), &s, ty));
                break;
            }
            node = try!(insert_dir(node.clone(), &s));
        }
        return Ok(Tree {root: root})
    }

    pub fn iter(&self) -> Iter {
        Iter {
            stack: vec![&self.root]
        }
    }

}

/// Directories contain a list of labels for each edge
/// Containers are an actual reference to the Container and it's data
pub enum IterContent<'a> {
    Directory(Vec<&'a str>),
    Container(&'a Container)
}

pub struct IterNode<'a> {
    pub path: &'a str,
    pub version: usize,
    pub content: IterContent<'a>
}

/// An iterator that performs a depth first walk of the entire tree.
pub struct Iter<'a> {
    stack: Vec<&'a Arc<RefCell<Node>>>,
}

impl<'a> Iterator for Iter<'a> {
    type Item = IterNode<'a>;
    fn next(&mut self) -> Option<IterNode<'a>> {
        if self.stack.len() == 0 {
            return None;
        }
        let node = self.stack.pop().unwrap();
        unsafe {
            let ptr = node.as_ptr();
            let content = match (*ptr).content {
                Content::Directory(ref edges) => {
                    self.stack.extend(edges.iter().rev().map(|edge| &edge.node));
                    IterContent::Directory(edges.iter().map(|edge| &edge.label as &str).collect())
                },
                Content::Leaf(ref container) => {
                    IterContent::Container(&container)
                }
            };
            Some(IterNode {
                path: &(*ptr).path,
                version: (*ptr).version,
                content: content
            })
        }
    }
}

/// Check for a leading slash and at least one level of depth in path.
///
/// Strip leading and trailing slashes and return normalized path as String
fn validate_path<S>(path: S) -> Result<String>
    where S: Into<String>
{
    let path = path.into();
    if !path.starts_with("/") {
        return Err(ErrorKind::BadPath(format!("{} does not start with a '/'", path)).into())
    }
    let path = path.trim_matches('/').to_string();
    if path.len() == 0 {
        return Err(ErrorKind::BadPath("Path must contain at least one component".to_string())
                   .into());
    }
    Ok(path)
}

fn insert_dir(parent: Arc<RefCell<Node>>, label: &str) -> Result<Arc<RefCell<Node>>>
{
    let mut path = parent.borrow().path.clone();
    if path.len() != 1 {
        // We aren't at the root.
        path.push_str("/");
    }
    path.push_str(label);
    let mut parent = parent.borrow_mut();
    if let Content::Directory(ref mut edges) = parent.content {
        match edges.binary_search_by_key(&label, |e| &e.label) {
            Ok(index) => {
                // Unsafe block needed because of the call to edges.get_unchecked_mut(index).
                // We know it's safe though because we just got the index in our binary search.
                unsafe {
                    let ref mut child = edges.get_unchecked_mut(index);
                    if !child.node.borrow().content.is_dir() {
                        let ref child_path = child.node.borrow().path;
                        let msg = format!("{} is a leaf node", child_path);
                        return Err(ErrorKind::InvalidPathContent(msg).into());
                    }
                    // Create a copy of child node and replace the old node
                    let node = cow_node(&child.node);
                    child.node = node.clone();
                    return Ok(node);
                }
            },
            Err(index) => {
                let content = Content::new(NodeType::Directory);
                // Edge doesn't exist, let's create it in the proper sort position
                let edge = Edge::new(label, Node::new(path, content));
                let node = edge.node.clone();
                edges.insert(index, edge);
                return Ok(node);
            }
        }
    }
    Err(ErrorKind::InvalidPathContent(parent.path.clone()).into())
}

fn insert_leaf(parent: Arc<RefCell<Node>>, label: &str, ty: NodeType) -> Result<()> {
    let mut path = parent.borrow().path.clone();
    if path.len() != 1 {
        // We aren't at the root.
        path.push_str("/");
    }
    path.push_str(label);
    if let Content::Directory(ref mut edges) = parent.borrow_mut().content {
        // Assume sorted vec
        if let Err(index) = edges.binary_search_by_key(&label, |e| &e.label) {
            // Edge doesn't exist, let's create it in proper sort position
            let edge = Edge::new(label, Node::new(path, Content::new(ty)));
            edges.insert(index, edge);
            return Ok(());
        }
        return Err(ErrorKind::AlreadyExists(path).into());
    }
    Err(ErrorKind::InvalidPathContent(parent.borrow().path.clone()).into())
}

/// Deep clone a node and bump it's version
fn cow_node(node: &Arc<RefCell<Node>>) -> Arc<RefCell<Node>> {
    // Create a shallow copy of the node (inc ref count on Arc)
    let mut new_node = node.clone();

    // Force a deep copy on write copy and increment the version number
    Arc::make_mut(&mut new_node).borrow_mut().version += 1;
    new_node
}

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

    #[test]
    fn create_nodes() {
        let original_tree = Tree::new();
        assert_eq!(original_tree.root.borrow().version, 0);
        let tree = original_tree.create("/somenode", NodeType::Directory).unwrap();
        assert_eq!(tree.root.borrow().version, 1);
        let tree = tree.create("/somenode/somechildnode", NodeType::Set).unwrap();
        assert_eq!(tree.root.borrow().version, 2);
        let tree = tree.create("/somedir1/somedir2/leaf", NodeType::Queue).unwrap();
        assert_eq!(tree.root.borrow().version, 3);
        assert_eq!(original_tree.root.borrow().version, 0);
        if let Content::Directory(ref edges) = tree.root.borrow().content {
            assert_eq!(edges.len(), 2);
            assert_eq!(edges[0].label, "somedir1".to_string());
            assert_eq!(edges[1].label, "somenode".to_string());
            assert_eq!(edges[1].node.borrow().version, 1);
            assert_eq!(edges[0].node.borrow().version, 0);
            if let Content::Directory(ref edges) = edges[1].node.borrow().content {
                assert_eq!(edges.len(), 1);
                assert_eq!(edges[0].label, "somechildnode".to_string());
                assert_eq!(edges[0].node.borrow().version, 0);
                assert_eq!(edges[0].node.borrow().path, "/somenode/somechildnode".to_string());
                assert_matches!(edges[0].node.borrow().content, Content::Leaf(Container::Set(_)));
            } else {
                assert!(false);
            }
            if let Content::Directory(ref edges) = edges[0].node.borrow().content {
                assert_eq!(edges.len(), 1);
                assert_eq!(edges[0].label, "somedir2".to_string());
                assert_eq!(edges[0].node.borrow().version, 0);
                assert_eq!(edges[0].node.borrow().path, "/somedir1/somedir2".to_string());
                if let Content::Directory(ref edges) = edges[0].node.borrow().content {
                    assert_eq!(edges.len(), 1);
                    assert_eq!(edges[0].label, "leaf");
                    assert_eq!(edges[0].node.borrow().version, 0);
                    assert_eq!(edges[0].node.borrow().path, "/somedir1/somedir2/leaf".to_string());
                    assert_matches!(edges[0].node.borrow().content,
                                    Content::Leaf(Container::Queue(_)));
                }
            } else {
                assert!(false)
            }
        } else {
            assert!(false);
        }
        let err = tree.create("/somenode/somechildnode", NodeType::Set).unwrap_err();
        assert_matches!(*err.kind(), ErrorKind::AlreadyExists(_));
        let err = tree.create("blahblah", NodeType::Set).unwrap_err();
        assert_matches!(*err.kind(), ErrorKind::BadPath(_));
        let err = tree.create("/somenode/somechildnode/leaf", NodeType::Set).unwrap_err();
        assert_matches!(*err.kind(), ErrorKind::InvalidPathContent(_));
    }

    #[test]
    fn create_nodes_iter_check() {
        let tree = Tree::new();
        let tree = tree.create("/somenode", NodeType::Directory).unwrap();
        let tree = tree.create("/somenode/somechildnode", NodeType::Set).unwrap();
        let tree = tree.create("/somedir1/somedir2/leaf", NodeType::Queue).unwrap();

        // Tuples are (path, num_edges, version)
        // Num edges is  None if not a directory
        // Note the sorted order
        let expected = [("/", Some(2), 3),
                        ("/somedir1", Some(1), 0),
                        ("/somedir1/somedir2", Some(1), 0),
                        ("/somedir1/somedir2/leaf", None, 0),
                        ("/somenode", Some(1), 1),
                        ("/somenode/somechildnode", None, 0)];

        // All the directories and leaves including "/"
        assert_eq!(tree.iter().count(), expected.len());
        for (i, node) in tree.iter().enumerate() {
            let (path, num_edges, version) = expected[i];
            assert_eq!(node.path, path);
            assert_eq!(node.version, version);
            if let Some(num_edges) = num_edges {
                if let IterContent::Directory(ref labels) = node.content {
                    assert_eq!(labels.len(), num_edges);
                } else {
                    assert!(false);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(core, collections)]
#![allow(dead_code)]
use std::collections::hash_map::HashMap;
use std::borrow::Cow;
use std::string::CowString;

#[cfg(test)]
mod tests;

#[derive(Debug)]
pub struct IrcMessage<'a> {
    pub tags: HashMap<CowString<'a>, CowString<'a>>,
    pub prefix: Option<CowString<'a>>,
    pub command: Option<CowString<'a>>,
    pub params: Vec<CowString<'a>>
}

impl <'b> IrcMessage<'b> {
    pub fn new_empty<'a>() -> IrcMessage<'a> {
        IrcMessage {
            tags: HashMap::new(),
            prefix: None,
            command: None,
            params: Vec::new()
        }
    }

    /// Parse a message from a string to an owned `IrcMessage`.
    pub fn parse_owned<'a>(s: &'a str) -> Result<IrcMessage<'static>, ()> {
        return parse_owned(s);
    }

    /// Parse a message from a string to an `IrcMessage` that still refers
    /// to the original `str`.  Useful for minimizing allocations.
    pub fn parse_slice<'a>(s: &'a str) -> Result<IrcMessage<'a>, ()> {
        return parse_slice(s);
    }
}

fn next_segment<'a>(line: &'a str) -> (&'a str, &'a str) {
    match line.find(' ') {
        Some(n) => {
            if line.len() == 0 {
                return (line, line);
            }
            let segment = line.slice_to(n);

            let mut p = n;

            while line.char_at(p) == ' ' && p < line.len() - 1 {
                p += 1;
            }

            (segment, line.slice_from(p))
        },
        None => (line, "")
    }
}

fn trim_space<'a>(line: &'a str) -> &'a str {
    if line.len() == 0 {
        return line;
    }

    let mut p = 0;
    while line.char_at(p) == ' ' && p < line.len() - 1 {
        p += 1;
    }

    line.slice_from(p)
}

fn parse_owned<'a>(line: &'a str) -> Result<IrcMessage<'static>, ()> {
    parse_into(line, |a| Cow::Owned(a.to_string()))
}

fn parse_slice<'a>(line: &'a str) -> Result<IrcMessage<'a>, ()> {
    parse_into(line, |a| Cow::Borrowed(a))
}

fn parse_into<'a, 'b, F>(line: &'a str, wrap: F) -> Result<IrcMessage<'b>, ()>
where F: Fn(&'a str) -> CowString<'b> {
    let mut message = IrcMessage::new_empty();

    // TAGS
    let line = if line.char_at(0) == '@' {
        let (tags, rest) = next_segment(line.slice_from(1));
        let mut raw_tags = tags.split(';');
        for tag in raw_tags {
            println!("{}", tag);
            if tag.contains_char('=') {
                let mut pair = tag.split('=');
                message.tags.insert(wrap(pair.next().unwrap()), wrap(pair.next().unwrap()));
            } else {
                message.tags.insert(wrap(tag), wrap("true"));
            }
        }
        rest
    } else {
        line
    };

    // PREFIX
    let line = if line.char_at(0) == ':' {
        let (prefix, rest) = next_segment(line.slice_from(1));
        message.prefix = Some(wrap(prefix));
        rest
    } else {
        line
    };

    // COMMAND
    let (command, line) = next_segment(line);
    message.command = Some(wrap(command));

    // PARAMS
    let mut rest = trim_space(line);
    while !rest.is_empty() {
        match next_segment(rest) {
            ("", _) => {
                break;
            }
            (_, _) if rest.char_at(0) == ':' => {
                message.params.push(wrap(rest.slice_from(1)));
                break;
            }
            (last, "") => {
                message.params.push(wrap(last));
                break;
            }
            (next, tail) => {
                message.params.push(wrap(next));
                rest = tail;
            }
        }
    }

    return Ok(message);
}
<commit_msg>Switch to new slicing syntax<commit_after>#![feature(core, collections)]
#![allow(dead_code)]
use std::collections::hash_map::HashMap;
use std::borrow::Cow;
use std::string::CowString;

#[cfg(test)]
mod tests;

#[derive(Debug)]
pub struct IrcMessage<'a> {
    pub tags: HashMap<CowString<'a>, CowString<'a>>,
    pub prefix: Option<CowString<'a>>,
    pub command: Option<CowString<'a>>,
    pub params: Vec<CowString<'a>>
}

impl <'b> IrcMessage<'b> {
    pub fn new_empty<'a>() -> IrcMessage<'a> {
        IrcMessage {
            tags: HashMap::new(),
            prefix: None,
            command: None,
            params: Vec::new()
        }
    }

    /// Parse a message from a string to an owned `IrcMessage`.
    pub fn parse_owned<'a>(s: &'a str) -> Result<IrcMessage<'static>, ()> {
        return parse_owned(s);
    }

    /// Parse a message from a string to an `IrcMessage` that still refers
    /// to the original `str`.  Useful for minimizing allocations.
    pub fn parse_slice<'a>(s: &'a str) -> Result<IrcMessage<'a>, ()> {
        return parse_slice(s);
    }
}

fn next_segment<'a>(line: &'a str) -> (&'a str, &'a str) {
    match line.find(' ') {
        Some(n) => {
            if line.len() == 0 {
                return (line, line);
            }
            let segment = &line[..n];

            let mut p = n;

            while line.char_at(p) == ' ' && p < line.len() - 1 {
                p += 1;
            }

            (segment, &line[p..])
        },
        None => (line, "")
    }
}

fn trim_space<'a>(line: &'a str) -> &'a str {
    if line.len() == 0 {
        return line;
    }

    let mut p = 0;
    while line.char_at(p) == ' ' && p < line.len() - 1 {
        p += 1;
    }

    &line[p..]
}

fn parse_owned<'a>(line: &'a str) -> Result<IrcMessage<'static>, ()> {
    parse_into(line, |a| Cow::Owned(a.to_string()))
}

fn parse_slice<'a>(line: &'a str) -> Result<IrcMessage<'a>, ()> {
    parse_into(line, |a| Cow::Borrowed(a))
}

fn parse_into<'a, 'b, F>(line: &'a str, wrap: F) -> Result<IrcMessage<'b>, ()>
where F: Fn(&'a str) -> CowString<'b> {
    let mut message = IrcMessage::new_empty();

    // TAGS
    let line = if line.char_at(0) == '@' {
        let (tags, rest) = next_segment(&line[1..]);
        let mut raw_tags = tags.split(';');
        for tag in raw_tags {
            println!("{}", tag);
            if tag.contains_char('=') {
                let mut pair = tag.split('=');
                message.tags.insert(wrap(pair.next().unwrap()), wrap(pair.next().unwrap()));
            } else {
                message.tags.insert(wrap(tag), wrap("true"));
            }
        }
        rest
    } else {
        line
    };

    // PREFIX
    let line = if line.char_at(0) == ':' {
        let (prefix, rest) = next_segment(&line[1..]);
        message.prefix = Some(wrap(prefix));
        rest
    } else {
        line
    };

    // COMMAND
    let (command, line) = next_segment(line);
    message.command = Some(wrap(command));

    // PARAMS
    let mut rest = trim_space(line);
    while !rest.is_empty() {
        match next_segment(rest) {
            ("", _) => {
                break;
            }
            (_, _) if rest.char_at(0) == ':' => {
                message.params.push(wrap(&rest[1..]));
                break;
            }
            (last, "") => {
                message.params.push(wrap(last));
                break;
            }
            (next, tail) => {
                message.params.push(wrap(next));
                rest = tail;
            }
        }
    }

    return Ok(message);
}
<|endoftext|>


<commit_before>extern crate itertools;

use itertools::Itertools;

use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;
use std::vec;

#[derive(Debug, Clone)]
pub enum EvalError {
    StackUnderflow,
    NameNotFound(String),
    TypeMismatch,
}

impl fmt::Display for EvalError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            EvalError::StackUnderflow => write!(f, "stack underflow"),
            EvalError::NameNotFound(ref name) => write!(f, "could not find name: {}", name),
            EvalError::TypeMismatch => write!(f, "type mismatch"),
        }
    }
}

pub type EvalResult<T> = Result<T, EvalError>;

// This wrapper struct is needed to allow for the derivation of traits on `Term`
#[derive(Copy)]
pub struct Prim {
    pub f: fn(&mut Evaluator) -> EvalResult<()>,
}

impl fmt::Debug for Prim {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Prim(<prim>)")
    }
}

impl Clone for Prim {
    fn clone(&self) -> Prim { *self }
}

impl PartialEq for Prim {
    fn eq(&self, _: &Prim) -> bool {
        unimplemented!() // TODO: figure out function equality
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Term {
    Number(i32),
    Quote(Stack),
    Name(String),
    Prim(Prim),
}

impl Term {
    pub fn prim(f: fn(&mut Evaluator) -> EvalResult<()>) -> Term {
        Term::Prim(Prim { f: f })
    }
}

impl fmt::Display for Term {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Term::Number(x) => write!(f, "{}", x),
            Term::Quote(ref stack) => write!(f, "[ {} ]", stack),
            Term::Name(ref name) => write!(f, "{}", name),
            Term::Prim(_) => write!(f, "<prim>"),
        }
    }
}

#[derive(Clone, Debug)]
pub struct Words {
    defs: HashMap<String, Term>,
}

impl Words {
    pub fn empty() -> Words {
        Words {
            defs: HashMap::new(),
        }
    }

    pub fn standard() -> Words {
        let mut words = Words::empty();

        words.define("dup", Term::prim(prim::dup)); // (A b -> A b b)
        words.define("pop", Term::prim(prim::pop)); // (A b -> A)
        words.define("swap", Term::prim(prim::swap)); // (A b c -> A c b)
        words.define("apply", Term::prim(prim::apply)); // (A (A -> B) -> B)
        words.define("quote", Term::prim(prim::quote)); // (A b -> A (C -> C b))
        words.define("compose", Term::prim(prim::compose)); // (A (B -> C) (C -> D) -> A (B -> D)))

        words.define("words", Term::prim(prim::words)); // (A ~> A)

        words.define("+", Term::prim(prim::add)); // (A num num -> A num)
        words.define("-", Term::prim(prim::sub)); // (A num num -> A num)
        words.define("*", Term::prim(prim::mul)); // (A num num -> A num)
        words.define("/", Term::prim(prim::div)); // (A num num -> A num)
        words.define("%", Term::prim(prim::rem)); // (A num num -> A num)

        words
    }

    pub fn define<S: Into<String>>(&mut self, name: S, x: Term) {
        self.defs.insert(name.into(), x);
    }

    pub fn lookup(&self, name: &str) -> Option<&Term> {
        self.defs.get(name)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Stack {
    terms: Vec<Term>,
}

impl Stack {
    pub fn new(terms: Vec<Term>) -> Stack {
        Stack { terms: terms }
    }

    fn push(&mut self, term: Term) {
        self.terms.push(term);
    }

    fn pop(&mut self) -> EvalResult<Term> {
        match self.terms.pop() {
            Some(term) => Ok(term),
            None => Err(EvalError::StackUnderflow),
        }
    }

    fn pop_number(&mut self) -> EvalResult<i32> {
        match try!(self.pop()) {
            Term::Number(x) => Ok(x),
            _ => Err(EvalError::TypeMismatch),
        }
    }

    fn pop_quote(&mut self) -> EvalResult<Stack> {
        match try!(self.pop()) {
            Term::Quote(stack) => Ok(stack),
            _ => Err(EvalError::TypeMismatch),
        }
    }

    fn peek(&mut self) -> EvalResult<&Term> {
        match self.terms.last() {
            Some(term) => Ok(term),
            None => Err(EvalError::StackUnderflow),
        }
    }

    pub fn quote(&mut self) -> EvalResult<()> {
        let term = try!(self.pop());
        self.push(Term::Quote(Stack::new(vec![term])));
        Ok(())
    }

    fn compose(&mut self, other: Stack) {
        self.terms.extend(other.terms);
    }

    fn dup(&mut self) -> EvalResult<()> {
        let term = try!(self.peek()).clone();
        self.push(term);
        Ok(())
    }

    fn swap(&mut self) -> EvalResult<()> {
        let term_a = try!(self.pop());
        let term_b = try!(self.pop());

        self.push(term_a);
        self.push(term_b);

        Ok(())
    }

    fn apply_binop<F: Fn(i32, i32) -> i32>(&mut self, f: F) -> EvalResult<()> {
        let x = try!(self.pop_number());
        let y = try!(self.pop_number());

        self.push(Term::Number(f(x, y)));

        Ok(())
    }
}

impl FromStr for Stack {
    type Err = String;

    fn from_str(src: &str) -> Result<Stack, String> {
        fn parse_tokens<'a, I>(tokens: &mut I, in_quote: bool) -> Result<Stack, String> where
            I: Iterator<Item = &'a str>,
        {
            let mut terms = vec![];

            while let Some(token) = tokens.next() {
                match token {
                    "[" => {
                        terms.push(Term::Quote(
                            try!(parse_tokens(tokens, true))
                        ))
                    },
                    "]" => {
                        if in_quote {
                            return Ok(Stack::new(terms));
                        } else {
                            return Err("found unexpected `]`".to_string());
                        }
                    },
                    token => match token.parse() {
                        Ok(x) => terms.push(Term::Number(x)),
                        Err(_) => terms.push(Term::Name(token.to_string())),
                    },
                }
            }
            if in_quote {
                Err("expected closing `]`".to_string())
            } else {
                Ok(Stack::new(terms))
            }
        }

        parse_tokens(&mut src.split_whitespace(), false)
    }
}

pub type Terms = vec::IntoIter<Term>;

impl IntoIterator for Stack {
    type Item = Term;
    type IntoIter = Terms;

    fn into_iter(self) -> Terms {
        self.terms.into_iter()
    }
}

impl fmt::Display for Stack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.terms.iter().format(" ", |t, f| f(t)))
    }
}

pub struct Evaluator<'a> {
    words: &'a Words,
    stack: Stack,
    quote: Terms,
}

impl<'a> Evaluator<'a> {
    pub fn new(words: &Words, quote: Stack) -> Evaluator {
        Evaluator {
            words: words,
            stack: Stack::new(vec![]),
            quote: quote.into_iter(),

        }
    }

    fn eval_name(&mut self, name: String) -> EvalResult<()> {
        match self.words.lookup(&name) {
            Some(term) => self.eval_term(term.clone()),
            None => Err(EvalError::NameNotFound(name)),
        }
    }

    fn eval_term(&mut self, term: Term) -> EvalResult<()> {
        match term {
            Term::Number(x) => { self.stack.push(Term::Number(x)); Ok(()) },
            Term::Quote(stack) => { self.stack.push(Term::Quote(stack)); Ok(()) },
            Term::Name(name) => self.eval_name(name),
            Term::Prim(prim) => (prim.f)(self),
        }
    }

    fn eval_quote(&mut self, quote: Stack) -> EvalResult<()> {
        let mut quote = quote.into_iter();
        while let Some(term) = quote.next() {
            try!(self.eval_term(term))
        }
        Ok(())
    }

    fn eval_stack(&mut self) -> EvalResult<()> {
        while let Some(term) = self.quote.next() {
            try!(self.eval_term(term))
        }
        Ok(())
    }

    pub fn eval(mut self) -> EvalResult<Stack> {
        try!(self.eval_stack());
        Ok(self.stack)
    }
}

mod prim {
    use std::ops::*;
    use super::*;

    // dup : (A b -> A b b)
    pub fn dup(ev: &mut Evaluator) -> EvalResult<()> {
        ev.stack.dup()
    }

    // pop : (A b -> A)
    pub fn pop(ev: &mut Evaluator) -> EvalResult<()> {
        ev.stack.pop().map(|_| ())
    }

    // swap : (A b c -> A c b)
    pub fn swap(ev: &mut Evaluator) -> EvalResult<()> {
        ev.stack.swap()
    }

    // apply : (A (A -> B) -> B)
    pub fn apply(ev: &mut Evaluator) -> EvalResult<()> {
        let quote = try!(ev.stack.pop_quote());

        ev.eval_quote(quote)
    }

    // quote : (A b -> A (C -> C b))
    pub fn quote(ev: &mut Evaluator) -> EvalResult<()> {
        let term = try!(ev.stack.pop());
        let quoted = Term::Quote(Stack::new(vec![term]));

        ev.stack.push(quoted);

        Ok(())
    }

    // compose : (A (B -> C) (C -> D) -> A (B -> D)))
    pub fn compose(ev: &mut Evaluator) -> EvalResult<()> {
        let stack_a = try!(ev.stack.pop_quote());
        let mut stack_b = try!(ev.stack.pop_quote());

        stack_b.compose(stack_a);
        ev.stack.push(Term::Quote(stack_b));

        Ok(())
    }

    // words : (A ~> A)
    pub fn words(ev: &mut Evaluator) -> EvalResult<()> {
        for name in ev.words.defs.keys() {
            println!("{}", name);
        }

        Ok(())
    }

    // add : (A num num -> A num)
    pub fn add(ev: &mut Evaluator) -> EvalResult<()> {
        ev.stack.apply_binop(i32::add)
    }

    // sub : (A num num -> A num)
    pub fn sub(ev: &mut Evaluator) -> EvalResult<()> {
        ev.stack.apply_binop(i32::sub)
    }

    // mul : (A num num -> A num)
    pub fn mul(ev: &mut Evaluator) -> EvalResult<()> {
        ev.stack.apply_binop(i32::mul)
    }

    // div : (A num num -> A num)
    pub fn div(ev: &mut Evaluator) -> EvalResult<()> {
        ev.stack.apply_binop(i32::div)
    }

    // rem : (A num num -> A num)
    pub fn rem(ev: &mut Evaluator) -> EvalResult<()> {
        ev.stack.apply_binop(i32::rem)
    }
}
<commit_msg>Reduce number of methods on Stack<commit_after>extern crate itertools;

use itertools::Itertools;

use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;
use std::vec;

#[derive(Debug, Clone)]
pub enum EvalError {
    StackUnderflow,
    NameNotFound(String),
    TypeMismatch,
}

impl fmt::Display for EvalError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            EvalError::StackUnderflow => write!(f, "stack underflow"),
            EvalError::NameNotFound(ref name) => write!(f, "could not find name: {}", name),
            EvalError::TypeMismatch => write!(f, "type mismatch"),
        }
    }
}

pub type EvalResult<T> = Result<T, EvalError>;

// This wrapper struct is needed to allow for the derivation of traits on `Term`
#[derive(Copy)]
pub struct Prim {
    pub f: fn(&mut Evaluator) -> EvalResult<()>,
}

impl fmt::Debug for Prim {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Prim(<prim>)")
    }
}

impl Clone for Prim {
    fn clone(&self) -> Prim { *self }
}

impl PartialEq for Prim {
    fn eq(&self, _: &Prim) -> bool {
        unimplemented!() // TODO: figure out function equality
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Term {
    Number(i32),
    Quote(Stack),
    Name(String),
    Prim(Prim),
}

impl Term {
    pub fn prim(f: fn(&mut Evaluator) -> EvalResult<()>) -> Term {
        Term::Prim(Prim { f: f })
    }
}

impl fmt::Display for Term {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Term::Number(x) => write!(f, "{}", x),
            Term::Quote(ref stack) => write!(f, "[ {} ]", stack),
            Term::Name(ref name) => write!(f, "{}", name),
            Term::Prim(_) => write!(f, "<prim>"),
        }
    }
}

#[derive(Clone, Debug)]
pub struct Words {
    defs: HashMap<String, Term>,
}

impl Words {
    pub fn empty() -> Words {
        Words {
            defs: HashMap::new(),
        }
    }

    pub fn standard() -> Words {
        let mut words = Words::empty();

        words.define("dup", Term::prim(prim::dup)); // (A b -> A b b)
        words.define("pop", Term::prim(prim::pop)); // (A b -> A)
        words.define("swap", Term::prim(prim::swap)); // (A b c -> A c b)
        words.define("apply", Term::prim(prim::apply)); // (A (A -> B) -> B)
        words.define("quote", Term::prim(prim::quote)); // (A b -> A (C -> C b))
        words.define("compose", Term::prim(prim::compose)); // (A (B -> C) (C -> D) -> A (B -> D)))

        words.define("words", Term::prim(prim::words)); // (A ~> A)

        words.define("+", Term::prim(prim::add)); // (A num num -> A num)
        words.define("-", Term::prim(prim::sub)); // (A num num -> A num)
        words.define("*", Term::prim(prim::mul)); // (A num num -> A num)
        words.define("/", Term::prim(prim::div)); // (A num num -> A num)
        words.define("%", Term::prim(prim::rem)); // (A num num -> A num)

        words
    }

    pub fn define<S: Into<String>>(&mut self, name: S, x: Term) {
        self.defs.insert(name.into(), x);
    }

    pub fn lookup(&self, name: &str) -> Option<&Term> {
        self.defs.get(name)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Stack {
    terms: Vec<Term>,
}

impl Stack {
    pub fn new(terms: Vec<Term>) -> Stack {
        Stack { terms: terms }
    }

    fn push(&mut self, term: Term) {
        self.terms.push(term);
    }

    fn pop(&mut self) -> EvalResult<Term> {
        match self.terms.pop() {
            Some(term) => Ok(term),
            None => Err(EvalError::StackUnderflow),
        }
    }

    fn pop_number(&mut self) -> EvalResult<i32> {
        match try!(self.pop()) {
            Term::Number(x) => Ok(x),
            _ => Err(EvalError::TypeMismatch),
        }
    }

    fn pop_quote(&mut self) -> EvalResult<Stack> {
        match try!(self.pop()) {
            Term::Quote(stack) => Ok(stack),
            _ => Err(EvalError::TypeMismatch),
        }
    }

    fn peek(&mut self) -> EvalResult<&Term> {
        match self.terms.last() {
            Some(term) => Ok(term),
            None => Err(EvalError::StackUnderflow),
        }
    }
}

impl FromStr for Stack {
    type Err = String;

    fn from_str(src: &str) -> Result<Stack, String> {
        fn parse_tokens<'a, I>(tokens: &mut I, in_quote: bool) -> Result<Stack, String> where
            I: Iterator<Item = &'a str>,
        {
            let mut terms = vec![];

            while let Some(token) = tokens.next() {
                match token {
                    "[" => {
                        terms.push(Term::Quote(
                            try!(parse_tokens(tokens, true))
                        ))
                    },
                    "]" => {
                        if in_quote {
                            return Ok(Stack::new(terms));
                        } else {
                            return Err("found unexpected `]`".to_string());
                        }
                    },
                    token => match token.parse() {
                        Ok(x) => terms.push(Term::Number(x)),
                        Err(_) => terms.push(Term::Name(token.to_string())),
                    },
                }
            }
            if in_quote {
                Err("expected closing `]`".to_string())
            } else {
                Ok(Stack::new(terms))
            }
        }

        parse_tokens(&mut src.split_whitespace(), false)
    }
}

pub type Terms = vec::IntoIter<Term>;

impl IntoIterator for Stack {
    type Item = Term;
    type IntoIter = Terms;

    fn into_iter(self) -> Terms {
        self.terms.into_iter()
    }
}

impl fmt::Display for Stack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.terms.iter().format(" ", |t, f| f(t)))
    }
}

pub struct Evaluator<'a> {
    words: &'a Words,
    stack: Stack,
    quote: Terms,
}

impl<'a> Evaluator<'a> {
    pub fn new(words: &Words, quote: Stack) -> Evaluator {
        Evaluator {
            words: words,
            stack: Stack::new(vec![]),
            quote: quote.into_iter(),

        }
    }

    fn eval_name(&mut self, name: String) -> EvalResult<()> {
        match self.words.lookup(&name) {
            Some(term) => self.eval_term(term.clone()),
            None => Err(EvalError::NameNotFound(name)),
        }
    }

    fn eval_term(&mut self, term: Term) -> EvalResult<()> {
        match term {
            Term::Number(x) => { self.stack.push(Term::Number(x)); Ok(()) },
            Term::Quote(stack) => { self.stack.push(Term::Quote(stack)); Ok(()) },
            Term::Name(name) => self.eval_name(name),
            Term::Prim(prim) => (prim.f)(self),
        }
    }

    fn eval_quote(&mut self, quote: Stack) -> EvalResult<()> {
        let mut quote = quote.into_iter();
        while let Some(term) = quote.next() {
            try!(self.eval_term(term))
        }
        Ok(())
    }

    fn eval_stack(&mut self) -> EvalResult<()> {
        while let Some(term) = self.quote.next() {
            try!(self.eval_term(term))
        }
        Ok(())
    }

    pub fn eval(mut self) -> EvalResult<Stack> {
        try!(self.eval_stack());
        Ok(self.stack)
    }
}

mod prim {
    use std::ops::*;
    use super::*;

    // dup : (A b -> A b b)
    pub fn dup(ev: &mut Evaluator) -> EvalResult<()> {
        let term = try!(ev.stack.peek()).clone();
        ev.stack.push(term);
        Ok(())
    }

    // pop : (A b -> A)
    pub fn pop(ev: &mut Evaluator) -> EvalResult<()> {
        ev.stack.pop().map(|_| ())
    }

    // swap : (A b c -> A c b)
    pub fn swap(ev: &mut Evaluator) -> EvalResult<()> {
        let term_a = try!(ev.stack.pop());
        let term_b = try!(ev.stack.pop());

        ev.stack.push(term_a);
        ev.stack.push(term_b);

        Ok(())
    }

    // apply : (A (A -> B) -> B)
    pub fn apply(ev: &mut Evaluator) -> EvalResult<()> {
        let quote = try!(ev.stack.pop_quote());

        ev.eval_quote(quote)
    }

    // quote : (A b -> A (C -> C b))
    pub fn quote(ev: &mut Evaluator) -> EvalResult<()> {
        let term = try!(ev.stack.pop());
        let quoted = Term::Quote(Stack::new(vec![term]));

        ev.stack.push(quoted);

        Ok(())
    }

    // compose : (A (B -> C) (C -> D) -> A (B -> D)))
    pub fn compose(ev: &mut Evaluator) -> EvalResult<()> {
        let stack_a = try!(ev.stack.pop_quote());
        let mut stack_b = try!(ev.stack.pop_quote());

        stack_b.terms.extend(stack_a.terms);
        ev.stack.push(Term::Quote(stack_b));

        Ok(())
    }

    // words : (A ~> A)
    pub fn words(ev: &mut Evaluator) -> EvalResult<()> {
        for name in ev.words.defs.keys() {
            println!("{}", name);
        }

        Ok(())
    }

    fn apply_binop<F: Fn(i32, i32) -> i32>(stack: &mut Stack, f: F) -> EvalResult<()> {
        let x = try!(stack.pop_number());
        let y = try!(stack.pop_number());

        stack.push(Term::Number(f(x, y)));

        Ok(())
    }

    // add : (A num num -> A num)
    pub fn add(ev: &mut Evaluator) -> EvalResult<()> {
        apply_binop(&mut ev.stack, i32::add)
    }

    // sub : (A num num -> A num)
    pub fn sub(ev: &mut Evaluator) -> EvalResult<()> {
        apply_binop(&mut ev.stack, i32::sub)
    }

    // mul : (A num num -> A num)
    pub fn mul(ev: &mut Evaluator) -> EvalResult<()> {
        apply_binop(&mut ev.stack, i32::mul)
    }

    // div : (A num num -> A num)
    pub fn div(ev: &mut Evaluator) -> EvalResult<()> {
        apply_binop(&mut ev.stack, i32::div)
    }

    // rem : (A num num -> A num)
    pub fn rem(ev: &mut Evaluator) -> EvalResult<()> {
        apply_binop(&mut ev.stack, i32::rem)
    }
}
<|endoftext|>


<commit_before>#![feature(unboxed_closures)]

//! Fern is a runtime-configurable rust logging library.

//! Current features are:
//!
//! - Multiple loggers. You can create as many loggers as you need, and configure them separately.
//! - Configurable output format via closures.
//! - Multiple outputs per logger - current options are to a file, or to stdout/stderr (or any combination of those)
//! - Each output can have a Level configured, so you can output all log messages to a log file, and only have warnings and above show up in the console!
//! - You can also define your own custom logging endpoints - have messages end up where you need them!
//! - Thread-local logger storage. This allows for convenient <level>!() and log!() macros via the fern_macros package.
//!
//! fern is still in development, and most features are experimental. The library is subject to change in non-backwards-compatible ways.
//!
//! This library can only be used while complying to the license terms in the `LICENSE` file.
//!
//! Examples
//! ========
//!
//! Usually, the first thing you want to do is create a logger. In fern, you can do this by first
//! creating a LoggerConfig struct, and then calling `.into_logger()` to turn it into a logger.
//!
//! Here's a logger that simply logs all messages to stdout, and an output.log file, formatting
//! each message with the current date, time, and logging level.
//! ```
//! let logger_config = fern::LoggerConfig {
//!     format: box |msg: &str, level: &fern::Level| {
//!         return format!("[{}][{}] {}", chrono::Local::now().format("%Y-%m-%d][%H:%M:%S"), level, msg);
//!     },
//!     output: vec![fern::OutputConfig::Stdout, fern::OutputConfig::File(Path::new("output.log"))],
//!     level: fern::Level::Debug,
//! };
//! ```
//!
//! In the above example, here's what each part does.
//!
//! `format:` is a closure which all messages will be run through. In this example, use a
//! format!() macro to format the messages using the current time, date, and logging level.
//!
//! Side note: `chrono::Local::now().format("%Y-%m-%d][%H:%M:%S")` is a usage of the chrono time
//! library, and just returns the date in the format described. An output of this might look like
//! `2014-12-01][12:55:04`.
//!
//! With this formatting, the final output of the logger will look something like:
//!
//! ```
//! [2014-12-01][12:55:04][INFO] A message logged at the Level::Info logging level.
//! ```
//!
//! `output:` is a Vec<> of other configurations to send the messages to. In this example, we send
//! them to `OutputConfig::Stdout` and `OutputConfig::File(Path::new(config.log_file.as_slice())`.
//! This will send messages to the console, and to a file called "output.log".
//!
//! `level:` is a `fern::Level` which describes the minimum level that should be allowed to pass
//! through this logger. Setting this to `Level::Debug` allows all messages to be logged, as Debug
//! is the lowest logging level.
//!
//! After creating your logging config, you can turn it into a Logger using `into_logger()`:
//! ```
//! let logger = match logger_config.into_logger() {
//!     Some(v) => v,
//!     Err(e) => panic!("Failed to create logger! Error: {}", e),
//! };
//! ```
//!
//! Eventually, this section will contain a few more examples as well. For now though, the above,
//! along with the LoggerConfig and OutputConfig docs, should be enough to get you started on
//! configuring your logger.
//!
//! #### Logging
//!
//! The next part of logging that you'll probably want to do is actually output some messages.
//!
//! The recommended/easiest way to do this is using the `local` module, along with the
//! `fern_macros` crate.
//!
//! To initialize your logger into thread-local storage for use, you can use
//! `fern::local::set_thread_logger()`
//! ```
//! use std::sync;
//!
//! fern::local::set_thread_logger(sync::Arc::new(logger));
//! ```
//!
//! You can then log anywhere in this thread using the following macros from fern_macros:
//! ```
//! #[feature(phase)]
//!
//! // ...
//!
//! #[phase(plugin)]
//! extern crate fern_macros;
//!
//! // ...
//!
//! info!("A message logged at info level");
//!
//! let var = true;
//! debug!("Debugging message containing a variable value: {}", var);
//!
//! warning!("Something bad happened!");
//!
//! severe!("Something really bad happened!");
//! ```
//!
//! If your application is multi-threaded, you can spread the logger across threads as follows (do
//! this instead of the initiating above):
//! ```
//! use std::sync;
//!
//! let logger_arc = sync::Arc::new(logger); // Create a reference counted logger
//!
//! fern::local::set_thread_logger(logger_arc.clone()); // Initialize the logger for this thread.
//!
//! spawn(move || {
//!     fern::local::set_thread_logger(logger_arc.clone());
//! });
//! ```
//!
//! You can also pass the reference counted logger between functions - if you don't want to
//! type out `sync::Arc<Box<fern::Logger + Sync + Send>>` for all the function declarations, you
//! can use `fern::ArcLogger` instead.

pub use api::{Logger, BoxedLogger, ArcLogger, Level};
pub use config::{LoggerConfig, OutputConfig};
pub use loggers::NullLogger;

pub mod local;
mod api;
mod config;
mod loggers;
<commit_msg>Fix documentation formatting errors which caused incorrect code highlighting!<commit_after>#![feature(unboxed_closures)]

//! Fern is a runtime-configurable rust logging library.

//! Current features are:
//!
//! - Multiple loggers. You can create as many loggers as you need, and configure them separately.
//! - Configurable output format via closures.
//! - Multiple outputs per logger - current options are to a file, or to stdout/stderr (or any combination of those)
//! - Each output can have a Level configured, so you can output all log messages to a log file, and only have warnings and above show up in the console!
//! - You can also define your own custom logging endpoints - have messages end up where you need them!
//! - Thread-local logger storage. This allows for convenient <level>!() and log!() macros via the fern_macros package.
//!
//! fern is still in development, and most features are experimental. The library is subject to change in non-backwards-compatible ways.
//!
//! This library can only be used while complying to the license terms in the `LICENSE` file.
//!
//! Examples
//! ========
//!
//! Usually, the first thing you want to do is create a logger. In fern, you can do this by first
//! creating a LoggerConfig struct, and then calling `.into_logger()` to turn it into a logger.
//!
//! Here's a logger that simply logs all messages to stdout, and an output.log file, formatting
//! each message with the current date, time, and logging level.
//!
//! ```
//! let logger_config = fern::LoggerConfig {
//!     format: box |msg: &str, level: &fern::Level| {
//!         return format!("[{}][{}] {}", chrono::Local::now().format("%Y-%m-%d][%H:%M:%S"), level, msg);
//!     },
//!     output: vec![fern::OutputConfig::Stdout, fern::OutputConfig::File(Path::new("output.log"))],
//!     level: fern::Level::Debug,
//! };
//! ```
//!
//! In the above example, here's what each part does.
//!
//! `format:` is a closure which all messages will be run through. In this example, use a
//! format!() macro to format the messages using the current time, date, and logging level.
//!
//! Side note: `chrono::Local::now().format("%Y-%m-%d][%H:%M:%S")` is a usage of the chrono time
//! library, and just returns the date in the format described. An output of this might look like
//! `2014-12-01][12:55:04`.
//!
//! With this formatting, the final output of the logger will look something like:
//!
//! ```
//! [2014-12-01][12:55:04][INFO] A message logged at the Level::Info logging level.
//! ```
//!
//! `output:` is a Vec<> of other configurations to send the messages to. In this example, we send
//! them to `OutputConfig::Stdout` and `OutputConfig::File(Path::new(config.log_file.as_slice())`.
//! This will send messages to the console, and to a file called "output.log".
//!
//! `level:` is a `fern::Level` which describes the minimum level that should be allowed to pass
//! through this logger. Setting this to `Level::Debug` allows all messages to be logged, as Debug
//! is the lowest logging level.
//!
//! After creating your logging config, you can turn it into a Logger using `into_logger()`:
//!
//! ```
//! let logger = match logger_config.into_logger() {
//!     Some(v) => v,
//!     Err(e) => panic!("Failed to create logger! Error: {}", e),
//! };
//! ```
//!
//! Eventually, this section will contain a few more examples as well. For now though, the above,
//! along with the LoggerConfig and OutputConfig docs, should be enough to get you started on
//! configuring your logger.
//!
//! #### Logging
//!
//! The next part of logging that you'll probably want to do is actually output some messages.
//!
//! The recommended/easiest way to do this is using the `local` module, along with the
//! `fern_macros` crate.
//!
//! To initialize your logger into thread-local storage for use, you can use
//! `fern::local::set_thread_logger()`
//!
//! ```
//! use std::sync;
//!
//! fern::local::set_thread_logger(sync::Arc::new(logger));
//! ```
//!
//! You can then log anywhere in this thread using the following macros from fern_macros:
//!
//! ```
//! #[feature(phase)]
//!
//! // ...
//!
//! #[phase(plugin)]
//! extern crate fern_macros;
//!
//! // ...
//!
//! info!("A message logged at info level");
//!
//! let var = true;
//! debug!("Debugging message containing a variable value: {}", var);
//!
//! warning!("Something bad happened!");
//!
//! severe!("Something really bad happened!");
//! ```
//!
//! If your application is multi-threaded, you can spread the logger across threads as follows (do
//! this instead of the initiating above):
//!
//! ```
//! use std::sync;
//!
//! let logger_arc = sync::Arc::new(logger); // Create a reference counted logger
//!
//! fern::local::set_thread_logger(logger_arc.clone()); // Initialize the logger for this thread.
//!
//! spawn(move || {
//!     fern::local::set_thread_logger(logger_arc.clone());
//! });
//! ```
//!
//! You can also pass the reference counted logger between functions - if you don't want to
//! type out `sync::Arc<Box<fern::Logger + Sync + Send>>` for all the function declarations, you
//! can use `fern::ArcLogger` instead.

pub use api::{Logger, BoxedLogger, ArcLogger, Level};
pub use config::{LoggerConfig, OutputConfig};
pub use loggers::NullLogger;

pub mod local;
mod api;
mod config;
mod loggers;
<|endoftext|>


<commit_before>// Copyright(C) 2016 Chris Liebert
#![crate_type = "dylib"]
#![crate_name = "quick3d"]
#![allow(dead_code)]
#[macro_use]
extern crate glium;

pub mod common;

pub mod loader;
#[macro_use]
pub mod renderer;

extern crate nalgebra;
extern crate libc;

use std::ffi::CStr;
use std::os::raw::c_char;

use glium::glutin;
use glium::glutin::{ElementState, Event, MouseButton, VirtualKeyCode};
use glium::DisplayBuild;
use glium::backend::glutin_backend::GlutinFacade;

use common::Camera;
use loader::DBLoader;
use renderer::Renderer;

#[no_mangle]
pub extern "C" fn camera_aim(camera: &Camera, x: libc::c_double, y: libc::c_double) {
	camera.aim(x as f64, y as f64);
}

#[no_mangle]
pub extern "C" fn camera_move_forward(camera: &Camera, amount: libc::c_float) {
	camera.move_forward(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_move_backward(camera: &Camera, amount: libc::c_float) {
	camera.move_backward(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_move_left(camera: &Camera, amount: libc::c_float) {
	camera.move_left(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_move_right(camera: &Camera, amount: libc::c_float) {
	camera.move_right(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_update(camera: &Camera) {
	camera.update();
}

#[no_mangle]
pub extern "C" fn create_camera(screen_width: f32, screen_height: f32) -> Box<Camera> {
    Box::new(Camera::new(screen_width, screen_height))
}

#[no_mangle]
pub extern "C" fn create_db_loader(filename_cstr: *const c_char) -> Box<DBLoader> {
    unsafe {
        let filename: String = CStr::from_ptr(filename_cstr).to_string_lossy().into_owned();
        let dbloader: DBLoader = DBLoader::new(&filename);
        println!("Loaded {}", &filename);
        Box::new(dbloader)
    }
}

#[no_mangle]
pub extern "C" fn create_display(screen_width: libc::int32_t,
                                 screen_height: libc::int32_t,
                                 title: *const c_char)
                                 -> Box<GlutinFacade> {
    let w: u32 = screen_width as u32;
    let h: u32 = screen_height as u32;
    let window_title: String;

    unsafe {
        window_title = CStr::from_ptr(title).to_string_lossy().into_owned();
        let display: GlutinFacade = glutin::WindowBuilder::new()
	        //.resizable()
	        //.with_vsync()
	        .with_gl_debug_flag(true)
	        .with_title(window_title)
	        .with_visibility(true)
	        .with_dimensions(w, h)
	        .build_glium()
	        .unwrap();
        return Box::new(display);
    }
}

#[no_mangle]
pub extern "C" fn create_renderer_from_db_loader(dbloader: &DBLoader,
                                                 display: &GlutinFacade)
                                                 -> Box<Renderer> {
    Box::new(renderer::Renderer::new(display, dbloader.load_scene()))
}

#[no_mangle]
pub extern "C" fn free_camera(ptr: *mut Camera) {
    let box_ptr: Box<Camera> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_db_loader(ptr: *mut DBLoader) {
    let box_ptr: Box<DBLoader> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_display(ptr: *mut GlutinFacade) {
    let box_ptr: Box<GlutinFacade> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_renderer(ptr: *mut Renderer) {
    let box_ptr: Box<Renderer> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_shader(ptr: *mut glium::program::Program) {
    let box_ptr: Box<glium::program::Program> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn get_shader_from_db_loader(shader_name_cstr: *const c_char,
                                            dbloader: &DBLoader,
                                            renderer: &Renderer,
                                            display: &GlutinFacade)
                                            -> Box<glium::program::Program> {
    unsafe {
        let shader_name: String = CStr::from_ptr(shader_name_cstr).to_string_lossy().into_owned();
        let shader_program = renderer.create_shader_program(&shader_name, dbloader, display);
        return Box::new(shader_program);
    }
}

#[repr(C)]
pub struct Mouse {
    pub dx: i32,
    pub dy: i32,
    pub last_x: i32,
    pub last_y: i32,
    pub left_button_pressed: bool,
    pub right_button_pressed: bool,
}

#[repr(C)]
pub struct Input {
    pub mouse: Mouse,
    pub closed: bool,
}

#[no_mangle]
pub unsafe extern "C" fn poll_event(display: &GlutinFacade) -> Input {
	// The margin from the edge of the screen to allow before
	// mouse cursor is moved to center

	static mut mouse_last_x: i32 = 0;
	static mut mouse_last_y: i32 = 0;
	static mut _mouse_dx: i32 = 0;
	static mut _mouse_dy: i32 = 0;
	static mut left_button_pressed: bool = false;
	static mut right_button_pressed: bool = false;

    // Get the screen width and height in pixels
    let pixel_dimensions: (u32, u32) = match display.get_window() {
        Some(window) => window.get_inner_size_pixels().unwrap(),
        None => {
            panic!("Error retrieving window when querying display size.");
        }
    };
    let screen_width: u32 = pixel_dimensions.0;
    let screen_height: u32 = pixel_dimensions.1;

    let screen_center_x: i32 = (screen_width / 2) as i32;
    let screen_center_y: i32 = (screen_height / 2) as i32;

    let mouse_grab_margin: i32 = screen_center_y / 2;

    let mut closed = false;

    for event in display.poll_events() {
        match event {
        	Event::Closed => closed = true,
            Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Escape)) => {
                closed = true
            }
            Event::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                left_button_pressed = true;
            }
            Event::MouseInput(ElementState::Released, MouseButton::Left) => {
                left_button_pressed = false;
            }
            Event::MouseInput(ElementState::Pressed, MouseButton::Right) => {
                right_button_pressed = true;
            }
            Event::MouseInput(ElementState::Released, MouseButton::Right) => {
                right_button_pressed = false;
            }
            Event::MouseMoved(x, y) => {
                _mouse_dx = mouse_last_x - x;
                _mouse_dy = mouse_last_y - y;
                mouse_last_x = x;
		        mouse_last_y = y;
                if left_button_pressed {
                    if x + mouse_grab_margin >= screen_width as i32 || x <= mouse_grab_margin {
                        let _ =
                            display.get_window().unwrap().set_cursor_position(screen_center_x, y);
                            _mouse_dx = 0;
                            mouse_last_x = screen_center_x;
                    } else if y + mouse_grab_margin >= screen_height as i32 || y <= mouse_grab_margin {
                        let _ =
                            display.get_window().unwrap().set_cursor_position(x, screen_center_y);
                            _mouse_dy = 0;
                            mouse_last_y = screen_center_y;
                    }
                }
            }
            _ => ()
        }
    }
    Input {
	    mouse: Mouse {
	        dx: _mouse_dx,
	        dy: _mouse_dy,
	        last_x: mouse_last_x,
	        last_y: mouse_last_y,
	        left_button_pressed: left_button_pressed,
	        right_button_pressed: right_button_pressed,
	    },
	    closed: closed,
    }
}

#[no_mangle]
pub extern "C" fn render(renderer: &Renderer,
                         shader_program: &glium::program::Program,
                         camera: &Camera,
                         display: &GlutinFacade) {
    renderer.render(display, shader_program, camera);
}

#[cfg(test)]
mod tests {
    use glium::glutin;
    use glium::backend::glutin_backend::GlutinFacade;
    use glium::DisplayBuild;
    use loader;
    use common::Scene;

    fn create_test_display() -> GlutinFacade {
        let display = glutin::WindowBuilder::new()
            .with_visibility(false)
            .with_gl_debug_flag(true)
            .build_glium()
            .unwrap();
        return display;
    }

    fn load_test_scene() -> Scene {
        let dbloader: loader::DBLoader = loader::DBLoader::new("test.db");
        return dbloader.load_scene();
    }

    #[test]
    fn loader_load_db_not_empty() {
        println!("Running loader_load_db_not_empty test");
        let scene: Scene = load_test_scene();
        assert!(scene.meshes.len() > 0);
        assert!(scene.materials.len() > 0);
    }

}
<commit_msg>Moved comment/adjusted whitespace<commit_after>// Copyright(C) 2016 Chris Liebert
#![crate_type = "dylib"]
#![crate_name = "quick3d"]
#![allow(dead_code)]
#[macro_use]
extern crate glium;

pub mod common;

pub mod loader;
#[macro_use]
pub mod renderer;

extern crate nalgebra;
extern crate libc;

use std::ffi::CStr;
use std::os::raw::c_char;

use glium::glutin;
use glium::glutin::{ElementState, Event, MouseButton, VirtualKeyCode};
use glium::DisplayBuild;
use glium::backend::glutin_backend::GlutinFacade;

use common::Camera;
use loader::DBLoader;
use renderer::Renderer;

#[no_mangle]
pub extern "C" fn camera_aim(camera: &Camera, x: libc::c_double, y: libc::c_double) {
	camera.aim(x as f64, y as f64);
}

#[no_mangle]
pub extern "C" fn camera_move_forward(camera: &Camera, amount: libc::c_float) {
	camera.move_forward(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_move_backward(camera: &Camera, amount: libc::c_float) {
	camera.move_backward(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_move_left(camera: &Camera, amount: libc::c_float) {
	camera.move_left(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_move_right(camera: &Camera, amount: libc::c_float) {
	camera.move_right(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_update(camera: &Camera) {
	camera.update();
}

#[no_mangle]
pub extern "C" fn create_camera(screen_width: f32, screen_height: f32) -> Box<Camera> {
    Box::new(Camera::new(screen_width, screen_height))
}

#[no_mangle]
pub extern "C" fn create_db_loader(filename_cstr: *const c_char) -> Box<DBLoader> {
    unsafe {
        let filename: String = CStr::from_ptr(filename_cstr).to_string_lossy().into_owned();
        let dbloader: DBLoader = DBLoader::new(&filename);
        println!("Loaded {}", &filename);
        Box::new(dbloader)
    }
}

#[no_mangle]
pub extern "C" fn create_display(screen_width: libc::int32_t,
                                 screen_height: libc::int32_t,
                                 title: *const c_char)
                                 -> Box<GlutinFacade> {
    let w: u32 = screen_width as u32;
    let h: u32 = screen_height as u32;
    let window_title: String;

    unsafe {
        window_title = CStr::from_ptr(title).to_string_lossy().into_owned();
        let display: GlutinFacade = glutin::WindowBuilder::new()
	        //.resizable()
	        //.with_vsync()
	        .with_gl_debug_flag(true)
	        .with_title(window_title)
	        .with_visibility(true)
	        .with_dimensions(w, h)
	        .build_glium()
	        .unwrap();
        return Box::new(display);
    }
}

#[no_mangle]
pub extern "C" fn create_renderer_from_db_loader(dbloader: &DBLoader,
                                                 display: &GlutinFacade)
                                                 -> Box<Renderer> {
    Box::new(renderer::Renderer::new(display, dbloader.load_scene()))
}

#[no_mangle]
pub extern "C" fn free_camera(ptr: *mut Camera) {
    let box_ptr: Box<Camera> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_db_loader(ptr: *mut DBLoader) {
    let box_ptr: Box<DBLoader> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_display(ptr: *mut GlutinFacade) {
    let box_ptr: Box<GlutinFacade> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_renderer(ptr: *mut Renderer) {
    let box_ptr: Box<Renderer> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_shader(ptr: *mut glium::program::Program) {
    let box_ptr: Box<glium::program::Program> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn get_shader_from_db_loader(shader_name_cstr: *const c_char,
                                            dbloader: &DBLoader,
                                            renderer: &Renderer,
                                            display: &GlutinFacade)
                                            -> Box<glium::program::Program> {
    unsafe {
        let shader_name: String = CStr::from_ptr(shader_name_cstr).to_string_lossy().into_owned();
        let shader_program = renderer.create_shader_program(&shader_name, dbloader, display);
        return Box::new(shader_program);
    }
}

#[repr(C)]
pub struct Mouse {
    pub dx: i32,
    pub dy: i32,
    pub last_x: i32,
    pub last_y: i32,
    pub left_button_pressed: bool,
    pub right_button_pressed: bool,
}

#[repr(C)]
pub struct Input {
    pub mouse: Mouse,
    pub closed: bool,
}

#[no_mangle]
pub unsafe extern "C" fn poll_event(display: &GlutinFacade) -> Input {
	static mut mouse_last_x: i32 = 0;
	static mut mouse_last_y: i32 = 0;
	static mut _mouse_dx: i32 = 0;
	static mut _mouse_dy: i32 = 0;
	static mut left_button_pressed: bool = false;
	static mut right_button_pressed: bool = false;

    // Get the screen width and height in pixels
    let pixel_dimensions: (u32, u32) = match display.get_window() {
        Some(window) => window.get_inner_size_pixels().unwrap(),
        None => {
            panic!("Error retrieving window when querying display size.");
        }
    };
    let screen_width: u32 = pixel_dimensions.0;
    let screen_height: u32 = pixel_dimensions.1;
    let screen_center_x: i32 = (screen_width / 2) as i32;
    let screen_center_y: i32 = (screen_height / 2) as i32;

    // The margin from the edge of the screen to allow before
	// mouse cursor is moved to center

    let mouse_grab_margin: i32 = screen_center_y / 2;

    let mut closed = false;

    for event in display.poll_events() {
        match event {
        	Event::Closed => closed = true,
            Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Escape)) => {
                closed = true
            }
            Event::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                left_button_pressed = true;
            }
            Event::MouseInput(ElementState::Released, MouseButton::Left) => {
                left_button_pressed = false;
            }
            Event::MouseInput(ElementState::Pressed, MouseButton::Right) => {
                right_button_pressed = true;
            }
            Event::MouseInput(ElementState::Released, MouseButton::Right) => {
                right_button_pressed = false;
            }
            Event::MouseMoved(x, y) => {
                _mouse_dx = mouse_last_x - x;
                _mouse_dy = mouse_last_y - y;
                mouse_last_x = x;
		        mouse_last_y = y;
                if left_button_pressed {
                    if x + mouse_grab_margin >= screen_width as i32 || x <= mouse_grab_margin {
                        let _ =
                            display.get_window().unwrap().set_cursor_position(screen_center_x, y);
                            _mouse_dx = 0;
                            mouse_last_x = screen_center_x;
                    } else if y + mouse_grab_margin >= screen_height as i32 || y <= mouse_grab_margin {
                        let _ =
                            display.get_window().unwrap().set_cursor_position(x, screen_center_y);
                            _mouse_dy = 0;
                            mouse_last_y = screen_center_y;
                    }
                }
            }
            _ => ()
        }
    }
    Input {
	    mouse: Mouse {
	        dx: _mouse_dx,
	        dy: _mouse_dy,
	        last_x: mouse_last_x,
	        last_y: mouse_last_y,
	        left_button_pressed: left_button_pressed,
	        right_button_pressed: right_button_pressed,
	    },
	    closed: closed,
    }
}

#[no_mangle]
pub extern "C" fn render(renderer: &Renderer,
                         shader_program: &glium::program::Program,
                         camera: &Camera,
                         display: &GlutinFacade) {
    renderer.render(display, shader_program, camera);
}

#[cfg(test)]
mod tests {
    use glium::glutin;
    use glium::backend::glutin_backend::GlutinFacade;
    use glium::DisplayBuild;
    use loader;
    use common::Scene;

    fn create_test_display() -> GlutinFacade {
        let display = glutin::WindowBuilder::new()
            .with_visibility(false)
            .with_gl_debug_flag(true)
            .build_glium()
            .unwrap();
        return display;
    }

    fn load_test_scene() -> Scene {
        let dbloader: loader::DBLoader = loader::DBLoader::new("test.db");
        return dbloader.load_scene();
    }

    #[test]
    fn loader_load_db_not_empty() {
        println!("Running loader_load_db_not_empty test");
        let scene: Scene = load_test_scene();
        assert!(scene.meshes.len() > 0);
        assert!(scene.materials.len() > 0);
    }

}
<|endoftext|>