<commit_before>#![feature(phase)]

extern crate fuse;
#[phase(plugin)]
extern crate json_macros;
extern crate time;
extern crate libc;
extern crate serialize;

use std::collections::TreeMap;
use std::io::{FileType, USER_FILE, USER_DIR};
use std::mem;
use std::os;
use libc::{ENOENT};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyEntry, ReplyDirectory};
use serialize::json;

struct JsonFilesystem {
    tree: json::Object,
    attrs: TreeMap<u64, FileAttr>,
    inodes: TreeMap<String, u64>,
}

impl JsonFilesystem {
    fn new(tree: &json::Object) -> JsonFilesystem {
        let mut attrs = TreeMap::new();
        let mut inodes = TreeMap::new();
        let mut attr: FileAttr = unsafe { mem::zeroed() };
        attr.ino = 1;
        attr.kind = FileType::Directory;
        attr.perm = USER_DIR;
        attrs.insert(1, attr);
        inodes.insert("/".to_string(), 1);
        for (i, key) in tree.keys().enumerate() {
            let mut attr: FileAttr = unsafe { mem::zeroed() };
            attr.ino = i as u64 + 2;
            attr.kind = FileType::RegularFile;
            attr.perm = USER_FILE;
            attrs.insert(attr.ino, attr);
            inodes.insert(key.clone(), attr.ino);
        }
        JsonFilesystem { tree: tree.clone(), attrs: attrs, inodes: inodes }
    }
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(ino={})", ino);
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT),
        };
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &PosixPath, reply: ReplyEntry) {
        println!("lookup(parent={}, name={})", parent, name.display());
        let inode = match self.inodes.get(name.as_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            },
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };

    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (i, key) in self.tree.keys().enumerate() {
                    let inode: u64 = 2 + i as u64;
                    let offset: u64 = 2 + i as u64;
                    println!("\tkey={}, inode={}, offset={}", key, inode, offset);
                    reply.add(inode, offset, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (day N)");
    let data = json!({
        "foo": "bar",
        "answer": 42,
    });
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem::new(tree);
    let mountpoint = match os::args().as_slice() {
        [_, ref path] => Path::new(path),
        _ => {
            println!("Usage: {} <MOUNTPOINT>", os::args()[0]);
            return;
        }
    };
    fuse::mount(fs, &mountpoint, &[]);
}
<commit_msg>Updated readdir to use self.inodes<commit_after>#![feature(phase)]

extern crate fuse;
#[phase(plugin)]
extern crate json_macros;
extern crate time;
extern crate libc;
extern crate serialize;

use std::collections::TreeMap;
use std::io::{FileType, USER_FILE, USER_DIR};
use std::mem;
use std::os;
use libc::{ENOENT};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyEntry, ReplyDirectory};
use serialize::json;

struct JsonFilesystem {
    tree: json::Object,
    attrs: TreeMap<u64, FileAttr>,
    inodes: TreeMap<String, u64>,
}

impl JsonFilesystem {
    fn new(tree: &json::Object) -> JsonFilesystem {
        let mut attrs = TreeMap::new();
        let mut inodes = TreeMap::new();
        let mut attr: FileAttr = unsafe { mem::zeroed() };
        attr.ino = 1;
        attr.kind = FileType::Directory;
        attr.perm = USER_DIR;
        attrs.insert(1, attr);
        inodes.insert("/".to_string(), 1);
        for (i, key) in tree.keys().enumerate() {
            let mut attr: FileAttr = unsafe { mem::zeroed() };
            attr.ino = i as u64 + 2;
            attr.kind = FileType::RegularFile;
            attr.perm = USER_FILE;
            attrs.insert(attr.ino, attr);
            inodes.insert(key.clone(), attr.ino);
        }
        JsonFilesystem { tree: tree.clone(), attrs: attrs, inodes: inodes }
    }
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(ino={})", ino);
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT),
        };
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &PosixPath, reply: ReplyEntry) {
        println!("lookup(parent={}, name={})", parent, name.display());
        let inode = match self.inodes.get(name.as_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            },
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };

    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (key, &inode) in self.inodes.iter() {
                    if inode == 1 { continue; }
                    let offset = inode; // hack
                    println!("\tkey={}, inode={}, offset={}", key, inode, offset);
                    reply.add(inode, offset, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (day N)");
    let data = json!({
        "foo": "bar",
        "answer": 42,
    });
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem::new(tree);
    let mountpoint = match os::args().as_slice() {
        [_, ref path] => Path::new(path),
        _ => {
            println!("Usage: {} <MOUNTPOINT>", os::args()[0]);
            return;
        }
    };
    fuse::mount(fs, &mountpoint, &[]);
}
<|endoftext|>


<commit_before>use std;
use types::*;
use serde_json;

pub fn escape_single_quote(s: &str) -> String {
    s.replace("'", "''")
}

#[test]
fn test_escape_single_quote() {
    assert_eq!(escape_single_quote("my' precious"), "my'' precious");
}

pub fn get_rootPath<'a>(path: &'a Path, languageId: &str, rootMarkers: &Option<RootMarkers>) -> Result<&'a Path> {
    if let Some(ref rootMarkers) = *rootMarkers {
        let empty = vec![];
        let rootMarkers = match *rootMarkers {
            RootMarkers::Array(ref arr) => arr,
            RootMarkers::Map(ref map) => map.get(languageId).unwrap_or(&empty),
        };

        for marker in rootMarkers {
            let ret = traverse_up(path, |dir| {
                let p = dir.join(marker);
                let p = p.to_str();
                if p.is_none() {
                    return false;
                }
                let p = p.unwrap_or_default();
                match glob::glob(p) {
                    Ok(paths) => paths.count() > 0,
                    _ => false,
                }
            });

            if ret.is_ok() {
                return ret;
            }
        }
    }

    match languageId {
        "rust" => traverse_up(path, |dir| dir.join("Cargo.toml").exists()),
        "php" => traverse_up(path, |dir| dir.join("composer.json").exists()),
        "javascript" | "typescript" => traverse_up(path, |dir| dir.join("package.json").exists()),
        "python" => traverse_up(path, |dir| {
            dir.join("__init__.py").exists() || dir.join("setup.py").exists()
        }),
        "c" | "cpp" => traverse_up(path, |dir| dir.join("compile_commands.json").exists()),
        "cs" => traverse_up(path, is_dotnet_root),
        "java" => traverse_up(path, |dir| {
            dir.join(".project").exists() || dir.join("pom.xml").exists()
        }),
        "haskell" => traverse_up(path, |dir| dir.join("stack.yaml").exists())
            .or_else(|_| traverse_up(path, |dir| dir.join(".cabal").exists())),
        _ => Err(format_err!("Unknown languageId: {}", languageId)),
    }.or_else(|_| {
        traverse_up(path, |dir| {
            dir.join(".git").exists() || dir.join(".hg").exists() || dir.join(".svn").exists()
        })
    })
        .or_else(|_| {
            let parent = path.parent()
                .ok_or_else(|| format_err!("Failed to get file dir"));
            warn!(
                "Unknown project type. Fallback to use dir as project root: {:?}",
                parent
            );
            parent
        })
}

fn traverse_up<F>(path: &Path, predicate: F) -> Result<&Path>
where
    F: Fn(&Path) -> bool,
{
    if predicate(path) {
        return Ok(path);
    }

    let next_path = path.parent().ok_or_else(|| format_err!("Hit root"))?;

    traverse_up(next_path, predicate)
}

fn is_dotnet_root(dir: &Path) -> bool {
    if dir.join("project.json").exists() {
        return true;
    }
    if !dir.is_dir() {
        return false;
    }

    let entries = match dir.read_dir() {
        Ok(entries) => entries,
        Err(_) => return false,
    };
    for entry in entries {
        if let Ok(entry) = entry {
            if entry.path().ends_with(".csproj") {
                return true;
            }
        }
    }

    false
}

pub trait ToUrl {
    fn to_url(&self) -> Result<Url>;
}

impl<P: AsRef<Path> + std::fmt::Debug> ToUrl for P {
    fn to_url(&self) -> Result<Url> {
        Url::from_file_path(self).or_else(|_| {
            Err(format_err!(
                "Failed to convert from path ({:?}) to Url",
                self
            ))
        })
    }
}

pub fn get_logpath() -> PathBuf {
    let dir = env::var("TMP")
        .or_else(|_| env::var("TEMP"))
        .unwrap_or_else(|_| "/tmp".to_owned());

    Path::new(&dir).join("LanguageClient.log")
}

pub fn get_logpath_server() -> PathBuf {
    let dir = env::var("TMP")
        .or_else(|_| env::var("TEMP"))
        .unwrap_or_else(|_| "/tmp".to_owned());

    Path::new(&dir).join("LanguageServer.log")
}

pub fn get_log_server() -> Result<String> {
    let mut f = std::fs::OpenOptions::new()
        .read(true)
        .open(get_logpath_server())?;
    let mut buffer = String::new();
    f.read_to_string(&mut buffer)?;
    Ok(buffer)
}

pub trait Strip {
    fn strip(&self) -> Self;
}

impl<'a> Strip for &'a str {
    fn strip(&self) -> Self {
        self.trim().trim_matches(|c| c == '\r' || c == '\n')
    }
}

impl Strip for String {
    fn strip(&self) -> Self {
        self.as_str().strip().to_owned()
    }
}

pub fn apply_TextEdits(lines: &[String], edits: &[TextEdit]) -> Result<Vec<String>> {
    // Edits are ordered from bottom to top, from right to left.
    let mut edits_by_index = vec![];
    for edit in edits {
        let start_line = edit.range.start.line.to_usize()?;
        let start_character: usize = edit.range.start.character.to_usize()?;
        let end_line: usize = edit.range.end.line.to_usize()?;
        let end_character: usize = edit.range.end.character.to_usize()?;

        let start = lines[..start_line]
            .iter()
            .map(|l| l.len())
            .fold(0, |acc, l| acc + l + 1 /*line ending*/) + start_character;
        let end = lines[..end_line]
            .iter()
            .map(|l| l.len())
            .fold(0, |acc, l| acc + l + 1 /*line ending*/) + end_character;

        edits_by_index.push((start, end, &edit.new_text));
    }

    let mut text = lines.join("\n");
    for (start, end, new_text) in edits_by_index {
        text = String::new() + &text[..start] + new_text + &text[end..];
    }

    Ok(text.split('\n').map(|l| l.to_owned()).collect())
}

#[test]
fn test_apply_TextEdit() {
    let lines: Vec<String> = r#"fn main() {
0;
}
"#.split('\n')
        .map(|l| l.to_owned())
        .collect();

    let expect: Vec<String> = r#"fn main() {
    0;
}
"#.split('\n')
        .map(|l| l.to_owned())
        .collect();

    let edit = TextEdit {
        range: Range {
            start: Position {
                line: 0,
                character: 0,
            },
            end: Position {
                line: 3,
                character: 0,
            },
        },
        new_text: r#"fn main() {
    0;
}
"#.to_owned(),
    };

    assert_eq!(apply_TextEdits(&lines, &[edit]).unwrap(), expect);
}

