<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use super::Position;
use super::symbols::SymbolTable;

pub type Functions = HashMap<String, Node<Function>>;

#[derive(PartialEq, Debug)]
pub struct Node<I> {
    pub pos: Position,
    pub node: I,
}

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Type {
    Void,
    Bool,
    Int,
    Float,
    Str,
}

#[derive(PartialEq, Debug)]
pub enum Literal {
    Bool(bool),
    Int(i32),
    Float(f32),
    Str(String),
}

impl Literal {
    pub fn get_type(&self) -> Type {
        match *self {
            Literal::Bool(_) => Type::Bool,
            Literal::Int(_) => Type::Int,
            Literal::Float(_) => Type::Float,
            Literal::Str(_) => Type::Str,
        }
    }
}

#[derive(Debug)]
pub struct Variable {
    pub id: u32,
    pub type_: Type,
    pub name: String,
}

impl Variable {
    pub fn stub(name: String) -> Variable {
        Variable {
            id: 0,
            type_: Type::Void,
            name: name,
        }
    }

    pub fn eq_name_type(&self, other: &Variable) -> bool {
        self.type_ == other.type_ && self.name == other.name
    }
}

impl PartialEq for Variable {
    fn eq(&self, other: &Variable) -> bool {
        if self.id == 0 || other.id == 0 {
            false
        } else {
            self.id == other.id
        }
    }
}

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum UnaryOp {
    NOT,
    MINUS,
}

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum BinaryOp {
    ADD,
    SUB,
    MUL,
    DIV,

    EQ,
    LT,
    LE,
}

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Op {
    UnaryOp(UnaryOp),
    BinaryOp(BinaryOp),
}

#[derive(PartialEq, Debug)]
pub struct Program {
    pub functions: Functions,
}

#[derive(PartialEq, Debug)]
pub struct Function {
    pub name: String,
    pub filename: String,
    pub body: Node<Statement>,
    pub args: Vec<Rc<Variable>>,
    pub ret_type: Type,
    pub symbols: Rc<RefCell<SymbolTable>>,
}

#[derive(PartialEq, Debug)]
pub enum Statement {
    Expression {
        expr: Box<Node<Expression>>,
    },
    Declaration {
        var: Rc<Variable>,
    },
    Assignment {
        var: Rc<Variable>,
        expr: Box<Node<Expression>>,
    },
    If {
        cond: Box<Node<Expression>>,
        on_true: Box<Node<Statement>>,
        on_false: Option<Box<Node<Statement>>>,
    },
    While {
        cond: Box<Node<Expression>>,
        body: Box<Node<Statement>>,
    },
    Return {
        expr: Option<Box<Node<Expression>>>,
    },
    Compound {
        stmts: Vec<Node<Statement>>,
        symbols: Rc<RefCell<SymbolTable>>,
    },
}

impl Node<Statement> {
    pub fn visit_stmt(&self, do_stmt: &mut FnMut(&Node<Statement>) -> bool) -> bool {
        do_stmt(self) || return false;
        match self.node {
            Statement::If { ref on_true, ref on_false, .. } => {
                on_true.visit_stmt(do_stmt) ||
                if let Some(ref stmt) = *on_false {
                    stmt.visit_stmt(do_stmt)
                } else {
                    true
                }
            }
            Statement::While { ref body, .. } => body.visit_stmt(do_stmt),
            Statement::Compound { ref stmts, .. } => {
                for stmt in stmts.iter() {
                    stmt.visit_stmt(do_stmt) || return false;
                }
                true
            }
            _ => true,
        }
    }

    pub fn visit_expr(&self, do_expr: &mut FnMut(&Node<Expression>) -> bool) -> bool {
        self.visit_stmt(&mut |stmt| {
            match stmt.node {
                Statement::Expression { ref expr } => do_expr(expr),
                Statement::Assignment { ref expr, .. } => do_expr(expr),
                Statement::If { ref cond, .. } => do_expr(cond),
                Statement::While { ref cond, .. } => do_expr(cond),
                Statement::Return { expr: Some(ref expr) } => do_expr(expr),
                _ => true,
            }
        })
    }
}

#[derive(PartialEq, Debug)]
pub enum Expression {
    Literal {
        lit: Literal,
    },
    Variable {
        var: Rc<Variable>,
    },
    Call {
        function: String,
        args: Vec<Node<Expression>>,
    },
    Unary {
        op: UnaryOp,
        expr: Box<Node<Expression>>,
    },
    Binary {
        op: BinaryOp,
        left: Box<Node<Expression>>,
        right: Box<Node<Expression>>,
    },
    Parenthesis {
        expr: Box<Node<Expression>>,
    },
}

impl Node<Expression> {
    pub fn visit_expr(&self, do_expr: &mut FnMut(&Node<Expression>) -> bool) -> bool {
        do_expr(self) || return false;
        match self.node {
            Expression::Call { ref args, .. } => {
                for arg in args.iter() {
                    arg.visit_expr(do_expr) || return false;
                }
                true
            }
            Expression::Unary { ref expr, .. } => expr.visit_expr(do_expr),
            Expression::Parenthesis { ref expr } => expr.visit_expr(do_expr),
            Expression::Binary { ref left, ref right, .. } => {
                left.visit_expr(do_expr) || return false;
                right.visit_expr(do_expr)
            }
            _ => true,
        }
    }
}

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

    #[test]
    fn literals() {
        assert_eq!(Type::Bool, Literal::Bool(false).get_type());
        assert_eq!(Type::Int, Literal::Int(0).get_type());
        assert_eq!(Type::Float, Literal::Float(0.0).get_type());
    }
}
<commit_msg>Front: Specify lifetime for visit_stmt / visit_expr<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use super::Position;
use super::symbols::SymbolTable;

pub type Functions = HashMap<String, Node<Function>>;

#[derive(PartialEq, Debug)]
pub struct Node<I> {
    pub pos: Position,
    pub node: I,
}

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Type {
    Void,
    Bool,
    Int,
    Float,
    Str,
}

#[derive(PartialEq, Debug)]
pub enum Literal {
    Bool(bool),
    Int(i32),
    Float(f32),
    Str(String),
}

impl Literal {
    pub fn get_type(&self) -> Type {
        match *self {
            Literal::Bool(_) => Type::Bool,
            Literal::Int(_) => Type::Int,
            Literal::Float(_) => Type::Float,
            Literal::Str(_) => Type::Str,
        }
    }
}

#[derive(Debug)]
pub struct Variable {
    pub id: u32,
    pub type_: Type,
    pub name: String,
}

impl Variable {
    pub fn stub(name: String) -> Variable {
        Variable {
            id: 0,
            type_: Type::Void,
            name: name,
        }
    }

    pub fn eq_name_type(&self, other: &Variable) -> bool {
        self.type_ == other.type_ && self.name == other.name
    }
}

impl PartialEq for Variable {
    fn eq(&self, other: &Variable) -> bool {
        if self.id == 0 || other.id == 0 {
            false
        } else {
            self.id == other.id
        }
    }
}

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum UnaryOp {
    NOT,
    MINUS,
}

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum BinaryOp {
    ADD,
    SUB,
    MUL,
    DIV,

    EQ,
    LT,
    LE,
}

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Op {
    UnaryOp(UnaryOp),
    BinaryOp(BinaryOp),
}

#[derive(PartialEq, Debug)]
pub struct Program {
    pub functions: Functions,
}

#[derive(PartialEq, Debug)]
pub struct Function {
    pub name: String,
    pub filename: String,
    pub body: Node<Statement>,
    pub args: Vec<Rc<Variable>>,
    pub ret_type: Type,
    pub symbols: Rc<RefCell<SymbolTable>>,
}

#[derive(PartialEq, Debug)]
pub enum Statement {
    Expression {
        expr: Box<Node<Expression>>,
    },
    Declaration {
        var: Rc<Variable>,
    },
    Assignment {
        var: Rc<Variable>,
        expr: Box<Node<Expression>>,
    },
    If {
        cond: Box<Node<Expression>>,
        on_true: Box<Node<Statement>>,
        on_false: Option<Box<Node<Statement>>>,
    },
    While {
        cond: Box<Node<Expression>>,
        body: Box<Node<Statement>>,
    },
    Return {
        expr: Option<Box<Node<Expression>>>,
    },
    Compound {
        stmts: Vec<Node<Statement>>,
        symbols: Rc<RefCell<SymbolTable>>,
    },
}

impl Node<Statement> {
    /// Visit all statements with a given closure.
    ///
    /// The given closure is called for each statement with a reference to the
    /// given node. This reference inherits the lifetime of `self`. The return
    /// value indicates whether further statements should be visited or not.
    ///
    /// Use this method as alternative to the [Visitor].
    ///
    /// [Visitor]: <trait.Visitor.html>
    pub fn visit_stmt<'a>(&'a self, do_stmt: &mut FnMut(&'a Node<Statement>) -> bool) -> bool {
        do_stmt(self) || return false;
        match self.node {
            Statement::If { ref on_true, ref on_false, .. } => {
                on_true.visit_stmt(do_stmt) ||
                if let Some(ref stmt) = *on_false {
                    stmt.visit_stmt(do_stmt)
                } else {
                    true
                }
            }
            Statement::While { ref body, .. } => body.visit_stmt(do_stmt),
            Statement::Compound { ref stmts, .. } => {
                for stmt in stmts.iter() {
                    stmt.visit_stmt(do_stmt) || return false;
                }
                true
            }
            _ => true,
        }
    }

    /// Visit all expressions with a given closure.
    ///
    /// Same as [visit_stmt], but for expressions.
    ///
    /// [visit_stmt]: <struct.Node.html#method.visit_expr>
    pub fn visit_expr<'a>(&'a self, do_expr: &mut FnMut(&'a Node<Expression>) -> bool) -> bool {
        self.visit_stmt(&mut |stmt| {
            match stmt.node {
                Statement::Expression { ref expr } => do_expr(expr),
                Statement::Assignment { ref expr, .. } => do_expr(expr),
                Statement::If { ref cond, .. } => do_expr(cond),
                Statement::While { ref cond, .. } => do_expr(cond),
                Statement::Return { expr: Some(ref expr) } => do_expr(expr),
                _ => true,
            }
        })
    }
}

#[derive(PartialEq, Debug)]
pub enum Expression {
    Literal {
        lit: Literal,
    },
    Variable {
        var: Rc<Variable>,
    },
    Call {
        function: String,
        args: Vec<Node<Expression>>,
    },
    Unary {
        op: UnaryOp,
        expr: Box<Node<Expression>>,
    },
    Binary {
        op: BinaryOp,
        left: Box<Node<Expression>>,
        right: Box<Node<Expression>>,
    },
    Parenthesis {
        expr: Box<Node<Expression>>,
    },
}

