<commit_before>// Copyright 2016 The rustc-perf Project Developers. See the COPYRIGHT
// file at the top-level directory.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::{HashMap, BTreeSet, BTreeMap};
use std::cmp::{PartialOrd, Ord, Ordering};
use std::fs::{self, File};
use std::path::PathBuf;
use std::io::Read;

use chrono::Duration;
use serde_json;

use errors::*;
use util;
use date::Date;

const WEEKS_IN_SUMMARY: usize = 12;

// FIXME: These definitions should live in a central location and be depended upon by both the
// benchmark and website infrastructure. Currently, they are simply duplicated.
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Pass {
    pub name: String,
    pub time: f64,
    pub mem: u64,
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Run {
    pub name: String,
    pub passes: Vec<Pass>,
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Patch {
    pub patch: String,
    pub name: String,
    pub runs: Vec<Run>,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct Commit {
    pub sha: String,
    pub date: Date,
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct CommitData {
    pub commit: Commit,
    pub benchmarks: HashMap<String, Vec<Patch>>,
}

impl PartialOrd for Commit {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.date.partial_cmp(&other.date)
    }
}

impl Ord for Commit {
    fn cmp(&self, other: &Self) -> Ordering {
        self.date.cmp(&other.date)
    }
}

impl CommitData {
    pub fn patches<'a>(&'a self) -> impl Iterator<Item=&'a Patch> + 'a {
        self.benchmarks.values().flat_map(|patches| patches)
    }
}

impl Patch {
    pub fn full_name(&self) -> String {
        self.name.clone() + &self.patch
    }

    pub fn run(&self) -> &Run {
        assert_eq!(self.runs.len(), 1);
        &self.runs[0]
    }
}

impl Run {
    pub fn get_pass(&self, pass: &str) -> Option<&Pass> {
        self.passes.iter().find(|p| p.name == pass)
    }
}

#[derive(Debug)]
pub struct InputData {
    pub summary: Summary,

    /// A set containing all crate names of the bootstrap kind.
    pub crate_list: BTreeSet<String>,

    /// A set containing all phase names, across all crates.
    pub phase_list: BTreeSet<String>,

    /// The last date that was seen while loading files. The DateTime variant is
    /// used here since the date may or may not contain a time. Since the
    /// timezone is not important, it isn't stored, hence the Naive variant.
    pub last_date: Date,

    pub data: BTreeMap<Commit, CommitData>,
}

impl InputData {
    /// Initialize `InputData from the file system.
    pub fn from_fs(repo_loc: &str) -> Result<InputData> {
        let repo_loc = PathBuf::from(repo_loc);
        let mut skipped = 0;
        let mut data = BTreeMap::new();

        // Read all files from repo_loc/processed
        let mut file_count = 0;
        for entry in fs::read_dir(repo_loc.join("times"))? {
            let entry = entry?;
            if entry.file_type()?.is_dir() {
                continue;
            }
            file_count += 1;

            let filename = entry.file_name();
            let filename = filename.to_str().unwrap();
            let mut file = File::open(entry.path())?;
            let mut file_contents = String::new();
            // Skip files whose size is 0.
            if file.read_to_string(&mut file_contents)? == 0 {
                warn!("Skipping empty file: {}", filename);
                skipped += 1;
                continue;
            }

            let contents: CommitData = match serde_json::from_str(&file_contents) {
                Ok(json) => json,
                Err(err) => {
                    error!("Failed to parse JSON for {}: {:?}", filename, err);
                    skipped += 1;
                    continue;
                }
            };
            if contents.benchmarks.is_empty() {
                warn!("empty benchmarks hash for {}", filename);
                skipped += 1;
                continue;
            }

            data.insert(contents.commit.clone(), contents);
        }

        info!("{} total files", file_count);
        info!("{} skipped files", skipped);
        info!("{} measured", data.len());

        InputData::new(data)
    }

    pub fn new(data: BTreeMap<Commit, CommitData>) -> Result<InputData> {
        let mut last_date = None;
        let mut phase_list = BTreeSet::new();
        let mut crate_list = BTreeSet::new();

        for run in data.values() {
            if last_date.is_none() || last_date.as_ref().unwrap() < &run.commit.date {
                last_date = Some(run.commit.date);
            }

            for patch in run.benchmarks.values().flat_map(|x| x) {
                crate_list.insert(patch.full_name());
                for pass in &patch.run().passes {
                    phase_list.insert(pass.name.clone());
                }
            }
        }

        let last_date = last_date.expect("No dates found");

        // Post processing to generate the summary data.
        let summary = Summary::new(&data, last_date);

        Ok(InputData {
               summary: summary,
               crate_list: crate_list,
               phase_list: phase_list,
               last_date: last_date,
               data: data,
           })
    }
}

#[derive(Debug)]
pub struct Comparison {
    pub a: Commit,
    pub b: Commit,

    /// Maps crate names to a map of phases to each phase's delta time over the range.
    pub by_crate: HashMap<String, HashMap<String, f64>>,
}

#[derive(Debug)]
pub struct Summary {
    pub total: Comparison,
    pub comparisons: Vec<Comparison>,
}

impl Summary {
    // Compute summary data. For each week, we find the last 3 weeks, and use
    // the median timing as the basis of the current week's summary.
    fn new(
        data: &BTreeMap<Commit, CommitData>,
        last_date: Date,
    ) -> Summary {
        // 12 week long mapping of crate names to by-phase percent changes with
        // the previous week.
        let mut weeks = Vec::with_capacity(WEEKS_IN_SUMMARY);

        for i in 0..WEEKS_IN_SUMMARY {
            debug!("summarizing week {}", i);
            let start = last_date.start_of_week() - Duration::weeks(i as i64);
            let end = start + Duration::weeks(1);
            debug!("start: {:?}, end: {:?}", start, end);

            let mut week = util::data_range(data, start, end);
            let first = week.clone().next();
            let last = week.next_back();

            if let (Some((_, first)), Some((_, last))) = (first, last) {
                debug!("actual: start: {:?}, end: {:?}", first.commit.date, last.commit.date);
                weeks.push(Summary::compare_points(first, last));
            } else {
                warn!("week {} - {} has too few commits", start, end);
            }
        }

        let totals = {
            let start = last_date.start_of_week() - Duration::weeks(13);
            let end = last_date + Duration::weeks(1);

            let mut week = util::data_range(data, start, end);
            Summary::compare_points(week.clone().next().expect("first commit exists").1,
                week.next_back().expect("last commit exists").1)
        };

        Summary {
            total: totals,
            comparisons: weeks,
        }
    }

    fn compare_points(a: &CommitData, b: &CommitData) -> Comparison {
        let mut by_crate = HashMap::new();
        for (crate_name, patches) in &a.benchmarks {
            if !b.benchmarks.contains_key(crate_name) {
                warn!("Comparing {} with {}: a contained {}, but b did not.",
                    a.commit.sha, b.commit.sha, crate_name);
                continue;
            }

            let a_patches = patches;
            let b_patches = &b.benchmarks[crate_name];
            assert_eq!(a_patches.len(), b_patches.len());

            for (a_patch, b_patch) in a_patches.iter().zip(b_patches) {
                let a_run = a_patch.run();
                let b_run = b_patch.run();
                assert_eq!(a_run.name, b_run.name);

                for a_pass in &a_run.passes {
                    let a_t = a_pass.time;
                    let b_t = b_run.get_pass(&a_pass.name).map(|p| p.time).unwrap_or(0.0);
                    by_crate.entry(a_run.name.clone())
                        .or_insert_with(HashMap::new)
                        .insert(a_pass.name.clone(), b_t - a_t);
                }
            }
        }
        Comparison {
            a: a.commit.clone(),
            b: b.commit.clone(),
            by_crate: by_crate,
        }
    }
}

/// One decimal place rounded percent
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub struct Percent(#[serde(with = "util::round_float")] pub f64);
<commit_msg>Change summarization to store in BTreeMap instead of HashMap.<commit_after>// Copyright 2016 The rustc-perf Project Developers. See the COPYRIGHT
// file at the top-level directory.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::{HashMap, BTreeSet, BTreeMap};
use std::cmp::{PartialOrd, Ord, Ordering};
use std::fs::{self, File};
use std::path::PathBuf;
use std::io::Read;

use chrono::Duration;
use serde_json;

use errors::*;
use util;
use date::Date;

const WEEKS_IN_SUMMARY: usize = 12;

// FIXME: These definitions should live in a central location and be depended upon by both the
// benchmark and website infrastructure. Currently, they are simply duplicated.
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Pass {
    pub name: String,
    pub time: f64,
    pub mem: u64,
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Run {
    pub name: String,
    pub passes: Vec<Pass>,
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Patch {
    pub patch: String,
    pub name: String,
    pub runs: Vec<Run>,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct Commit {
    pub sha: String,
    pub date: Date,
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct CommitData {
    pub commit: Commit,
    pub benchmarks: HashMap<String, Vec<Patch>>,
}

impl PartialOrd for Commit {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.date.partial_cmp(&other.date)
    }
}

impl Ord for Commit {
    fn cmp(&self, other: &Self) -> Ordering {
        self.date.cmp(&other.date)
    }
}

impl CommitData {
    pub fn patches<'a>(&'a self) -> impl Iterator<Item=&'a Patch> + 'a {
        self.benchmarks.values().flat_map(|patches| patches)
    }
}

impl Patch {
    pub fn full_name(&self) -> String {
        self.name.clone() + &self.patch
    }

    pub fn run(&self) -> &Run {
        assert_eq!(self.runs.len(), 1);
        &self.runs[0]
    }
}

impl Run {
    pub fn get_pass(&self, pass: &str) -> Option<&Pass> {
        self.passes.iter().find(|p| p.name == pass)
    }
}

#[derive(Debug)]
pub struct InputData {
    pub summary: Summary,

    /// A set containing all crate names of the bootstrap kind.
    pub crate_list: BTreeSet<String>,

    /// A set containing all phase names, across all crates.
    pub phase_list: BTreeSet<String>,

    /// The last date that was seen while loading files. The DateTime variant is
    /// used here since the date may or may not contain a time. Since the
    /// timezone is not important, it isn't stored, hence the Naive variant.
    pub last_date: Date,

    pub data: BTreeMap<Commit, CommitData>,
}

impl InputData {
    /// Initialize `InputData from the file system.
    pub fn from_fs(repo_loc: &str) -> Result<InputData> {
        let repo_loc = PathBuf::from(repo_loc);
        let mut skipped = 0;
        let mut data = BTreeMap::new();

        // Read all files from repo_loc/processed
        let mut file_count = 0;
        for entry in fs::read_dir(repo_loc.join("times"))? {
            let entry = entry?;
            if entry.file_type()?.is_dir() {
                continue;
            }
            file_count += 1;

            let filename = entry.file_name();
            let filename = filename.to_str().unwrap();
            let mut file = File::open(entry.path())?;
            let mut file_contents = String::new();
            // Skip files whose size is 0.
            if file.read_to_string(&mut file_contents)? == 0 {
                warn!("Skipping empty file: {}", filename);
                skipped += 1;
                continue;
            }

            let contents: CommitData = match serde_json::from_str(&file_contents) {
                Ok(json) => json,
                Err(err) => {
                    error!("Failed to parse JSON for {}: {:?}", filename, err);
                    skipped += 1;
                    continue;
                }
            };
            if contents.benchmarks.is_empty() {
                warn!("empty benchmarks hash for {}", filename);
                skipped += 1;
                continue;
            }

            data.insert(contents.commit.clone(), contents);
        }

        info!("{} total files", file_count);
        info!("{} skipped files", skipped);
        info!("{} measured", data.len());

        InputData::new(data)
    }

    pub fn new(data: BTreeMap<Commit, CommitData>) -> Result<InputData> {
        let mut last_date = None;
        let mut phase_list = BTreeSet::new();
        let mut crate_list = BTreeSet::new();

        for run in data.values() {
            if last_date.is_none() || last_date.as_ref().unwrap() < &run.commit.date {
                last_date = Some(run.commit.date);
            }

            for patch in run.benchmarks.values().flat_map(|x| x) {
                crate_list.insert(patch.full_name());
                for pass in &patch.run().passes {
                    phase_list.insert(pass.name.clone());
                }
            }
        }

        let last_date = last_date.expect("No dates found");

        // Post processing to generate the summary data.
        let summary = Summary::new(&data, last_date);

        Ok(InputData {
               summary: summary,
               crate_list: crate_list,
               phase_list: phase_list,
               last_date: last_date,
               data: data,
           })
    }
}

#[derive(Debug)]
pub struct Comparison {
    pub a: Commit,
    pub b: Commit,

    /// Maps crate names to a map of phases to each phase's delta time over the range.
    pub by_crate: BTreeMap<String, BTreeMap<String, f64>>,
}

#[derive(Debug)]
pub struct Summary {
    pub total: Comparison,
    pub comparisons: Vec<Comparison>,
}

impl Summary {
    // Compute summary data. For each week, we find the last 3 weeks, and use
    // the median timing as the basis of the current week's summary.
    fn new(
        data: &BTreeMap<Commit, CommitData>,
        last_date: Date,
    ) -> Summary {
        // 12 week long mapping of crate names to by-phase percent changes with
        // the previous week.
        let mut weeks = Vec::with_capacity(WEEKS_IN_SUMMARY);

        for i in 0..WEEKS_IN_SUMMARY {
            debug!("summarizing week {}", i);
            let start = last_date.start_of_week() - Duration::weeks(i as i64);
            let end = start + Duration::weeks(1);
            debug!("start: {:?}, end: {:?}", start, end);

            let mut week = util::data_range(data, start, end);
            let first = week.clone().next();
            let last = week.next_back();

            if let (Some((_, first)), Some((_, last))) = (first, last) {
                debug!("actual: start: {:?}, end: {:?}", first.commit.date, last.commit.date);
                weeks.push(Summary::compare_points(first, last));
            } else {
                warn!("week {} - {} has too few commits", start, end);
            }
        }

        let totals = {
            let start = last_date.start_of_week() - Duration::weeks(13);
            let end = last_date + Duration::weeks(1);

            let mut week = util::data_range(data, start, end);
            Summary::compare_points(week.clone().next().expect("first commit exists").1,
                week.next_back().expect("last commit exists").1)
        };

        Summary {
            total: totals,
            comparisons: weeks,
        }
    }

    fn compare_points(a: &CommitData, b: &CommitData) -> Comparison {
        let mut by_crate = BTreeMap::new();
        for (crate_name, patches) in &a.benchmarks {
            if !b.benchmarks.contains_key(crate_name) {
                warn!("Comparing {} with {}: a contained {}, but b did not.",
                    a.commit.sha, b.commit.sha, crate_name);
                continue;
            }

            let a_patches = patches;
            let b_patches = &b.benchmarks[crate_name];
            assert_eq!(a_patches.len(), b_patches.len());

            for (a_patch, b_patch) in a_patches.iter().zip(b_patches) {
                let a_run = a_patch.run();
                let b_run = b_patch.run();
                assert_eq!(a_run.name, b_run.name);

                for a_pass in &a_run.passes {
                    let a_t = a_pass.time;
                    let b_t = b_run.get_pass(&a_pass.name).map(|p| p.time).unwrap_or(0.0);
                    by_crate.entry(a_run.name.clone())
                        .or_insert_with(BTreeMap::new)
                        .insert(a_pass.name.clone(), b_t - a_t);
                }
            }
        }
        Comparison {
            a: a.commit.clone(),
            b: b.commit.clone(),
            by_crate: by_crate,
        }
    }
}

/// One decimal place rounded percent
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub struct Percent(#[serde(with = "util::round_float")] pub f64);
<|endoftext|>


<commit_before>/*
Copyright (C) 2013 James Miller <james@aatch.net>

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

*/

extern mod extra;

use ffi::base::*;

use std::cast;
use std::libc::{c_int,free};
use std::option::Option;

use std::{num,ptr,vec,libc,str};
use std::num::*;

use xproto;

pub struct Connection {
    priv c : *connection
}

impl<'self> Connection {
    #[inline]
    pub fn flush(&self) -> bool {
        unsafe {
            xcb_flush(self.c) > 0
        }
    }

    #[inline]
    pub fn get_maximum_request_length(&self) -> u32 {
        unsafe {
            xcb_get_maximum_request_length(self.c)
        }
    }

    #[inline]
    pub fn wait_for_event(&self) -> Option<GenericEvent> {
        unsafe {
            let event = xcb_wait_for_event(self.c);
            if ptr::is_null(event) {
                None
            } else {
                Some(Event {event:event})
            }
        }
    }

    #[inline]
    pub fn poll_for_event(&self) -> Option<GenericEvent> {
        unsafe {
            let event = xcb_poll_for_event(self.c);
            if ptr::is_null(event) {
                None
            } else {
                Some(Event {event:event})
            }
        }
    }

    #[inline]
    pub fn poll_for_queued_event(&self) -> Option<GenericEvent> {
        unsafe {
            let event = xcb_poll_for_queued_event(self.c);
            if ptr::is_null(event) {
                None
            } else {
                Some(Event {event:event})
            }
        }
    }

    #[inline]
    pub fn get_setup(&self) -> &'self xproto::Setup {
        unsafe {
            let setup = xcb_get_setup(self.c);
            if ptr::is_null(setup) {
                fail!(~"NULL setup on connection")
            } else {
                cast::transmute(setup)
            }
        }
    }

    #[inline]
    pub fn has_error(&self) -> bool {
        unsafe {
            xcb_connection_has_error(self.c) > 0
        }
    }

    #[inline]
    pub fn generate_id<T>(&self) -> T {
        unsafe {
            cast::transmute(xcb_generate_id(self.c))
        }
    }

    #[inline]
    pub unsafe fn get_raw_conn(&self) -> *connection {
        self.c
    }

    pub fn send_event<T>(&self,
                  propogate: bool,
                  destination: xproto::Window,
                  event_mask : u32,
                  event : Event<T>) {
        use ffi;
        unsafe {
        ffi::xproto::xcb_send_event(self.c,
            propogate as u8, destination as ffi::xproto::window,
            event_mask, event.event as *libc::c_char);
        }
    }

    #[inline]
    pub fn connect() -> (Connection, int) {
        let screen : c_int = 0;
        unsafe {
            let conn = xcb_connect(ptr::null(), &screen);
            if ptr::is_null(conn) {
                fail!(~"Couldn't connect")
            } else {
                xcb_prefetch_maximum_request_length(conn);
                (Connection {c:conn}, screen as int)
            }
        }
    }

    #[inline]
    pub fn connect_to_display(display:&str) -> Option<(Connection, int)> {
        let screen : c_int = 0;
        unsafe {
            let conn = do str::as_c_str(display) |s| {
                xcb_connect(s as *u8, &screen)
            };
            if ptr::is_null(conn) {
                None
            } else {
                xcb_prefetch_maximum_request_length(conn);
                Some((Connection {c:conn}, screen as int))
            }
        }
    }

    #[inline]
    pub fn connect_with_auth(display:&str, auth_info: &AuthInfo) -> Option<(Connection, int)> {
        let screen : c_int = 0;
        unsafe {
            let conn = do str::as_c_str(display) |s| {
                xcb_connect_to_display_with_auth_info(s as *u8,
                    cast::transmute(auth_info), &screen)
            };
            if ptr::is_null(conn) {
                None
            } else {
                xcb_prefetch_maximum_request_length(conn);
                Some((Connection {c:conn}, screen as int))
            }
        }
    }

    pub unsafe fn from_raw_conn(conn:*connection) -> Connection {
        if ptr::is_null(conn) {
            fail!("Cannot construct from null pointer");
        }

        Connection {c:conn}
    }

}

impl Drop for Connection {
    fn finalize(&self) {
        unsafe {
            xcb_disconnect(self.c);
        }
    }
}

pub struct Event<T> {
    event:*T
}

#[unsafe_destructor]
impl<T> Drop for Event<T> {
    fn finalize(&self) {
        use std::libc::c_void;
        unsafe {
            free(self.event as *c_void);
        }
    }
}

pub struct Error<T> {
    error:*T
}

pub fn mk_error<T>(err:*T) -> Error<T> {
    Error {error:err}
}

#[unsafe_destructor]
impl<T> Drop for Error<T> {
    fn finalize(&self) {
        use std::libc::c_void;
        unsafe {
            free(self.error as *c_void);
        }
    }
}

pub type AuthInfo = auth_info;
//TODO: Implement wrapper functions for constructing auth_info

pub struct Struct<T> {
    strct: T
}

pub struct Cookie<'self, T> {
    cookie: T,
    conn: &'self Connection,
    checked: bool
}

pub trait ReplyCookie<R> {
    fn get_reply(&self) -> Result<Reply<R>, GenericError>;
}

impl<'self, T> Cookie<'self, T> {
    pub fn request_check(&self) -> Option<GenericError> {
        unsafe {
            // Crazy pointer dance to get the right bit
            // of the struct
            let c : *void_cookie = cast::transmute(&self.cookie);
            let err = xcb_request_check(self.conn.c, *c);
            if ptr::is_null(err) {
                None
            } else {
                Some(Error {error:err})
            }
        }
    }
}

pub struct Reply<T> {
    reply:*T
}

pub fn mk_reply<T>(reply:*T) -> Reply<T> {
    Reply {reply:reply}
}

#[unsafe_destructor]
impl<T> Drop for Reply<T> {
    fn finalize(&self) {
        use std::libc::c_void;
        unsafe {
            free(self.reply as *c_void);
        }
    }
}

pub type GenericReply = Reply<generic_reply>;
pub type GenericEvent = Event<generic_event>;
pub type GenericError = Error<generic_error>;
pub type VoidCookie<'self> = Cookie<'self, void_cookie>;

/**
 * Casts the generic event to the right event. Assumes that the given
 * event is really the correct type.
 */
#[inline(always)]
pub fn cast_event<'r, T>(event : &'r GenericEvent) -> &'r T {
    // This isn't very safe... but other options incur yet more overhead
    // that I really don't want to.
    unsafe { cast::transmute(event) }
}

//Accessor methods for all Events
pub trait EventUtil {
    #[inline(always)]
    pub fn response_type(&self) -> u8;
}

impl<T> EventUtil for Event<T> {
    pub fn response_type(&self) -> u8 {
        unsafe {
            let gev : *generic_event = cast::transmute(self.event);
            (*gev).response_type
        }
    }
}

pub fn pack_bitfield<T:Ord+Zero+NumCast+Copy,L:Copy>(bf : &[(T,L)]) -> (T, ~[L]) {
    let len = bf.len();

    let sorted = extra::sort::merge_sort(bf, |a,b| {
        let &(a, _) = a;
        let &(b, _) = b;
        a < b});

    let mut mask = 0u;
    let mut list : ~[L] = vec::with_capacity(len);

    for sorted.each |el| {
        let &(f, v) = el;
        let fld = num::cast(f);
        if (mask & fld) > 0 {
            loop;
        } else {
            mask |= fld;
            list.push(v);
        }
    }

    (num::cast(mask), list)
}
<commit_msg>Update for Rust 0.7<commit_after>/*
Copyright (C) 2013 James Miller <james@aatch.net>

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

*/

extern mod extra;

use ffi::base::*;

use std::cast;
use std::libc::{c_int,free};
use std::option::Option;

use std::{num,ptr,vec,libc,str};
use std::num::*;

use xproto;

pub struct Connection {
    priv c : *connection
}

impl<'self> Connection {
    #[inline]
    pub fn flush(&self) -> bool {
        unsafe {
            xcb_flush(self.c) > 0
        }
    }

    #[inline]
    pub fn get_maximum_request_length(&self) -> u32 {
        unsafe {
            xcb_get_maximum_request_length(self.c)
        }
    }

    #[inline]
    pub fn wait_for_event(&self) -> Option<GenericEvent> {
        unsafe {
            let event = xcb_wait_for_event(self.c);
            if ptr::is_null(event) {
                None
            } else {
                Some(Event {event:event})
            }
        }
    }

    #[inline]
    pub fn poll_for_event(&self) -> Option<GenericEvent> {
        unsafe {
            let event = xcb_poll_for_event(self.c);
            if ptr::is_null(event) {
                None
            } else {
                Some(Event {event:event})
            }
        }
    }

    #[inline]
    pub fn poll_for_queued_event(&self) -> Option<GenericEvent> {
        unsafe {
            let event = xcb_poll_for_queued_event(self.c);
            if ptr::is_null(event) {
                None
            } else {
                Some(Event {event:event})
            }
        }
    }

    #[inline]
    pub fn get_setup(&self) -> &'self xproto::Setup {
        unsafe {
            let setup = xcb_get_setup(self.c);
            if ptr::is_null(setup) {
                fail!(~"NULL setup on connection")
            } else {
                cast::transmute(setup)
            }
        }
    }

    #[inline]
    pub fn has_error(&self) -> bool {
        unsafe {
            xcb_connection_has_error(self.c) > 0
        }
    }

    #[inline]
    pub fn generate_id<T>(&self) -> T {
        unsafe {
            cast::transmute(xcb_generate_id(self.c))
        }
    }

    #[inline]
    pub unsafe fn get_raw_conn(&self) -> *connection {
        self.c
    }

    pub fn send_event<T>(&self,
                  propogate: bool,
                  destination: xproto::Window,
                  event_mask : u32,
                  event : Event<T>) {
        use ffi;
        unsafe {
        ffi::xproto::xcb_send_event(self.c,
            propogate as u8, destination as ffi::xproto::window,
            event_mask, event.event as *libc::c_char);
        }
    }

    #[inline]
    pub fn connect() -> (Connection, int) {
        let screen : c_int = 0;
        unsafe {
            let conn = xcb_connect(ptr::null(), &screen);
            if ptr::is_null(conn) {
                fail!(~"Couldn't connect")
            } else {
                xcb_prefetch_maximum_request_length(conn);
                (Connection {c:conn}, screen as int)
            }
        }
    }

    #[inline]
    pub fn connect_to_display(display:&str) -> Option<(Connection, int)> {
        let screen : c_int = 0;
        unsafe {
            let conn = do str::as_c_str(display) |s| {
                xcb_connect(s as *u8, &screen)
            };
            if ptr::is_null(conn) {
                None
            } else {
                xcb_prefetch_maximum_request_length(conn);
                Some((Connection {c:conn}, screen as int))
            }
        }
    }

    #[inline]
    pub fn connect_with_auth(display:&str, auth_info: &AuthInfo) -> Option<(Connection, int)> {
        let screen : c_int = 0;
        unsafe {
            let conn = do str::as_c_str(display) |s| {
                xcb_connect_to_display_with_auth_info(s as *u8,
                    cast::transmute(auth_info), &screen)
            };
            if ptr::is_null(conn) {
                None
            } else {
                xcb_prefetch_maximum_request_length(conn);
                Some((Connection {c:conn}, screen as int))
            }
        }
    }

    pub unsafe fn from_raw_conn(conn:*connection) -> Connection {
        if ptr::is_null(conn) {
            fail!("Cannot construct from null pointer");
        }

        Connection {c:conn}
    }

}