fn get_command_add_sign(sign: &Sign, filename: &str) -> String {
    format!(
        " | execute 'sign place {} line={} name=LanguageClient{:?} file={}'",
        sign.id, sign.line, sign.severity, filename
    )
}

#[test]
fn test_get_command_add_sign() {
    let sign = Sign::new(1, DiagnosticSeverity::Error);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75000 line=1 name=LanguageClientError file='"
    );

    let sign = Sign::new(7, DiagnosticSeverity::Error);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75024 line=7 name=LanguageClientError file='"
    );

    let sign = Sign::new(7, DiagnosticSeverity::Hint);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75027 line=7 name=LanguageClientHint file='"
    );
}

fn get_command_delete_sign(sign: &Sign, filename: &str) -> String {
    format!(" | execute 'sign unplace {} file={}'", sign.id, filename)
}

#[test]
fn test_get_command_delete_sign() {}

use diff;

pub fn get_command_update_signs(signs_prev: &[Sign], signs: &[Sign], filename: &str) -> String {
    let mut cmd = "echo".to_owned();
    for comp in diff::slice(signs_prev, signs) {
        match comp {
            diff::Result::Left(sign) => {
                cmd += &get_command_delete_sign(sign, filename);
            }
            diff::Result::Right(sign) => {
                cmd += &get_command_add_sign(sign, filename);
            }
            diff::Result::Both(_, _) => (),
        }
    }

    cmd
}

#[test]
fn test_get_command_update_signs() {}

pub trait Merge {
    fn merge(&mut self, other: Self) -> ();
}

impl<K, V> Merge for HashMap<K, V>
where
    K: std::cmp::Eq + std::hash::Hash,
{
    fn merge(&mut self, other: Self) -> () {
        for (k, v) in other {
            self.insert(k, v);
        }
    }
}

pub trait Combine {
    fn combine(self, other: Self) -> Self
    where
        Self: Sized;
}

impl Combine for Value {
    fn combine(self, other: Self) -> Self {
        match (self, other) {
            (this, Value::Null) => this,
            (Value::Object(this), Value::Object(other)) => {
                let mut map = serde_json::map::Map::new();
                let mut keys: HashSet<String> = HashSet::new();
                for k in this.keys() {
                    keys.insert(k.clone());
                }
                for k in other.keys() {
                    keys.insert(k.clone());
                }
                for k in keys.drain() {
                    let v1 = this.get(&k).unwrap_or(&Value::Null).clone();
                    let v2 = other.get(&k).unwrap_or(&Value::Null).clone();
                    map.insert(k, v1.combine(v2));
                }
                Value::Object(map)
            }
            (_, other) => other,
        }
    }
}

pub fn vim_cmd_args_to_value(args: &[String]) -> Result<Value> {
    let mut map = serde_json::map::Map::new();
    for arg in args {
        let mut tokens: Vec<_> = arg.splitn(2, '=').collect();
        tokens.reverse();
        let key = tokens
            .pop()
            .ok_or_else(|| format_err!("Failed to parse command arguments."))?;
        let value = tokens
            .pop()
            .ok_or_else(|| format_err!("Failed to parse command arguments."))?;
        let value = Value::String(value.to_owned());
        map.insert(key.to_owned(), value);
    }

    Ok(Value::Object(map))
}

#[test]
fn test_vim_cmd_args_to_value() {
    let cmdargs = ["rootPath=/tmp".to_owned()];
    assert_eq!(
        vim_cmd_args_to_value(&cmdargs).unwrap(),
        json!({
        "rootPath": "/tmp"
    })
    );
}

pub fn diff_value<'a>(v1: &'a Value, v2: &'a Value, path: &str) -> HashMap<String, (Value, Value)> {
    let mut diffs = HashMap::new();
    match (v1, v2) {
        (&Value::Null, &Value::Null)
        | (&Value::Bool(_), &Value::Bool(_))
        | (&Value::Number(_), &Value::Number(_))
        | (&Value::String(_), &Value::String(_))
        | (&Value::Array(_), &Value::Array(_)) => if v1 != v2 {
            diffs.insert(path.to_owned(), (v1.clone(), v2.clone()));
        },
        (&Value::Object(ref map1), &Value::Object(ref map2)) => {
            let keys1: HashSet<&String> = map1.keys().collect();
            let keys2: HashSet<&String> = map2.keys().collect();
            for k in keys1.union(&keys2) {
                let mut next_path = String::from(path);
                next_path += ".";
                next_path += k;
                let next_diffs = diff_value(
                    map1.get(*k).unwrap_or(&Value::Null),
                    map2.get(*k).unwrap_or(&Value::Null),
                    &next_path,
                );
                diffs.merge(next_diffs);
            }
        }
        _ => {
            diffs.insert(path.to_owned(), (v1.clone(), v2.clone()));
        }
    }

    diffs
}

#[test]
fn test_diff_value() {
    assert_eq!(diff_value(&json!({}), &json!({}), "state",), hashmap!());
    assert_eq!(
        diff_value(
            &json!({
                "line": 1,
            }),
            &json!({
                "line": 3,
            }),
            "state"
        ),
        hashmap!{
            "state.line".to_owned() => (json!(1), json!(3)),
        }
    );
}

pub trait Canonicalize {
    fn canonicalize(&self) -> String;
}

impl<P> Canonicalize for P
where
    P: AsRef<Path>,
{
    fn canonicalize(&self) -> String {
        if let Ok(fc) = std::fs::canonicalize(self) {
            if let Some(fs) = fc.to_str() {
                return fs.to_owned();
            }
        }

        self.as_ref()
            .to_str()
            .map(|s| s.to_owned())
            .unwrap_or_default()
    }
}
<commit_msg>Added Scala support<commit_after>use std;
use types::*;
use serde_json;

pub fn escape_single_quote(s: &str) -> String {
    s.replace("'", "''")
}

#[test]
fn test_escape_single_quote() {
    assert_eq!(escape_single_quote("my' precious"), "my'' precious");
}

pub fn get_rootPath<'a>(path: &'a Path, languageId: &str, rootMarkers: &Option<RootMarkers>) -> Result<&'a Path> {
    if let Some(ref rootMarkers) = *rootMarkers {
        let empty = vec![];
        let rootMarkers = match *rootMarkers {
            RootMarkers::Array(ref arr) => arr,
            RootMarkers::Map(ref map) => map.get(languageId).unwrap_or(&empty),
        };

        for marker in rootMarkers {
            let ret = traverse_up(path, |dir| {
                let p = dir.join(marker);
                let p = p.to_str();
                if p.is_none() {
                    return false;
                }
                let p = p.unwrap_or_default();
                match glob::glob(p) {
                    Ok(paths) => paths.count() > 0,
                    _ => false,
                }
            });

            if ret.is_ok() {
                return ret;
            }
        }
    }

    match languageId {
        "rust" => traverse_up(path, |dir| dir.join("Cargo.toml").exists()),
        "php" => traverse_up(path, |dir| dir.join("composer.json").exists()),
        "javascript" | "typescript" => traverse_up(path, |dir| dir.join("package.json").exists()),
        "python" => traverse_up(path, |dir| {
            dir.join("__init__.py").exists() || dir.join("setup.py").exists()
        }),
        "c" | "cpp" => traverse_up(path, |dir| dir.join("compile_commands.json").exists()),
        "cs" => traverse_up(path, is_dotnet_root),
        "java" => traverse_up(path, |dir| {
            dir.join(".project").exists() || dir.join("pom.xml").exists()
        }),
        "scala" => traverse_up(path, |dir| dir.join("build.sbt").exists()),
        "haskell" => traverse_up(path, |dir| dir.join("stack.yaml").exists())
            .or_else(|_| traverse_up(path, |dir| dir.join(".cabal").exists())),
        _ => Err(format_err!("Unknown languageId: {}", languageId)),
    }.or_else(|_| {
        traverse_up(path, |dir| {
            dir.join(".git").exists() || dir.join(".hg").exists() || dir.join(".svn").exists()
        })
    })
        .or_else(|_| {
            let parent = path.parent()
                .ok_or_else(|| format_err!("Failed to get file dir"));
            warn!(
                "Unknown project type. Fallback to use dir as project root: {:?}",
                parent
            );
            parent
        })
}

fn traverse_up<F>(path: &Path, predicate: F) -> Result<&Path>
where
    F: Fn(&Path) -> bool,
{
    if predicate(path) {
        return Ok(path);
    }

    let next_path = path.parent().ok_or_else(|| format_err!("Hit root"))?;

    traverse_up(next_path, predicate)
}

fn is_dotnet_root(dir: &Path) -> bool {
    if dir.join("project.json").exists() {
        return true;
    }
    if !dir.is_dir() {
        return false;
    }

    let entries = match dir.read_dir() {
        Ok(entries) => entries,
        Err(_) => return false,
    };
    for entry in entries {
        if let Ok(entry) = entry {
            if entry.path().ends_with(".csproj") {
                return true;
            }
        }
    }

    false
}

pub trait ToUrl {
    fn to_url(&self) -> Result<Url>;
}

impl<P: AsRef<Path> + std::fmt::Debug> ToUrl for P {
    fn to_url(&self) -> Result<Url> {
        Url::from_file_path(self).or_else(|_| {
            Err(format_err!(
                "Failed to convert from path ({:?}) to Url",
                self
            ))
        })
    }
}

pub fn get_logpath() -> PathBuf {
    let dir = env::var("TMP")
        .or_else(|_| env::var("TEMP"))
        .unwrap_or_else(|_| "/tmp".to_owned());

    Path::new(&dir).join("LanguageClient.log")
}

pub fn get_logpath_server() -> PathBuf {
    let dir = env::var("TMP")
        .or_else(|_| env::var("TEMP"))
        .unwrap_or_else(|_| "/tmp".to_owned());

    Path::new(&dir).join("LanguageServer.log")
}

pub fn get_log_server() -> Result<String> {
    let mut f = std::fs::OpenOptions::new()
        .read(true)
        .open(get_logpath_server())?;
    let mut buffer = String::new();
    f.read_to_string(&mut buffer)?;
    Ok(buffer)
}

pub trait Strip {
    fn strip(&self) -> Self;
}

impl<'a> Strip for &'a str {
    fn strip(&self) -> Self {
        self.trim().trim_matches(|c| c == '\r' || c == '\n')
    }
}

impl Strip for String {
    fn strip(&self) -> Self {
        self.as_str().strip().to_owned()
    }
}