impl Node<Expression> {
    /// Visit all expressions with a given closure.
    ///
    /// Same as [visit_stmt], but for expressions.
    ///
    /// [visit_stmt]: <struct.Node.html#method.visit_expr>
    pub fn visit_expr<'a>(&'a self, do_expr: &mut FnMut(&'a Node<Expression>) -> bool) -> bool {
        do_expr(self) || return false;
        match self.node {
            Expression::Call { ref args, .. } => {
                for arg in args.iter() {
                    arg.visit_expr(do_expr) || return false;
                }
                true
            }
            Expression::Unary { ref expr, .. } => expr.visit_expr(do_expr),
            Expression::Parenthesis { ref expr } => expr.visit_expr(do_expr),
            Expression::Binary { ref left, ref right, .. } => {
                left.visit_expr(do_expr) || return false;
                right.visit_expr(do_expr)
            }
            _ => true,
        }
    }
}

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

    #[test]
    fn literals() {
        assert_eq!(Type::Bool, Literal::Bool(false).get_type());
        assert_eq!(Type::Int, Literal::Int(0).get_type());
        assert_eq!(Type::Float, Literal::Float(0.0).get_type());
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 Luis de Bethencourt <luis@debethencourt.com>
// Copyright 2013 The Rust Project Developers
// http://rust-lang.org

// 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.

/*!
 * Gregorian Calendar module for the datetime library of the Rust programming
 * language
 *
 * Implements a hybrid calendar that supports both the Julian and Gregorian
 * calendar systems.
 *
 * http://en.wikipedia.org/wiki/Gregorian_calendar
 * http://en.wikipedia.org/wiki/Julian_calendar
 */

static YEAR_BASE: int = 1900;
static DAYSPERLYEAR: uint = 366;
static DAYSPERNYEAR: uint = 365;
static DAYSPERWEEK: uint = 7;

pub fn is_leap_year(year: uint) -> bool {
    !(year % 4 != 0) && ((year % 100 != 0) || !(year % 400 != 0))
}

pub fn year_size(year: uint) -> uint {
    if is_leap_year(year) { DAYSPERLYEAR } else { DAYSPERNYEAR }
}

pub struct GCalendar {
    /**
    */
    sec: uint,
    min: uint,
    hour: uint,
    day_of_month: uint,
    month: uint,
    year: uint,
    day_of_week: uint,
    day_of_year: uint
}

impl GCalendar {
    /**
    * Allocates a GCalendar object
    */
    pub fn new_at_epoch() -> GCalendar {
        GCalendar {
            sec: 0,
            min: 0,
            hour: 0,
            day_of_month: 0,
            month: 0,
            year: 0,
            day_of_week: 0,
            day_of_year: 0,
        }
    }

    pub fn new(sec: uint, min: uint, hour: uint, day_of_month: uint, month: uint,
            year: uint, day_of_week: uint, day_of_year: uint) -> GCalendar {
        GCalendar {
            sec: sec,
            min: min,
            hour: hour,
            day_of_month: day_of_month,
            month: month,
            year: year,
            day_of_week: day_of_week,
            day_of_year: day_of_year,
        }
    }

    pub fn new_from_epoch(since_epoch: uint) -> GCalendar {
        let epoch_year = 1970;
        let mut year = epoch_year;

        let millisecs_day = 86400000;

        let mut dayclock = since_epoch % millisecs_day;
        let mut dayno = since_epoch / millisecs_day;

        let hour = dayclock / 3600000;
        dayclock = dayclock - (hour * 3600000);

        let min = dayclock / 60000;
        dayclock = dayclock - (min * 60000);

        let sec = dayclock / 1000;

        while (dayno >= year_size(year)) {
            dayno -= year_size(year);
            year += 1;
        }
        let year = year;

        GCalendar {
            sec: sec,
            min: min,
            hour: hour,
            day_of_month: 0,
            month: 0,
            year: year,
            day_of_week: 0,
            day_of_year: dayno,
        }
    }

    pub fn get_sec(&self) -> uint {
        self.sec
    }

    pub fn get_min(&self) -> uint {
        self.min
    }

    pub fn get_hour(&self) -> uint {
        self.hour
    }

    pub fn get_year(&self) -> uint {
        self.year
    }

    pub fn get_day_of_year(&self) -> uint {
        self.day_of_year
    }

    pub fn get_date(&self) -> ~str {
        // ToDo
        ~""
    }
}

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

    #[test]
    fn new() {
        let gc = GCalendar::new(21, 0, 12, 23, 9, 1983, 5, 265);
        assert_eq!(gc.get_sec(), 21);
        assert_eq!(gc.get_min(), 0);
        assert_eq!(gc.get_hour(), 12);
        assert_eq!(gc.get_year(), 1983);
        assert_eq!(gc.get_day_of_year(), 265);
    }

    fn new_from_epoch() {
        let gc = GCalendar::new_from_epoch(433166421023);
        assert_eq!(gc.get_sec(), 21);
        assert_eq!(gc.get_min(), 0);
        assert_eq!(gc.get_hour(), 12);
        assert_eq!(gc.get_year(), 1983);
        assert_eq!(gc.get_day_of_year(), 265);
    }
}
<commit_msg>gcalendar.rs: less boolean operations in is_leap_year()<commit_after>// Copyright 2013 Luis de Bethencourt <luis@debethencourt.com>
// Copyright 2013 The Rust Project Developers
// http://rust-lang.org

// 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.

/*!
 * Gregorian Calendar module for the datetime library of the Rust programming
 * language
 *
 * Implements a hybrid calendar that supports both the Julian and Gregorian
 * calendar systems.
 *
 * http://en.wikipedia.org/wiki/Gregorian_calendar
 * http://en.wikipedia.org/wiki/Julian_calendar
 */

static YEAR_BASE: int = 1900;
static DAYSPERLYEAR: uint = 366;
static DAYSPERNYEAR: uint = 365;
static DAYSPERWEEK: uint = 7;

pub fn is_leap_year(year: uint) -> bool {
    (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))
}

pub fn year_size(year: uint) -> uint {
    if is_leap_year(year) { DAYSPERLYEAR } else { DAYSPERNYEAR }
}

pub struct GCalendar {
    /**
    */
    sec: uint,
    min: uint,
    hour: uint,
    day_of_month: uint,
    month: uint,
    year: uint,
    day_of_week: uint,
    day_of_year: uint
}

impl GCalendar {
    /**
    * Allocates a GCalendar object
    */
    pub fn new_at_epoch() -> GCalendar {
        GCalendar {
            sec: 0,
            min: 0,
            hour: 0,
            day_of_month: 0,
            month: 0,
            year: 0,
            day_of_week: 0,
            day_of_year: 0,
        }
    }

    pub fn new(sec: uint, min: uint, hour: uint, day_of_month: uint, month: uint,
            year: uint, day_of_week: uint, day_of_year: uint) -> GCalendar {
        GCalendar {
            sec: sec,
            min: min,
            hour: hour,
            day_of_month: day_of_month,
            month: month,
            year: year,
            day_of_week: day_of_week,
            day_of_year: day_of_year,
        }
    }

    pub fn new_from_epoch(since_epoch: uint) -> GCalendar {
        let epoch_year = 1970;
        let mut year = epoch_year;

        let millisecs_day = 86400000;

        let mut dayclock = since_epoch % millisecs_day;
        let mut dayno = since_epoch / millisecs_day;

        let hour = dayclock / 3600000;
        dayclock = dayclock - (hour * 3600000);

        let min = dayclock / 60000;
        dayclock = dayclock - (min * 60000);

        let sec = dayclock / 1000;

        while (dayno >= year_size(year)) {
            dayno -= year_size(year);
            year += 1;
        }
        let year = year;

        GCalendar {
            sec: sec,
            min: min,
            hour: hour,
            day_of_month: 0,
            month: 0,
            year: year,
            day_of_week: 0,
            day_of_year: dayno,
        }
    }

    pub fn get_sec(&self) -> uint {
        self.sec
    }

    pub fn get_min(&self) -> uint {
        self.min
    }

    pub fn get_hour(&self) -> uint {
        self.hour
    }

    pub fn get_year(&self) -> uint {
        self.year
    }

    pub fn get_day_of_year(&self) -> uint {
        self.day_of_year
    }

    pub fn get_date(&self) -> ~str {
        // ToDo
        ~""
    }
}

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

    #[test]
    fn new() {
        let gc = GCalendar::new(21, 0, 12, 23, 9, 1983, 5, 265);
        assert_eq!(gc.get_sec(), 21);
        assert_eq!(gc.get_min(), 0);
        assert_eq!(gc.get_hour(), 12);
        assert_eq!(gc.get_year(), 1983);
        assert_eq!(gc.get_day_of_year(), 265);
    }

    fn new_from_epoch() {
        let gc = GCalendar::new_from_epoch(433166421023);
        assert_eq!(gc.get_sec(), 21);
        assert_eq!(gc.get_min(), 0);
        assert_eq!(gc.get_hour(), 12);
        assert_eq!(gc.get_year(), 1983);
        assert_eq!(gc.get_day_of_year(), 265);
    }
}
<|endoftext|>


<commit_before>/*
Module: task

Task management.

An executing Rust program consists of a tree of tasks, each with their own
stack, and sole ownership of their allocated heap data. Tasks communicate
with each other using ports and channels.

When a task fails, that failure will propagate to its parent (the task
that spawned it) and the parent will fail as well. The reverse is not
true: when a parent task fails its children will continue executing. When
the root (main) task fails, all tasks fail, and then so does the entire
process.

A task may remove itself from this failure propagation mechanism by
calling the <unsupervise> function, after which failure will only
result in the termination of that task.

Tasks may execute in parallel and are scheduled automatically by the runtime.

Example:

> spawn("Hello, World", fn (&&msg: str) {
>   log msg;
> });

*/
import cast = unsafe::reinterpret_cast;
import comm;
import option::{some, none};
import option = option::t;
import ptr;

export task;
export joinable_task;
export sleep;
export yield;
export task_notification;
export join;
export unsupervise;
export pin;
export unpin;
export set_min_stack;
export task_result;
export tr_success;
export tr_failure;
export get_task;
export spawn;
export spawn_notify;
export spawn_joinable;

native "cdecl" mod rustrt {
    // these must run on the Rust stack so that they can swap stacks etc:
    fn task_sleep(time_in_us: uint);
    fn task_yield();
    fn start_task(id: task, closure: *u8);
}

native "c-stack-cdecl" mod rustrt2 = "rustrt" {
    // these can run on the C stack:
    fn pin_task();
    fn unpin_task();
    fn get_task_id() -> task_id;

    fn set_min_stack(stack_size: uint);

    fn new_task() -> task_id;
    fn drop_task(task_id: *rust_task);
    fn get_task_pointer(id: task_id) -> *rust_task;

    fn migrate_alloc(alloc: *u8, target: task_id);
}

/* Section: Types */

type rust_task =
    {id: task,
     mutable notify_enabled: u32,
     mutable notify_chan: comm::chan<task_notification>,
     mutable stack_ptr: *u8};

resource rust_task_ptr(task: *rust_task) { rustrt2::drop_task(task); }

type task_id = int;

/*
Type: task

A handle to a task
*/
type task = task_id;

/*
Type: joinable_task

A task that sends notification upon termination
*/
type joinable_task = (task, comm::port<task_notification>);

/*
Tag: task_result

Indicates the manner in which a task exited
*/
tag task_result {
    /* Variant: tr_success */
    tr_success;
    /* Variant: tr_failure */
    tr_failure;
}

/*
Tag: task_notification

Message sent upon task exit to indicate normal or abnormal termination
*/
tag task_notification {
    /* Variant: exit */
    exit(task, task_result);
}

/* Section: Operations */

/*
Type: get_task

Retreives a handle to the currently executing task
*/
fn get_task() -> task { rustrt2::get_task_id() }