impl Drop for Connection {
    fn drop(&self) {
        unsafe {
            xcb_disconnect(self.c);
        }
    }
}

pub struct Event<T> {
    event:*T
}

#[unsafe_destructor]
impl<T> Drop for Event<T> {
    fn drop(&self) {
        use std::libc::c_void;
        unsafe {
            free(self.event as *c_void);
        }
    }
}

pub struct Error<T> {
    error:*T
}

pub fn mk_error<T>(err:*T) -> Error<T> {
    Error {error:err}
}

#[unsafe_destructor]
impl<T> Drop for Error<T> {
    fn drop(&self) {
        use std::libc::c_void;
        unsafe {
            free(self.error as *c_void);
        }
    }
}

pub type AuthInfo = auth_info;
//TODO: Implement wrapper functions for constructing auth_info

pub struct Struct<T> {
    strct: T
}

pub struct Cookie<'self, T> {
    cookie: T,
    conn: &'self Connection,
    checked: bool
}

pub trait ReplyCookie<R> {
    fn get_reply(&self) -> Result<Reply<R>, GenericError>;
}

impl<'self, T> Cookie<'self, T> {
    pub fn request_check(&self) -> Option<GenericError> {
        unsafe {
            // Crazy pointer dance to get the right bit
            // of the struct
            let c : *void_cookie = cast::transmute(&self.cookie);
            let err = xcb_request_check(self.conn.c, *c);
            if ptr::is_null(err) {
                None
            } else {
                Some(Error {error:err})
            }
        }
    }
}