pub fn apply_TextEdits(lines: &[String], edits: &[TextEdit]) -> Result<Vec<String>> {
    // Edits are ordered from bottom to top, from right to left.
    let mut edits_by_index = vec![];
    for edit in edits {
        let start_line = edit.range.start.line.to_usize()?;
        let start_character: usize = edit.range.start.character.to_usize()?;
        let end_line: usize = edit.range.end.line.to_usize()?;
        let end_character: usize = edit.range.end.character.to_usize()?;

        let start = lines[..start_line]
            .iter()
            .map(|l| l.len())
            .fold(0, |acc, l| acc + l + 1 /*line ending*/) + start_character;
        let end = lines[..end_line]
            .iter()
            .map(|l| l.len())
            .fold(0, |acc, l| acc + l + 1 /*line ending*/) + end_character;

        edits_by_index.push((start, end, &edit.new_text));
    }

    let mut text = lines.join("\n");
    for (start, end, new_text) in edits_by_index {
        text = String::new() + &text[..start] + new_text + &text[end..];
    }

    Ok(text.split('\n').map(|l| l.to_owned()).collect())
}

#[test]
fn test_apply_TextEdit() {
    let lines: Vec<String> = r#"fn main() {
0;
}
"#.split('\n')
        .map(|l| l.to_owned())
        .collect();

    let expect: Vec<String> = r#"fn main() {
    0;
}
"#.split('\n')
        .map(|l| l.to_owned())
        .collect();

    let edit = TextEdit {
        range: Range {
            start: Position {
                line: 0,
                character: 0,
            },
            end: Position {
                line: 3,
                character: 0,
            },
        },
        new_text: r#"fn main() {
    0;
}
"#.to_owned(),
    };

    assert_eq!(apply_TextEdits(&lines, &[edit]).unwrap(), expect);
}

fn get_command_add_sign(sign: &Sign, filename: &str) -> String {
    format!(
        " | execute 'sign place {} line={} name=LanguageClient{:?} file={}'",
        sign.id, sign.line, sign.severity, filename
    )
}

#[test]
fn test_get_command_add_sign() {
    let sign = Sign::new(1, DiagnosticSeverity::Error);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75000 line=1 name=LanguageClientError file='"
    );

    let sign = Sign::new(7, DiagnosticSeverity::Error);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75024 line=7 name=LanguageClientError file='"
    );

    let sign = Sign::new(7, DiagnosticSeverity::Hint);
    assert_eq!(
        get_command_add_sign(&sign, ""),
        " | execute 'sign place 75027 line=7 name=LanguageClientHint file='"
    );
}

fn get_command_delete_sign(sign: &Sign, filename: &str) -> String {
    format!(" | execute 'sign unplace {} file={}'", sign.id, filename)
}

#[test]
fn test_get_command_delete_sign() {}

use diff;

pub fn get_command_update_signs(signs_prev: &[Sign], signs: &[Sign], filename: &str) -> String {
    let mut cmd = "echo".to_owned();
    for comp in diff::slice(signs_prev, signs) {
        match comp {
            diff::Result::Left(sign) => {
                cmd += &get_command_delete_sign(sign, filename);
            }
            diff::Result::Right(sign) => {
                cmd += &get_command_add_sign(sign, filename);
            }
            diff::Result::Both(_, _) => (),
        }
    }

    cmd
}

#[test]
fn test_get_command_update_signs() {}

pub trait Merge {
    fn merge(&mut self, other: Self) -> ();
}

impl<K, V> Merge for HashMap<K, V>
where
    K: std::cmp::Eq + std::hash::Hash,
{
    fn merge(&mut self, other: Self) -> () {
        for (k, v) in other {
            self.insert(k, v);
        }
    }
}

pub trait Combine {
    fn combine(self, other: Self) -> Self
    where
        Self: Sized;
}

impl Combine for Value {
    fn combine(self, other: Self) -> Self {
        match (self, other) {
            (this, Value::Null) => this,
            (Value::Object(this), Value::Object(other)) => {
                let mut map = serde_json::map::Map::new();
                let mut keys: HashSet<String> = HashSet::new();
                for k in this.keys() {
                    keys.insert(k.clone());
                }
                for k in other.keys() {
                    keys.insert(k.clone());
                }
                for k in keys.drain() {
                    let v1 = this.get(&k).unwrap_or(&Value::Null).clone();
                    let v2 = other.get(&k).unwrap_or(&Value::Null).clone();
                    map.insert(k, v1.combine(v2));
                }
                Value::Object(map)
            }
            (_, other) => other,
        }
    }
}

pub fn vim_cmd_args_to_value(args: &[String]) -> Result<Value> {
    let mut map = serde_json::map::Map::new();
    for arg in args {
        let mut tokens: Vec<_> = arg.splitn(2, '=').collect();
        tokens.reverse();
        let key = tokens
            .pop()
            .ok_or_else(|| format_err!("Failed to parse command arguments."))?;
        let value = tokens
            .pop()
            .ok_or_else(|| format_err!("Failed to parse command arguments."))?;
        let value = Value::String(value.to_owned());
        map.insert(key.to_owned(), value);
    }

    Ok(Value::Object(map))
}

#[test]
fn test_vim_cmd_args_to_value() {
    let cmdargs = ["rootPath=/tmp".to_owned()];
    assert_eq!(
        vim_cmd_args_to_value(&cmdargs).unwrap(),
        json!({
        "rootPath": "/tmp"
    })
    );
}

pub fn diff_value<'a>(v1: &'a Value, v2: &'a Value, path: &str) -> HashMap<String, (Value, Value)> {
    let mut diffs = HashMap::new();
    match (v1, v2) {
        (&Value::Null, &Value::Null)
        | (&Value::Bool(_), &Value::Bool(_))
        | (&Value::Number(_), &Value::Number(_))
        | (&Value::String(_), &Value::String(_))
        | (&Value::Array(_), &Value::Array(_)) => if v1 != v2 {
            diffs.insert(path.to_owned(), (v1.clone(), v2.clone()));
        },
        (&Value::Object(ref map1), &Value::Object(ref map2)) => {
            let keys1: HashSet<&String> = map1.keys().collect();
            let keys2: HashSet<&String> = map2.keys().collect();
            for k in keys1.union(&keys2) {
                let mut next_path = String::from(path);
                next_path += ".";
                next_path += k;
                let next_diffs = diff_value(
                    map1.get(*k).unwrap_or(&Value::Null),
                    map2.get(*k).unwrap_or(&Value::Null),
                    &next_path,
                );
                diffs.merge(next_diffs);
            }
        }
        _ => {
            diffs.insert(path.to_owned(), (v1.clone(), v2.clone()));
        }
    }

    diffs
}

#[test]
fn test_diff_value() {
    assert_eq!(diff_value(&json!({}), &json!({}), "state",), hashmap!());
    assert_eq!(
        diff_value(
            &json!({
                "line": 1,
            }),
            &json!({
                "line": 3,
            }),
            "state"
        ),
        hashmap!{
            "state.line".to_owned() => (json!(1), json!(3)),
        }
    );
}

pub trait Canonicalize {
    fn canonicalize(&self) -> String;
}

impl<P> Canonicalize for P
where
    P: AsRef<Path>,
{
    fn canonicalize(&self) -> String {
        if let Ok(fc) = std::fs::canonicalize(self) {
            if let Some(fs) = fc.to_str() {
                return fs.to_owned();
            }
        }

        self.as_ref()
            .to_str()
            .map(|s| s.to_owned())
            .unwrap_or_default()
    }
}
<|endoftext|>


<commit_before>use std::{mem};

use num::{BigInt, One};
use num::bigint::{Sign};

use deserializer::{DeserializationError, DeserializationResult};

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ObjectIdentifier {
    pub parts: Vec<u32>
}

impl ObjectIdentifier {
    pub fn new(oid: Vec<u32>) -> Option<ObjectIdentifier> {
        if oid.len() < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
            return None;
        }

        return Some(ObjectIdentifier{
            parts: oid,
        });
    }
}

fn _int_length(v: i64) -> usize {
    let mut num_bytes = 1;
    let mut i = v;

    while i > 127 || i < -128 {
        num_bytes += 1;
        i >>= 8;
    }
    return num_bytes;
}

pub trait Integer {
    fn encode(&self) -> Vec<u8>;
    fn decode(Vec<u8>) -> DeserializationResult<Self>;
}

macro_rules! primitive_integer {
    ($Int:ident) => {
        impl Integer for $Int {
            fn encode(&self) -> Vec<u8> {
                let n = _int_length(*self as i64);
                let mut result = Vec::with_capacity(n);
                for i in (1..n+1).rev() {
                    result.push((self >> ((i - 1) * 8)) as u8);
                }
                return result;
            }

            fn decode(data: Vec<u8>) -> DeserializationResult<$Int> {
                if data.len() > mem::size_of::<$Int>() {
                    return Err(DeserializationError::IntegerOverflow);
                }
                let mut ret = 0;
                for b in data.iter() {
                    ret <<= 8;
                    ret |= *b as i64;
                }
                // Shift up and down in order to sign extend the result.
                ret <<= 64 - data.len() * 8;
                ret >>= 64 - data.len() * 8;
                return Ok(ret as $Int);
            }
        }
    }
}

primitive_integer!(i8);
primitive_integer!(i32);
primitive_integer!(i64);

impl Integer for BigInt {
    fn encode(&self) -> Vec<u8> {
        // TODO: allocating the bytes to get the sign is silly.
        let (sign, _) = self.to_bytes_be();
        match sign {
            Sign::Plus => {
                let (_, mut bytes) = self.to_bytes_be();
                if bytes[0] & 0x80 != 0 {
                    // If the data has a leading 0x80, pad with a zero-byte.
                    bytes.insert(0, 0);
                }
                return bytes;
            },
            Sign::NoSign => {
                return b"\x00".to_vec();
            },
            Sign::Minus => {
                // Convert negative numbers to two's-complement by subtracting one and inverting.
                let n_minus_1 = -self - BigInt::one();
                let (_, mut bytes) = n_minus_1.to_bytes_be();
                // TODO: rewrite this in-place.
                bytes = bytes.iter().map(|b| b ^ 0xff).collect();
                if bytes[0] & 0x80 == 0 {
                    bytes.insert(0, 0xff);
                }
                return bytes;
            },
        }
    }

    fn decode(data: Vec<u8>) -> DeserializationResult<BigInt> {
        panic!();
    }
}

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

    #[test]
    fn test_object_identifier_new() {
        assert!(ObjectIdentifier::new(vec![]).is_none());
        assert!(ObjectIdentifier::new(vec![3, 10]).is_none());
        assert!(ObjectIdentifier::new(vec![1, 50]).is_none());
    }
}
<commit_msg>passing tests<commit_after>use std::{mem};