/*
Function: sleep

Hints the scheduler to yield this task for a specified ammount of time.

Parameters:

time_in_us - maximum number of microseconds to yield control for
*/
fn sleep(time_in_us: uint) { ret rustrt::task_sleep(time_in_us); }

/*
Function: yield

Yield control to the task scheduler

The scheduler may schedule another task to execute.
*/
fn yield() { ret rustrt::task_yield(); }

/*
Function: join

Wait for a child task to exit

The child task must have been spawned with <spawn_joinable>, which
produces a notification port that the child uses to communicate its
exit status.

Returns:

A task_result indicating whether the task terminated normally or failed
*/
fn join(task_port: joinable_task) -> task_result {
    let (id, port) = task_port;
    alt comm::recv::<task_notification>(port) {
      exit(_id, res) {
        if _id == id {
            ret res
        } else { fail #fmt["join received id %d, expected %d", _id, id] }
      }
    }
}

/*
Function: unsupervise

Detaches this task from its parent in the task tree

An unsupervised task will not propagate its failure up the task tree
*/
fn unsupervise() { ret sys::unsupervise(); }

/*
Function: pin

Pins the current task and future child tasks to a single scheduler thread
*/
fn pin() { rustrt2::pin_task(); }

/*
Function: unpin

Unpin the current task and future child tasks
*/
fn unpin() { rustrt2::unpin_task(); }

/*
Function: set_min_stack

Set the minimum stack size (in bytes) for tasks spawned in the future.

This function has global effect and should probably not be used.
*/
fn set_min_stack(stack_size: uint) { rustrt2::set_min_stack(stack_size); }

/*
Function: spawn

Creates and executes a new child task

Sets up a new task with its own call stack and schedules it to be executed.
Upon execution the new task will call function `f` with the provided
argument `data`.

Function `f` is a bare function, meaning it may not close over any data, as do
shared functions (fn@) and lambda blocks. `data` must be a uniquely owned
type; it is moved into the new task and thus can no longer be accessed
locally.

Parameters:

data - A unique-type value to pass to the new task
f - A function to execute in the new task

Returns:

A handle to the new task
*/
fn spawn<uniq T>(-data: T, f: fn(T)) -> task {
    spawn_inner(data, f, none)
}

/*
Function: spawn_notify

Create and execute a new child task, requesting notification upon its
termination

Immediately before termination, either on success or failure, the spawned
task will send a <task_notification> message on the provided channel.
*/
fn spawn_notify<uniq T>(-data: T, f: fn(T),
                         notify: comm::chan<task_notification>) -> task {
    spawn_inner(data, f, some(notify))
}

/*
Function: spawn_joinable

Create and execute a task which can later be joined with the <join> function

This is a convenience wrapper around spawn_notify which, when paired
with <join> can be easily used to spawn a task then wait for it to
complete.
*/
fn spawn_joinable<uniq T>(-data: T, f: fn(T)) -> joinable_task {
    let p = comm::port::<task_notification>();
    let id = spawn_notify(data, f, comm::chan::<task_notification>(p));
    ret (id, p);
}

// FIXME: To transition from the unsafe spawn that spawns a shared closure to
// the safe spawn that spawns a bare function we're going to write
// barefunc-spawn on top of unsafe-spawn.  Sadly, bind does not work reliably
// enough to suite our needs (#1034, probably others yet to be discovered), so
// we're going to copy the bootstrap data into a unique pointer, cast it to an
// unsafe pointer then wrap up the bare function and the unsafe pointer in a
// shared closure to spawn.
//
// After the transition this should all be rewritten.

fn spawn_inner<uniq T>(-data: T, f: fn(T),
                          notify: option<comm::chan<task_notification>>)
    -> task unsafe {

    fn wrapper<uniq T>(-data: *u8, f: fn(T)) unsafe {
        let data: ~T = unsafe::reinterpret_cast(data);
        f(*data);
    }

    let data = ~data;
    let dataptr: *u8 = unsafe::reinterpret_cast(data);
    unsafe::leak(data);
    let wrapped = bind wrapper(dataptr, f);
    ret unsafe_spawn_inner(wrapped, notify);
}

// FIXME: This is the old spawn function that spawns a shared closure.
// It is a hack and needs to be rewritten.
fn unsafe_spawn_inner(-thunk: fn@(),
                      notify: option<comm::chan<task_notification>>) ->
   task unsafe {
    let id = rustrt2::new_task();

    let raw_thunk: {code: u32, env: u32} = cast(thunk);

    // set up the task pointer
    let task_ptr <- rust_task_ptr(rustrt2::get_task_pointer(id));

    assert (ptr::null() != (**task_ptr).stack_ptr);

    // copy the thunk from our stack to the new stack
    let sp: uint = cast((**task_ptr).stack_ptr);
    let ptrsize = sys::size_of::<*u8>();
    let thunkfn: *mutable uint = cast(sp - ptrsize * 2u);
    let thunkenv: *mutable uint = cast(sp - ptrsize);
    *thunkfn = cast(raw_thunk.code);;
    *thunkenv = cast(raw_thunk.env);;
    // align the stack to 16 bytes
    (**task_ptr).stack_ptr = cast(sp - ptrsize * 4u);

    // set up notifications if they are enabled.
    alt notify {
      some(c) {
        (**task_ptr).notify_enabled = 1u32;;
        (**task_ptr).notify_chan = c;
      }
      none { }
    }

    // give the thunk environment's allocation to the new task
    rustrt2::migrate_alloc(cast(raw_thunk.env), id);
    rustrt::start_task(id, cast(thunkfn));
    // don't cleanup the thunk in this task
    unsafe::leak(thunk);
    ret id;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>start_task can run on the C stack<commit_after>/*
Module: task

Task management.

An executing Rust program consists of a tree of tasks, each with their own
stack, and sole ownership of their allocated heap data. Tasks communicate
with each other using ports and channels.

When a task fails, that failure will propagate to its parent (the task
that spawned it) and the parent will fail as well. The reverse is not
true: when a parent task fails its children will continue executing. When
the root (main) task fails, all tasks fail, and then so does the entire
process.

A task may remove itself from this failure propagation mechanism by
calling the <unsupervise> function, after which failure will only
result in the termination of that task.

Tasks may execute in parallel and are scheduled automatically by the runtime.

Example:

> spawn("Hello, World", fn (&&msg: str) {
>   log msg;
> });

*/
import cast = unsafe::reinterpret_cast;
import comm;
import option::{some, none};
import option = option::t;
import ptr;

export task;
export joinable_task;
export sleep;
export yield;
export task_notification;
export join;
export unsupervise;
export pin;
export unpin;
export set_min_stack;
export task_result;
export tr_success;
export tr_failure;
export get_task;
export spawn;
export spawn_notify;
export spawn_joinable;

native "cdecl" mod rustrt {
    // these must run on the Rust stack so that they can swap stacks etc:
    fn task_sleep(time_in_us: uint);
    fn task_yield();
}

native "c-stack-cdecl" mod rustrt2 = "rustrt" {
    // these can run on the C stack:
    fn pin_task();
    fn unpin_task();
    fn get_task_id() -> task_id;

    fn set_min_stack(stack_size: uint);

    fn new_task() -> task_id;
    fn drop_task(task_id: *rust_task);
    fn get_task_pointer(id: task_id) -> *rust_task;

    fn migrate_alloc(alloc: *u8, target: task_id);

    fn start_task(id: task, closure: *u8);

}

/* Section: Types */

type rust_task =
    {id: task,
     mutable notify_enabled: u32,
     mutable notify_chan: comm::chan<task_notification>,
     mutable stack_ptr: *u8};

resource rust_task_ptr(task: *rust_task) { rustrt2::drop_task(task); }

type task_id = int;

/*
Type: task

A handle to a task
*/
type task = task_id;

/*
Type: joinable_task

A task that sends notification upon termination
*/
type joinable_task = (task, comm::port<task_notification>);

/*
Tag: task_result

Indicates the manner in which a task exited
*/
tag task_result {
    /* Variant: tr_success */
    tr_success;
    /* Variant: tr_failure */
    tr_failure;
}

/*
Tag: task_notification

Message sent upon task exit to indicate normal or abnormal termination
*/
tag task_notification {
    /* Variant: exit */
    exit(task, task_result);
}

/* Section: Operations */

/*
Type: get_task

Retreives a handle to the currently executing task
*/
fn get_task() -> task { rustrt2::get_task_id() }

/*
Function: sleep

Hints the scheduler to yield this task for a specified ammount of time.

Parameters:

time_in_us - maximum number of microseconds to yield control for
*/
fn sleep(time_in_us: uint) { ret rustrt::task_sleep(time_in_us); }

/*
Function: yield

Yield control to the task scheduler

The scheduler may schedule another task to execute.
*/
fn yield() { ret rustrt::task_yield(); }

/*
Function: join

Wait for a child task to exit

The child task must have been spawned with <spawn_joinable>, which
produces a notification port that the child uses to communicate its
exit status.

Returns:

A task_result indicating whether the task terminated normally or failed
*/
fn join(task_port: joinable_task) -> task_result {
    let (id, port) = task_port;
    alt comm::recv::<task_notification>(port) {
      exit(_id, res) {
        if _id == id {
            ret res
        } else { fail #fmt["join received id %d, expected %d", _id, id] }
      }
    }
}

/*
Function: unsupervise

Detaches this task from its parent in the task tree

An unsupervised task will not propagate its failure up the task tree
*/
fn unsupervise() { ret sys::unsupervise(); }

/*
Function: pin

Pins the current task and future child tasks to a single scheduler thread
*/
fn pin() { rustrt2::pin_task(); }

/*
Function: unpin

Unpin the current task and future child tasks
*/
fn unpin() { rustrt2::unpin_task(); }

/*
Function: set_min_stack

Set the minimum stack size (in bytes) for tasks spawned in the future.

This function has global effect and should probably not be used.
*/
fn set_min_stack(stack_size: uint) { rustrt2::set_min_stack(stack_size); }

/*
Function: spawn

Creates and executes a new child task

Sets up a new task with its own call stack and schedules it to be executed.
Upon execution the new task will call function `f` with the provided
argument `data`.

Function `f` is a bare function, meaning it may not close over any data, as do
shared functions (fn@) and lambda blocks. `data` must be a uniquely owned
type; it is moved into the new task and thus can no longer be accessed
locally.

Parameters:

data - A unique-type value to pass to the new task
f - A function to execute in the new task

Returns:

A handle to the new task
*/
fn spawn<uniq T>(-data: T, f: fn(T)) -> task {
    spawn_inner(data, f, none)
}

/*
Function: spawn_notify

Create and execute a new child task, requesting notification upon its
termination

Immediately before termination, either on success or failure, the spawned
task will send a <task_notification> message on the provided channel.
*/
fn spawn_notify<uniq T>(-data: T, f: fn(T),
                         notify: comm::chan<task_notification>) -> task {
    spawn_inner(data, f, some(notify))
}

/*
Function: spawn_joinable

Create and execute a task which can later be joined with the <join> function

This is a convenience wrapper around spawn_notify which, when paired
with <join> can be easily used to spawn a task then wait for it to
complete.
*/
fn spawn_joinable<uniq T>(-data: T, f: fn(T)) -> joinable_task {
    let p = comm::port::<task_notification>();
    let id = spawn_notify(data, f, comm::chan::<task_notification>(p));
    ret (id, p);
}

// FIXME: To transition from the unsafe spawn that spawns a shared closure to
// the safe spawn that spawns a bare function we're going to write
// barefunc-spawn on top of unsafe-spawn.  Sadly, bind does not work reliably
// enough to suite our needs (#1034, probably others yet to be discovered), so
// we're going to copy the bootstrap data into a unique pointer, cast it to an
// unsafe pointer then wrap up the bare function and the unsafe pointer in a
// shared closure to spawn.
//
// After the transition this should all be rewritten.

fn spawn_inner<uniq T>(-data: T, f: fn(T),
                          notify: option<comm::chan<task_notification>>)
    -> task unsafe {

    fn wrapper<uniq T>(-data: *u8, f: fn(T)) unsafe {
        let data: ~T = unsafe::reinterpret_cast(data);
        f(*data);
    }

    let data = ~data;
    let dataptr: *u8 = unsafe::reinterpret_cast(data);
    unsafe::leak(data);
    let wrapped = bind wrapper(dataptr, f);
    ret unsafe_spawn_inner(wrapped, notify);
}

// FIXME: This is the old spawn function that spawns a shared closure.
// It is a hack and needs to be rewritten.
fn unsafe_spawn_inner(-thunk: fn@(),
                      notify: option<comm::chan<task_notification>>) ->
   task unsafe {
    let id = rustrt2::new_task();

    let raw_thunk: {code: u32, env: u32} = cast(thunk);

    // set up the task pointer
    let task_ptr <- rust_task_ptr(rustrt2::get_task_pointer(id));

    assert (ptr::null() != (**task_ptr).stack_ptr);

    // copy the thunk from our stack to the new stack
    let sp: uint = cast((**task_ptr).stack_ptr);
    let ptrsize = sys::size_of::<*u8>();
    let thunkfn: *mutable uint = cast(sp - ptrsize * 2u);
    let thunkenv: *mutable uint = cast(sp - ptrsize);
    *thunkfn = cast(raw_thunk.code);;
    *thunkenv = cast(raw_thunk.env);;
    // align the stack to 16 bytes
    (**task_ptr).stack_ptr = cast(sp - ptrsize * 4u);

    // set up notifications if they are enabled.
    alt notify {
      some(c) {
        (**task_ptr).notify_enabled = 1u32;;
        (**task_ptr).notify_chan = c;
      }
      none { }
    }

    // give the thunk environment's allocation to the new task
    rustrt2::migrate_alloc(cast(raw_thunk.env), id);
    rustrt2::start_task(id, cast(thunkfn));
    // don't cleanup the thunk in this task
    unsafe::leak(thunk);
    ret id;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


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

use std::collections::HashMap;

use auth;
use cursor::{CursorIter, UserCursor, ListCursor};
use error::Error::TwitterError;
use links;
use user;
use tweet;

///Look up the lists the given user has been added to.
pub fn memberships<'a>(user: &'a user::UserID, token: &'a auth::Token) -> CursorIter<'a, ListCursor> {
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    CursorIter::new(links::lists::LISTS_MEMBERSHIPS, token, Some(params), Some(20))
}

///Return up to 100 lists the given user is subscribed to, including those the user made
///themselves.
///
///TODO: this is not strictly `subscriptions` and `ownerships` blended
pub fn list<'a>(user: &'a user::UserID, owned_first: bool, token: &'a auth::Token)
    -> WebResponse<Vec<List>>
{
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    add_param(&mut params, "reverse", owned_first.to_string());

    let mut resp = try!(auth::get(links::lists::LISTS_LIST, token, Some(&params)));
    parse_response(&mut resp)
}

///Look up the lists the given user is subscribed to, but not ones the user made themselves.
pub fn subscriptions<'a>(user: &'a user::UserID, token: &'a auth::Token) -> CursorIter<'a, ListCursor> {
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    CursorIter::new(links::lists::LISTS_SUBSCRIPTIONS, token, Some(params), Some(20))
}

///Look up the lists created by the given user.
pub fn ownerships<'a>(user: &'a user::UserID, token: &'a auth::Token) -> CursorIter<'a, ListCursor> {
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    CursorIter::new(links::lists::LISTS_OWNERSHIPS, token, Some(params), Some(20))
}

///Look up information for a single list.
pub fn show<'a>(list: ListID<'a>, token: &'a auth::Token) -> WebResponse<List> {
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);

    let mut resp = try!(auth::get(links::lists::LISTS_SHOW, token, Some(&params)));

    parse_response(&mut resp)
}

///Look up the users that have been added to the given list.
pub fn members<'a>(list: ListID<'a>, token: &'a auth::Token) -> CursorIter<'a, UserCursor> {
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);

    CursorIter::new(links::lists::LISTS_MEMBERS, token, Some(params), Some(20))
}

///Look up the users that have subscribed to the given list.
pub fn suscribers<'a>(list: ListID<'a>, token: &'a auth::Token) -> CursorIter<'a, UserCursor> {
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);

    CursorIter::new(links::lists::LISTS_SUBSCRIBERS, token, Some(params), Some(20))
}