pub struct Reply<T> {
    reply:*T
}

pub fn mk_reply<T>(reply:*T) -> Reply<T> {
    Reply {reply:reply}
}

#[unsafe_destructor]
impl<T> Drop for Reply<T> {
    fn drop(&self) {
        use std::libc::c_void;
        unsafe {
            free(self.reply as *c_void);
        }
    }
}

pub type GenericReply = Reply<generic_reply>;
pub type GenericEvent = Event<generic_event>;
pub type GenericError = Error<generic_error>;
pub type VoidCookie<'self> = Cookie<'self, void_cookie>;

/**
 * Casts the generic event to the right event. Assumes that the given
 * event is really the correct type.
 */
#[inline(always)]
pub fn cast_event<'r, T>(event : &'r GenericEvent) -> &'r T {
    // This isn't very safe... but other options incur yet more overhead
    // that I really don't want to.
    unsafe { cast::transmute(event) }
}

//Accessor methods for all Events
pub trait EventUtil {
    #[inline(always)]
    pub fn response_type(&self) -> u8;
}

impl<T> EventUtil for Event<T> {
    pub fn response_type(&self) -> u8 {
        unsafe {
            let gev : *generic_event = cast::transmute(self.event);
            (*gev).response_type
        }
    }
}

pub fn pack_bitfield<T:Ord+Zero+NumCast+Copy,L:Copy>(bf : &[(T,L)]) -> (T, ~[L]) {
    let len = bf.len();

    let sorted = extra::sort::merge_sort(bf, |a,b| {
        let &(a, _) = a;
        let &(b, _) = b;
        a < b});

    let mut mask = 0u;
    let mut list : ~[L] = vec::with_capacity(len);

    for sorted.iter().advance |el| {
        let &(f, v) = el;
        let fld = num::cast(f);
        if (mask & fld) > 0 {
            loop;
        } else {
            mask |= fld;
            list.push(v);
        }
    }

    (num::cast(mask), list)
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Write;

fn main() {
    println!("Welcome to Rust-Calculus!");
    println!("To evaluate an expression, simply type one in and hit RETURN.");
    println!("To set a variable, simply type VAR_NAME=EXPRESSION and hit RETURN.");
    println!("Valid commands are: sym_int, int, sym_def, and def.");
    println!("Type 'quit' to exit.");
    let mut input = String::new();
    let stdin = io::stdin();
    let mut stdout = io::stdout();
    loop {
    	input.clear();
    	print!(">>>> ");
    	stdout.flush().ok();
        stdin.read_line(&mut input).unwrap();
        println!("You typed: {}", input.trim());
        input = strip_white_space(&input);
        match input.to_lowercase().as_ref() {
            "quit" => {print!("Exiting..."); break;},
            _ => {println!("You typed: {}", input.trim());},
        }
    }
}

fn strip_white_space(input: &String) -> String {
	input.split_whitespace().collect::<Vec<&str>>().join("")
}
<commit_msg>Added a bunch of useful enums for the lexicon<commit_after>use std::io;
use std::io::Write;

#[derive(Debug, PartialEq, Clone)]
enum Token<'a> {
    Unknown(&'a str), // Invalid test (basically non-ascii)
    Literal(&'a str), // Numeric literal number
    Function(Function<'a>), // Pre-defined function (like cos() or a user defined f(x)=... )
    Constant(Constant), // Constant like pi or e
    Variable(&'a str), // str re3presenting an arbitary varible name (no space)
    Operator(Operator), // Any of the 4 operators (+-*/)
    Open(Vec<Token<'a>>), // Open parens '(' followed by vector of tokens and a Token::Close
    Close, // Closing parens ')'
}
#[derive(Debug, PartialEq, Clone)]
enum Function<'a> {
    Sqrt(Vec<Token<'a>>),
    Ln(Vec<Token<'a>>),
    Log(f64, Vec<Token<'a>>),
    Sin(Vec<Token<'a>>),
    Cos(Vec<Token<'a>>),
    Tan(Vec<Token<'a>>),
    Asin(Vec<Token<'a>>),
    Acos(Vec<Token<'a>>),
    Atan(Vec<Token<'a>>),
    Sinh(Vec<Token<'a>>),
    Cosh(Vec<Token<'a>>),
    Tanh(Vec<Token<'a>>),
    Asinh(Vec<Token<'a>>),
    Acosh(Vec<Token<'a>>),
    Atanh(Vec<Token<'a>>),
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Constant {
	Pi,
	E,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Operator {
    Add,
    Sub,
    Div,
    Mul,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
enum Assoc {
    Left,
    Right,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
enum Order {
    AddSub = 1,
    MulDiv = 2,
    IMul = 3, // Implicit multiplication
    Pow = 4,
    Paren = 5,
}

fn main() {
    println!("Welcome to Rust-Calculus!");
    println!("To evaluate an expression, simply type one in and hit RETURN.");
    println!("To set a variable, simply type VAR_NAME=EXPRESSION and hit RETURN.");
    println!("Valid commands are: sym_int, int, sym_def, and def.");
    println!("Type 'quit' to exit.");
    let mut input = String::new();
    let stdin = io::stdin();
    let mut stdout = io::stdout();
    loop {
    	input.clear();
    	print!(">>>> ");
    	stdout.flush().ok();
        stdin.read_line(&mut input).unwrap();
        println!("You typed: {}", input.trim());
        input = strip_white_space(&input);
        match input.to_lowercase().as_ref() {
            "quit" => {print!("Exiting..."); break;},
            _ => {println!("You typed: {}", input.trim());},
        }
    }
}

fn strip_white_space(input: &String) -> String {
	input.split_whitespace().collect::<Vec<&str>>().join("")
}
<|endoftext|>


<commit_before>extern crate postgres;
extern crate regex;
extern crate getopts;
extern crate bit_set;
#[macro_use]
extern crate serde;
extern crate serde_json;
extern crate serde_yaml;

use postgres::{Connection, TlsMode};

use std::env;
use getopts::Options;
use std::process;
use std::fs;
use std::fs::File;
use std::io::BufReader;

extern crate pombase;

use pombase::db::*;
use pombase::web::data_build::*;

const PKG_NAME: &'static str = env!("CARGO_PKG_NAME");
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

fn make_subdirs(output_dir: &str) {
    let subdirs = vec!["gene", "genotype", "term", "reference"];

    for subdir in &subdirs {
        let dir = String::new() + output_dir + "/" + subdir;
        fs::create_dir_all(&dir).unwrap_or_else(|why| {
            println!("Creating output directory failed: {:?}", why.kind());
        });
    }
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn read_config(config_file_name: &str) -> Config {
    let file = match File::open(config_file_name) {
        Ok(file) => file,
        Err(err) => {
            print!("Failed to read {}: {}\n", config_file_name, err);
            process::exit(1);
        }
    };
    let reader = BufReader::new(file);

    match serde_yaml::from_reader(reader) {
        Ok(config) => config,
        Err(err) => {
            print!("failed to parse {}: {}", config_file_name, err);
            process::exit(1);
        },
    }
}

fn main() {
    print!("{} v{}\n", PKG_NAME, VERSION);

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.optflag("h", "help", "print this help message");
    opts.optopt("c", "config-file", "Configuration file name", "CONFIG");
    opts.optopt("p", "postgresql-connection-string",
                "PostgresSQL connection string like: postgres://user:pass@host/db_name",
                "CONN_STR");
    opts.optopt("d", "output-directory",
                "Destination directory for JSON output", "DIR");
    opts.optopt("O", "organism",
                "Only output genes from this organism (eg. 'Schizosaccharomyces_pombe')", "GENUS_SPECIES");
    opts.optflag("j", "store-json",
                 "optionally create a 'web_json' schema to store the generated JSON in the database");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let program = args[0].clone();

    if matches.opt_present("help") {
        print_usage(&program, opts);
        process::exit(0);
    }

    if !matches.opt_present("config-file") {
        print!("no -c|--config-file option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("postgresql-connection-string") {
        print!("no -p|--postgresql-connection-string option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("output-directory") {
        print!("no -d|--output-directory option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("organism") {
        print!("no -O|--organism option\n");
        print_usage(&program, opts);
        process::exit(1);
    }

    let config = read_config(&matches.opt_str("c").unwrap());
    let connection_string = matches.opt_str("p").unwrap();
    let output_dir = matches.opt_str("d").unwrap();
    let organism_genus_species = matches.opt_str("O").unwrap();

    make_subdirs(&output_dir);

    let conn = Connection::connect(connection_string.as_str(), TlsMode::None).unwrap();

    let raw = Raw::new(&conn);
    let mut web_data_build = WebDataBuild::new(&raw, &config);
    let web_data = web_data_build.get_web_data();

    web_data.write(&output_dir, &organism_genus_species);

    if matches.opt_present("store-json") {
        conn.execute("DROP SCHEMA IF EXISTS web_json CASCADE", &[]).unwrap();
        conn.execute("CREATE SCHEMA web_json", &[]).unwrap();
        conn.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm;", &[]).unwrap();
        conn.execute("CREATE TABLE web_json.gene (uniquename TEXT, data JSONB)", &[]).unwrap();
        conn.execute("CREATE TABLE web_json.term (termid TEXT, data JSONB)", &[]).unwrap();
        conn.execute("CREATE TABLE web_json.reference (uniquename TEXT, data JSONB)", &[]).unwrap();

        web_data.store_jsonb(&conn);

        print!("stored results as JSONB using {}\n", &connection_string);
    }
}
<commit_msg>Fix warning from rustc 1.16<commit_after>extern crate postgres;
extern crate regex;
extern crate getopts;
extern crate bit_set;
extern crate serde;
extern crate serde_json;
extern crate serde_yaml;

use postgres::{Connection, TlsMode};

use std::env;
use getopts::Options;
use std::process;
use std::fs;
use std::fs::File;
use std::io::BufReader;

extern crate pombase;

use pombase::db::*;
use pombase::web::data_build::*;

const PKG_NAME: &'static str = env!("CARGO_PKG_NAME");
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

fn make_subdirs(output_dir: &str) {
    let subdirs = vec!["gene", "genotype", "term", "reference"];

    for subdir in &subdirs {
        let dir = String::new() + output_dir + "/" + subdir;
        fs::create_dir_all(&dir).unwrap_or_else(|why| {
            println!("Creating output directory failed: {:?}", why.kind());
        });
    }
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn read_config(config_file_name: &str) -> Config {
    let file = match File::open(config_file_name) {
        Ok(file) => file,
        Err(err) => {
            print!("Failed to read {}: {}\n", config_file_name, err);
            process::exit(1);
        }
    };
    let reader = BufReader::new(file);

    match serde_yaml::from_reader(reader) {
        Ok(config) => config,
        Err(err) => {
            print!("failed to parse {}: {}", config_file_name, err);
            process::exit(1);
        },
    }
}

fn main() {
    print!("{} v{}\n", PKG_NAME, VERSION);

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.optflag("h", "help", "print this help message");
    opts.optopt("c", "config-file", "Configuration file name", "CONFIG");
    opts.optopt("p", "postgresql-connection-string",
                "PostgresSQL connection string like: postgres://user:pass@host/db_name",
                "CONN_STR");
    opts.optopt("d", "output-directory",
                "Destination directory for JSON output", "DIR");
    opts.optopt("O", "organism",
                "Only output genes from this organism (eg. 'Schizosaccharomyces_pombe')", "GENUS_SPECIES");
    opts.optflag("j", "store-json",
                 "optionally create a 'web_json' schema to store the generated JSON in the database");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let program = args[0].clone();

    if matches.opt_present("help") {
        print_usage(&program, opts);
        process::exit(0);
    }

    if !matches.opt_present("config-file") {
        print!("no -c|--config-file option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("postgresql-connection-string") {
        print!("no -p|--postgresql-connection-string option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("output-directory") {
        print!("no -d|--output-directory option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("organism") {
        print!("no -O|--organism option\n");
        print_usage(&program, opts);
        process::exit(1);
    }

    let config = read_config(&matches.opt_str("c").unwrap());
    let connection_string = matches.opt_str("p").unwrap();
    let output_dir = matches.opt_str("d").unwrap();
    let organism_genus_species = matches.opt_str("O").unwrap();

    make_subdirs(&output_dir);

    let conn = Connection::connect(connection_string.as_str(), TlsMode::None).unwrap();

    let raw = Raw::new(&conn);
    let mut web_data_build = WebDataBuild::new(&raw, &config);
    let web_data = web_data_build.get_web_data();

    web_data.write(&output_dir, &organism_genus_species);

    if matches.opt_present("store-json") {
        conn.execute("DROP SCHEMA IF EXISTS web_json CASCADE", &[]).unwrap();
        conn.execute("CREATE SCHEMA web_json", &[]).unwrap();
        conn.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm;", &[]).unwrap();
        conn.execute("CREATE TABLE web_json.gene (uniquename TEXT, data JSONB)", &[]).unwrap();
        conn.execute("CREATE TABLE web_json.term (termid TEXT, data JSONB)", &[]).unwrap();
        conn.execute("CREATE TABLE web_json.reference (uniquename TEXT, data JSONB)", &[]).unwrap();

        web_data.store_jsonb(&conn);

        print!("stored results as JSONB using {}\n", &connection_string);
    }
}
<|endoftext|>


<commit_before>#[cfg(not(test))]
use std::process::Command;

#[cfg(not(test))]
use std::fs::{File, OpenOptions};

#[cfg(not(test))]
use std::io::{BufRead, BufReader, Write};

#[cfg(not(test))]
fn main() {
    let message = match (walk_the_path(), seek_the_path()) {
        (true, true) => concat!("Eternity lies ahead of us, and behind.",
            " Your path is not yet finished."),

        (true, false) => "What is the sound of one hand clapping (for you)?",

        (false, _) => concat!("Meditate on your approach and return.",
            " Mountains are merely mountains.")
    };

    println!("{}", message);
}

macro_rules! koan {
    ($name:expr) => (
        include!(concat!("koans/", $name, ".rs"));
    );
}

#[cfg(not(test))]
fn seek_the_path() -> bool {
    let mut koans = BufReader::new(File::open("src/koans.txt").unwrap()).lines();
    let mut path = OpenOptions::new()
        .read(true)
        .write(true)
        .open("src/path_to_enlightenment.rs").unwrap();
    let passed_count = BufReader::new(&path).lines().count();

    if let Some(Ok(next_koan)) = koans.nth(passed_count) {
        println!("Ahead of you lies {}.", next_koan);
        write!(&mut path, "koan!(\"{}\");\n", next_koan).unwrap();
        true
    } else {
        println!("There will be no more tasks.");
        false
    }
}

#[cfg(not(test))]
fn walk_the_path() -> bool {
    Command::new("cargo")
        .arg("test")
        .arg("-q")
        .status()
        .unwrap()
        .success()
}

#[cfg(test)]
mod path_to_enlightenment;
<commit_msg>Seek the path only once you have walked it<commit_after>#[cfg(not(test))]
use std::process::Command;

#[cfg(not(test))]
use std::fs::{File, OpenOptions};

#[cfg(not(test))]
use std::io::{BufRead, BufReader, Write};

#[cfg(not(test))]
fn main() {
    let message = match walk_the_path() {
        true => match seek_the_path() {
            true => "Eternity lies ahead of us, and behind. Your path is not yet finished.",
            false => "What is the sound of one hand clapping (for you)?"
        },
        false => "Meditate on your approach and return. Mountains are merely mountains."
    };

    println!("{}", message);
}

macro_rules! koan {
    ($name:expr) => (
        include!(concat!("koans/", $name, ".rs"));
    );
}

#[cfg(not(test))]
fn seek_the_path() -> bool {
    let mut koans = BufReader::new(File::open("src/koans.txt").unwrap()).lines();
    let mut path = OpenOptions::new()
        .read(true)
        .write(true)
        .open("src/path_to_enlightenment.rs").unwrap();
    let passed_count = BufReader::new(&path).lines().count();

    if let Some(Ok(next_koan)) = koans.nth(passed_count) {
        println!("Ahead of you lies {}.", next_koan);
        write!(&mut path, "koan!(\"{}\");\n", next_koan).unwrap();
        true
    } else {
        println!("There will be no more tasks.");
        false
    }
}

#[cfg(not(test))]
fn walk_the_path() -> bool {
    Command::new("cargo")
        .arg("test")
        .arg("-q")
        .status()
        .unwrap()
        .success()
}

#[cfg(test)]
mod path_to_enlightenment;
<|endoftext|>


<commit_before>extern crate regex;
extern crate readline;

mod errors;
mod atom;
mod parser;

use parser::*;
use atom::*;
use errors::Error;
use errors::Error::*;

use std::collections::HashMap;
use std::string::String;

type EvalResult = Result<Eval, Error>;
type Function = Fn(&Vec<Eval>) -> EvalResult;
type FunctionMap = HashMap<String, Box<Function>>;

#[derive(Debug, Clone, PartialEq)]
enum Eval {
    Atom(Atom),
    Node(Node),
    Proc(Procedure)
}

#[derive (Debug, Clone, PartialEq)]
struct Procedure {
    params: Vec<Atom>,
    body: Node,
}

fn eval_procedure(p: &Procedure, args: &Vec<Eval>, env: &mut Env) ->  EvalResult {
    try!(env.apply(&p.params, args));

    let res = eval(&p.body, env);

    env.pop();

    res
}

#[derive (Debug,Clone)]
struct Env {
    def_map: Vec<HashMap<String, Eval>>,
}

impl Env {
    fn find(&self, key: &str, i: usize) -> Option<&Eval> {
        let map = &self.def_map[i];

        let val = map.get(key);

        match val {
            Some(_) => val,
            None => {
                if i > 0 {
                    self.find(key, i - 1 )
                } else {
                    None
                }
            }
        }
    }

    fn apply(&mut self, params: &Vec<Atom>, args: &Vec<Eval>) -> Result<(),Error> {
        if params.len() != args.len() {
            return Err(InvalidArguments);
        }

        let mut m = HashMap::new();

        for p in params.iter().zip(args.iter()) {
            if let &Atom::Symbol(ref sym) = p.0 {
                m.insert(sym.clone(), p.1.clone());
            } else {
                return Err(InvalidArguments);
            }
        }

        self.def_map.push(m);

        Ok(())
    }

    fn pop(&mut self) {
        self.def_map.pop();
    }

    fn get(&self, key: &str) -> Option<&Eval> {
        self.find(key, self.def_map.len() - 1 )
    }

    fn set(&mut self, key: String, value: Eval) {
        if let Some(map) = self.def_map.last_mut() {
            map.insert(key, value);
        }
    }
}
fn add(v: &Vec<Eval>, env: &Env) -> EvalResult {
    let mut result = 0;

    for i in v {
        match *i {
            Eval::Atom(Atom::Integer(d)) => {
                result += d
            },
            Eval::Atom(Atom::Symbol(ref s)) => {
                let v = env.get(s);
                match v {
                    Some(&Eval::Atom(Atom::Integer(d))) => result += d,
                    _ => return Err(UnexpectedType)
                }

            },
            _ => return Err(Error::UnexpectedType)
        }
    }

    Ok(Eval::Atom(Atom::Integer(result)))
}

fn sub(v: &Vec<Eval>) -> EvalResult {
    if v.len() < 1 {
        return Err(Error::InvalidArguments)
    }

    let mut result = match v[0] {
        Eval::Atom(Atom::Integer(d)) => d,
        _ => return Err(Error::UnexpectedType)
    };

    for i in v.iter().skip(1) {
        match *i {
            Eval::Atom(Atom::Integer(d)) => result -= d,
            _ => return Err(Error::UnexpectedType)
        }
    }

    Ok(Eval::Atom(Atom::Integer(result)))
}

fn equals(args: &Vec<Eval>) -> EvalResult {
    let v = &args[0];

    for i in args.iter().skip(1) {
        if v != i {
            return Ok(Eval::Atom(Atom::Boolean(false)))
        }
    }
    Ok(Eval::Atom(Atom::Boolean(true)))
}

fn default_env() -> Env {
    Env{def_map: vec![HashMap::new()]}
}

fn try_built_ins(sym: &str, args: &Vec<Eval>, env: &Env) -> Option<EvalResult> {
    match sym {
        "nil" => Some(Ok(Eval::Atom(Atom::Nil))),
        "+" => Some(add(args, env)),
        "-" => Some(sub(args)),
        "=" => Some(equals(args)),
        _ => None
    }
}

fn define(args: Vec<Eval>, env: &mut Env) -> EvalResult {
    if args.len() != 2 {
        return Err(Error::InvalidArguments);
    }

    if let Eval::Atom(Atom::Symbol(ref key)) = args[0] {
        env.set(key.clone(), args[1].clone());
        Ok(Eval::Atom(Atom::Nil))
    } else {
        Err(Error::InvalidArguments)
    }
}

fn set(args: Vec<Eval>, env: &mut Env) -> EvalResult {
    // FIXME: get rid of the clones
    if args.len() != 2 {
        return Err(InvalidArguments)
    }

    if let Eval::Atom(Atom::Symbol(ref key)) = args[0] {
        // if env.def_map.contains_key(key) {
        //     let entry = env.def_map.entry((*key).clone()).or_insert(Eval::Atom(Atom::Nil));
        //     *entry = args[1].clone();
        //     return Ok(args[1].clone())
        // }
    }
    Err(InvalidArguments)
}

fn get(args: Vec<Eval>, env: &Env) -> EvalResult {
    if args.len() != 1 {
        return Err(Error::InvalidArguments)
    }

    if let Eval::Atom(Atom::Symbol(ref s)) = args[0] {
        if let Some(a) = env.get(s) {
            Ok(a.clone())
        } else {
            Ok(Eval::Atom(Atom::Nil))
        }
    } else {
        Err(Error::InvalidArguments)
    }
}

fn eval_args(list: &Vec<Node>, env: &mut Env) -> Result<Vec<Eval>, Error> {
    let mut args = vec![];

    for i in list.iter().skip(1) {
        let atom = try!(eval(i, env));
        args.push(atom);
    }
    Ok(args)
}

fn quote(v: &Vec<Node>) -> Result<Eval, Error> {
    Ok(Eval::Node(v[1].clone()))
}

fn reduce_fn_params(l: &Vec<Node>) -> Result<Vec<Atom>,Error> {
    let mut v = vec![];

    for node in l {
        match node {
            &Node::Atom(ref a) => v.push(a.clone()),
            _ => return Err(InvalidArguments)
        }
    }
    Ok(v)
}

fn collect_body(l: &Vec<Node>) -> Vec<Node> {
    let mut v = vec![];

    for i in l.iter().skip(2) {
        v.push(i.clone());
    }
    v
}

fn eval_node(atom: &Atom, list: &Vec<Node>, env: &mut Env) -> EvalResult {
    match atom {
        &Atom::Symbol(ref s) =>  {
            match s.as_ref() {
                "def" => {
                    let args = try!(eval_args(&list, env));
                    return define(args, env);
                },
                "fn" => {
                    let params = match list[1] {
                        Node::List(ref l) => try!(reduce_fn_params(l)),
                        _ => return Err(InvalidArguments)
                    };

                    let prc = Procedure{ params: params, body: Node::List(collect_body(list))};
                    return Ok(Eval::Proc(prc))
                },
                "quote" => {
                    return quote(&list);
                },
                "set!" => {
                    return set( try!(eval_args(&list, env)), env);
                },
                "get" => {
                    return get( try!(eval_args(&list, env)), env);
                },
                "if" => {
                    let predicate = try!(eval(&list[1], env));

                    let truthy = match predicate {
                        Eval::Atom(Atom::Boolean(b)) => b,
                        Eval::Atom(Atom::Nil) => false,
                        _ => true
                    };

                    if truthy {
                        return eval(&list[2], env);
                    } else if list.len() > 2 {
                        return eval(&list[3], env);
                    } else {
                        return Ok(Eval::Atom(Atom::Boolean(false)))
                    }
                },
                _ => ()
            };

            let args = try!(eval_args(&list, env));

            if let Some(r) = try_built_ins(&s, &args, env) {
                return r
            }

            if let Some(&Eval::Proc(ref p)) = env.get(&s) {
                let mut renv = env.clone();
                let r = eval_procedure(p, &args, &mut renv);
                return r
            }

            Ok(Eval::Atom(Atom::Nil))
        },
        _ => {
            Ok(Eval::Atom(atom.clone()))
        }
    }
}

fn eval(node: &Node, env: &mut Env) -> Result<Eval, Error> {
    match node {
        &Node::List(ref list) => {
            match list[0] {
                Node::Atom(ref atom) => {
                    return eval_node(atom, list, env)
               },
                Node::List(_) => {
                    let r = try!(eval(&list[0], env));

                    match r {
                        Eval::Atom(a) => return eval_node(&a, list, env),
                        Eval::Proc(p) => return eval_procedure(&p, &try!(eval_args(&list, env)), env),
                        _ => return Err(InvalidArguments)
                    }
                }
            }
        },
        &Node::Atom(ref atom) => Ok(Eval::Atom(atom.clone()))
    }
}

fn repl() {
    println!("Rust Lisp!");
    let mut env = default_env();

    loop {
        match readline::readline(">") {
            Some(s) => {
                if let Ok(p) = parser::tokenize(&s) {
                    match eval(&p, &mut env) {
                        Ok(r) => println!("{:?}", r),
                        Err(e) => println!("Error in evaluation: {:?}", e)
                    }
                } else {
                    println!("Error in parsing");
                }
            },
            None => {
                println!("Exiting...");
                break;
            }
        }
    }
}

pub fn main() {
    repl();
}

#[cfg(test)]
mod test {
    use parser::*;
    use super::default_env;
    use super::eval;
    use atom::Atom;
    use super::Eval;

    fn teval(s: &str) -> Eval {
        eval(&tokenize(s).unwrap(), &mut default_env()).unwrap()
    }

    fn make_atom_node(s: &str) -> Node {
        return Node::Atom(Atom::parse(s));
    }

    fn as_list(n: &Node) -> &Vec<Node> {
        match n {
            &Node::List(ref l) => l,
            _ => panic!("don't get here!")
        }
    }

    fn as_atom(n: &Node) -> &Atom {
        match n {
            &Node::Atom(ref a) => a,
            _ => panic!("not here!")
        }
    }

    fn atom(s: &str) -> Atom {
        Atom::parse(s)
    }

    #[test]
    fn simple_read_tokens() {
        let x = tokenize("(+ 1 2)").unwrap();

        let l = as_list(&x);

        assert_eq!(3, l.len());

        let xx : Vec<Node> = vec![make_atom_node("+"), make_atom_node("1"), make_atom_node("2")];

        for pair in xx.iter().zip(l.iter()) {
            assert_eq!(pair.0, pair.1);
        }
    }

    #[test]
    fn nested_read_tokens() {
        let x = tokenize("(+ 1 (* 2 2))").unwrap();

        let l = as_list(&x);

        assert_eq!( atom("+"), *as_atom(&l[0]));
        assert_eq!( atom("1"), *as_atom(&l[1]));

        let l2 = as_list(&l[2]);

        assert_eq!( 3, l.len());
        assert_eq!( atom("*"), *as_atom(&l2[0]));
        assert_eq!( atom("2"), *as_atom(&l2[1]));
        assert_eq!( atom("2"), *as_atom(&l2[2]));
    }

    #[test]
    fn subexp_token_test() {
        let x = tokenize("(+ 1 (+ 2 3) 4)").unwrap();

        let l = as_list(&x);

        assert_eq!( atom("+"), *as_atom(&l[0]));
        assert_eq!( atom("1"), *as_atom(&l[1]));

        let l2 = as_list(&l[2]);

        assert_eq!( 3, l2.len());
        assert_eq!( atom("+"), *as_atom(&l2[0]));
        assert_eq!( atom("2"), *as_atom(&l2[1]));
        assert_eq!( atom("3"), *as_atom(&l2[2]));

        assert_eq!(atom("4"), *as_atom(&l[3]));
    }

    #[test]
    fn if_special_form() {
        let x = eval(&tokenize("(if (= 1 1) true false)").unwrap(), &mut default_env()).unwrap();

        assert_eq!(Eval::Atom(Atom::Boolean(true)), x);
    }

    #[test]
    fn if_special_form_false() {
        let x = eval(&tokenize("(if (= 1 2) true false)").unwrap(), &mut default_env()).unwrap();

        assert_eq!(Eval::Atom(Atom::Boolean(false)), x);
    }

    #[test]
    fn if_no_else() {
        let x = teval("(if (= 1 1) true)");

        assert_eq!(Eval::Atom(Atom::Boolean(true)), x);
    }

    #[test]
    #[should_panic]
    fn unmatched_bracket() {
        tokenize("(+ 1").unwrap();
    }

    #[test]
    #[should_panic]
    fn eof() {
         tokenize("").unwrap();
    }
}
<commit_msg>lexcial bindings!<commit_after>extern crate regex;
extern crate readline;

mod errors;
mod atom;
mod parser;

use parser::*;
use atom::*;
use errors::Error;
use errors::Error::*;

use std::collections::HashMap;
use std::string::String;

type EvalResult = Result<Eval, Error>;
type Function = Fn(&Vec<Eval>) -> EvalResult;
type FunctionMap = HashMap<String, Box<Function>>;

#[derive(Debug, Clone, PartialEq)]
enum Eval {
    Atom(Atom),
    Node(Node),
    Proc(Procedure)
}

#[derive (Debug, Clone, PartialEq)]
struct Procedure {
    params: Vec<Atom>,
    body: Node,
}

fn eval_procedure(p: &Procedure, args: &Vec<Eval>, env: &mut Env) ->  EvalResult {
    try!(env.apply(&p.params, args));

    let res = eval(&p.body, env);

    env.pop();

    res
}

#[derive (Debug,Clone)]
struct Env {
    def_map: Vec<HashMap<String, Eval>>,
}

impl Env {
    fn find(&self, key: &str, i: usize) -> Option<&Eval> {
        let map = &self.def_map[i];

        let val = map.get(key);

        match val {
            Some(_) => val,
            None => {
                if i > 0 {
                    self.find(key, i - 1 )
                } else {
                    None
                }
            }
        }
    }

    fn apply(&mut self, params: &Vec<Atom>, args: &Vec<Eval>) -> Result<(),Error> {
        if params.len() != args.len() {
            return Err(InvalidArguments);
        }

        let mut m = HashMap::new();

        for p in params.iter().zip(args.iter()) {
            if let &Atom::Symbol(ref sym) = p.0 {
                m.insert(sym.clone(), p.1.clone());
            } else {
                return Err(InvalidArguments);
            }
        }

        self.def_map.push(m);

        Ok(())
    }

    fn pop(&mut self) {
        self.def_map.pop();
    }

    fn get(&self, key: &str) -> Option<&Eval> {
        self.find(key, self.def_map.len() - 1 )
    }

    fn set(&mut self, key: String, value: Eval) {
        if let Some(map) = self.def_map.last_mut() {
            map.insert(key, value);
        }
    }
}
fn add(v: &Vec<Eval>, env: &Env) -> EvalResult {
    let mut result = 0;

    for i in v {
        match *i {
            Eval::Atom(Atom::Integer(d)) => {
                result += d
            },
            Eval::Atom(Atom::Symbol(ref s)) => {
                let v = env.get(s);
                match v {
                    Some(&Eval::Atom(Atom::Integer(d))) => result += d,
                    _ => return Err(UnexpectedType)
                }

            },
            _ => return Err(Error::UnexpectedType)
        }
    }

    Ok(Eval::Atom(Atom::Integer(result)))
}

fn sub(v: &Vec<Eval>) -> EvalResult {
    if v.len() < 1 {
        return Err(Error::InvalidArguments)
    }

    let mut result = match v[0] {
        Eval::Atom(Atom::Integer(d)) => d,
        _ => return Err(Error::UnexpectedType)
    };

    for i in v.iter().skip(1) {
        match *i {
            Eval::Atom(Atom::Integer(d)) => result -= d,
            _ => return Err(Error::UnexpectedType)
        }
    }

    Ok(Eval::Atom(Atom::Integer(result)))
}

fn equals(args: &Vec<Eval>, env: &Env) -> EvalResult {
    if let Some(v) = args.first() {
        for i in args.iter().skip(1) {
            match *i {
                Eval::Atom(Atom::Symbol(ref s)) => {
                    match env.get(s) {
                        Some(d) => {
                            if d != v {
                                return Ok(Eval::Atom(Atom::Boolean(false)));
                            }
                        },
                        None => {
                            if v != &Eval::Atom(Atom::Nil) {
                                return Ok(Eval::Atom(Atom::Boolean(false)));
                            }
                        }
                    }
                }
                _ => {
                    if v != i {
                        return Ok(Eval::Atom(Atom::Boolean(false)))
                    }
                }
            }
        }
        Ok(Eval::Atom(Atom::Boolean(true)))
    } else {
        Err(InvalidArguments)
    }
}

fn default_env() -> Env {
    Env{def_map: vec![HashMap::new()]}
}

fn try_built_ins(sym: &str, args: &Vec<Eval>, env: &Env) -> Option<EvalResult> {
    match sym {
        "nil" => Some(Ok(Eval::Atom(Atom::Nil))),
        "+" => Some(add(args, env)),
        "-" => Some(sub(args)),
        "=" => Some(equals(args, env)),
        _ => None
    }
}

fn define(args: Vec<Eval>, env: &mut Env) -> EvalResult {
    if args.len() != 2 {
        return Err(Error::InvalidArguments);
    }
    if let Eval::Atom(Atom::Symbol(ref key)) = args[0] {
        env.set(key.clone(), args[1].clone());
        Ok(Eval::Atom(Atom::Nil))
    } else {
        Err(Error::InvalidArguments)
    }
}

fn set(args: Vec<Eval>, env: &mut Env) -> EvalResult {
    // FIXME: get rid of the clones
    if args.len() != 2 {
        return Err(InvalidArguments)
    }

    if let Eval::Atom(Atom::Symbol(ref key)) = args[0] {
        // if env.def_map.contains_key(key) {
        //     let entry = env.def_map.entry((*key).clone()).or_insert(Eval::Atom(Atom::Nil));
        //     *entry = args[1].clone();
        //     return Ok(args[1].clone())
        // }
    }
    Err(InvalidArguments)
}

fn get(args: Vec<Eval>, env: &Env) -> EvalResult {
    if args.len() != 1 {
        return Err(Error::InvalidArguments)
    }

    if let Eval::Atom(Atom::Symbol(ref s)) = args[0] {
        if let Some(a) = env.get(s) {
            Ok(a.clone())
        } else {
            Ok(Eval::Atom(Atom::Nil))
        }
    } else {
        Err(Error::InvalidArguments)
    }
}

fn eval_args(list: &Vec<Node>, env: &mut Env) -> Result<Vec<Eval>, Error> {
    let mut args = vec![];

    for i in list.iter().skip(1) {
        let atom = try!(eval(i, env));
        args.push(atom);
    }
    Ok(args)
}

fn quote(v: &Vec<Node>) -> Result<Eval, Error> {
    Ok(Eval::Node(v[1].clone()))
}

fn reduce_fn_params(l: &Vec<Node>) -> Result<Vec<Atom>,Error> {
    let mut v = vec![];

    for node in l {
        match node {
            &Node::Atom(ref a) => v.push(a.clone()),
            _ => {
                return Err(InvalidArguments)
            }
        }
    }
    Ok(v)
}

fn collect_body(l: &Vec<Node>) -> Vec<Node> {
    let mut v = vec![];

    for i in l.iter().skip(2) {
        v.push(i.clone());
    }
    v
}

fn eval_node(atom: &Atom, list: &Vec<Node>, env: &mut Env) -> EvalResult {
    match atom {
        &Atom::Symbol(ref s) =>  {
            match s.as_ref() {
                "def" => {
                    let args = try!(eval_args(&list, env));
                    return define(args, env);
                },
                "fn" => {
                    let params = match list[1] {
                        Node::List(ref l) => try!(reduce_fn_params(l)),
                        _ => {
                            return Err(InvalidArguments)
                        }
                    };

                    let prc = Procedure{ params: params,
                                         body: Node::List(collect_body(list))
                    };

                    return Ok(Eval::Proc(prc))
                },
                "quote" => {
                    return quote(&list);
                },
                "set!" => {
                    return set( try!(eval_args(&list, env)), env);
                },
                "get" => {
                    return get( try!(eval_args(&list, env)), env);
                },
                "if" => {
                    let predicate = try!(eval(&list[1], env));

                    let truthy = match predicate {
                        Eval::Atom(Atom::Boolean(b)) => b,
                        Eval::Atom(Atom::Nil) => false,
                        _ => true
                    };

                    if truthy {
                        return eval(&list[2], env);
                    } else if list.len() > 2 {
                        return eval(&list[3], env);
                    } else {
                        return Ok(Eval::Atom(Atom::Boolean(false)))
                    }
                },
                _ => ()
            };

            let args = try!(eval_args(&list, env));

            if let Some(r) = try_built_ins(&s, &args, env) {
                return r
            }

            if let Some(&Eval::Proc(ref p)) = env.get(&s) {
                let mut renv = env.clone();
                let r = eval_procedure(p, &args, &mut renv);
                return r
            }

            Ok(Eval::Atom(Atom::Nil))
        },
        _ => {
            Ok(Eval::Atom(atom.clone()))
        }
    }
}

fn eval(node: &Node, env: &mut Env) -> Result<Eval, Error> {
    match node {
        &Node::List(ref list) => {
            match list[0] {
                Node::Atom(ref atom) => {
                    return eval_node(atom, list, env)
               },
                Node::List(_) => {
                    let r = try!(eval(&list[0], env));

                    match r {
                        Eval::Atom(a) => return eval_node(&a, list, env),
                        Eval::Proc(p) => return eval_procedure(&p, &try!(eval_args(&list, env)), env),
                        _ => {
                            return Err(InvalidArguments)
                        }
                    }
                }
            }
        },
        &Node::Atom(ref atom) => {
            match atom {
                &Atom::Symbol(ref s) => {
                    match env.get(s) {
                        Some(e) => return Ok(e.clone()),
                        _ => return Ok(Eval::Atom(atom.clone()))
                    }
                }
                _ => Ok(Eval::Atom(atom.clone()))
            }
        }
    }
}

fn repl() {
    println!("Rust Lisp!");
    let mut env = default_env();

    loop {
        match readline::readline(">") {
            Some(s) => {
                if let Ok(p) = parser::tokenize(&s) {
                    match eval(&p, &mut env) {
                        Ok(r) => println!("{:?}", r),
                        Err(e) => println!("Error in evaluation: {:?}", e)
                    }
                } else {
                    println!("Error in parsing");
                }
            },
            None => {
                println!("Exiting...");
                break;
            }
        }
    }
}

pub fn main() {
    repl();
}

#[cfg(test)]
mod test {
    use parser::*;
    use super::default_env;
    use super::eval;
    use atom::Atom;
    use super::Eval;

    fn teval(s: &str) -> Eval {
        eval(&tokenize(s).unwrap(), &mut default_env()).unwrap()
    }

    fn make_atom_node(s: &str) -> Node {
        return Node::Atom(Atom::parse(s));
    }

    fn as_list(n: &Node) -> &Vec<Node> {
        match n {
            &Node::List(ref l) => l,
            _ => panic!("don't get here!")
        }
    }

    fn as_atom(n: &Node) -> &Atom {
        match n {
            &Node::Atom(ref a) => a,
            _ => panic!("not here!")
        }
    }

    fn atom(s: &str) -> Atom {
        Atom::parse(s)
    }

    #[test]
    fn simple_read_tokens() {
        let x = tokenize("(+ 1 2)").unwrap();

        let l = as_list(&x);

        assert_eq!(3, l.len());

        let xx : Vec<Node> = vec![make_atom_node("+"), make_atom_node("1"), make_atom_node("2")];

        for pair in xx.iter().zip(l.iter()) {
            assert_eq!(pair.0, pair.1);
        }
    }

    #[test]
    fn nested_read_tokens() {
        let x = tokenize("(+ 1 (* 2 2))").unwrap();

        let l = as_list(&x);

        assert_eq!( atom("+"), *as_atom(&l[0]));
        assert_eq!( atom("1"), *as_atom(&l[1]));

        let l2 = as_list(&l[2]);

        assert_eq!( 3, l.len());
        assert_eq!( atom("*"), *as_atom(&l2[0]));
        assert_eq!( atom("2"), *as_atom(&l2[1]));
        assert_eq!( atom("2"), *as_atom(&l2[2]));
    }

    #[test]
    fn subexp_token_test() {
        let x = tokenize("(+ 1 (+ 2 3) 4)").unwrap();

        let l = as_list(&x);

        assert_eq!( atom("+"), *as_atom(&l[0]));
        assert_eq!( atom("1"), *as_atom(&l[1]));

        let l2 = as_list(&l[2]);

        assert_eq!( 3, l2.len());
        assert_eq!( atom("+"), *as_atom(&l2[0]));
        assert_eq!( atom("2"), *as_atom(&l2[1]));
        assert_eq!( atom("3"), *as_atom(&l2[2]));

        assert_eq!(atom("4"), *as_atom(&l[3]));
    }

    #[test]
    fn if_special_form() {
        let x = eval(&tokenize("(if (= 1 1) true false)").unwrap(), &mut default_env()).unwrap();

        assert_eq!(Eval::Atom(Atom::Boolean(true)), x);
    }

    #[test]
    fn if_special_form_false() {
        let x = eval(&tokenize("(if (= 1 2) true false)").unwrap(), &mut default_env()).unwrap();

        assert_eq!(Eval::Atom(Atom::Boolean(false)), x);
    }

    #[test]
    fn if_no_else() {
        let x = teval("(if (= 1 1) true)");

        assert_eq!(Eval::Atom(Atom::Boolean(true)), x);
    }

    #[test]
    #[should_panic]
    fn unmatched_bracket() {
        tokenize("(+ 1").unwrap();
    }

    #[test]
    #[should_panic]
    fn eof() {
         tokenize("").unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate iron;
#[macro_use]
extern crate router;
extern crate persistent;
extern crate rustc_serialize;
extern crate rusqlite;
#[macro_use]
extern crate log;

mod views;
mod query;
mod mapping;
mod logger;

use std::sync::{Mutex, RwLock};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::fs;

use iron::prelude::*;
use iron::typemap::Key;
use rustc_serialize::json::Json;
use rusqlite::Connection;

#[derive(Debug)]
struct Document {
    data: Json,
}

impl Document {
    fn from_json(data: Json) -> Document {
        Document { data: data }
    }
}

#[derive(Debug)]
struct Index {
    pub connection: Mutex<Connection>,
    pub mappings: HashMap<String, mapping::Mapping>,
    pub docs: HashMap<String, Document>,
}

impl Index {
    fn new(connection: Connection) -> Index {
        Index {
            connection: Mutex::new(connection),
            mappings: HashMap::new(),
            docs: HashMap::new(),
        }
    }

    fn initialise(&mut self) {
        let connection = self.connection.lock().unwrap();

        connection.execute("CREATE TABLE document (
              id              INTEGER PRIMARY KEY,
              mapping         TEXT NOT NULL,
              data            BLOB
              )", &[]).unwrap();
    }
}

struct Globals {
    pub indices_path: PathBuf,
    pub indices: RwLock<HashMap<String, Index>>,
}

impl Globals {
    fn new(indices_path: PathBuf, indices: HashMap<String, Index>) -> Globals {
        Globals {
            indices_path: indices_path,
            indices: RwLock::new(indices),
        }
    }
}

impl Key for Globals {
    type Value = Globals;
}

fn load_index(path: &Path) -> Index {
    Index::new(Connection::open(path).unwrap())
}

fn load_indices(indices_path: &Path) -> HashMap<String, Index> {
    let mut indices = HashMap::new();

    for file in fs::read_dir(&indices_path).unwrap() {
        let path = file.unwrap().path();
        let index_name: String = path.file_stem().unwrap().to_str().unwrap().to_owned();
        if path.extension().unwrap().to_str() == Some("rsi") {
            info!("Loaded index: {}", index_name);
            indices.insert(index_name, load_index(path.as_path()));
        }
    }

    indices
}

fn main() {
    logger::init().unwrap();

    let indices_path = Path::new("./indices").to_path_buf();
    let indices = load_indices(&indices_path.as_path());
    let router = views::get_router();
    let mut chain = Chain::new(router);
    chain.link(persistent::Read::<Globals>::both(Globals::new(indices_path, indices)));
    Iron::new(chain).http("localhost:9200").unwrap();
}
<commit_msg>Print version on startup<commit_after>extern crate iron;
#[macro_use]
extern crate router;
extern crate persistent;
extern crate rustc_serialize;
extern crate rusqlite;
#[macro_use]
extern crate log;

mod views;
mod query;
mod mapping;
mod logger;

use std::sync::{Mutex, RwLock};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::fs;

use iron::prelude::*;
use iron::typemap::Key;
use rustc_serialize::json::Json;
use rusqlite::Connection;

const VERSION: &'static str = "0.1a0";

#[derive(Debug)]
struct Document {
    data: Json,
}

impl Document {
    fn from_json(data: Json) -> Document {
        Document { data: data }
    }
}

#[derive(Debug)]
struct Index {
    pub connection: Mutex<Connection>,
    pub mappings: HashMap<String, mapping::Mapping>,
    pub docs: HashMap<String, Document>,
}

impl Index {
    fn new(connection: Connection) -> Index {
        Index {
            connection: Mutex::new(connection),
            mappings: HashMap::new(),
            docs: HashMap::new(),
        }
    }

    fn initialise(&mut self) {
        let connection = self.connection.lock().unwrap();

        connection.execute("CREATE TABLE document (
              id              INTEGER PRIMARY KEY,
              mapping         TEXT NOT NULL,
              data            BLOB
              )", &[]).unwrap();
    }
}

struct Globals {
    pub indices_path: PathBuf,
    pub indices: RwLock<HashMap<String, Index>>,
}

impl Globals {
    fn new(indices_path: PathBuf, indices: HashMap<String, Index>) -> Globals {
        Globals {
            indices_path: indices_path,
            indices: RwLock::new(indices),
        }
    }
}

impl Key for Globals {
    type Value = Globals;
}

fn load_index(path: &Path) -> Index {
    Index::new(Connection::open(path).unwrap())
}

fn load_indices(indices_path: &Path) -> HashMap<String, Index> {
    let mut indices = HashMap::new();

    for file in fs::read_dir(&indices_path).unwrap() {
        let path = file.unwrap().path();
        let index_name: String = path.file_stem().unwrap().to_str().unwrap().to_owned();
        if path.extension().unwrap().to_str() == Some("rsi") {
            info!("Loaded index: {}", index_name);
            indices.insert(index_name, load_index(path.as_path()));
        }
    }

    indices
}

fn main() {
    println!("rsearch ({})", VERSION);
    println!("");

    logger::init().unwrap();

    let indices_path = Path::new("./indices").to_path_buf();
    let indices = load_indices(&indices_path.as_path());
    let router = views::get_router();
    let mut chain = Chain::new(router);
    chain.link(persistent::Read::<Globals>::both(Globals::new(indices_path, indices)));
    Iron::new(chain).http("localhost:9200").unwrap();
}
<|endoftext|>