use num::{BigInt, One};
use num::bigint::{Sign};

use deserializer::{DeserializationError, DeserializationResult};

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ObjectIdentifier {
    pub parts: Vec<u32>
}

impl ObjectIdentifier {
    pub fn new(oid: Vec<u32>) -> Option<ObjectIdentifier> {
        if oid.len() < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
            return None;
        }

        return Some(ObjectIdentifier{
            parts: oid,
        });
    }
}

fn _int_length(v: i64) -> usize {
    let mut num_bytes = 1;
    let mut i = v;

    while i > 127 || i < -128 {
        num_bytes += 1;
        i >>= 8;
    }
    return num_bytes;
}

pub trait Integer {
    fn encode(&self) -> Vec<u8>;
    fn decode(Vec<u8>) -> DeserializationResult<Self>;
}

macro_rules! primitive_integer {
    ($Int:ident) => {
        impl Integer for $Int {
            fn encode(&self) -> Vec<u8> {
                let n = _int_length(*self as i64);
                let mut result = Vec::with_capacity(n);
                for i in (1..n+1).rev() {
                    result.push((self >> ((i - 1) * 8)) as u8);
                }
                return result;
            }

            fn decode(data: Vec<u8>) -> DeserializationResult<$Int> {
                if data.len() > mem::size_of::<$Int>() {
                    return Err(DeserializationError::IntegerOverflow);
                }
                let mut ret = 0;
                for b in data.iter() {
                    ret <<= 8;
                    ret |= *b as i64;
                }
                // Shift up and down in order to sign extend the result.
                ret <<= 64 - data.len() * 8;
                ret >>= 64 - data.len() * 8;
                return Ok(ret as $Int);
            }
        }
    }
}

primitive_integer!(i8);
primitive_integer!(i32);
primitive_integer!(i64);

impl Integer for BigInt {
    fn encode(&self) -> Vec<u8> {
        // TODO: allocating the bytes to get the sign is silly.
        let (sign, _) = self.to_bytes_be();
        match sign {
            Sign::Plus => {
                let (_, mut bytes) = self.to_bytes_be();
                if bytes[0] & 0x80 != 0 {
                    // If the data has a leading 0x80, pad with a zero-byte.
                    bytes.insert(0, 0);
                }
                return bytes;
            },
            Sign::NoSign => {
                return b"\x00".to_vec();
            },
            Sign::Minus => {
                // Convert negative numbers to two's-complement by subtracting one and inverting.
                let n_minus_1 = -self - BigInt::one();
                let (_, mut bytes) = n_minus_1.to_bytes_be();
                // TODO: rewrite this in-place.
                bytes = bytes.iter().map(|b| b ^ 0xff).collect();
                if bytes[0] & 0x80 == 0 {
                    bytes.insert(0, 0xff);
                }
                return bytes;
            },
        }
    }

    fn decode(data: Vec<u8>) -> DeserializationResult<BigInt> {
        if data[0] & 0x80 == 0x80 {
            let inverse_bytes = data.iter().map(|b| !b).collect::<Vec<u8>>();
            return Ok(-(BigInt::from_bytes_be(Sign::Plus, &inverse_bytes[..]) + BigInt::one()));
        } else {
            return Ok(BigInt::from_bytes_be(Sign::Plus, &data[..]));
        }
    }
}

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

    #[test]
    fn test_object_identifier_new() {
        assert!(ObjectIdentifier::new(vec![]).is_none());
        assert!(ObjectIdentifier::new(vec![3, 10]).is_none());
        assert!(ObjectIdentifier::new(vec![1, 50]).is_none());
    }
}
<|endoftext|>


<commit_before>use common::{TagClass, TagStructure};

use std::io::Write;

use byteorder::BigEndian;
use byteorder::ByteOrder;
use byteorder::WriteBytesExt;

pub fn write_type(mut w: &mut Write, class: TagClass, structure: TagStructure, id: u64) {
    let mut extended_tag: Option<Vec<u8>> = None;

    let type_byte = {
        // First two bits: Class
        (class as u8) << 6 |
        // Bit 6: Primitive/Constructed
        (structure as u8) << 5 |
        // Bit 5-1: Tag Number
        if id > 30
        {
            let mut tagbytes: Vec<u8> = Vec::new();

            let mut tag = id;
            while tag > 0
            {
                // Only take the 7 lower bits.
                let mut byte = (tag & 0x7F) as u8;

                tag >>= 7;

                tagbytes.push(byte);
            }

            extended_tag = Some(tagbytes);

            // This means we need to set the 5 tag bits to 11111, so 31 or 0x1F
            0x1F
        }
        else
        {
            extended_tag = None;
            id as u8
        }
    }; // let type_byte

    w.write_u8(type_byte);

    let mut written = 1;

    if let Some(mut ext_bytes) = extended_tag
    {
        for _ in 0..ext_bytes.len()-1
        {
            let mut byte = ext_bytes.pop().unwrap();

            // Set the first bit
            byte |= 0x80;

            w.write_u8(byte);
        }

        let byte = ext_bytes.pop().unwrap();
        w.write_u8(byte);
    }
}

// Yes I know you could overflow the length in theory. But, do you have 2^64 bytes of memory?
pub fn write_length(mut w: &mut Write, mut length: u64) {
    // Short form
    if length < 128
    {
        w.write_u8(length as u8);
    }
    // Long form
    else
    {
        let mut count = 0u8;
        let mut len = length;
        while {count += 1; len >>= 8; len > 0 }{}

        w.write_u8(count | 0x80);
        w.write_uint::<BigEndian>(length, count as usize);
    }
}

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

    use byteorder::{BigEndian, WriteBytesExt};

    use common::{Tag, TagPrimitive, TagConstructed};
    use common::{TypeHeader, ClassT};

    #[test]
    fn encode_simple_tag() {
        let mut payload: Vec<u8> = Vec::new();
        payload.write_i16::<BigEndian>(1616);

        let tag = Tag::Primitive(TagPrimitive {
            class: ClassT::Universal,
            tag_number: 2u64,
            inner: payload,
        });

        let mut buf = Vec::<u8>::new();
        super::encode_into(&mut buf, &tag);

        assert_eq!(buf, vec![0x2, 0x2, 0x06, 0x50]);
    }

    #[test]
    fn encode_constructed_tag()
    {
        let childtag = Tag::Primitive(TagPrimitive {
            class: ClassT::Universal,
            tag_number: 12u64,
            inner: "Hello World!".to_string().into_bytes(),
        });

        let tag = Tag::Constructed(TagConstructed {
            class: ClassT::Universal,
            tag_number: 16u64,
            inner: vec![childtag],
        });

        let mut buf = Vec::<u8>::new();
        super::encode_into(&mut buf, &tag);

        assert_eq!(buf, vec![48,14,12,12,72,101,108,108,111,32,87,111,114,108,100,33]);
    }
}
<commit_msg>Adds encode_into function<commit_after>use common::{TagClass, TagStructure};
use structure::{StructureTag, PL};

use std::io;
use std::io::Write;

use byteorder::BigEndian;
use byteorder::ByteOrder;
use byteorder::WriteBytesExt;

pub fn encode_into(buf: &mut Vec<u8>, tag: StructureTag) -> io::Result<()> {
    let structure = match tag.payload {
        PL::P(_) => TagStructure::Primitive,
        PL::C(_) => TagStructure::Constructed,
    };

    write_type(buf, tag.class, structure, tag.id);
    match tag.payload {
        PL::P(v) => {
            for byte in v {
                buf.push(byte);
            }
        },
        PL::C(tags) => {
            for tag in tags {
                try!(encode_into(buf, tag));
            }
        }
    };

    Ok(())
}

pub fn write_type(mut w: &mut Write, class: TagClass, structure: TagStructure, id: u64) {
    let mut extended_tag: Option<Vec<u8>> = None;

    let type_byte = {
        // First two bits: Class
        (class as u8) << 6 |
        // Bit 6: Primitive/Constructed
        (structure as u8) << 5 |
        // Bit 5-1: Tag Number
        if id > 30
        {
            let mut tagbytes: Vec<u8> = Vec::new();

            let mut tag = id;
            while tag > 0
            {
                // Only take the 7 lower bits.
                let mut byte = (tag & 0x7F) as u8;

                tag >>= 7;

                tagbytes.push(byte);
            }

            extended_tag = Some(tagbytes);

            // This means we need to set the 5 tag bits to 11111, so 31 or 0x1F
            0x1F
        }
        else
        {
            extended_tag = None;
            id as u8
        }
    }; // let type_byte

    w.write_u8(type_byte);

    let mut written = 1;

    if let Some(mut ext_bytes) = extended_tag
    {
        for _ in 0..ext_bytes.len()-1
        {
            let mut byte = ext_bytes.pop().unwrap();

            // Set the first bit
            byte |= 0x80;

            w.write_u8(byte);
        }

        let byte = ext_bytes.pop().unwrap();
        w.write_u8(byte);
    }
}

// Yes I know you could overflow the length in theory. But, do you have 2^64 bytes of memory?
pub fn write_length(mut w: &mut Write, mut length: u64) {
    // Short form
    if length < 128
    {
        w.write_u8(length as u8);
    }
    // Long form
    else
    {
        let mut count = 0u8;
        let mut len = length;
        while {count += 1; len >>= 8; len > 0 }{}

        w.write_u8(count | 0x80);
        w.write_uint::<BigEndian>(length, count as usize);
    }
}

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

    use byteorder::{BigEndian, WriteBytesExt};

    use common::{Tag, TagPrimitive, TagConstructed};
    use common::{TypeHeader, ClassT};

    #[test]
    fn encode_simple_tag() {
        let mut payload: Vec<u8> = Vec::new();
        payload.write_i16::<BigEndian>(1616);

        let tag = Tag::Primitive(TagPrimitive {
            class: ClassT::Universal,
            tag_number: 2u64,
            inner: payload,
        });

        let mut buf = Vec::<u8>::new();
        super::encode_into(&mut buf, &tag);

        assert_eq!(buf, vec![0x2, 0x2, 0x06, 0x50]);
    }

    #[test]
    fn encode_constructed_tag()
    {
        let childtag = Tag::Primitive(TagPrimitive {
            class: ClassT::Universal,
            tag_number: 12u64,
            inner: "Hello World!".to_string().into_bytes(),
        });

        let tag = Tag::Constructed(TagConstructed {
            class: ClassT::Universal,
            tag_number: 16u64,
            inner: vec![childtag],
        });

        let mut buf = Vec::<u8>::new();
        super::encode_into(&mut buf, &tag);

        assert_eq!(buf, vec![48,14,12,12,72,101,108,108,111,32,87,111,114,108,100,33]);
    }
}
<|endoftext|>


<commit_before>use std::fmt;