///Check whether the given user is subscribed to the given list.
pub fn is_subscribed<'a, T: Into<user::UserID<'a>>>(user: T, list: ListID<'a>, token: &auth::Token) ->
    WebResponse<bool>
{
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);
    add_name_param(&mut params, &user.into());

    let mut resp = try!(auth::get(links::lists::LISTS_SUBSCRIBERS_SHOW, token, Some(&params)));

    let out: WebResponse<user::TwitterUser> = parse_response(&mut resp);

    match out {
        Ok(user) => Ok(Response::map(user, |_| true)),
        Err(TwitterError(terrs)) => {
            //TODO: this is currently a copy of is_member, is the error code different?
            if terrs.errors.iter().any(|e| e.code == 109) {
                //here's a fun conundrum: since "is not in this list" is returned as an error code,
                //the rate limit info that would otherwise be part of the response isn't there. the
                //rate_headers method was factored out specifically for this location, since it's
                //still there, just accompanying an error response instead of a user.
                Ok(Response::map(rate_headers(&resp), |_| false))
            }
            else {
                Err(TwitterError(terrs))
            }
        },
        Err(err) => Err(err),
    }
}

///Check whether the given user has been added to the given list.
pub fn is_member<'a, T: Into<user::UserID<'a>>>(user: T, list: ListID<'a>, token: &auth::Token) ->
    WebResponse<bool>
{
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);
    add_name_param(&mut params, &user.into());

    let mut resp = try!(auth::get(links::lists::LISTS_MEMBERS_SHOW, token, Some(&params)));

    let out: WebResponse<user::TwitterUser> = parse_response(&mut resp);

    match out {
        Ok(user) => Ok(Response::map(user, |_| true)),
        Err(TwitterError(terrs)) => {
            if terrs.errors.iter().any(|e| e.code == 109) {
                //here's a fun conundrum: since "is not in this list" is returned as an error code,
                //the rate limit info that would otherwise be part of the response isn't there. the
                //rate_headers method was factored out specifically for this location, since it's
                //still there, just accompanying an error response instead of a user.
                Ok(Response::map(rate_headers(&resp), |_| false))
            }
            else {
                Err(TwitterError(terrs))
            }
        },
        Err(err) => Err(err),
    }
}

///Begin navigating the collection of tweets made by the users added to the given list.
pub fn statuses<'a>(list: ListID<'a>, with_rts: bool, token: &'a auth::Token)
    -> tweet::Timeline<'a>
{
    let mut params = HashMap::new();
    add_list_param(&mut params, &list);
    add_param(&mut params, "include_rts", with_rts.to_string());

    tweet::Timeline::new(links::lists::LISTS_STATUSES, Some(params), token)
}
<commit_msg>touch up list subscribers code after testing<commit_after>use common::*;
use super::*;

use std::collections::HashMap;

use auth;
use cursor::{CursorIter, UserCursor, ListCursor};
use error::Error::TwitterError;
use links;
use user;
use tweet;

///Look up the lists the given user has been added to.
pub fn memberships<'a>(user: &'a user::UserID, token: &'a auth::Token) -> CursorIter<'a, ListCursor> {
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    CursorIter::new(links::lists::LISTS_MEMBERSHIPS, token, Some(params), Some(20))
}

///Return up to 100 lists the given user is subscribed to, including those the user made
///themselves.
///
///TODO: this is not strictly `subscriptions` and `ownerships` blended
pub fn list<'a>(user: &'a user::UserID, owned_first: bool, token: &'a auth::Token)
    -> WebResponse<Vec<List>>
{
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    add_param(&mut params, "reverse", owned_first.to_string());

    let mut resp = try!(auth::get(links::lists::LISTS_LIST, token, Some(&params)));
    parse_response(&mut resp)
}

///Look up the lists the given user is subscribed to, but not ones the user made themselves.
pub fn subscriptions<'a>(user: &'a user::UserID, token: &'a auth::Token) -> CursorIter<'a, ListCursor> {
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    CursorIter::new(links::lists::LISTS_SUBSCRIPTIONS, token, Some(params), Some(20))
}

///Look up the lists created by the given user.
pub fn ownerships<'a>(user: &'a user::UserID, token: &'a auth::Token) -> CursorIter<'a, ListCursor> {
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    CursorIter::new(links::lists::LISTS_OWNERSHIPS, token, Some(params), Some(20))
}

///Look up information for a single list.
pub fn show<'a>(list: ListID<'a>, token: &'a auth::Token) -> WebResponse<List> {
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);

    let mut resp = try!(auth::get(links::lists::LISTS_SHOW, token, Some(&params)));

    parse_response(&mut resp)
}

///Look up the users that have been added to the given list.
pub fn members<'a>(list: ListID<'a>, token: &'a auth::Token) -> CursorIter<'a, UserCursor> {
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);

    CursorIter::new(links::lists::LISTS_MEMBERS, token, Some(params), Some(20))
}

///Look up the users that have subscribed to the given list.
pub fn subscribers<'a>(list: ListID<'a>, token: &'a auth::Token) -> CursorIter<'a, UserCursor> {
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);

    CursorIter::new(links::lists::LISTS_SUBSCRIBERS, token, Some(params), Some(20))
}

///Check whether the given user is subscribed to the given list.
pub fn is_subscribed<'a, T: Into<user::UserID<'a>>>(user: T, list: ListID<'a>, token: &auth::Token) ->
    WebResponse<bool>
{
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);
    add_name_param(&mut params, &user.into());

    let mut resp = try!(auth::get(links::lists::LISTS_SUBSCRIBERS_SHOW, token, Some(&params)));

    let out: WebResponse<user::TwitterUser> = parse_response(&mut resp);

    match out {
        Ok(user) => Ok(Response::map(user, |_| true)),
        Err(TwitterError(terrs)) => {
            if terrs.errors.iter().any(|e| e.code == 109) {
                //here's a fun conundrum: since "is not in this list" is returned as an error code,
                //the rate limit info that would otherwise be part of the response isn't there. the
                //rate_headers method was factored out specifically for this location, since it's
                //still there, just accompanying an error response instead of a user.
                Ok(Response::map(rate_headers(&resp), |_| false))
            }
            else {
                Err(TwitterError(terrs))
            }
        },
        Err(err) => Err(err),
    }
}