#[derive(Debug)]
pub enum ErrorLevel {
    Info,
    Warning,
    Error,
}

// Use a hashmap which contains an error level and a string
pub struct ErrorStack(Vec<(ErrorLevel, &'static str)>);

impl fmt::Display for ErrorStack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0
            .iter()
            .map(|e| write!(f, "[{:?}] {}\n", e.0, e.1))

            // We must consume the closure
            .collect::<Vec<fmt::Result>>();

        write!(f, "")
    }
}<commit_msg>Move to a for-loop instead<commit_after>use std::fmt;

#[derive(Debug)]
pub enum ErrorLevel {
    Info,
    Warning,
    Error,
}

// Use a hashmap which contains an error level and a string
pub struct ErrorStack(Vec<(ErrorLevel, &'static str)>);

impl fmt::Display for ErrorStack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for error in &self.0 {
            write!(f, "[{:?}] {}\n", error.0, error.1).unwrap();
        }

        write!(f, "")
    }
}
<|endoftext|>


<commit_before>use super::geometry::*;

fn rotate(x: f32, y: f32, around_x: f32, around_y: f32, angle: f32) -> (f32, f32) {
    use std::f32;

    let s = f32::sin(angle);
    let c = f32::cos(angle);

    let x = x - around_x;
    let y = y - around_y;

    let x = x * c - y * s;
    let y = x * s + y * c;

    (x + around_x, y + around_y)
}

pub trait Rotation {
    fn rotate_x_y(&mut self, x: f32, y: f32, angle: f32);
    fn rotate_x_z(&mut self, x: f32, y: f32, angle: f32);
    fn rotate_y_z(&mut self, x: f32, y: f32, angle: f32);
}

impl Rotation for Point {
    /// Rotates on x and y axes. You shouldn't rotate a point you rotated
    /// earlier, instead keep rotating the initial one.
    /// For some reason, it breaks for some reason if you keep rotating too much
    fn rotate_x_y(&mut self, x: f32, y: f32, angle: f32) -> Point {
        let (x, y) = rotate(self.x, self.y, x, y, angle);
        Point {
            x: x,
            y: y,
            z: self.z,
        }
    }

    /// Rotate on x and z axes. Same error as with rotate_x_y
    fn rotate_x_z(&mut self, x: f32, z: f32, angle: f32) {
        let (x, z) = rotate(self.x, self.z, x, z, angle);
        self.x = x;
        self.z = z;
    }

    /// Rotate on y and z axes. Same error as with rotate_x_y
    fn rotate_y_z(&mut self, y: f32, z: f32, angle: f32) {
        let (y, z) = rotate(self.y, self.z, y, z, angle);
        self.y = y;
        self.z = z;
    }
}

impl Rotation for Triangle {
    fn rotate_x_y(&mut self, x: f32, y: f32, angle: f32) {
        self.p1.rotate_x_y(x, y, angle);
        self.p2.rotate_x_y(x, y, angle);
        self.p3.rotate_x_y(x, y, angle);
    }

    fn rotate_x_z(&mut self, x: f32, z: f32, angle: f32) {
        self.p1.rotate_x_z(x, z, angle);
        self.p2.rotate_x_z(x, z, angle);
        self.p3.rotate_x_z(x, z, angle);
    }

    fn rotate_y_z(&mut self, y: f32, z: f32, angle: f32) {
        self.p1.rotate_y_z(y, z, angle);
        self.p2.rotate_y_z(y, z, angle);
        self.p3.rotate_y_z(y, z, angle);
    }
}<commit_msg>Fix variable shadowing in rotation function<commit_after>use super::geometry::*;

fn rotate(x: f32, y: f32, around_x: f32, around_y: f32, angle: f32) -> (f32, f32) {
    use std::f32;

    let s = f32::sin(angle);
    let c = f32::cos(angle);

    let x = x - around_x;
    let y = y - around_y;

    let new_x = x * c - y * s;
    let new_y = x * s + y * c;

    (new_x + around_x, new_y + around_y)
}

pub trait Rotation {
    fn rotate_x_y(&mut self, x: f32, y: f32, angle: f32);
    fn rotate_x_z(&mut self, x: f32, y: f32, angle: f32);
    fn rotate_y_z(&mut self, x: f32, y: f32, angle: f32);
}

impl Rotation for Point {
    /// Rotates on x and y axes.
    fn rotate_x_y(&mut self, x: f32, y: f32, angle: f32) {
        let (x, y) = rotate(self.x, self.y, x, y, angle);
        self.x = x;
        self.y = y;
    }

    /// Rotate on x and z axes.
    fn rotate_x_z(&mut self, x: f32, z: f32, angle: f32) {
        let (x, z) = rotate(self.x, self.z, x, z, angle);
        self.x = x;
        self.z = z;
    }

    /// Rotate on y and z axes.
    fn rotate_y_z(&mut self, y: f32, z: f32, angle: f32) {
        let (y, z) = rotate(self.y, self.z, y, z, angle);
        self.y = y;
        self.z = z;
    }
}

impl Rotation for Triangle {
    /// Rotates on x and y axes.
    fn rotate_x_y(&mut self, x: f32, y: f32, angle: f32) {
        self.p1.rotate_x_y(x, y, angle);
        self.p2.rotate_x_y(x, y, angle);
        self.p3.rotate_x_y(x, y, angle);
    }

    /// Rotate on x and z axes.
    fn rotate_x_z(&mut self, x: f32, z: f32, angle: f32) {
        self.p1.rotate_x_z(x, z, angle);
        self.p2.rotate_x_z(x, z, angle);
        self.p3.rotate_x_z(x, z, angle);
    }

    /// Rotate on y and z axes.
    fn rotate_y_z(&mut self, y: f32, z: f32, angle: f32) {
        self.p1.rotate_y_z(y, z, angle);
        self.p2.rotate_y_z(y, z, angle);
        self.p3.rotate_y_z(y, z, angle);
    }
}<|endoftext|>


<commit_before>use database::schema::*;
use database::models::U64;

use chrono::{Utc, TimeZone, Duration};

insertable! {
  #[derive(Debug, Queryable, Identifiable)]
  pub struct Timeout,
  #[derive(Debug, Insertable)]
  #[table_name = "timeouts"]
  pub struct NewTimeout {
    pub user_id: U64,
    pub server_id: U64,
    pub role_id: U64,
    pub seconds: i32,
    pub start: i64
  }
}

impl Timeout {
  pub fn ends(&self) -> i64 {
    (Utc.timestamp(self.start as i64, 0) + Duration::seconds(i64::from(self.seconds))).timestamp()
  }
}

impl NewTimeout {
  pub fn new(user_id: u64, server_id: u64, role_id: u64, seconds: i32, start: i64) -> Self {
    NewTimeout {
      user_id: user_id.into(),
      server_id: server_id.into(),
      role_id: role_id.into(),
      seconds,
      start
    }
  }
}
<commit_msg>refactor: remove useless cast<commit_after>use database::schema::*;
use database::models::U64;

use chrono::{Utc, TimeZone, Duration};

insertable! {
  #[derive(Debug, Queryable, Identifiable)]
  pub struct Timeout,
  #[derive(Debug, Insertable)]
  #[table_name = "timeouts"]
  pub struct NewTimeout {
    pub user_id: U64,
    pub server_id: U64,
    pub role_id: U64,
    pub seconds: i32,
    pub start: i64
  }
}

impl Timeout {
  pub fn ends(&self) -> i64 {
    (Utc.timestamp(self.start, 0) + Duration::seconds(i64::from(self.seconds))).timestamp()
  }
}