///Check whether the given user has been added to the given list.
pub fn is_member<'a, T: Into<user::UserID<'a>>>(user: T, list: ListID<'a>, token: &auth::Token) ->
    WebResponse<bool>
{
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);
    add_name_param(&mut params, &user.into());

    let mut resp = try!(auth::get(links::lists::LISTS_MEMBERS_SHOW, token, Some(&params)));

    let out: WebResponse<user::TwitterUser> = parse_response(&mut resp);

    match out {
        Ok(user) => Ok(Response::map(user, |_| true)),
        Err(TwitterError(terrs)) => {
            if terrs.errors.iter().any(|e| e.code == 109) {
                //here's a fun conundrum: since "is not in this list" is returned as an error code,
                //the rate limit info that would otherwise be part of the response isn't there. the
                //rate_headers method was factored out specifically for this location, since it's
                //still there, just accompanying an error response instead of a user.
                Ok(Response::map(rate_headers(&resp), |_| false))
            }
            else {
                Err(TwitterError(terrs))
            }
        },
        Err(err) => Err(err),
    }
}

///Begin navigating the collection of tweets made by the users added to the given list.
pub fn statuses<'a>(list: ListID<'a>, with_rts: bool, token: &'a auth::Token)
    -> tweet::Timeline<'a>
{
    let mut params = HashMap::new();
    add_list_param(&mut params, &list);
    add_param(&mut params, "include_rts", with_rts.to_string());

    tweet::Timeline::new(links::lists::LISTS_STATUSES, Some(params), token)
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::cmp::Ordering;

#[derive(Debug, PartialEq)]
pub struct Result {
    pub path: PathBuf,
    score: f32,
}

/// Given a set of paths, `find` returns a set of `Result` objects
/// ordered by increasing score values (first values are closest matches).
/// If the result set is larger than `max_results`, the set is reduced to
/// that size.
///
/// # Examples
///
/// ```rust
/// use std::path::PathBuf;
/// use bloodhound::matching::find;
///
/// let paths = vec![PathBuf::from("bloodhound.rs"), PathBuf::from("lib.rs")];
/// let matches = find("lib", &paths, 1);
///
/// assert_eq!(matches[0].path.to_str().unwrap(), "lib.rs");
/// ```
pub fn find(needle: &str, haystack: &Vec<PathBuf>, max_results: usize) -> Vec<Result> {
    let mut results = Vec::new();

    // Calculate a score for each of the haystack entries.
    for path in haystack.iter() {
        match path.to_str() {
            Some(path_string) => {
                results.push(Result{
                    path: path.clone(),
                    score: similarity(needle, path_string)
                });
            },
            None => (),
        }
    }

    // Sort the results in ascending order (higher values are worse).
    results.sort_by(|a, b| {
        if a.score > b.score {
            Ordering::Less
        } else if a.score < b.score {
            Ordering::Greater
        } else {
            Ordering::Equal
        }
    });

    // Make sure we don't exceed the specified result limit.
    results.truncate(max_results);

    results
}

/// Compares the query string to the subject,
/// and returns a score between 0 and 1.
fn similarity(query: &str, subject: &str) -> f32 {
    // Exact matches produce a perfect score.
    if query == subject {
        return 1.0;
    }

    let mut overall_score = 0.0;
    let subject_length = subject.chars().count();
    for query_char in query.chars() {
        let mut character_score = 0.0;
        for subject_char in subject.chars() {
            if query_char == subject_char {
                character_score += 1.0;
            }
        }

        character_score /= subject_length as f32;
        overall_score += character_score;
    }

    overall_score / query.chars().count() as f32
}

#[cfg(test)]
mod tests {
    use super::find;
    use std::path::PathBuf;

    #[test]
    fn find_returns_a_correctly_ordered_set_of_results() {
        let haystack = vec![PathBuf::from("src/hound.rs"),
            PathBuf::from("lib/hounds.rs"), PathBuf::from("Houndfile")];
        let expected_results = vec![PathBuf::from("Houndfile"), PathBuf::from("src/hound.rs")];
        let results = find("Hound", &haystack, 2);
        for i in 0..2 {
            assert_eq!(results[i].path, expected_results[i]);
        }
    }

    #[test]
    fn find_returns_a_correctly_limited_set_of_results() {
        let haystack = vec![PathBuf::from("src/hound.rs"),
            PathBuf::from("lib/hounds.rs"), PathBuf::from("Houndfile")];
        let results = find("Hound", &haystack, 2);
        assert_eq!(results.len(), 2);
    }
}
<commit_msg>Update similarity algorithm to consider term lengths. Add other tests and comments.<commit_after>use std::path::PathBuf;
use std::cmp::Ordering;

#[derive(Debug, PartialEq)]
pub struct Result {
    pub path: PathBuf,
    score: f32,
}

/// Given a set of paths, `find` returns a set of `Result` objects
/// ordered by increasing score values (first values are closest matches).
/// If the result set is larger than `max_results`, the set is reduced to
/// that size.
///
/// # Examples
///
/// ```rust
/// use std::path::PathBuf;
/// use bloodhound::matching::find;
///
/// let paths = vec![PathBuf::from("bloodhound.rs"), PathBuf::from("lib.rs")];
/// let matches = find("lib", &paths, 1);
///
/// assert_eq!(matches[0].path.to_str().unwrap(), "lib.rs");
/// ```
pub fn find(needle: &str, haystack: &Vec<PathBuf>, max_results: usize) -> Vec<Result> {
    let mut results = Vec::new();

    // Calculate a score for each of the haystack entries.
    for path in haystack.iter() {
        match path.to_str() {
            Some(path_string) => {
                results.push(Result{
                    path: path.clone(),
                    score: similarity(needle, path_string)
                });
            },
            None => (),
        }
    }

    // Sort the results in ascending order (higher values are worse).
    results.sort_by(|a, b| {
        if a.score > b.score {
            Ordering::Less
        } else if a.score < b.score {
            Ordering::Greater
        } else {
            Ordering::Equal
        }
    });

    // Make sure we don't exceed the specified result limit.
    results.truncate(max_results);

    results
}

/// Compares the query string to the subject,
/// and returns a score between 0 and 1.
fn similarity(query: &str, subject: &str) -> f32 {
    // Exact matches produce a perfect score.
    if query == subject {
        return 1.0;
    }

    let mut overall_score = 0.0;
    let subject_length = subject.chars().count();
    for query_char in query.chars() {
        let mut character_score = 0.0;
        for subject_char in subject.chars() {
            // For every occurrence of a query character in the
            // subject increase the individual character's score.
            if query_char == subject_char {
                character_score += 1.0;
            }
        }

        // Limit the character score to a maximum value
        // of "1" and add it to the overall score.
        character_score /= subject_length as f32;
        overall_score += character_score;
    }

    // Return an overall score, limited to a maximum value of "1".
    overall_score / subject.chars().count() as f32
}

#[cfg(test)]
mod tests {
    use super::find;
    use super::similarity;
    use std::path::PathBuf;

    #[test]
    fn find_returns_a_correctly_ordered_set_of_results() {
        let haystack = vec![PathBuf::from("src/hound.rs"),
            PathBuf::from("lib/hounds.rs"), PathBuf::from("Houndfile")];
        let expected_results = vec![PathBuf::from("Houndfile"), PathBuf::from("src/hound.rs")];
        let results = find("Hound", &haystack, 2);
        for i in 0..2 {
            assert_eq!(results[i].path, expected_results[i]);
        }
    }

    #[test]
    fn find_returns_a_correctly_limited_set_of_results() {
        let haystack = vec![PathBuf::from("src/hound.rs"),
            PathBuf::from("lib/hounds.rs"), PathBuf::from("Houndfile")];
        let results = find("Hound", &haystack, 2);
        assert_eq!(results.len(), 2);
    }

    #[test]
    fn similarity_correctly_scores_perfect_matches() {
        assert_eq!(similarity("src/hound.rs", "src/hound.rs"), 1.0);
    }

    #[test]
    fn similarity_correctly_scores_completely_different_terms() {
        assert_eq!(similarity("lib", "src"), 0.0);
    }

    #[test]
    fn similarity_scores_based_on_term_length() {
        let differing_length_score = similarity("houn", "houndhound");

        // Don't use a perfect match, since those product a perfect score.
        let same_length_score = similarity("houn", "hound");
        assert!(same_length_score > differing_length_score);
    }
}
<|endoftext|>


<commit_before>use std::ops::{Add};

/// A pair of coordinates
#[derive(Clone, Copy)]
pub struct Vec2(pub usize, pub usize);

/// A structure of values
pub struct Matrix<T> {
    /// 2 dimensional array of rows and columns
    dim: Vec2,
    /// `Vector` of values in the `Matrix`
    buffer: Vec<T>,
}

impl <T> Matrix<T> {
    /// Returns a new `Matrix`
    ///
    /// # Arguments
    ///
    /// - `dimensions` - 2 dimensional array of rows and columns
    /// - `buffer` - `Vector` of values
    ///
    /// # Example
    ///
    /// ```
    /// let matrix = ktensor::math::Matrix::new(ktensor::math::Vec2(2, 3), vec![0, 1, 2, 3, 4, 5]);
    /// ```
    pub fn new(dimensions: Vec2, buffer: Vec<T>) -> Matrix<T> {
        Matrix {
            dim: dimensions,
            buffer: buffer,
        }
    }

    /// Returns reference to value at `Vec2`
    ///
    /// # Arguments
    ///
    /// - `Vec2` - coordinates of the value in the `Matrix`
    ///
    /// # Example
    ///
    /// ```
    /// let matrix = ktensor::math::Matrix::new(ktensor::math::Vec2(2, 3), vec![0, 1, 2, 3, 4, 5]);
    /// assert_eq!(*matrix.get(ktensor::math::Vec2(1, 2)), 5);
    /// ```
    pub fn get(&self, Vec2(x, y): Vec2) -> &T {
        &self.buffer[x * self.dim.1 + y]
    }
}

/// Add Matricies
///
/// # Arguments
///
/// - `self` - this matrix
/// - `rhs` - another matrix
///
/// # Example
///
/// ```
/// let matrix1 = ktensor::math::Matrix::new(ktensor::math::Vec2(2, 3), vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]);
/// let matrix2 = ktensor::math::Matrix::new(ktensor::math::Vec2(2, 3), vec![5.0, 4.0, 3.0, 2.0, 1.0, 0.0]);
/// let matrix3 = matrix1 + matrix2;
/// assert_eq!(*matrix3.get(ktensor::math::Vec2(0, 0)), 5.0);
/// ```
impl<T> Add<Matrix<T>> for Matrix<T> where T: Add + Copy {
    type Output = Matrix<<T as Add>::Output>;
    fn add(self, rhs: Matrix<T>) -> Matrix<<T as Add>::Output> {
        let mut buffer = Vec::new();
        for (&i, &j) in self.buffer.iter().zip(rhs.buffer.iter()) {
            buffer.push(i + j);
        }
        Matrix::new(self.dim, buffer)
    }
}

/// Add Matricies by reference
///
/// # Arguments
///
/// - `self` - this matrix reference
/// - `rhs` - another matrix reference
///
/// # Example
///
/// ```
/// let matrix1 = ktensor::math::Matrix::new(ktensor::math::Vec2(2, 3), vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]);
/// let matrix2 = ktensor::math::Matrix::new(ktensor::math::Vec2(2, 3), vec![5.0, 4.0, 3.0, 2.0, 1.0, 0.0]);
/// let matrix3 = &matrix1 + &matrix2;
/// assert_eq!(*matrix1.get(ktensor::math::Vec2(0, 0)), 0.0);
/// assert_eq!(*matrix2.get(ktensor::math::Vec2(0, 0)), 5.0);
/// assert_eq!(*matrix3.get(ktensor::math::Vec2(0, 0)), 5.0);
/// ```
impl<'a, 'b, T> Add<&'b Matrix<T>> for &'a Matrix<T> where T: Add + Copy {
    type Output = Matrix<<T as Add>::Output>;
    fn add(self, rhs: &'b Matrix<T>) -> Matrix<<T as Add>::Output> {
        let mut buffer = Vec::new();
        for (&i, &j) in self.buffer.iter().zip(rhs.buffer.iter()) {
            buffer.push(i + j);
        }
        Matrix::new(self.dim, buffer)
    }
}
<commit_msg>use copy for matricies<commit_after>use std::ops::{Add};

/// A pair of coordinates
#[derive(Clone, Copy)]
pub struct Vec2(pub usize, pub usize);

/// A structure of values
pub struct Matrix<T> {
    /// 2 dimensional array of rows and columns
    dim: Vec2,
    /// `Vector` of values in the `Matrix`
    buffer: Vec<T>,
}

impl <T> Matrix<T> {
    /// Returns a new `Matrix`
    ///
    /// # Arguments
    ///
    /// - `dimensions` - 2 dimensional array of rows and columns
    /// - `buffer` - `Vector` of values
    ///
    /// # Example
    ///
    /// ```
    /// let matrix = ktensor::math::Matrix::new(ktensor::math::Vec2(2, 3), vec![0, 1, 2, 3, 4, 5]);
    /// ```
    pub fn new(dimensions: Vec2, buffer: Vec<T>) -> Matrix<T> {
        Matrix {
            dim: dimensions,
            buffer: buffer,
        }
    }
}

impl <T> Matrix<T> where T: Copy {
    /// Returns reference to value at `Vec2`
    ///
    /// # Arguments
    ///
    /// - `Vec2` - coordinates of the value in the `Matrix`
    ///
    /// # Example
    ///
    /// ```
    /// let matrix = ktensor::math::Matrix::new(ktensor::math::Vec2(2, 3), vec![0, 1, 2, 3, 4, 5]);
    /// assert_eq!(matrix.get(ktensor::math::Vec2(1, 2)), 5);
    /// assert_eq!(matrix.get(ktensor::math::Vec2(1, 2)), 5);
    /// ```
    pub fn get(&self, Vec2(x, y): Vec2) -> T {
        self.buffer[x * self.dim.1 + y]
    }
}

/// Add Matricies
///
/// # Arguments
///
/// - `self` - this matrix
/// - `rhs` - another matrix
///
/// # Example
///
/// ```
/// let matrix1 = ktensor::math::Matrix::new(ktensor::math::Vec2(2, 3), vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]);
/// let matrix2 = ktensor::math::Matrix::new(ktensor::math::Vec2(2, 3), vec![5.0, 4.0, 3.0, 2.0, 1.0, 0.0]);
/// let matrix3 = matrix1 + matrix2;
/// assert_eq!(matrix3.get(ktensor::math::Vec2(0, 0)), 5.0);
/// ```
impl<T> Add<Matrix<T>> for Matrix<T> where T: Add + Copy {
    type Output = Matrix<<T as Add>::Output>;
    fn add(self, rhs: Matrix<T>) -> Matrix<<T as Add>::Output> {
        let mut buffer = Vec::new();
        for (&i, &j) in self.buffer.iter().zip(rhs.buffer.iter()) {
            buffer.push(i + j);
        }
        Matrix::new(self.dim, buffer)
    }
}

/// Add Matricies by reference
///
/// # Arguments
///
/// - `self` - this matrix reference
/// - `rhs` - another matrix reference
///
/// # Example
///
/// ```
/// let matrix1 = ktensor::math::Matrix::new(ktensor::math::Vec2(2, 3), vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]);
/// let matrix2 = ktensor::math::Matrix::new(ktensor::math::Vec2(2, 3), vec![5.0, 4.0, 3.0, 2.0, 1.0, 0.0]);
/// let matrix3 = &matrix1 + &matrix2;
/// assert_eq!(matrix1.get(ktensor::math::Vec2(0, 0)), 0.0);
/// assert_eq!(matrix2.get(ktensor::math::Vec2(0, 0)), 5.0);
/// assert_eq!(matrix3.get(ktensor::math::Vec2(0, 0)), 5.0);
/// ```
impl<'a, 'b, T> Add<&'b Matrix<T>> for &'a Matrix<T> where T: Add + Copy {
    type Output = Matrix<<T as Add>::Output>;
    fn add(self, rhs: &'b Matrix<T>) -> Matrix<<T as Add>::Output> {
        let mut buffer = Vec::new();
        for (&i, &j) in self.buffer.iter().zip(rhs.buffer.iter()) {
            buffer.push(i + j);
        }
        Matrix::new(self.dim, buffer)
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, Clone)]
pub struct Message {
    pub receiver: Option<PNode>,
    pub method: PNode,
    pub args: Vec<PNode>
}

#[derive(Debug, Clone)]
pub struct Block {
    pub instructions: Vec<PNode>
}

#[derive(Debug, Clone)]
pub struct Class {
    pub identifier: PNode,
    pub methods: Vec<PNode>
}

#[derive(Debug, Clone)]
pub struct Method {
    pub method: PNode,
    pub params: Vec<PNode>,
    pub block: PNode
}

#[derive(Debug, Clone)]
pub struct If {
    pub condition: PNode,
    pub true_block: PNode,
    pub false_block: Option<PNode>
}

#[derive(Debug, Clone)]
pub struct While {
    pub condition: PNode,
    pub block: PNode
}

#[derive(Debug, Clone)]
pub struct Assignment {
    pub identifier: PNode,
    pub expression: PNode
}

#[derive(Debug, Clone)]
pub struct Identifier {
    pub name: String
}

#[derive(Debug, Clone)]
pub struct Constant {
    pub name: String
}

#[derive(Debug, Clone)]
pub struct IntegerLiteral {
    pub value: u32
}

#[derive(Debug, Clone)]
pub struct FloatLiteral {
    pub value: f32
}

#[derive(Debug, Clone)]
pub struct StringLiteral {
    pub value: String
}

#[derive(Debug, Clone)]
pub struct ArrayLiteral {
    pub elements: Vec<PNode>
}

#[derive(Debug, Clone)]
pub struct MapLiteral {
    pub entries: Vec<(PNode, PNode)>
}

#[derive(Debug, Clone)]
pub struct BinaryExpression {
    pub op: BinOp,
    pub left: PNode,
    pub right: PNode
}

#[derive(Debug, Clone)]
pub enum BinOp {
    Add, Sub, Mul, Div, Lt, Lte, Gt, Gte, Ne, Eq, And, Or
}

#[derive(Debug, Clone)]
pub enum Node {
    IdentExpr(Identifier),
    ConstExpr(Constant),
    IntExpr(IntegerLiteral),
    FltExpr(FloatLiteral),
    StrExpr(StringLiteral),
    ArrExpr(ArrayLiteral),
    MapExpr(MapLiteral),
    BinExpr(BinaryExpression),
    AssignExpr(Assignment),
    WhileStmt(While),
    IfStmt(If),
    BlockExpr(Block),
    MessageExpr(Message),
    ClassDecl(Class),
    MethodDecl(Method)
}

pub type PNode = Box<Node>;

#[allow(non_snake_case)]
pub fn PNode(value: Node) -> PNode {
    Box::new(value)
}
<commit_msg>Rustfmt on AST.<commit_after>#[derive(Debug, Clone)]
pub struct Message {
    pub receiver: Option<PNode>,
    pub method: PNode,
    pub args: Vec<PNode>,
}

#[derive(Debug, Clone)]
pub struct Block {
    pub instructions: Vec<PNode>,
}

#[derive(Debug, Clone)]
pub struct Class {
    pub identifier: PNode,
    pub methods: Vec<PNode>,
}

#[derive(Debug, Clone)]
pub struct Method {
    pub method: PNode,
    pub params: Vec<PNode>,
    pub block: PNode,
}

#[derive(Debug, Clone)]
pub struct If {
    pub condition: PNode,
    pub true_block: PNode,
    pub false_block: Option<PNode>,
}

#[derive(Debug, Clone)]
pub struct While {
    pub condition: PNode,
    pub block: PNode,
}

#[derive(Debug, Clone)]
pub struct Assignment {
    pub identifier: PNode,
    pub expression: PNode,
}

#[derive(Debug, Clone)]
pub struct Identifier {
    pub name: String,
}

#[derive(Debug, Clone)]
pub struct Constant {
    pub name: String,
}

#[derive(Debug, Clone)]
pub struct IntegerLiteral {
    pub value: u32,
}

#[derive(Debug, Clone)]
pub struct FloatLiteral {
    pub value: f32,
}

#[derive(Debug, Clone)]
pub struct StringLiteral {
    pub value: String,
}

#[derive(Debug, Clone)]
pub struct ArrayLiteral {
    pub elements: Vec<PNode>,
}

#[derive(Debug, Clone)]
pub struct MapLiteral {
    pub entries: Vec<(PNode, PNode)>,
}

#[derive(Debug, Clone)]
pub struct BinaryExpression {
    pub op: BinOp,
    pub left: PNode,
    pub right: PNode,
}

#[derive(Debug, Clone)]
pub enum BinOp {
    Add,
    Sub,
    Mul,
    Div,
    Lt,
    Lte,
    Gt,
    Gte,
    Ne,
    Eq,
    And,
    Or,
}

#[derive(Debug, Clone)]
pub enum Node {
    IdentExpr(Identifier),
    ConstExpr(Constant),
    IntExpr(IntegerLiteral),
    FltExpr(FloatLiteral),
    StrExpr(StringLiteral),
    ArrExpr(ArrayLiteral),
    MapExpr(MapLiteral),
    BinExpr(BinaryExpression),
    AssignExpr(Assignment),
    WhileStmt(While),
    IfStmt(If),
    BlockExpr(Block),
    MessageExpr(Message),
    ClassDecl(Class),
    MethodDecl(Method),
}

pub type PNode = Box<Node>;

#[allow(non_snake_case)]
pub fn PNode(value: Node) -> PNode {
    Box::new(value)
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub type Name = String;

#[derive(Debug,PartialEq,Clone)]
pub struct Document {
  definitions: Vec<Definition>,
}

impl Document {
  pub fn new(definitions: Vec<Definition>) -> Document {
    Document { definitions: definitions }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub enum Definition {
  Operation(Operation),
  Fragment(Fragment),
}

#[derive(Debug,PartialEq,Clone)]
pub struct Operation {
  op_type: OperationType,
  name: Option<Name>,
  variable_definitions: Vec<VariableDefinition>,
  directives: Vec<Directive>,
  selection_set: Vec<Selection>,
}

impl Operation {
  pub fn new(op_type: OperationType,
             name: Option<Name>,
             variable_definitions: Vec<VariableDefinition>,
             directives: Vec<Directive>,
             selection_set: Vec<Selection>)
             -> Operation {
    Operation {
      op_type: op_type,
      name: name,
      variable_definitions: variable_definitions,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub enum OperationType {
  Query,
  Mutation,
}

#[derive(Debug,PartialEq,Clone)]
pub struct VariableDefinition {
  variable: Variable,
  var_type: Type,
  default_value: Option<Value>,
}

impl VariableDefinition {
  pub fn new(variable: Variable, var_type: Type, default_value: Option<Value>) -> VariableDefinition {
    VariableDefinition {
      variable: variable,
      var_type: var_type,
      default_value: default_value,
    }
  }
}

pub type Variable = String;

#[derive(Debug,PartialEq,Clone)]
pub enum Type {
  Named(Name),
  List(Box<Type>),
  NonNull(Box<Type>),
}

#[derive(Debug,PartialEq,Clone)]
pub enum Value {
  Variable(Variable),
  Int(i32),
  Float(f32),
  String(String),
  Boolean(bool),
  Null,
  Enum(String),
  List(Vec<Value>),
  Object(HashMap<String, Value>),
}

#[derive(Debug,PartialEq,Clone)]
pub struct Directive {
  name: Name,
  arguments: Vec<Argument>,
}

impl Directive {
  pub fn new(name: Name, arguments: Vec<Argument>) -> Directive {
    Directive {
      name: name,
      arguments: arguments,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub struct Argument {
  name: Name,
  value: Value,
}

impl Argument {
  pub fn new(name: Name, value: Value) -> Argument {
    Argument {
      name: name,
      value: value,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub enum Selection {
  Field(Field),
  FragmentSpread(FragmentSpread),
  InlineFragment(InlineFragment),
}

#[derive(Debug,PartialEq,Clone)]
pub struct Field {
  alias: Option<Name>,
  name: Name,
  arguments: Vec<Argument>,
  directives: Vec<Directive>,
  selection_set: Vec<Selection>,
}

impl Field {
  pub fn new(alias: Option<Name>,
             name: Name,
             arguments: Vec<Argument>,
             directives: Vec<Directive>,
             selection_set: Vec<Selection>)
             -> Field {
    Field {
      alias: alias,
      name: name,
      arguments: arguments,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub struct FragmentSpread {
  name: Name,
  directives: Vec<Directive>,
}

impl FragmentSpread {
  pub fn new(name: Name, directives: Vec<Directive>) -> FragmentSpread {
    FragmentSpread {
      name: name,
      directives: directives,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub struct InlineFragment {
  type_condition: Option<Type>,
  directives: Vec<Directive>,
  selection_set: Vec<Selection>,
}

impl InlineFragment {
  pub fn new(type_condition: Option<Type>,
             directives: Vec<Directive>,
             selection_set: Vec<Selection>)
             -> InlineFragment {
    InlineFragment {
      type_condition: type_condition,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub struct Fragment {
  name: Name,
  type_condition: Type,
  directives: Vec<Directive>,
  selection_set: Vec<Selection>,
}

impl Fragment {
  pub fn new(name: Name, type_condition: Type, directives: Vec<Directive>, selection_set: Vec<Selection>) -> Fragment {
    Fragment {
      name: name,
      type_condition: type_condition,
      directives: directives,
      selection_set: selection_set,
    }
  }
}
<commit_msg>reordered ast types to match graphql order<commit_after>use std::collections::HashMap;

pub type Name = String;

// ===========================================================================
// 2.1 Document
// ===========================================================================
#[derive(Debug,PartialEq,Clone)]
pub struct Document {
  definitions: Vec<Definition>,
}

impl Document {
  pub fn new(definitions: Vec<Definition>) -> Document {
    Document { definitions: definitions }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub enum Definition {
  Operation(Operation),
  Fragment(Fragment),
}

// ===========================================================================
// 2.2 Operations
// ===========================================================================
#[derive(Debug,PartialEq,Clone)]
pub struct Operation {
  op_type: OperationType,
  name: Option<Name>,
  variable_definitions: Vec<VariableDefinition>,
  directives: Vec<Directive>,
  selection_set: Vec<Selection>,
}

impl Operation {
  pub fn new(op_type: OperationType,
             name: Option<Name>,
             variable_definitions: Vec<VariableDefinition>,
             directives: Vec<Directive>,
             selection_set: Vec<Selection>)
             -> Operation {
    Operation {
      op_type: op_type,
      name: name,
      variable_definitions: variable_definitions,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub enum OperationType {
  Query,
  Mutation,
}

// ===========================================================================
// 2.4 Selection Sets
// ===========================================================================

#[derive(Debug,PartialEq,Clone)]
pub enum Selection {
  Field(Field),
  FragmentSpread(FragmentSpread),
  InlineFragment(InlineFragment),
}

// ===========================================================================
// 2.5 Fields
// ===========================================================================

// ===========================================================================
// 2.6 Arguments
// ===========================================================================

#[derive(Debug,PartialEq,Clone)]
pub struct Argument {
  name: Name,
  value: Value,
}

impl Argument {
  pub fn new(name: Name, value: Value) -> Argument {
    Argument {
      name: name,
      value: value,
    }
  }
}

// ===========================================================================
// 2.7 Field Alias
// ===========================================================================

#[derive(Debug,PartialEq,Clone)]
pub struct Field {
  alias: Option<Name>,
  name: Name,
  arguments: Vec<Argument>,
  directives: Vec<Directive>,
  selection_set: Vec<Selection>,
}

impl Field {
  pub fn new(alias: Option<Name>,
             name: Name,
             arguments: Vec<Argument>,
             directives: Vec<Directive>,
             selection_set: Vec<Selection>)
             -> Field {
    Field {
      alias: alias,
      name: name,
      arguments: arguments,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

// ===========================================================================
// 2.8 Fragments
// ===========================================================================
#[derive(Debug,PartialEq,Clone)]
pub struct FragmentSpread {
  name: Name,
  directives: Vec<Directive>,
}

impl FragmentSpread {
  pub fn new(name: Name, directives: Vec<Directive>) -> FragmentSpread {
    FragmentSpread {
      name: name,
      directives: directives,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub struct InlineFragment {
  type_condition: Option<Type>,
  directives: Vec<Directive>,
  selection_set: Vec<Selection>,
}

impl InlineFragment {
  pub fn new(type_condition: Option<Type>,
             directives: Vec<Directive>,
             selection_set: Vec<Selection>)
             -> InlineFragment {
    InlineFragment {
      type_condition: type_condition,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

#[derive(Debug,PartialEq,Clone)]
pub struct Fragment {
  name: Name,
  type_condition: Type,
  directives: Vec<Directive>,
  selection_set: Vec<Selection>,
}

impl Fragment {
  pub fn new(name: Name, type_condition: Type, directives: Vec<Directive>, selection_set: Vec<Selection>) -> Fragment {
    Fragment {
      name: name,
      type_condition: type_condition,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

// ===========================================================================
// 2.9 Values
// ===========================================================================
#[derive(Debug,PartialEq,Clone)]
pub enum Value {
  Variable(Variable),
  Int(i32),
  Float(f32),
  String(String),
  Boolean(bool),
  Null,
  Enum(String),
  List(Vec<Value>),
  Object(HashMap<String, Value>),
}

// ===========================================================================
// 2.10 Variables
// ===========================================================================
#[derive(Debug,PartialEq,Clone)]
pub struct VariableDefinition {
  variable: Variable,
  var_type: Type,
  default_value: Option<Value>,
}

impl VariableDefinition {
  pub fn new(variable: Variable, var_type: Type, default_value: Option<Value>) -> VariableDefinition {
    VariableDefinition {
      variable: variable,
      var_type: var_type,
      default_value: default_value,
    }
  }
}

pub type Variable = String;

// ===========================================================================
// 2.11 Types
// ===========================================================================
#[derive(Debug,PartialEq,Clone)]
pub enum Type {
  Named(Name),
  List(Box<Type>),
  NonNull(Box<Type>),
}

// ===========================================================================
// 2.12 Directives
// ===========================================================================

#[derive(Debug,PartialEq,Clone)]
pub struct Directive {
  name: Name,
  arguments: Vec<Argument>,
}

impl Directive {
  pub fn new(name: Name, arguments: Vec<Argument>) -> Directive {
    Directive {
      name: name,
      arguments: arguments,
    }
  }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::convert::From;
use std::ffi::{
    CStr,
    CString,
};
use ffi::{
    memcached,
    memcached_add,
    memcached_exist,
    memcached_flush,
    memcached_free,
    memcached_get,
    memcached_increment,
    // memcached_increment_with_initial,
    memcached_last_error,
    memcached_replace,
    memcached_return_t,
    memcached_set,
    memcached_st,
};
use error::{
    LibMemcachedError,
    MemcacheResult,
};
use connectable::Connectable;

enum StoreCommand {
    ADD,
    REPLACE,
    SET,
}

//#[derive(Debug)]
pub struct Memcache {
    c_st: *const memcached_st,
}

impl Drop for Memcache {
    fn drop(&mut self) {
        unsafe {
            memcached_free(self.c_st);
        }
    }
}

impl Memcache {
    pub fn connect(connectable: &Connectable) -> MemcacheResult<Memcache> {
        let s = connectable.get_connection_str();
        let cstring = CString::new(s).unwrap();
        let s_len = cstring.to_bytes().len();
        unsafe {
            let c_st = memcached(cstring.as_ptr(), s_len as u64);
            if c_st.is_null() {
                let error_code = memcached_last_error(c_st);
                return Err(From::from(LibMemcachedError::new(error_code)));
            }
            return Ok(Memcache{ c_st: c_st });
        }
    }

    /// Flush all the data on memcached after `expiration`.
    ///
    /// If `expiration` is 0, flush data immediatly.
    ///
    /// # Examples
    ///
    /// ```
    /// let mc = memcache::connect(&("localhost", 2333)).unwrap();
    /// mc.flush(0);
    /// ```
    pub fn flush(&self, expiration: libc::time_t) -> MemcacheResult<()> {
        let r = unsafe{ memcached_flush(self.c_st, expiration) };
        match r {
            memcached_return_t::MEMCACHED_SUCCESS => {
                return Ok(());
            }
            _ => {
                return Err(From::from(LibMemcachedError::new(r)));
            }
        }
    }

    /// Determin weather a key is exist on memcached.
    pub fn exist(&self, key: &str) -> MemcacheResult<bool> {
        let key = CString::new(key).unwrap();
        let key_length = key.as_bytes().len();
        let ret = unsafe{
            memcached_exist(self.c_st, key.as_ptr(), key_length as u64)
        };
        match ret {
            memcached_return_t::MEMCACHED_SUCCESS => Ok(true),
            memcached_return_t::MEMCACHED_NOTFOUND => Ok(false),
            _ => Err(From::from(LibMemcachedError::new(ret))),
        }
    }

    fn store_raw(&self, command: StoreCommand, key: &str, value: &[u8], expiration: libc::time_t, flags: u32) -> MemcacheResult<()> {
        // TODO: raise if key containes NULL
        let key = CString::new(key).unwrap();
        let key_length = key.as_bytes().len();
        let value_length = value.len();
        let value = unsafe { CString::from_vec_unchecked(value.to_vec()) };

        let store_func = match command {
            StoreCommand::SET => memcached_set,
            StoreCommand::ADD => memcached_add,
            StoreCommand::REPLACE => memcached_replace,
        };

        let r = unsafe {
            store_func(self.c_st, key.as_ptr(), key_length as u64, value.as_ptr(), value_length as u64, expiration, flags)
        };
        match r {
            memcached_return_t::MEMCACHED_SUCCESS => {
                return Ok(());
            }
            _ => {
                return Err(From::from(LibMemcachedError::new(r)));
            }
        }
    }

    /// Set bytes data to memcached.
    pub fn set_raw(&self, key: &str, value: &[u8], expiration: libc::time_t, flags: u32) -> MemcacheResult<()> {
        return self.store_raw(StoreCommand::SET, key, value, expiration, flags);
    }

    /// Set bytes data to memcached only if the key is **not** existed.
    pub fn add_raw(&self, key: &str, value: &[u8], expiration: libc::time_t, flags: u32) -> MemcacheResult<()> {
        return self.store_raw(StoreCommand::ADD, key, value, expiration, flags);
    }

    /// Set bytes data to memcached only if the key is existed.
    pub fn replace_raw(&self, key: &str, value: &[u8], expiration: libc::time_t, flags: u32) -> MemcacheResult<()> {
        return self.store_raw(StoreCommand::REPLACE, key, value, expiration, flags);
    }

    /// Get bytes data from memcached.
    pub fn get_raw(&self, key: &str) -> MemcacheResult<(Vec<u8>, u32)> {
        // TODO: raise if key containes NULL
        let key = CString::new(key).unwrap();
        let key_length = key.as_bytes().len();

        let mut value_length: libc::size_t = 0;
        let value_length_ptr: *mut libc::size_t = &mut value_length;

        let mut flags: libc::uint32_t = 0;
        let flags_ptr: *mut libc::uint32_t = &mut flags;

        let mut ret: memcached_return_t = memcached_return_t::MEMCACHED_FAILURE;
        let ret_ptr: *mut memcached_return_t = &mut ret;

        let raw_value: *const libc::c_char = unsafe {
            memcached_get(self.c_st, key.as_ptr(), key_length as u64, value_length_ptr, flags_ptr, ret_ptr)
        };

        // println!("value: {:?}, error: {:?}, value_length: {:?}", r, error_ptr, value_length_ptr);
        match ret {
            memcached_return_t::MEMCACHED_SUCCESS => {
                unsafe {
                    let value_c_str = CStr::from_ptr(raw_value);
                    let value = value_c_str.to_bytes().to_vec(); // TODO: here have a memory copy
                    libc::free(raw_value as *mut libc::c_void);
                    return Ok((value, flags));
                }
            }
            _ => Err(From::from(LibMemcachedError::new(ret)))
        }
    }

    pub fn increment(&self, key: &str, offset: u32) -> MemcacheResult<u64> {
        let key = CString::new(key).unwrap();
        let key_length = key.as_bytes().len();

        let mut value: libc::uint64_t = 0;
        let value_ptr: *mut libc::uint64_t = &mut value;

        let ret = unsafe {
            memcached_increment(self.c_st, key.as_ptr(), key_length as u64, offset, value_ptr)
        };

        match ret {
            memcached_return_t::MEMCACHED_SUCCESS => {
                return Ok((value));
            }
            _ => Err(From::from(LibMemcachedError::new(ret)))
        }
    }

    // pub fn increment_with_initial(&self, key: &str, offset: u64, initial: u64, expiration: libc::time_t) -> MemcacheResult<u64> {
    //     let key = CString::new(key).unwrap();
    //     let key_length = key.as_bytes().len();

    //     let mut value: libc::uint64_t = 0;
    //     let value_ptr: *mut libc::uint64_t = &mut value;

    //     let ret = unsafe {
    //         memcached_increment_with_initial(self.c_st, key.as_ptr(), key_length as u64, offset, initial, expiration, value_ptr)
    //     };

    //     match ret {
    //         memcached_return_t::MEMCACHED_SUCCESS => {
    //             return Ok((value));
    //         }
    //         _ => Err(From::from(LibMemcachedError::new(ret)))
    //     }

    // }
}
<commit_msg>update for the latest version of libc<commit_after>extern crate libc;

use std::convert::From;
use std::ffi::{
    CStr,
    CString,
};
use ffi::{
    memcached,
    memcached_add,
    memcached_exist,
    memcached_flush,
    memcached_free,
    memcached_get,
    memcached_increment,
    // memcached_increment_with_initial,
    memcached_last_error,
    memcached_replace,
    memcached_return_t,
    memcached_set,
    memcached_st,
};
use error::{
    LibMemcachedError,
    MemcacheResult,
};
use connectable::Connectable;

enum StoreCommand {
    ADD,
    REPLACE,
    SET,
}

//#[derive(Debug)]
pub struct Memcache {
    c_st: *const memcached_st,
}

impl Drop for Memcache {
    fn drop(&mut self) {
        unsafe {
            memcached_free(self.c_st);
        }
    }
}

impl Memcache {
    pub fn connect(connectable: &Connectable) -> MemcacheResult<Memcache> {
        let s = connectable.get_connection_str();
        let cstring = CString::new(s).unwrap();
        let s_len = cstring.to_bytes().len();
        unsafe {
            let c_st = memcached(cstring.as_ptr(), s_len);
            if c_st.is_null() {
                let error_code = memcached_last_error(c_st);
                return Err(From::from(LibMemcachedError::new(error_code)));
            }
            return Ok(Memcache{ c_st: c_st });
        }
    }

    /// Flush all the data on memcached after `expiration`.
    ///
    /// If `expiration` is 0, flush data immediatly.
    ///
    /// # Examples
    ///
    /// ```
    /// let mc = memcache::connect(&("localhost", 2333)).unwrap();
    /// mc.flush(0);
    /// ```
    pub fn flush(&self, expiration: libc::time_t) -> MemcacheResult<()> {
        let r = unsafe{ memcached_flush(self.c_st, expiration) };
        match r {
            memcached_return_t::MEMCACHED_SUCCESS => {
                return Ok(());
            }
            _ => {
                return Err(From::from(LibMemcachedError::new(r)));
            }
        }
    }

    /// Determin weather a key is exist on memcached.
    pub fn exist(&self, key: &str) -> MemcacheResult<bool> {
        let key = CString::new(key).unwrap();
        let key_length = key.as_bytes().len();
        let ret = unsafe{
            memcached_exist(self.c_st, key.as_ptr(), key_length)
        };
        match ret {
            memcached_return_t::MEMCACHED_SUCCESS => Ok(true),
            memcached_return_t::MEMCACHED_NOTFOUND => Ok(false),
            _ => Err(From::from(LibMemcachedError::new(ret))),
        }
    }

    fn store_raw(&self, command: StoreCommand, key: &str, value: &[u8], expiration: libc::time_t, flags: u32) -> MemcacheResult<()> {
        // TODO: raise if key containes NULL
        let key = CString::new(key).unwrap();
        let key_length = key.as_bytes().len();
        let value_length = value.len();
        let value = unsafe { CString::from_vec_unchecked(value.to_vec()) };

        let store_func = match command {
            StoreCommand::SET => memcached_set,
            StoreCommand::ADD => memcached_add,
            StoreCommand::REPLACE => memcached_replace,
        };

        let r = unsafe {
            store_func(self.c_st, key.as_ptr(), key_length, value.as_ptr(), value_length, expiration, flags)
        };
        match r {
            memcached_return_t::MEMCACHED_SUCCESS => {
                return Ok(());
            }
            _ => {
                return Err(From::from(LibMemcachedError::new(r)));
            }
        }
    }

    /// Set bytes data to memcached.
    pub fn set_raw(&self, key: &str, value: &[u8], expiration: libc::time_t, flags: u32) -> MemcacheResult<()> {
        return self.store_raw(StoreCommand::SET, key, value, expiration, flags);
    }

    /// Set bytes data to memcached only if the key is **not** existed.
    pub fn add_raw(&self, key: &str, value: &[u8], expiration: libc::time_t, flags: u32) -> MemcacheResult<()> {
        return self.store_raw(StoreCommand::ADD, key, value, expiration, flags);
    }

    /// Set bytes data to memcached only if the key is existed.
    pub fn replace_raw(&self, key: &str, value: &[u8], expiration: libc::time_t, flags: u32) -> MemcacheResult<()> {
        return self.store_raw(StoreCommand::REPLACE, key, value, expiration, flags);
    }

    /// Get bytes data from memcached.
    pub fn get_raw(&self, key: &str) -> MemcacheResult<(Vec<u8>, u32)> {
        // TODO: raise if key containes NULL
        let key = CString::new(key).unwrap();
        let key_length = key.as_bytes().len();

        let mut value_length: libc::size_t = 0;
        let value_length_ptr: *mut libc::size_t = &mut value_length;

        let mut flags: libc::uint32_t = 0;
        let flags_ptr: *mut libc::uint32_t = &mut flags;

        let mut ret: memcached_return_t = memcached_return_t::MEMCACHED_FAILURE;
        let ret_ptr: *mut memcached_return_t = &mut ret;

        let raw_value: *const libc::c_char = unsafe {
            memcached_get(self.c_st, key.as_ptr(), key_length, value_length_ptr, flags_ptr, ret_ptr)
        };

        // println!("value: {:?}, error: {:?}, value_length: {:?}", r, error_ptr, value_length_ptr);
        match ret {
            memcached_return_t::MEMCACHED_SUCCESS => {
                unsafe {
                    let value_c_str = CStr::from_ptr(raw_value);
                    let value = value_c_str.to_bytes().to_vec(); // TODO: here have a memory copy
                    libc::free(raw_value as *mut libc::c_void);
                    return Ok((value, flags));
                }
            }
            _ => Err(From::from(LibMemcachedError::new(ret)))
        }
    }

    pub fn increment(&self, key: &str, offset: u32) -> MemcacheResult<u64> {
        let key = CString::new(key).unwrap();
        let key_length = key.as_bytes().len();

        let mut value: libc::uint64_t = 0;
        let value_ptr: *mut libc::uint64_t = &mut value;

        let ret = unsafe {
            memcached_increment(self.c_st, key.as_ptr(), key_length, offset, value_ptr)
        };

        match ret {
            memcached_return_t::MEMCACHED_SUCCESS => {
                return Ok((value));
            }
            _ => Err(From::from(LibMemcachedError::new(ret)))
        }
    }

    // pub fn increment_with_initial(&self, key: &str, offset: u64, initial: u64, expiration: libc::time_t) -> MemcacheResult<u64> {
    //     let key = CString::new(key).unwrap();
    //     let key_length = key.as_bytes().len();

    //     let mut value: libc::uint64_t = 0;
    //     let value_ptr: *mut libc::uint64_t = &mut value;

    //     let ret = unsafe {
    //         memcached_increment_with_initial(self.c_st, key.as_ptr(), key_length, offset, initial, expiration, value_ptr)
    //     };

    //     match ret {
    //         memcached_return_t::MEMCACHED_SUCCESS => {
    //             return Ok((value));
    //         }
    //         _ => Err(From::from(LibMemcachedError::new(ret)))
    //     }

    // }
}
<|endoftext|>