impl NewTimeout {
  pub fn new(user_id: u64, server_id: u64, role_id: u64, seconds: i32, start: i64) -> Self {
    NewTimeout {
      user_id: user_id.into(),
      server_id: server_id.into(),
      role_id: role_id.into(),
      seconds,
      start
    }
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015-2017 The imgui-rs Developers
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use glium::glutin;
use glium::{Display, Surface};
use imgui::{ImGui, Ui};
use imgui_glium_renderer::Renderer;
use std::time::Instant;

#[derive(Copy, Clone, PartialEq, Debug, Default)]
struct MouseState {
    pos: (i32, i32),
    pressed: (bool, bool, bool),
    wheel: f32,
}

pub fn run<F: FnMut(&Ui, (f32, f32)) -> bool>(
    title: String,
    dimensions: (u32, u32),
    clear_color: [f32; 4],
    mut run_ui: F,
) {
    let mut events_loop = glutin::EventsLoop::new();
    let window = glutin::WindowBuilder::new()
        .with_title(title)
        .with_dimensions(dimensions.0, dimensions.1);
    let context = glutin::ContextBuilder::new().with_vsync(true);
    let display = Display::new(window, context, &events_loop).unwrap();

    let mut imgui = ImGui::init();
    let mut renderer = Renderer::init(&mut imgui, &display).expect("Failed to initialize renderer");

    imgui.set_ini_filename(None);

    configure_keys(&mut imgui);

    let mut last_frame = Instant::now();
    let mut mouse_state = MouseState::default();
    let mut quit = false;

    loop {
        events_loop.poll_events(|event| {
            use glium::glutin::ElementState::Pressed;
            use glium::glutin::WindowEvent::*;
            use glium::glutin::{Event, MouseButton, MouseScrollDelta, TouchPhase};

            if let Event::WindowEvent { event, .. } = event {
                match event {
                    Closed => quit = true,
                    KeyboardInput { input, .. } => {
                        use glium::glutin::VirtualKeyCode as Key;

                        let pressed = input.state == Pressed;
                        match input.virtual_keycode {
                            Some(Key::Tab) => imgui.set_key(0, pressed),
                            Some(Key::Left) => imgui.set_key(1, pressed),
                            Some(Key::Right) => imgui.set_key(2, pressed),
                            Some(Key::Up) => imgui.set_key(3, pressed),
                            Some(Key::Down) => imgui.set_key(4, pressed),
                            Some(Key::PageUp) => imgui.set_key(5, pressed),
                            Some(Key::PageDown) => imgui.set_key(6, pressed),
                            Some(Key::Home) => imgui.set_key(7, pressed),
                            Some(Key::End) => imgui.set_key(8, pressed),
                            Some(Key::Delete) => imgui.set_key(9, pressed),
                            Some(Key::Back) => imgui.set_key(10, pressed),
                            Some(Key::Return) => imgui.set_key(11, pressed),
                            Some(Key::Escape) => imgui.set_key(12, pressed),
                            Some(Key::A) => imgui.set_key(13, pressed),
                            Some(Key::C) => imgui.set_key(14, pressed),
                            Some(Key::V) => imgui.set_key(15, pressed),
                            Some(Key::X) => imgui.set_key(16, pressed),
                            Some(Key::Y) => imgui.set_key(17, pressed),
                            Some(Key::Z) => imgui.set_key(18, pressed),
                            Some(Key::LControl) | Some(Key::RControl) => {
                                imgui.set_key_ctrl(pressed)
                            }
                            Some(Key::LShift) | Some(Key::RShift) => imgui.set_key_shift(pressed),
                            Some(Key::LAlt) | Some(Key::RAlt) => imgui.set_key_alt(pressed),
                            Some(Key::LWin) | Some(Key::RWin) => imgui.set_key_super(pressed),
                            Some(Key::Q) => {
                                if cfg!(target_os = "macos") && input.modifiers.logo {
                                    quit = true;
                                }
                            }
                            _ => {}
                        }
                    }
                    CursorMoved {
                        position: (x, y), ..
                    } => mouse_state.pos = (x as i32, y as i32),
                    MouseInput { state, button, .. } => match button {
                        MouseButton::Left => mouse_state.pressed.0 = state == Pressed,
                        MouseButton::Right => mouse_state.pressed.1 = state == Pressed,
                        MouseButton::Middle => mouse_state.pressed.2 = state == Pressed,
                        _ => {}
                    },
                    MouseWheel {
                        delta: MouseScrollDelta::LineDelta(_, y),
                        phase: TouchPhase::Moved,
                        ..
                    }
                    | MouseWheel {
                        delta: MouseScrollDelta::PixelDelta(_, y),
                        phase: TouchPhase::Moved,
                        ..
                    } => mouse_state.wheel = y,
                    ReceivedCharacter(c) => imgui.add_input_character(c),
                    _ => (),
                }
            }
        });

        if quit {
            break;
        }

        let now = Instant::now();
        let delta = now - last_frame;
        let delta_s = delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1_000_000_000.0;
        last_frame = now;

        update_mouse(&mut imgui, &mut mouse_state);

        let gl_window = display.gl_window();
        let size_pixels = gl_window.get_inner_size().unwrap();
        let hidpi = gl_window.hidpi_factor();
        let size_points = (
            (size_pixels.0 as f32 / hidpi) as u32,
            (size_pixels.1 as f32 / hidpi) as u32,
        );

        let ui = imgui.frame(size_points, size_pixels, delta_s);
        if !run_ui(&ui, (size_points.0 as f32, size_points.1 as f32)) {
            break;
        }

        let mut target = display.draw();
        target.clear_color(
            clear_color[0],
            clear_color[1],
            clear_color[2],
            clear_color[3],
        );
        renderer.render(&mut target, ui).expect("Rendering failed");
        target.finish().unwrap();
    }
}

fn configure_keys(imgui: &mut ImGui) {
    use imgui::ImGuiKey;

    imgui.set_imgui_key(ImGuiKey::Tab, 0);
    imgui.set_imgui_key(ImGuiKey::LeftArrow, 1);
    imgui.set_imgui_key(ImGuiKey::RightArrow, 2);
    imgui.set_imgui_key(ImGuiKey::UpArrow, 3);
    imgui.set_imgui_key(ImGuiKey::DownArrow, 4);
    imgui.set_imgui_key(ImGuiKey::PageUp, 5);
    imgui.set_imgui_key(ImGuiKey::PageDown, 6);
    imgui.set_imgui_key(ImGuiKey::Home, 7);
    imgui.set_imgui_key(ImGuiKey::End, 8);
    imgui.set_imgui_key(ImGuiKey::Delete, 9);
    imgui.set_imgui_key(ImGuiKey::Backspace, 10);
    imgui.set_imgui_key(ImGuiKey::Enter, 11);
    imgui.set_imgui_key(ImGuiKey::Escape, 12);
    imgui.set_imgui_key(ImGuiKey::A, 13);
    imgui.set_imgui_key(ImGuiKey::C, 14);
    imgui.set_imgui_key(ImGuiKey::V, 15);
    imgui.set_imgui_key(ImGuiKey::X, 16);
    imgui.set_imgui_key(ImGuiKey::Y, 17);
    imgui.set_imgui_key(ImGuiKey::Z, 18);
}

fn update_mouse(imgui: &mut ImGui, mouse_state: &mut MouseState) {
    let scale = imgui.display_framebuffer_scale();
    imgui.set_mouse_pos(
        mouse_state.pos.0 as f32 / scale.0,
        mouse_state.pos.1 as f32 / scale.1,
    );
    imgui.set_mouse_down(&[
        mouse_state.pressed.0,
        mouse_state.pressed.1,
        mouse_state.pressed.2,
        false,
        false,
    ]);
    imgui.set_mouse_wheel(mouse_state.wheel / scale.1);
    mouse_state.wheel = 0.0;
}
<commit_msg>Only draw UI on mouse event, remove unused code<commit_after>/*
 * Copyright (C) 2015-2017 The imgui-rs Developers
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use std::time::{Duration, Instant};

use glium::glutin;
use glium::{Display, Surface};
use imgui::{ImGui, Ui};
use imgui_glium_renderer::Renderer;

const FRAME_DURATION: Duration = Duration::from_millis(40);

#[derive(Copy, Clone, PartialEq, Debug, Default)]
struct MouseState {
    pos: (i32, i32),
    pressed: (bool, bool, bool),
    wheel: f32,
}

pub fn run<F: FnMut(&Ui, (f32, f32)) -> bool>(
    title: String,
    dimensions: (u32, u32),
    clear_color: [f32; 4],
    mut run_ui: F,
) {
    let mut events_loop = glutin::EventsLoop::new();
    let window = glutin::WindowBuilder::new()
        .with_title(title)
        .with_dimensions(dimensions.0, dimensions.1);
    let context = glutin::ContextBuilder::new().with_vsync(true);
    let display = Display::new(window, context, &events_loop).unwrap();

    let mut imgui = ImGui::init();
    let mut renderer = Renderer::init(&mut imgui, &display).expect("Failed to initialize renderer");

    imgui.set_ini_filename(None);

    let mut last_frame = Instant::now();
    let mut mouse_state = MouseState::default();

    // Render one frame before the event loop so the screen isn't empty
    render(
        &mut imgui,
        &mut run_ui,
        &display,
        &mut renderer,
        clear_color,
        0.1,
    );

    events_loop.run_forever(|event| {
        use glium::glutin::ElementState::Pressed;
        use glium::glutin::WindowEvent::*;
        use glium::glutin::{ControlFlow, Event, MouseButton, VirtualKeyCode};

        if let Event::WindowEvent { event, .. } = event {
            match event {
                Closed => return ControlFlow::Break,
                KeyboardInput { input, .. } => {
                    if let Some(VirtualKeyCode::Q) = input.virtual_keycode {
                        if cfg!(target_os = "macos") && input.modifiers.logo {
                            return ControlFlow::Break;
                        }
                    }
                }
                CursorMoved {
                    position: (x, y), ..
                } => {
                    mouse_state.pos = (x as i32, y as i32);
                    update_mouse(&mut imgui, &mut mouse_state);

                    let now = Instant::now();
                    let delta = now - last_frame;
                    if delta < FRAME_DURATION {
                        return ControlFlow::Continue;
                    }
                    let delta_s =
                        delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1_000_000_000.0;
                    last_frame = now;

                    if !render(
                        &mut imgui,
                        &mut run_ui,
                        &display,
                        &mut renderer,
                        clear_color,
                        delta_s,
                    ) {
                        return ControlFlow::Break;
                    }
                }
                MouseInput { state, button, .. } => if MouseButton::Left == button {
                    mouse_state.pressed.0 = state == Pressed;
                    update_mouse(&mut imgui, &mut mouse_state);

                    let now = Instant::now();
                    let delta = now - last_frame;
                    let delta_s =
                        delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1_000_000_000.0;
                    last_frame = now;

                    // Render twice to immediately show the results of the click
                    if !render(
                        &mut imgui,
                        &mut run_ui,
                        &display,
                        &mut renderer,
                        clear_color,
                        delta_s,
                    ) {
                        return ControlFlow::Break;
                    }
                    if !render(
                        &mut imgui,
                        &mut run_ui,
                        &display,
                        &mut renderer,
                        clear_color,
                        delta_s,
                    ) {
                        return ControlFlow::Break;
                    }
                },
                _ => (),
            }
        }
        ControlFlow::Continue
    });
}

pub fn render<F: FnMut(&Ui, (f32, f32)) -> bool>(
    imgui: &mut ImGui,
    mut run_ui: F,
    display: &Display,
    renderer: &mut Renderer,
    clear_color: [f32; 4],
    delta_s: f32,
) -> bool {
    let gl_window = display.gl_window();
    let size_pixels = gl_window.get_inner_size().unwrap();
    let hidpi = gl_window.hidpi_factor();
    let size_points = (
        (size_pixels.0 as f32 / hidpi) as u32,
        (size_pixels.1 as f32 / hidpi) as u32,
    );

    let ui = imgui.frame(size_points, size_pixels, delta_s);
    if !run_ui(&ui, (size_points.0 as f32, size_points.1 as f32)) {
        return false;
    }

    let mut target = display.draw();
    target.clear_color(
        clear_color[0],
        clear_color[1],
        clear_color[2],
        clear_color[3],
    );
    renderer.render(&mut target, ui).expect("Rendering failed");
    target.finish().unwrap();
    true
}

fn update_mouse(imgui: &mut ImGui, mouse_state: &mut MouseState) {
    let scale = imgui.display_framebuffer_scale();
    imgui.set_mouse_pos(
        mouse_state.pos.0 as f32 / scale.0,
        mouse_state.pos.1 as f32 / scale.1,
    );
    imgui.set_mouse_down(&[
        mouse_state.pressed.0,
        mouse_state.pressed.1,
        mouse_state.pressed.2,
        false,
        false,
    ]);
    imgui.set_mouse_wheel(mouse_state.wheel / scale.1);
    mouse_state.wheel = 0.0;
}
<|endoftext|>


<commit_before>use std::rc::Rc;

use std::cmp::{max, min, Ordering};
use interpreter::{TreeInterpreter, InterpretResult};
use variable::Variable;

/// Handles the dispatching of named functions using an array of arguments.
pub trait FnDispatcher {
    /// Dispatches and interprets a function by name.
    fn call(&self, fn_name: &str, args: &Vec<Rc<Variable>>, intr: &TreeInterpreter)
        -> InterpretResult;
}

/// Validates the arity of a function.
#[inline]
fn arity(fn_name: &str, arity: usize, args: &Vec<Rc<Variable>>) -> Result<(), String> {
    if args.len() != arity {
        Err(format!("{} arity error: expected {} args, found {}", fn_name, arity, args.len()))
    } else {
        Ok(())
    }
}

/// Validates that an array contains only a single allowed type.
#[inline]
fn homogeneous_array(valid_types: Vec<&str>, array: &Vec<Rc<Variable>>) -> bool {
    let matched_type = array[0].get_type();
    if !valid_types.contains(&matched_type) {
        return false;
    }
    for a in array {
        if a.get_type() != matched_type {
            return false;
        }
    }
    return true;
}

/// Macro used to variadically validate validate Variable and argument arity.
macro_rules! validate {
    // Validate positional arguments only.
    ($name:expr, $args:expr, $($x:expr),*) => (
        {
            let validators: Vec<Box<Fn(&Rc<Variable>) -> Result<(), String>>> = vec![$($x), *];
            try!(arity($name, validators.len(), $args));
            for (k, v) in $args.iter().enumerate() {
                if let Err(e) = validators[k](v) {
                    return Err(format!("{} error at argument {}: {}", $name, k, e));
                }
            }
        }
    );
    // Validate positional arguments with a variadic validator.
    ($name:expr, $args:expr, $($x:expr),* ...$variadic:expr ) => (
        {
            let validators: Vec<Box<Fn(&Rc<Variable>) -> Result<(), String>>> = vec![$($x), *];
            if $args.len() < validators.len() {
                return Err(format!("{} arity error: expected at least {} args, found {}",
                                   $name, validators.len(), $args.len()));
            }
            for (k, v) in $args.iter().enumerate() {
                try!((match validators.get(k) {
                    Some(validator) => validator(v),
                    None => $variadic(v)
                }).or_else(|e| Err(format!("{} error at argument {}: {}", $name, k, e))));
            }
        }
    );
}

/// Validates that a vector contains a homogeneous array of a specific type(s).
macro_rules! array {
    ($($x:ident)|*) => [
        Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
            let valid_types = vec![$(stringify!($x)), *];
            match **arg {
                Variable::Array(ref array) if array.is_empty() => Ok(()),
                Variable::Array(ref array) if homogeneous_array(valid_types, array) => Ok(()),
                _ => Err(format!("type array[{}]", valid_types.join("|")))
            }
        })
    ];
}

/// Creates a closure used to validate the type of the given variable.
macro_rules! types {
    ($($x:ident)|*) => [
        {
            Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
                let valid_types = vec![$(stringify!($x)), *];
                let arg_type = arg.get_type();
                if arg_type == "any" || valid_types.contains(&arg_type) {
                    Ok(())
                } else {
                    Err(format!("type {}", valid_types.join("|")))
                }
            })
        }
    ];
}

/// Macro used to implement min and max functions.
macro_rules! min_max {
    ($operator:ident, $args:expr) => (
        match *$args[0] {
            Variable::Array(ref array) if array.is_empty() => Ok(Rc::new(Variable::Null)),
            Variable::Array(ref array) => {
                if array[0].is_string() {
                    Ok(Rc::new(Variable::String(array.iter().fold(
                        array[0].as_string().unwrap().clone(),
                        |acc, item| $operator(acc, item.as_string().unwrap().clone())))))
                } else {
                    Ok(Rc::new(Variable::F64(array.iter().fold(
                        array[0].as_f64().unwrap(),
                        |acc, item| acc.$operator(item.as_f64().unwrap())))))
                }
            },
            _ => panic!() // never encountered due to previous validation
        }
    )
}

/// Built-in function implementations.
#[derive(Clone)]
pub struct BuiltinFunctions;

impl BuiltinFunctions {
    /// Creates a new Builtins function dispatcher.
    pub fn new() -> BuiltinFunctions {
        BuiltinFunctions
    }
}

impl FnDispatcher for BuiltinFunctions {
    fn call(&self, fn_name: &str, args: &Vec<Rc<Variable>>, intr: &TreeInterpreter)
        -> InterpretResult
    {
        match fn_name {
            "abs" => {
                validate!("abs", args, types![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().abs())))
            },
            "avg" => {
                validate!("avg", args, array!(number));
                let array = args[0].as_array().unwrap();
                let sum = array.iter().fold(0f64, |a, ref b| a + b.as_f64().unwrap());
                Ok(Rc::new(Variable::F64(sum / (array.len() as f64))))
            },
            "ceil" => {
                validate!("ceil", args, types![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().ceil())))
            },
            "contains" => {
                validate!("contains", args, types![array|string], types![any]);
                match *args[0] {
                    Variable::Array(ref a) => Ok(Rc::new(Variable::Boolean(a.contains(&args[1])))),
                    Variable::String(ref subj) => {
                        match args[1].as_string() {
                            Some(search) => Ok(Rc::new(Variable::Boolean(subj.contains(search)))),
                            None => Err(format!("contains found {:?} for string search arg",
                                                args[1]))
                        }
                    },
                    _ => panic!() // never encountered due to previous validation
                }
            },
            "ends_with" => {
                validate!("ends_with", args, types![string], types![string]);
                let subject = args[0].as_string().unwrap();
                let search = args[1].as_string().unwrap();
                Ok(Rc::new(Variable::Boolean(subject.ends_with(search))))
            },
            "floor" => {
                validate!("floor", args, types![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().floor())))
            },
            "join" => {
                validate!("join", args, types![string], array![string]);
                Ok(Rc::new(Variable::String(args.iter().skip(1)
                    .map(|ref v| v.as_string().unwrap().clone())
                    .collect::<Vec<String>>()
                    .join(args[0].as_string().unwrap()))))
            },
            "keys" => {
                validate!("keys", args, types![object]);
                Ok(Rc::new(args[0].object_keys_to_array().unwrap()))
            },
            "length" => {
                validate!("length", args, types![array|object|string]);
                match *args[0] {
                    Variable::Array(ref a) => Ok(Rc::new(Variable::U64(a.len() as u64))),
                    Variable::Object(ref m) => Ok(Rc::new(Variable::U64(m.len() as u64))),
                    Variable::String(ref s) => Ok(Rc::new(Variable::U64(s.len() as u64))),
                    _ => panic!() // never encountered due to previous validation
                }
            },
            "max" => {
                validate!("max", args, array![string|number]);
                min_max!(max, args)
            },
            "max_by" => {
                validate!("max_by", args, types![array], types![expref]);
                let vals = args[0].as_array().expect("Expected array");
                let ast = args[1].as_expref().expect("Expected expref");
                if vals.is_empty() { return Ok(Rc::new(Variable::Null)); }
                let mut acc = try!(intr.interpret(args[0].clone(), ast));
                let iter = vals.iter().skip(1).map(|v| intr.interpret(v.clone(), ast));
                match acc.get_type() {
                    "string" => {
                        for item in iter {
                            match item {
                                Err(_) => return item,
                                Ok(ref v) if v.is_string() => acc = max(acc, v.clone()),
                                _ => return Err(format!("max_by: expected string from expref. \
                                                         Found {:?}", item))
                            }
                        }
                    },
                    "number" => {
                        for item in iter {
                            match item {
                                Err(_) => return item,
                                Ok(ref v) if v.is_number() => acc = max(acc, v.clone()),
                                _ => return Err(format!("max_by: expected number from expref. \
                                                         Found {:?}", item))
                            }
                        }
                    },
                    _ => return Err("max_by: expected string or number from expref".to_string())
                }
                Ok(acc)
            },
            "merge" => {
                validate!("merge", args, types![object] ...types![object]);
                let mut result = args[0].as_object().unwrap().clone();
                for arg in args.iter().skip(1) {
                    result.extend(arg.as_object().unwrap().clone());
                }
                Ok(Rc::new(Variable::Object(result)))
            },
            "min" => {
                validate!("min", args, array![string|number]);
                min_max!(min, args)
            },
            "not_null" => {
                validate!("not_null", args, types![any] ...types![any]);
                for arg in args {
                    if **arg != Variable::Null {
                        return Ok(arg.clone());
                    }
                }
                Ok(Rc::new(Variable::Null))
            },
            "reverse" => {
                validate!("reverse", args, types![array]);
                let mut values = args.clone();
                values.reverse();
                Ok(Rc::new(Variable::Array(values)))
            },
            "sort" => {
                validate!("sort", args, array![string|number]);
                let mut values: Vec<Rc<Variable>> = args[0].as_array().unwrap().clone();
                if values[0].is_string() {
                    values.sort_by(|a, b| a.as_string().unwrap().cmp(b.as_string().unwrap()));
                } else {
                    values.sort_by(|a, b| a.as_f64().unwrap()
                        .partial_cmp(&b.as_f64().unwrap())
                        .unwrap_or(Ordering::Equal));
                }
                Ok(Rc::new(Variable::Array(values)))
            },
            "starts_with" => {
                validate!("starts_with", args, types![string], types![string]);
                let subject = args[0].as_string().unwrap();
                let search = args[1].as_string().unwrap();
                Ok(Rc::new(Variable::Boolean(subject.starts_with(search))))
            },
            "sum" => {
                validate!("sum", args, array![number]);
                let array = args[0].as_array().unwrap();
                Ok(Rc::new(Variable::F64(array.iter().fold(
                    array[0].as_f64().unwrap().clone(),
                    |acc, item| acc.max(item.as_f64().unwrap())))))
            },
            "to_array" => {
                try!(arity("to_array", 1, args));
                match *args[0] {
                    Variable::Array(_) => Ok(args[0].clone()),
                    _ => Ok(Rc::new(Variable::Array(vec![args[0].clone()])))
                }
            },
            "to_number" => {
                try!(arity("to_number", 1, args));
                match *args[0] {
                    Variable::I64(_) | Variable::F64(_) | Variable::U64(_) => Ok(args[0].clone()),
                    Variable::String(ref s) => {
                        match s.parse::<f64>() {
                            Ok(f)  => Ok(Rc::new(Variable::F64(f))),
                            Err(_) => Ok(Rc::new(Variable::Null))
                        }
                    },
                    _ => Ok(Rc::new(Variable::Null))
                }
            },
            "to_string" => {
                validate!("to_string", args, types![object|array|boolean|number|string|null]);
                Ok(Rc::new(Variable::String(args[0].to_string().unwrap())))
            },
            "type" => {
                try!(arity("type", 1, args));
                Ok(Rc::new(Variable::String(args[0].get_type().to_string())))
            },
            "values" => {
                validate!("values", args, types![object]);
                Ok(Rc::new(args[0].object_values_to_array().unwrap()))
            },
            _ => Err(format!("Unknown function: {}", fn_name))
        }
    }
}
<commit_msg>Adding max_by and min_by functions using a macro<commit_after>use std::rc::Rc;
use std::cmp::{max, min, Ordering};

use interpreter::{TreeInterpreter, InterpretResult};
use variable::Variable;

/// Handles the dispatching of named functions using an array of arguments.
pub trait FnDispatcher {
    /// Dispatches and interprets a function by name.
    fn call(&self, fn_name: &str, args: &Vec<Rc<Variable>>, intr: &TreeInterpreter)
        -> InterpretResult;
}

/// Validates the arity of a function.
#[inline]
fn arity(fn_name: &str, arity: usize, args: &Vec<Rc<Variable>>) -> Result<(), String> {
    if args.len() != arity {
        Err(format!("{} arity error: expected {} args, found {}", fn_name, arity, args.len()))
    } else {
        Ok(())
    }
}

/// Validates that an array contains only a single allowed type.
#[inline]
fn homogeneous_array(valid_types: Vec<&str>, array: &Vec<Rc<Variable>>) -> bool {
    let matched_type = array[0].get_type();
    if !valid_types.contains(&matched_type) {
        return false;
    }
    for a in array {
        if a.get_type() != matched_type {
            return false;
        }
    }
    return true;
}

/// Macro used to variadically validate validate Variable and argument arity.
macro_rules! validate {
    // Validate positional arguments only.
    ($name:expr, $args:expr, $($x:expr),*) => (
        {
            let validators: Vec<Box<Fn(&Rc<Variable>) -> Result<(), String>>> = vec![$($x), *];
            try!(arity($name, validators.len(), $args));
            for (k, v) in $args.iter().enumerate() {
                if let Err(e) = validators[k](v) {
                    return Err(format!("{} error at argument {}: {}", $name, k, e));
                }
            }
        }
    );
    // Validate positional arguments with a variadic validator.
    ($name:expr, $args:expr, $($x:expr),* ...$variadic:expr ) => (
        {
            let validators: Vec<Box<Fn(&Rc<Variable>) -> Result<(), String>>> = vec![$($x), *];
            if $args.len() < validators.len() {
                return Err(format!("{} arity error: expected at least {} args, found {}",
                                   $name, validators.len(), $args.len()));
            }
            for (k, v) in $args.iter().enumerate() {
                try!((match validators.get(k) {
                    Some(validator) => validator(v),
                    None => $variadic(v)
                }).or_else(|e| Err(format!("{} error at argument {}: {}", $name, k, e))));
            }
        }
    );
}

/// Validates that a vector contains a homogeneous array of a specific type(s).
macro_rules! array {
    ($($x:ident)|*) => [
        Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
            let valid_types = vec![$(stringify!($x)), *];
            match **arg {
                Variable::Array(ref array) if array.is_empty() => Ok(()),
                Variable::Array(ref array) if homogeneous_array(valid_types, array) => Ok(()),
                _ => Err(format!("type array[{}]", valid_types.join("|")))
            }
        })
    ];
}

/// Creates a closure used to validate the type of the given variable.
macro_rules! types {
    ($($x:ident)|*) => [
        {
            Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
                let valid_types = vec![$(stringify!($x)), *];
                let arg_type = arg.get_type();
                if arg_type == "any" || valid_types.contains(&arg_type) {
                    Ok(())
                } else {
                    Err(format!("type {}", valid_types.join("|")))
                }
            })
        }
    ];
}

/// Macro used to implement min and max functions.
macro_rules! min_max {
    ($operator:ident, $args:expr) => (
        match *$args[0] {
            Variable::Array(ref array) if array.is_empty() => Ok(Rc::new(Variable::Null)),
            Variable::Array(ref array) => {
                if array[0].is_string() {
                    Ok(Rc::new(Variable::String(array.iter().fold(
                        array[0].as_string().unwrap().clone(),
                        |acc, item| $operator(acc, item.as_string().unwrap().clone())))))
                } else {
                    Ok(Rc::new(Variable::F64(array.iter().fold(
                        array[0].as_f64().unwrap(),
                        |acc, item| acc.$operator(item.as_f64().unwrap())))))
                }
            },
            _ => unreachable!()
        }
    )
}

/// Macro used to implement max_by and min_by functions.
macro_rules! max_by_min_by {
    ($operator:ident, $args:expr, $interpreter:expr) => (
        {
            let vals = $args[0].as_array().expect("Expected array");
            let ast = $args[1].as_expref().expect("Expected expref");
            let initial = try!($interpreter.interpret(vals[0].clone(), ast));
            let entered_type = initial.get_type();
            if entered_type != "string" && entered_type != "number" {
                return Err(format!("{}_by expref expects string|number, found {}",
                                   stringify!($operator), entered_type));
            }
            vals.iter().skip(1).map(|v| $interpreter.interpret(v.clone(), ast))
                .fold(Ok(initial.clone()), |a, b| {
                    let (a_val, b_val) = (try!(a), try!(b));
                    if b_val.get_type() != entered_type {
                        Err(format!("{}_by expref expects {}, found {:?}",
                                    stringify!($operator), entered_type, b_val))
                    } else {
                        Ok($operator(a_val, b_val))
                    }
                })
        }
    )
}

/// Built-in function implementations.
#[derive(Clone)]
pub struct BuiltinFunctions;

impl BuiltinFunctions {
    /// Creates a new Builtins function dispatcher.
    pub fn new() -> BuiltinFunctions {
        BuiltinFunctions
    }
}

impl FnDispatcher for BuiltinFunctions {
    fn call(&self, fn_name: &str, args: &Vec<Rc<Variable>>, intr: &TreeInterpreter)
        -> InterpretResult
    {
        match fn_name {
            "abs" => {
                validate!("abs", args, types![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().abs())))
            },
            "avg" => {
                validate!("avg", args, array!(number));
                let array = args[0].as_array().unwrap();
                let sum = array.iter().fold(0f64, |a, ref b| a + b.as_f64().unwrap());
                Ok(Rc::new(Variable::F64(sum / (array.len() as f64))))
            },
            "ceil" => {
                validate!("ceil", args, types![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().ceil())))
            },
            "contains" => {
                validate!("contains", args, types![array|string], types![any]);
                match *args[0] {
                    Variable::Array(ref a) => Ok(Rc::new(Variable::Boolean(a.contains(&args[1])))),
                    Variable::String(ref subj) => {
                        match args[1].as_string() {
                            None => Ok(Rc::new(Variable::Boolean(false))),
                            Some(s) => Ok(Rc::new(Variable::Boolean(subj.contains(s))))
                        }
                    },
                    _ => unreachable!()
                }
            },
            "ends_with" => {
                validate!("ends_with", args, types![string], types![string]);
                let subject = args[0].as_string().unwrap();
                let search = args[1].as_string().unwrap();
                Ok(Rc::new(Variable::Boolean(subject.ends_with(search))))
            },
            "floor" => {
                validate!("floor", args, types![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().floor())))
            },
            "join" => {
                validate!("join", args, types![string], array![string]);
                Ok(Rc::new(Variable::String(args.iter().skip(1)
                    .map(|ref v| v.as_string().unwrap().clone())
                    .collect::<Vec<String>>()
                    .join(args[0].as_string().unwrap()))))
            },
            "keys" => {
                validate!("keys", args, types![object]);
                Ok(Rc::new(args[0].object_keys_to_array().unwrap()))
            },
            "length" => {
                validate!("length", args, types![array|object|string]);
                match *args[0] {
                    Variable::Array(ref a) => Ok(Rc::new(Variable::U64(a.len() as u64))),
                    Variable::Object(ref m) => Ok(Rc::new(Variable::U64(m.len() as u64))),
                    Variable::String(ref s) => Ok(Rc::new(Variable::U64(s.len() as u64))),
                    _ => unreachable!()
                }
            },
            "max" => {
                validate!("max", args, array![string|number]);
                min_max!(max, args)
            },
            "min" => {
                validate!("min", args, array![string|number]);
                min_max!(min, args)
            },
            "max_by" => {
                validate!("max_by", args, types![array], types![expref]);
                max_by_min_by!(max, args, intr)
            },
            "min_by" => {
                validate!("min_by", args, types![array], types![expref]);
                max_by_min_by!(min, args, intr)
            },
            "merge" => {
                validate!("merge", args, types![object] ...types![object]);
                let mut result = args[0].as_object().unwrap().clone();
                for arg in args.iter().skip(1) {
                    result.extend(arg.as_object().unwrap().clone());
                }
                Ok(Rc::new(Variable::Object(result)))
            },
            "not_null" => {
                validate!("not_null", args, types![any] ...types![any]);
                for arg in args {
                    if **arg != Variable::Null {
                        return Ok(arg.clone());
                    }
                }
                Ok(Rc::new(Variable::Null))
            },
            "reverse" => {
                validate!("reverse", args, types![array]);
                let mut values = args.clone();
                values.reverse();
                Ok(Rc::new(Variable::Array(values)))
            },
            "sort" => {
                validate!("sort", args, array![string|number]);
                let mut values: Vec<Rc<Variable>> = args[0].as_array().unwrap().clone();
                if values[0].is_string() {
                    values.sort_by(|a, b| a.as_string().unwrap().cmp(b.as_string().unwrap()));
                } else {
                    values.sort_by(|a, b| a.as_f64().unwrap()
                        .partial_cmp(&b.as_f64().unwrap())
                        .unwrap_or(Ordering::Equal));
                }
                Ok(Rc::new(Variable::Array(values)))
            },
            "starts_with" => {
                validate!("starts_with", args, types![string], types![string]);
                let subject = args[0].as_string().unwrap();
                let search = args[1].as_string().unwrap();
                Ok(Rc::new(Variable::Boolean(subject.starts_with(search))))
            },
            "sum" => {
                validate!("sum", args, array![number]);
                let array = args[0].as_array().unwrap();
                Ok(Rc::new(Variable::F64(array.iter().fold(
                    array[0].as_f64().unwrap().clone(),
                    |acc, item| acc.max(item.as_f64().unwrap())))))
            },
            "to_array" => {
                try!(arity("to_array", 1, args));
                match *args[0] {
                    Variable::Array(_) => Ok(args[0].clone()),
                    _ => Ok(Rc::new(Variable::Array(vec![args[0].clone()])))
                }
            },
            "to_number" => {
                try!(arity("to_number", 1, args));
                match *args[0] {
                    Variable::I64(_) | Variable::F64(_) | Variable::U64(_) => Ok(args[0].clone()),
                    Variable::String(ref s) => {
                        match s.parse::<f64>() {
                            Ok(f)  => Ok(Rc::new(Variable::F64(f))),
                            Err(_) => Ok(Rc::new(Variable::Null))
                        }
                    },
                    _ => Ok(Rc::new(Variable::Null))
                }
            },
            "to_string" => {
                validate!("to_string", args, types![object|array|boolean|number|string|null]);
                Ok(Rc::new(Variable::String(args[0].to_string().unwrap())))
            },
            "type" => {
                try!(arity("type", 1, args));
                Ok(Rc::new(Variable::String(args[0].get_type().to_string())))
            },
            "values" => {
                validate!("values", args, types![object]);
                Ok(Rc::new(args[0].object_values_to_array().unwrap()))
            },
            _ => Err(format!("Unknown function: {}", fn_name))
        }
    }
}
<|endoftext|>