<commit_before>extern crate postgres;
extern crate postgres_array;
extern crate rustc_serialize;

pub mod fact_db;
pub mod pg_db;
pub mod engine;

pub mod native_types;

#[derive (Clone)]
pub enum DB {
  Postgres(String)
}

pub enum Error {
  NoDB,
  PgConnect(::postgres::error::ConnectError),
  PgErr(::postgres::error::Error),
  PgDbErr(pg_db::DBError),
  IOErr(::std::io::Error),
  PgConnectStr(Box<::std::error::Error + Send + Sync>),
  EngineErr(engine::Error)
}

use self::Error::*;

use engine::Engine;
use pg_db::PgDB;
use fact_db::FactDB;
use native_types::*;

pub type Result<T> = ::std::result::Result<T, Error>;

use std::fmt::{Debug, Display, Formatter};

impl Display for Error {
  fn fmt(&self, fmt : &mut Formatter)
        -> ::std::result::Result<(),::std::fmt::Error> {
    match *self {
      NoDB             => fmt.write_str("No database specified"),
      PgConnect(ref e) => fmt.write_fmt(format_args!("Connection failed: {}", e)),
      PgErr(ref e)     => fmt.write_fmt(format_args!("Postgres error: {}", e)),
      PgDbErr(ref e)   => fmt.write_fmt(format_args!("Deductive DB (postgres) error: {}", e)),
      PgConnectStr(ref e) => fmt.write_fmt(format_args!("Connection string failed to parse: {}", e)),
      IOErr(ref e) => fmt.write_fmt(format_args!("IO failed: {}", e)),
      EngineErr(ref e) => fmt.write_fmt(format_args!("Engine Error: {}", e))
    }
  }
}

impl Debug for Error  {
  fn fmt(&self, fmt : &mut Formatter)
        -> ::std::result::Result<(),::std::fmt::Error> {
    Display::fmt(self, fmt)
  }
}

impl ::std::error::Error for Error {
  fn description(&self) -> &str {
    match self {
      &NoDB              => "No database specified",
      &PgConnect(ref e)  => e.description(),
      &PgErr(ref e)      => e.description(),
      &PgDbErr(ref e)    => e.description(),
      &IOErr(ref e)      => e.description(),
      &EngineErr(ref e)  => e.description(),
      &PgConnectStr(_)   => "Connection string failed to parse"
    }
  }
}

impl From<::postgres::error::ConnectError> for Error {
  fn from(ce : ::postgres::error::ConnectError) -> Error {PgConnect(ce)}
}

impl From<::postgres::error::Error> for Error {
  fn from(e : ::postgres::error::Error) -> Error {PgErr(e)}
}

impl From<pg_db::DBError> for Error {
  fn from(e : pg_db::DBError) -> Error {PgDbErr(e)}
}

impl From<engine::Error> for Error {
  fn from(e : engine::Error) -> Error {EngineErr(e)}
}

impl From<::std::io::Error> for Error {
  fn from(e : ::std::io::Error) -> Error {IOErr(e)}
}

impl<'a> DB {
  fn destroy(&self) -> Result<()> {
    match self {
      &DB::Postgres(ref str) => {
        use postgres::{Connection, SslMode, IntoConnectParams};
        let mut params = try!(str.into_connect_params().map_err(PgConnectStr));
        let old_db = try!(params.database.ok_or(NoDB));
        params.database = Some("postgres".to_owned());
        let conn = try!(Connection::connect(params, SslMode::None));
        let disco_query = format!("SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '{}' AND pid <> pg_backend_pid()", &old_db);
        try!(conn.execute(&disco_query, &[]));
        let drop_query = format!("DROP DATABASE {}", &old_db);
        try!(conn.execute(&drop_query, &[]));
      }
    }
    Ok(())
  }
  fn create(&self) -> Result<Box<FactDB>> {
    match self {
      &DB::Postgres(ref str) => {
        use postgres::{Connection, SslMode, IntoConnectParams};
        let mut params = try!(str.into_connect_params().map_err(PgConnectStr));
        let old_db = try!(params.database.ok_or(NoDB));
        params.database = Some("postgres".to_owned());
        let conn = try!(Connection::connect(params, SslMode::None));
        let create_query = format!("CREATE DATABASE {}", &old_db);
        //TODO accept success or db already exists, not other errors
        let _ = conn.execute(&create_query, &[]);
        Ok(Box::new(try!(PgDB::new(str))))
      }
    }
  }
}

pub struct Holmes {
  db : DB,
  engine : Engine
}

impl Holmes {
  pub fn new(db : DB) -> Result<Holmes> {
    Ok(Holmes {
      engine : Engine::new(try!(db.create())),
      db : db
    })
  }
  pub fn destroy(self) -> Result<()> {
    let db = self.db.clone();
    drop(self);
    db.destroy()
  }
  pub fn add_predicate(&mut self, pred : &native_types::Predicate)
                      -> Result<()> {
    self.engine.new_predicate(pred).map_err(|e| {EngineErr(e)})
  }
  pub fn add_fact(&mut self, fact : &native_types::Fact)
                      -> Result<()> {
    self.engine.new_fact(fact).map_err(|e| {EngineErr(e)})
  }
  pub fn query(&mut self, query : &Vec<native_types::Clause>) -> Result<Vec<Vec<native_types::HValue>>> {
    self.engine.derive(query).map_err(|e| {EngineErr(e)})
  }
  pub fn add_rule(&mut self, rule : &native_types::Rule) -> Result<()> {
    self.engine.new_rule(rule).map_err(|e| {EngineErr(e)})
  }
  pub fn reg_func(&mut self,
                  name : String,
                  input_type  : native_types::HType,
                  output_type : native_types::HType,
                  func : Box<Fn(native_types::HValue) -> native_types::HValue>) -> Result<()> {
    self.engine.reg_func(name, native_types::HFunc {
      input_type  : input_type,
      output_type : output_type,
      run : func
    });
    Ok(())
  }
}

#[macro_export]
macro_rules! htype_raw {
  (string) => { ::holmes::native_types::HType::HString};
  (blob  ) => { ::holmes::native_types::HType::Blob};
  (uint64) => { ::holmes::native_types::HType::UInt64};
}

#[macro_export]
macro_rules! htype {
  ([$t:tt]) => { ::holmes::native_types::HType::List(Box::new(htype!($t))) };
  (($($t:tt),*)) => { ::holmes::native_types::HType::Tuple(vec![$(htype!($t)),*]) };
  ($i:ident) => { htype_raw!($i) };
}

#[macro_export]
macro_rules! holmes_exec {
  ($holmes:ident, { $( $action:expr );* }) => {
      {
        $( try!($action($holmes)); );*
        let res : ::holmes::Result<()> = Ok(());
        res
      }
  };
}

#[macro_export]
macro_rules! predicate {
  ($holmes:ident, $pred_name:ident($($t:tt),*)) => {
    $holmes.add_predicate(&::holmes::native_types::Predicate {
      name  : stringify!($pred_name).to_string(),
      types : vec![$(htype!($t),)*]
    })
  };
  ($pred_name:ident($($t:tt),*)) => { |holmes : &mut Holmes| {
    let res : ::holmes::Result<()> = predicate!(holmes, $pred_name($($t),*));
    res
  }};
}

#[macro_export]
macro_rules! fact {
  ($holmes:ident, $pred_name:ident($($a:expr),*)) => {
    $holmes.add_fact(&::holmes::native_types::Fact {
      pred_name : stringify!($pred_name).to_string(),
      args : vec![$(::holmes::native_types::ToHValue::to_hvalue($a)),*]
    })
  };
  ($pred_name:ident($($a:expr),*)) => { |holmes : &mut Holmes| {
    let res : ::holmes::Result<()> = fact!(holmes, $pred_name($($a),*));
    res
  }};
}

#[macro_export]
macro_rules! bind_match {
  ($vars:ident, $n:ident, [$bm:tt]) => { ::holmes::native_types::BindExpr::Iterate(Box::new(bind_match!($vars, $n, $bm))) };
  ($vars:ident, $n:ident, |$($bm:tt),*|) => {
    ::holmes::native_types::BindExpr::Destructure(vec![$(bind_match!($vars, $n, $bm)),*])
  };
  ($vars:ident, $n:ident, $cm:tt) => { ::holmes::native_types::BindExpr::Normal(clause_match!($vars, $n, $cm)) };
}

#[macro_export]
macro_rules! clause_match {
  ($vars:ident, $n:ident, [_]) => { ::holmes::native_types::MatchExpr::Unbound };
  ($vars:ident, $n:ident, ($v:expr)) => {
      ::holmes::native_types::MatchExpr::HConst(::holmes::native_types::ToHValue::to_hvalue($v)) };
  ($vars:ident, $n:ident, $m:ident) => {{
    use std::collections::hash_map::Entry::*;
    use ::holmes::native_types::MatchExpr::*;
    match $vars.entry(stringify!($m).to_string()) {
      Occupied(entry) => Var(*entry.get()),
      Vacant(entry) => {
        $n = $n + 1;
        entry.insert($n - 1);
        Var($n - 1)
      }
    }
  }};
}

#[macro_export]
macro_rules! query {
  ($holmes:ident, $($pred_name:ident($($m:tt),*))&*) => {{
    use std::collections::HashMap;
    let mut vars : HashMap<String, ::holmes::native_types::HVar> = HashMap::new();
    let mut n : ::holmes::native_types::HVar = 0;
    $holmes.query(&vec![$(::holmes::native_types::Clause {
      pred_name : stringify!($pred_name).to_string(),
      args : vec![$(clause_match!(vars, n, $m)),*]
    }),*])
  }}
}

pub fn var_to_evar(var : MatchExpr) -> Expr {
  match var {
    MatchExpr::Var(var_no) => Expr::EVar(var_no),
    x => panic!("var_to_evar was passed nonvar: {:?}", x)
  }
}

#[macro_export]
macro_rules! hexpr {
  ($vars:ident, $n:ident, [$hexpr_name:ident]) => {
    ::holmes::var_to_evar(clause_match!($vars, $n, $hexpr_name))
  };
  ($vars:ident, $n:ident, ($hexpr:expr)) => {
    ::holmes::native_types::Expr::EVal(::holmes::native_types::ToHValue::to_hvalue($hexpr))
  };
  ($vars:ident, $n:ident, {$hexpr_func:ident($($hexpr_arg:tt),*)}) => {
    ::holmes::native_types::Expr::EApp(stringify!($hexpr_func).to_string(), vec![$(hexpr!($vars, $n, $hexpr_arg)),*])
  };
}

#[macro_export]
macro_rules! rule {
  ($holmes:ident, $head_name:ident($($m:tt),*) <= $($body_name:ident($($mb:tt),*))&*,
   {$(let $bind:tt = $hexpr:tt);*}) => {{
    use std::collections::HashMap;
    let mut vars : HashMap<String, ::holmes::native_types::HVar> = HashMap::new();
    let mut n : ::holmes::native_types::HVar = 0;
    $holmes.add_rule(&::holmes::native_types::Rule {
      body : vec![$(::holmes::native_types::Clause {
        pred_name : stringify!($body_name).to_string(),
        args : vec![$(clause_match!(vars, n, $mb)),*]
      }),*],
      head : ::holmes::native_types::Clause {
        pred_name : stringify!($head_name).to_string(),
        args : vec![$(clause_match!(vars, n, $m)),*]
      },
      wheres : vec! [$(::holmes::native_types::WhereClause {
        lhs   : bind_match!(vars, n, $bind),
        rhs   : hexpr!(vars, n, $hexpr)
      }),*]
    })
  }};
  ($holmes:ident, $head_name:ident($($m:tt),*) <= $($body_name:ident($($mb:tt),*))&*,
   {$(let $($bind:tt),* = $hexpr:tt);*}) => {{
    use std::collections::HashMap;
    let mut vars : HashMap<String, ::holmes::native_types::HVar> = HashMap::new();
    let mut n : ::holmes::native_types::HVar = 0;
    $holmes.add_rule(&::holmes::native_types::Rule {
      body : vec![$(::holmes::native_types::Clause {
        pred_name : stringify!($body_name).to_string(),
        args : vec![$(clause_match!(vars, n, $mb)),*]
      }),*],
      head : ::holmes::native_types::Clause {
        pred_name : stringify!($head_name).to_string(),
        args : vec![$(clause_match!(vars, n, $m)),*]
      },
      wheres : vec! [$(::holmes::native_types::WhereClause {
        lhs   : ::holmes::native_types::BindExpr::Destructure(
                  vec![$(bind_match!(vars, n, $bind)),*]),
        rhs   : hexpr!(vars, n, $hexpr)
      }),*]
    })
  }};
  ($($head_name:ident($($m:tt),*)),* <= $($body_name:ident($($mb:tt),*))&*) => {
    |holmes : &mut Holmes| {
      rule!(holmes, $($head_name($($m),*)),* <= $($body_name($($mb),*))&*, {})
    }
  };
  ($($head_name:ident($($m:tt),*)),* <= $($body_name:ident($($mb:tt),*))&*, {$(let $($bind:tt),* = $hexpr:tt);*}) => {
    |holmes : &mut Holmes| {
      rule!(holmes, $($head_name($($m),*)),* <= $($body_name($($mb),*))&*, {$(let $($bind),* = $hexpr);*})
    }
  };

}

#[macro_export]
macro_rules! func {
  ($holmes:ident, let $name:ident : $src:tt -> $dst:tt = $body:expr) => {
    $holmes.reg_func(stringify!($name).to_string(),
                     htype!($src),
                     htype!($dst),
                     Box::new($body))
  };
  (let $name:ident : $src:tt -> $dst:tt = $body:expr) => {
    |holmes : &mut Holmes| {
      func!(holmes, let $name : $src -> $dst = $body)
    }
  };
}
<commit_msg>Change destructuring sigils<commit_after>extern crate postgres;
extern crate postgres_array;
extern crate rustc_serialize;

pub mod fact_db;
pub mod pg_db;
pub mod engine;

pub mod native_types;

#[derive (Clone)]
pub enum DB {
  Postgres(String)
}

pub enum Error {
  NoDB,
  PgConnect(::postgres::error::ConnectError),
  PgErr(::postgres::error::Error),
  PgDbErr(pg_db::DBError),
  IOErr(::std::io::Error),
  PgConnectStr(Box<::std::error::Error + Send + Sync>),
  EngineErr(engine::Error)
}

use self::Error::*;

use engine::Engine;
use pg_db::PgDB;
use fact_db::FactDB;
use native_types::*;

pub type Result<T> = ::std::result::Result<T, Error>;

use std::fmt::{Debug, Display, Formatter};

impl Display for Error {
  fn fmt(&self, fmt : &mut Formatter)
        -> ::std::result::Result<(),::std::fmt::Error> {
    match *self {
      NoDB             => fmt.write_str("No database specified"),
      PgConnect(ref e) => fmt.write_fmt(format_args!("Connection failed: {}", e)),
      PgErr(ref e)     => fmt.write_fmt(format_args!("Postgres error: {}", e)),
      PgDbErr(ref e)   => fmt.write_fmt(format_args!("Deductive DB (postgres) error: {}", e)),
      PgConnectStr(ref e) => fmt.write_fmt(format_args!("Connection string failed to parse: {}", e)),
      IOErr(ref e) => fmt.write_fmt(format_args!("IO failed: {}", e)),
      EngineErr(ref e) => fmt.write_fmt(format_args!("Engine Error: {}", e))
    }
  }
}

impl Debug for Error  {
  fn fmt(&self, fmt : &mut Formatter)
        -> ::std::result::Result<(),::std::fmt::Error> {
    Display::fmt(self, fmt)
  }
}

impl ::std::error::Error for Error {
  fn description(&self) -> &str {
    match self {
      &NoDB              => "No database specified",
      &PgConnect(ref e)  => e.description(),
      &PgErr(ref e)      => e.description(),
      &PgDbErr(ref e)    => e.description(),
      &IOErr(ref e)      => e.description(),
      &EngineErr(ref e)  => e.description(),
      &PgConnectStr(_)   => "Connection string failed to parse"
    }
  }
}

impl From<::postgres::error::ConnectError> for Error {
  fn from(ce : ::postgres::error::ConnectError) -> Error {PgConnect(ce)}
}

impl From<::postgres::error::Error> for Error {
  fn from(e : ::postgres::error::Error) -> Error {PgErr(e)}
}

impl From<pg_db::DBError> for Error {
  fn from(e : pg_db::DBError) -> Error {PgDbErr(e)}
}

impl From<engine::Error> for Error {
  fn from(e : engine::Error) -> Error {EngineErr(e)}
}

impl From<::std::io::Error> for Error {
  fn from(e : ::std::io::Error) -> Error {IOErr(e)}
}

impl<'a> DB {
  fn destroy(&self) -> Result<()> {
    match self {
      &DB::Postgres(ref str) => {
        use postgres::{Connection, SslMode, IntoConnectParams};
        let mut params = try!(str.into_connect_params().map_err(PgConnectStr));
        let old_db = try!(params.database.ok_or(NoDB));
        params.database = Some("postgres".to_owned());
        let conn = try!(Connection::connect(params, SslMode::None));
        let disco_query = format!("SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '{}' AND pid <> pg_backend_pid()", &old_db);
        try!(conn.execute(&disco_query, &[]));
        let drop_query = format!("DROP DATABASE {}", &old_db);
        try!(conn.execute(&drop_query, &[]));
      }
    }
    Ok(())
  }
  fn create(&self) -> Result<Box<FactDB>> {
    match self {
      &DB::Postgres(ref str) => {
        use postgres::{Connection, SslMode, IntoConnectParams};
        let mut params = try!(str.into_connect_params().map_err(PgConnectStr));
        let old_db = try!(params.database.ok_or(NoDB));
        params.database = Some("postgres".to_owned());
        let conn = try!(Connection::connect(params, SslMode::None));
        let create_query = format!("CREATE DATABASE {}", &old_db);
        //TODO accept success or db already exists, not other errors
        let _ = conn.execute(&create_query, &[]);
        Ok(Box::new(try!(PgDB::new(str))))
      }
    }
  }
}

pub struct Holmes {
  db : DB,
  engine : Engine
}

impl Holmes {
  pub fn new(db : DB) -> Result<Holmes> {
    Ok(Holmes {
      engine : Engine::new(try!(db.create())),
      db : db
    })
  }
  pub fn destroy(self) -> Result<()> {
    let db = self.db.clone();
    drop(self);
    db.destroy()
  }
  pub fn add_predicate(&mut self, pred : &native_types::Predicate)
                      -> Result<()> {
    self.engine.new_predicate(pred).map_err(|e| {EngineErr(e)})
  }
  pub fn add_fact(&mut self, fact : &native_types::Fact)
                      -> Result<()> {
    self.engine.new_fact(fact).map_err(|e| {EngineErr(e)})
  }
  pub fn query(&mut self, query : &Vec<native_types::Clause>) -> Result<Vec<Vec<native_types::HValue>>> {
    self.engine.derive(query).map_err(|e| {EngineErr(e)})
  }
  pub fn add_rule(&mut self, rule : &native_types::Rule) -> Result<()> {
    self.engine.new_rule(rule).map_err(|e| {EngineErr(e)})
  }
  pub fn reg_func(&mut self,
                  name : String,
                  input_type  : native_types::HType,
                  output_type : native_types::HType,
                  func : Box<Fn(native_types::HValue) -> native_types::HValue>) -> Result<()> {
    self.engine.reg_func(name, native_types::HFunc {
      input_type  : input_type,
      output_type : output_type,
      run : func
    });
    Ok(())
  }
}

#[macro_export]
macro_rules! htype_raw {
  (string) => { ::holmes::native_types::HType::HString};
  (blob  ) => { ::holmes::native_types::HType::Blob};
  (uint64) => { ::holmes::native_types::HType::UInt64};
}

#[macro_export]
macro_rules! htype {
  ([$t:tt]) => { ::holmes::native_types::HType::List(Box::new(htype!($t))) };
  (($($t:tt),*)) => { ::holmes::native_types::HType::Tuple(vec![$(htype!($t)),*]) };
  ($i:ident) => { htype_raw!($i) };
}

#[macro_export]
macro_rules! holmes_exec {
  ($holmes:ident, { $( $action:expr );* }) => {
      {
        $( try!($action($holmes)); );*
        let res : ::holmes::Result<()> = Ok(());
        res
      }
  };
}

#[macro_export]
macro_rules! predicate {
  ($holmes:ident, $pred_name:ident($($t:tt),*)) => {
    $holmes.add_predicate(&::holmes::native_types::Predicate {
      name  : stringify!($pred_name).to_string(),
      types : vec![$(htype!($t),)*]
    })
  };
  ($pred_name:ident($($t:tt),*)) => { |holmes : &mut Holmes| {
    let res : ::holmes::Result<()> = predicate!(holmes, $pred_name($($t),*));
    res
  }};
}

#[macro_export]
macro_rules! fact {
  ($holmes:ident, $pred_name:ident($($a:expr),*)) => {
    $holmes.add_fact(&::holmes::native_types::Fact {
      pred_name : stringify!($pred_name).to_string(),
      args : vec![$(::holmes::native_types::ToHValue::to_hvalue($a)),*]
    })
  };
  ($pred_name:ident($($a:expr),*)) => { |holmes : &mut Holmes| {
    let res : ::holmes::Result<()> = fact!(holmes, $pred_name($($a),*));
    res
  }};
}

#[macro_export]
macro_rules! bind_match {
  ($vars:ident, $n:ident, [ $bm:tt ]) => { ::holmes::native_types::BindExpr::Iterate(Box::new(bind_match!($vars, $n, $bm))) };
  ($vars:ident, $n:ident, {$($bm:tt),*}) => {
    ::holmes::native_types::BindExpr::Destructure(vec![$(bind_match!($vars, $n, $bm)),*])
  };
  ($vars:ident, $n:ident, $cm:tt) => { ::holmes::native_types::BindExpr::Normal(clause_match!($vars, $n, $cm)) };
}

#[macro_export]
macro_rules! clause_match {
  ($vars:ident, $n:ident, [_]) => { ::holmes::native_types::MatchExpr::Unbound };
  ($vars:ident, $n:ident, ($v:expr)) => {
      ::holmes::native_types::MatchExpr::HConst(::holmes::native_types::ToHValue::to_hvalue($v)) };
  ($vars:ident, $n:ident, $m:ident) => {{
    use std::collections::hash_map::Entry::*;
    use ::holmes::native_types::MatchExpr::*;
    match $vars.entry(stringify!($m).to_string()) {
      Occupied(entry) => Var(*entry.get()),
      Vacant(entry) => {
        $n = $n + 1;
        entry.insert($n - 1);
        Var($n - 1)
      }
    }
  }};
}

#[macro_export]
macro_rules! query {
  ($holmes:ident, $($pred_name:ident($($m:tt),*))&*) => {{
    use std::collections::HashMap;
    let mut vars : HashMap<String, ::holmes::native_types::HVar> = HashMap::new();
    let mut n : ::holmes::native_types::HVar = 0;
    $holmes.query(&vec![$(::holmes::native_types::Clause {
      pred_name : stringify!($pred_name).to_string(),
      args : vec![$(clause_match!(vars, n, $m)),*]
    }),*])
  }}
}

pub fn var_to_evar(var : MatchExpr) -> Expr {
  match var {
    MatchExpr::Var(var_no) => Expr::EVar(var_no),
    x => panic!("var_to_evar was passed nonvar: {:?}", x)
  }
}

#[macro_export]
macro_rules! hexpr {
  ($vars:ident, $n:ident, [$hexpr_name:ident]) => {
    ::holmes::var_to_evar(clause_match!($vars, $n, $hexpr_name))
  };
  ($vars:ident, $n:ident, ($hexpr:expr)) => {
    ::holmes::native_types::Expr::EVal(::holmes::native_types::ToHValue::to_hvalue($hexpr))
  };
  ($vars:ident, $n:ident, {$hexpr_func:ident($($hexpr_arg:tt),*)}) => {
    ::holmes::native_types::Expr::EApp(stringify!($hexpr_func).to_string(), vec![$(hexpr!($vars, $n, $hexpr_arg)),*])
  };
}

#[macro_export]
macro_rules! rule {
  ($holmes:ident, $head_name:ident($($m:tt),*) <= $($body_name:ident($($mb:tt),*))&*,
   {$(let $bind:tt = $hexpr:tt);*}) => {{
    use std::collections::HashMap;
    let mut vars : HashMap<String, ::holmes::native_types::HVar> = HashMap::new();
    let mut n : ::holmes::native_types::HVar = 0;
    $holmes.add_rule(&::holmes::native_types::Rule {
      body : vec![$(::holmes::native_types::Clause {
        pred_name : stringify!($body_name).to_string(),
        args : vec![$(clause_match!(vars, n, $mb)),*]
      }),*],
      head : ::holmes::native_types::Clause {
        pred_name : stringify!($head_name).to_string(),
        args : vec![$(clause_match!(vars, n, $m)),*]
      },
      wheres : vec! [$(::holmes::native_types::WhereClause {
        lhs   : bind_match!(vars, n, $bind),
        rhs   : hexpr!(vars, n, $hexpr)
      }),*]
    })
  }};
  ($holmes:ident, $head_name:ident($($m:tt),*) <= $($body_name:ident($($mb:tt),*))&*,
   {$(let $($bind:tt),* = $hexpr:tt);*}) => {{
    use std::collections::HashMap;
    let mut vars : HashMap<String, ::holmes::native_types::HVar> = HashMap::new();
    let mut n : ::holmes::native_types::HVar = 0;
    $holmes.add_rule(&::holmes::native_types::Rule {
      body : vec![$(::holmes::native_types::Clause {
        pred_name : stringify!($body_name).to_string(),
        args : vec![$(clause_match!(vars, n, $mb)),*]
      }),*],
      head : ::holmes::native_types::Clause {
        pred_name : stringify!($head_name).to_string(),
        args : vec![$(clause_match!(vars, n, $m)),*]
      },
      wheres : vec! [$(::holmes::native_types::WhereClause {
        lhs   : ::holmes::native_types::BindExpr::Destructure(
                  vec![$(bind_match!(vars, n, $bind)),*]),
        rhs   : hexpr!(vars, n, $hexpr)
      }),*]
    })
  }};
  ($($head_name:ident($($m:tt),*)),* <= $($body_name:ident($($mb:tt),*))&*) => {
    |holmes : &mut Holmes| {
      rule!(holmes, $($head_name($($m),*)),* <= $($body_name($($mb),*))&*, {})
    }
  };
  ($($head_name:ident($($m:tt),*)),* <= $($body_name:ident($($mb:tt),*))&*, {$(let $($bind:tt),* = $hexpr:tt);*}) => {
    |holmes : &mut Holmes| {
      rule!(holmes, $($head_name($($m),*)),* <= $($body_name($($mb),*))&*, {$(let $($bind),* = $hexpr);*})
    }
  };

}

#[macro_export]
macro_rules! func {
  ($holmes:ident, let $name:ident : $src:tt -> $dst:tt = $body:expr) => {
    $holmes.reg_func(stringify!($name).to_string(),
                     htype!($src),
                     htype!($dst),
                     Box::new($body))
  };
  (let $name:ident : $src:tt -> $dst:tt = $body:expr) => {
    |holmes : &mut Holmes| {
      func!(holmes, let $name : $src -> $dst = $body)
    }
  };
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate pest;

use pest::prelude::*;

#[derive(Debug, PartialEq)]
pub struct Block {
    statements: Vec<Statement>,
}

#[derive(Debug, PartialEq)]
pub struct Path {
    keys: Vec<String>,
}

#[derive(Debug, PartialEq)]
pub enum Statement {
    Program(Block),
    Section(Path, Block),
    Inverted(Path, Block),
    Variable(Path),
    Html(Path),
    Partial(String),
    Content(String),
}

impl_rdp! {
    grammar! {
        program     = { block ~ eoi }
        block       = { statement* }
        statement   = { content | variable | html | section | inverted | partial }
        content     = @{ (!open ~ any)+ }
        variable    = { open ~ path ~ close }
        html        = { ["{{{"] ~ path ~ ["}}}"]}
        section     = { ["{{#"] ~ path ~ close ~ block ~ ["{{/"] ~ path ~ close }
        inverted    = { ["{{^"] ~ path ~ close ~ block ~ ["{{/"] ~ path ~ close }
        comment     = _{ ["{{!"] ~ (!close ~ any)* ~ close }
        partial     = { ["{{>"] ~ partial_id ~ close }
        partial_id  = { (['a'..'z'] | ['A'..'Z'] | ['0'..'9'] | ["-"] | ["_"] | ["/"])+ }
        open        = _{ ["{{"] }
        close       = _{ ["}}"] }
        path        = @{ identifier ~ (["."] ~ identifier)* }
        identifier  = { (['a'..'z'] | ['A'..'Z'] | ['0'..'9'] | ["-"] | ["_"])+ }
        whitespace  = _{ [" "] | ["\t"] | ["\r"] | ["\n"]}
    }

    process! {
        tree(&self) -> Statement {
            (_: program, block: _block()) => {
                Statement::Program(block)
            }
        }

        _block(&self) -> Block {
            (_: block, list: _statements()) => {
                Block { statements: list }
            }
        }

        _statements(&self) -> Vec<Statement> {
            (_: statement, head: _statement(), mut tail: _statements()) => {
                tail.insert(0, head);
                tail
            },
            () => {
                Vec::new()
            }
        }

        _statement(&self) -> Statement {
            (&text: content) => {
                Statement::Content(String::from(text))
            },
            (_: variable, path: _path()) => {
                Statement::Variable(path)
            },
            (_: html, path: _path()) => {
                Statement::Html(path)
            },
            (_: partial, &name: partial_id) => {
                Statement::Partial(String::from(name))
            },
            (_: section, open: _path(), block: _block(), close: _path()) => {
                if open != close {
                    panic!("Section open and close paths must match");
                }
                Statement::Section(open, block)
            },
            (_: inverted, open: _path(), block: _block(), close: _path()) => {
                if open != close {
                    panic!("Section open and close paths must match");
                }
                Statement::Inverted(open, block)
            }
        }

        _path(&self) -> Path {
            (_: path, list: _identifier()) => {
                Path { keys: list }
            }
        }

        _identifier(&self) -> Vec<String> {
            (&head: identifier, mut tail: _identifier()) => {
                tail.insert(0, String::from(head));
                tail
            },
            () => {
                Vec::new()
            }
        }
    }
}
}

#[cfg(test)]
mod tests {
    use pest::prelude::*;
    use super::{Block, Path, Rdp, Rule, Statement};

    #[test]
    fn identifier() {
        let mut parser = Rdp::new(StringInput::new("abc"));
        assert!(parser.identifier());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::identifier, 0, 3)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn path() {
        let mut parser = Rdp::new(StringInput::new("a.b.c"));
        assert!(parser.path());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::path, 0, 5),
                            Token::new(Rule::identifier, 0, 1),
                            Token::new(Rule::identifier, 2, 3),
                            Token::new(Rule::identifier, 4, 5)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn partial_id() {
        let mut parser = Rdp::new(StringInput::new("a/b/c"));
        assert!(parser.partial_id());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::partial_id, 0, 5)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn partial() {
        let mut parser = Rdp::new(StringInput::new("{{> a/b}}"));
        assert!(parser.partial());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::partial, 0, 9), Token::new(Rule::partial_id, 4, 7)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn comment() {
        let mut parser = Rdp::new(StringInput::new("{{! a b c}}"));
        assert!(parser.comment());
        assert!(parser.end());
        assert!(parser.queue().is_empty());
    }

    #[test]
    fn inverted() {
        let mut parser = Rdp::new(StringInput::new("{{^ a}}{{/ a}}"));
        assert!(parser.inverted());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::inverted, 0, 14),
                            Token::new(Rule::path, 4, 5),
                            Token::new(Rule::identifier, 4, 5),
                            Token::new(Rule::path, 11, 12),
                            Token::new(Rule::identifier, 11, 12)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn section() {
        let mut parser = Rdp::new(StringInput::new("{{# a}}{{/ a}}"));
        assert!(parser.section());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::section, 0, 14),
                            Token::new(Rule::path, 4, 5),
                            Token::new(Rule::identifier, 4, 5),
                            Token::new(Rule::path, 11, 12),
                            Token::new(Rule::identifier, 11, 12)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn variable() {
        let mut parser = Rdp::new(StringInput::new("{{ a }}"));
        assert!(parser.variable());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::variable, 0, 7),
                            Token::new(Rule::path, 3, 4),
                            Token::new(Rule::identifier, 3, 4)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn html() {
        let mut parser = Rdp::new(StringInput::new("{{{ a }}}"));
        assert!(parser.html());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::html, 0, 9),
                            Token::new(Rule::path, 4, 5),
                            Token::new(Rule::identifier, 4, 5)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn program() {
        let mut parser = Rdp::new(StringInput::new("
            {{> includes/header }}

                {{# robots}}

{{ name.first }}

                {{/ robots}}
                {{^ robots}}
                    {{! else clause }}
                    No robots
                {{/ robots}}

            {{> includes/footer }}
            {{{ unescaped.html }}}
        "));
        assert!(parser.program());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::program, 0, 380),
                            Token::new(Rule::block, 0, 371),
                            Token::new(Rule::statement, 0, 13),
                            Token::new(Rule::content, 0, 13),
                            Token::new(Rule::statement, 13, 35),
                            Token::new(Rule::partial, 13, 35),
                            Token::new(Rule::partial_id, 17, 32),
                            Token::new(Rule::statement, 48, 69),
                            Token::new(Rule::content, 48, 69),
                            Token::new(Rule::statement, 69, 156),
                            Token::new(Rule::section, 69, 156),
                            Token::new(Rule::path, 73, 79),
                            Token::new(Rule::identifier, 73, 79),
                            Token::new(Rule::block, 102, 144),
                            Token::new(Rule::statement, 102, 106),
                            Token::new(Rule::content, 102, 106),
                            Token::new(Rule::statement, 106, 122),
                            Token::new(Rule::variable, 106, 122),
                            Token::new(Rule::path, 109, 119),
                            Token::new(Rule::identifier, 109, 113),
                            Token::new(Rule::identifier, 114, 119),
                            Token::new(Rule::statement, 122, 144),
                            Token::new(Rule::content, 122, 144),
                            Token::new(Rule::path, 148, 154),
                            Token::new(Rule::identifier, 148, 154),
                            Token::new(Rule::statement, 173, 283),
                            Token::new(Rule::inverted, 173, 283),
                            Token::new(Rule::path, 177, 183),
                            Token::new(Rule::identifier, 177, 183),
                            Token::new(Rule::block, 245, 271),
                            Token::new(Rule::statement, 245, 271),
                            Token::new(Rule::content, 245, 271),
                            Token::new(Rule::path, 275, 281),
                            Token::new(Rule::identifier, 275, 281),
                            Token::new(Rule::statement, 296, 314),
                            Token::new(Rule::content, 296, 314),
                            Token::new(Rule::statement, 314, 336),
                            Token::new(Rule::partial, 314, 336),
                            Token::new(Rule::partial_id, 318, 333),
                            Token::new(Rule::statement, 349, 371),
                            Token::new(Rule::html, 349, 371),
                            Token::new(Rule::path, 353, 367),
                            Token::new(Rule::identifier, 353, 362),
                            Token::new(Rule::identifier, 363, 367)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn tree() {
        let mut parser = Rdp::new(StringInput::new("
            {{> includes/header }}

                {{# robots}}

{{ name.first }}

                {{/ robots}}
                {{^ robots}}
                    {{! else clause }}
                    No robots
                {{/ robots}}

            {{> includes/footer }}
            {{{ unescaped.html }}}
        "));

        assert!(parser.program());
        assert!(parser.end());

        let list =
            vec![Statement::Content(String::from("
")),
                 Statement::Variable(Path { keys: vec!["name".to_string(), "first".to_string()] }),
                 Statement::Content(String::from("
\n                "))];

        let section = Statement::Section(Path { keys: vec![String::from("robots")] },
                                         Block { statements: list });

        let invblock = vec![Statement::Content("No robots\n                ".to_string())];
        let inverted = Statement::Inverted(Path { keys: vec![String::from("robots")] },
                                           Block { statements: invblock });

        let program =
            vec![Statement::Content(String::from("\n            ")),
                 Statement::Partial(String::from("includes/header")),
                 Statement::Content(String::from("
\n                ")),
                 section,
                 inverted,
                 Statement::Content(String::from("
\n            ")),
                 Statement::Partial(String::from("includes/footer")),
                 Statement::Html(Path { keys: vec!["unescaped".to_string(), "html".to_string()] })];
        let expected = Statement::Program(Block { statements: program });

        assert_eq!(expected, parser.tree());
    }
}
<commit_msg>Fix typo<commit_after>#[macro_use]
extern crate pest;

use pest::prelude::*;

#[derive(Debug, PartialEq)]
pub struct Block {
    statements: Vec<Statement>,
}

#[derive(Debug, PartialEq)]
pub struct Path {
    keys: Vec<String>,
}

#[derive(Debug, PartialEq)]
pub enum Statement {
    Program(Block),
    Section(Path, Block),
    Inverted(Path, Block),
    Variable(Path),
    Html(Path),
    Partial(String),
    Content(String),
}

impl_rdp! {
    grammar! {
        program     = { block ~ eoi }
        block       = { statement* }
        statement   = { content | variable | html | section | inverted | partial }
        content     = @{ (!open ~ any)+ }
        variable    = { open ~ path ~ close }
        html        = { ["{{{"] ~ path ~ ["}}}"] }
        section     = { ["{{#"] ~ path ~ close ~ block ~ ["{{/"] ~ path ~ close }
        inverted    = { ["{{^"] ~ path ~ close ~ block ~ ["{{/"] ~ path ~ close }
        comment     = _{ ["{{!"] ~ (!close ~ any)* ~ close }
        partial     = { ["{{>"] ~ partial_id ~ close }
        partial_id  = { (['a'..'z'] | ['A'..'Z'] | ['0'..'9'] | ["-"] | ["_"] | ["/"])+ }
        open        = _{ ["{{"] }
        close       = _{ ["}}"] }
        path        = @{ identifier ~ (["."] ~ identifier)* }
        identifier  = { (['a'..'z'] | ['A'..'Z'] | ['0'..'9'] | ["-"] | ["_"])+ }
        whitespace  = _{ [" "] | ["\t"] | ["\r"] | ["\n"]}
    }

    process! {
        tree(&self) -> Statement {
            (_: program, block: _block()) => {
                Statement::Program(block)
            }
        }

        _block(&self) -> Block {
            (_: block, list: _statements()) => {
                Block { statements: list }
            }
        }

        _statements(&self) -> Vec<Statement> {
            (_: statement, head: _statement(), mut tail: _statements()) => {
                tail.insert(0, head);
                tail
            },
            () => {
                Vec::new()
            }
        }

        _statement(&self) -> Statement {
            (&text: content) => {
                Statement::Content(String::from(text))
            },
            (_: variable, path: _path()) => {
                Statement::Variable(path)
            },
            (_: html, path: _path()) => {
                Statement::Html(path)
            },
            (_: partial, &name: partial_id) => {
                Statement::Partial(String::from(name))
            },
            (_: section, open: _path(), block: _block(), close: _path()) => {
                if open != close {
                    panic!("Section open and close paths must match");
                }
                Statement::Section(open, block)
            },
            (_: inverted, open: _path(), block: _block(), close: _path()) => {
                if open != close {
                    panic!("Section open and close paths must match");
                }
                Statement::Inverted(open, block)
            }
        }

        _path(&self) -> Path {
            (_: path, list: _identifier()) => {
                Path { keys: list }
            }
        }

        _identifier(&self) -> Vec<String> {
            (&head: identifier, mut tail: _identifier()) => {
                tail.insert(0, String::from(head));
                tail
            },
            () => {
                Vec::new()
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use pest::prelude::*;
    use super::{Block, Path, Rdp, Rule, Statement};

    #[test]
    fn identifier() {
        let mut parser = Rdp::new(StringInput::new("abc"));
        assert!(parser.identifier());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::identifier, 0, 3)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn path() {
        let mut parser = Rdp::new(StringInput::new("a.b.c"));
        assert!(parser.path());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::path, 0, 5),
                            Token::new(Rule::identifier, 0, 1),
                            Token::new(Rule::identifier, 2, 3),
                            Token::new(Rule::identifier, 4, 5)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn partial_id() {
        let mut parser = Rdp::new(StringInput::new("a/b/c"));
        assert!(parser.partial_id());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::partial_id, 0, 5)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn partial() {
        let mut parser = Rdp::new(StringInput::new("{{> a/b}}"));
        assert!(parser.partial());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::partial, 0, 9), Token::new(Rule::partial_id, 4, 7)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn comment() {
        let mut parser = Rdp::new(StringInput::new("{{! a b c}}"));
        assert!(parser.comment());
        assert!(parser.end());
        assert!(parser.queue().is_empty());
    }

    #[test]
    fn inverted() {
        let mut parser = Rdp::new(StringInput::new("{{^ a}}{{/ a}}"));
        assert!(parser.inverted());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::inverted, 0, 14),
                            Token::new(Rule::path, 4, 5),
                            Token::new(Rule::identifier, 4, 5),
                            Token::new(Rule::path, 11, 12),
                            Token::new(Rule::identifier, 11, 12)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn section() {
        let mut parser = Rdp::new(StringInput::new("{{# a}}{{/ a}}"));
        assert!(parser.section());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::section, 0, 14),
                            Token::new(Rule::path, 4, 5),
                            Token::new(Rule::identifier, 4, 5),
                            Token::new(Rule::path, 11, 12),
                            Token::new(Rule::identifier, 11, 12)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn variable() {
        let mut parser = Rdp::new(StringInput::new("{{ a }}"));
        assert!(parser.variable());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::variable, 0, 7),
                            Token::new(Rule::path, 3, 4),
                            Token::new(Rule::identifier, 3, 4)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn html() {
        let mut parser = Rdp::new(StringInput::new("{{{ a }}}"));
        assert!(parser.html());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::html, 0, 9),
                            Token::new(Rule::path, 4, 5),
                            Token::new(Rule::identifier, 4, 5)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn program() {
        let mut parser = Rdp::new(StringInput::new("
            {{> includes/header }}

                {{# robots}}

{{ name.first }}

                {{/ robots}}
                {{^ robots}}
                    {{! else clause }}
                    No robots
                {{/ robots}}

            {{> includes/footer }}
            {{{ unescaped.html }}}
        "));
        assert!(parser.program());
        assert!(parser.end());

        let expected = vec![Token::new(Rule::program, 0, 380),
                            Token::new(Rule::block, 0, 371),
                            Token::new(Rule::statement, 0, 13),
                            Token::new(Rule::content, 0, 13),
                            Token::new(Rule::statement, 13, 35),
                            Token::new(Rule::partial, 13, 35),
                            Token::new(Rule::partial_id, 17, 32),
                            Token::new(Rule::statement, 48, 69),
                            Token::new(Rule::content, 48, 69),
                            Token::new(Rule::statement, 69, 156),
                            Token::new(Rule::section, 69, 156),
                            Token::new(Rule::path, 73, 79),
                            Token::new(Rule::identifier, 73, 79),
                            Token::new(Rule::block, 102, 144),
                            Token::new(Rule::statement, 102, 106),
                            Token::new(Rule::content, 102, 106),
                            Token::new(Rule::statement, 106, 122),
                            Token::new(Rule::variable, 106, 122),
                            Token::new(Rule::path, 109, 119),
                            Token::new(Rule::identifier, 109, 113),
                            Token::new(Rule::identifier, 114, 119),
                            Token::new(Rule::statement, 122, 144),
                            Token::new(Rule::content, 122, 144),
                            Token::new(Rule::path, 148, 154),
                            Token::new(Rule::identifier, 148, 154),
                            Token::new(Rule::statement, 173, 283),
                            Token::new(Rule::inverted, 173, 283),
                            Token::new(Rule::path, 177, 183),
                            Token::new(Rule::identifier, 177, 183),
                            Token::new(Rule::block, 245, 271),
                            Token::new(Rule::statement, 245, 271),
                            Token::new(Rule::content, 245, 271),
                            Token::new(Rule::path, 275, 281),
                            Token::new(Rule::identifier, 275, 281),
                            Token::new(Rule::statement, 296, 314),
                            Token::new(Rule::content, 296, 314),
                            Token::new(Rule::statement, 314, 336),
                            Token::new(Rule::partial, 314, 336),
                            Token::new(Rule::partial_id, 318, 333),
                            Token::new(Rule::statement, 349, 371),
                            Token::new(Rule::html, 349, 371),
                            Token::new(Rule::path, 353, 367),
                            Token::new(Rule::identifier, 353, 362),
                            Token::new(Rule::identifier, 363, 367)];
        assert_eq!(&expected, parser.queue());
    }

    #[test]
    fn tree() {
        let mut parser = Rdp::new(StringInput::new("
            {{> includes/header }}

                {{# robots}}

{{ name.first }}

                {{/ robots}}
                {{^ robots}}
                    {{! else clause }}
                    No robots
                {{/ robots}}

            {{> includes/footer }}
            {{{ unescaped.html }}}
        "));

        assert!(parser.program());
        assert!(parser.end());

        let list =
            vec![Statement::Content(String::from("
")),
                 Statement::Variable(Path { keys: vec!["name".to_string(), "first".to_string()] }),
                 Statement::Content(String::from("
\n                "))];

        let section = Statement::Section(Path { keys: vec![String::from("robots")] },
                                         Block { statements: list });

        let invblock = vec![Statement::Content("No robots\n                ".to_string())];
        let inverted = Statement::Inverted(Path { keys: vec![String::from("robots")] },
                                           Block { statements: invblock });

        let program =
            vec![Statement::Content(String::from("\n            ")),
                 Statement::Partial(String::from("includes/header")),
                 Statement::Content(String::from("
\n                ")),
                 section,
                 inverted,
                 Statement::Content(String::from("
\n            ")),
                 Statement::Partial(String::from("includes/footer")),
                 Statement::Html(Path { keys: vec!["unescaped".to_string(), "html".to_string()] })];
        let expected = Statement::Program(Block { statements: program });

        assert_eq!(expected, parser.tree());
    }
}
<|endoftext|>


<commit_before>#![crate_name = "neovim"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![allow(raw_pointer_derive)]

extern crate libc;

use std::ffi::CString;
use std::fmt;
use std::string::String;
use std::vec::Vec;

#[cfg(target_os="macos")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    #[link(name = "iconv")]
    extern{}
}

#[cfg(target_os="linux")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

#[cfg(target_os="windows")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

mod ffi;

pub enum Object {
    Buffer(ffi::C_Buffer),
    Window(ffi::C_Window),
    Tabpage(ffi::C_Tabpage),
    Boolean(ffi::C_Boolean),
    Integer(ffi::C_Integer),
    Float(ffi::C_Float),
    String(String),
    Array(ffi::C_Array),
    Dictionary(ffi::C_Dictionary),
}

impl fmt::Show for Object {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Object::Buffer(ref obj) => write!(f, "Buffer({})", obj),
            Object::Window(ref obj) => write!(f, "Window({})", obj),
            Object::Tabpage(ref obj) => write!(f, "Tabpage({})", obj),
            Object::Boolean(ref obj) => write!(f, "Boolean({})", obj),
            Object::Integer(ref obj) => write!(f, "Integer({})", obj),
            Object::Float(ref obj) => write!(f, "Float({})", obj),
            Object::String(ref obj) => write!(f, "String({})", obj),
            Object::Array(ref obj) => {
                write!(f, "Array(").ok();
                for i in range(0, obj.size) {
                    let inner_obj_opt = unsafe { c_object_to_object(obj.items.offset(i as int)) };
                    if let Some(inner_obj) = inner_obj_opt {
                        write!(f, "{}", inner_obj).ok();
                        if i + 1 < obj.size {
                            write!(f, ", ").ok();
                        }
                    } else {
                        write!(f, "Nil ").ok();
                    }
                }
                write!(f, ")")
            },
            Object::Dictionary(ref obj) => write!(f, "Dictionary(Length: {})", obj.size),
        }
    }
}

unsafe fn c_object_to_object(obj: *mut ffi::C_Object) -> Option<Object> {
    match (*obj).object_type {
        ffi::ObjectType::BufferType =>
            Some(Object::Buffer((*(obj as *mut ffi::C_Object_Buffer)).data)),
        ffi::ObjectType::WindowType =>
            Some(Object::Window((*(obj as *mut ffi::C_Object_Window)).data)),
        ffi::ObjectType::TabpageType =>
            Some(Object::Tabpage((*(obj as *mut ffi::C_Object_Tabpage)).data)),
        ffi::ObjectType::NilType =>
            None,
        ffi::ObjectType::BooleanType =>
            Some(Object::Boolean((*(obj as *mut ffi::C_Object_Boolean)).data)),
        ffi::ObjectType::IntegerType =>
            Some(Object::Integer((*(obj as *mut ffi::C_Object_Integer)).data)),
        ffi::ObjectType::FloatType =>
            Some(Object::Float((*(obj as *mut ffi::C_Object_Float)).data)),
        ffi::ObjectType::StringType => {
            let vim_str: ffi::C_String = (*(obj as *mut ffi::C_Object_String)).data;
            let v = Vec::from_raw_buf(vim_str.data as *const u8, vim_str.size as uint);
            Some(Object::String(String::from_utf8_unchecked(v)))
        },
        ffi::ObjectType::ArrayType =>
            Some(Object::Array((*(obj as *mut ffi::C_Object_Array)).data)),
        ffi::ObjectType::DictionaryType =>
            Some(Object::Dictionary((*(obj as *mut ffi::C_Object_Dictionary)).data)),
    }
}

pub fn main_setup(args: Vec<String>) -> i32 {
    let v: Vec<CString> = args.iter().map(|s| CString::from_slice(s.as_bytes())).collect();
    let vp: Vec<*const ffi::c_char> = v.iter().map(|s| s.as_ptr()).collect();
    let p_vp: *const *const ffi::c_char = vp.as_ptr();

    unsafe { ffi::nvim_main_setup(vp.len() as i32, p_vp) }
}

pub fn main_loop() -> i32 {
    unsafe { ffi::nvim_main_loop() }
}

pub fn channel_from_fds(read_fd: i32, write_fd: i32) -> u64 {
    unsafe { ffi::channel_from_fds(read_fd, write_fd) }
}

pub fn serialize_message(id: u64, method: &'static str, args: &Array) -> String {
    unsafe {
        let buf = ffi::vim_msgpack_new();
        let vim_str = ffi::C_String {data: method.as_ptr() as *const i8, size: method.len() as u64};
        ffi::vim_serialize_request(id, vim_str, args.unwrap_value(), buf);
        let v = Vec::from_raw_buf((*buf).data as *const u8, (*buf).size as uint);
        ffi::vim_msgpack_free(buf);
        String::from_utf8_unchecked(v)
    }
}

pub fn deserialize_message(message: &String) -> Array {
    unsafe {
        let mut arr_raw = Array::new().unwrap_value();
        let s = ffi::C_String {
            data: message.as_slice().as_ptr() as *const i8,
            size: message.len() as u64
        };
        ffi::vim_msgpack_parse(s, &mut arr_raw);
        Array::wrap_value(arr_raw)
    }
}

#[derive(Copy)]
pub struct Array {
    value: ffi::C_Array
}

impl Array {
    pub fn new() -> Array {
        Array {
            value: ffi::C_Array {
                items: ::std::ptr::null_mut(),
                size: 0,
                capacity: 0,
            }
        }
    }

    pub fn add_buffer(&mut self, val: ffi::C_Buffer) {
        unsafe { ffi::vim_array_add_buffer(val, &mut self.value) }
    }

    pub fn add_window(&mut self, val: ffi::C_Window) {
        unsafe { ffi::vim_array_add_window(val, &mut self.value) }
    }

    pub fn add_tabpage(&mut self, val: ffi::C_Tabpage) {
        unsafe { ffi::vim_array_add_tabpage(val, &mut self.value) }
    }

    pub fn add_nil(&mut self) {
        unsafe { ffi::vim_array_add_nil(&mut self.value) }
    }

    pub fn add_boolean(&mut self, val: ffi::C_Boolean) {
        unsafe { ffi::vim_array_add_boolean(val, &mut self.value) }
    }

    pub fn add_integer(&mut self, val: ffi::C_Integer) {
        unsafe { ffi::vim_array_add_integer(val, &mut self.value) }
    }

    pub fn add_float(&mut self, val: ffi::C_Float) {
        unsafe { ffi::vim_array_add_float(val, &mut self.value) }
    }

    pub fn add_string(&mut self, val: &str) {
        unsafe {
            // we need to copy the string into memory not managed by Rust,
            // so api_free_array can clear it
            let ptr = ffi::malloc(val.len() as u64);
            ::std::ptr::copy_memory(ptr, val.as_ptr() as *const ffi::c_void, val.len());
            let vim_str = ffi::C_String {data: ptr as *const i8, size: val.len() as u64};
            ffi::vim_array_add_string(vim_str, &mut self.value)
        }
    }

    pub fn add_array(&mut self, val: &Array) {
        unsafe { ffi::vim_array_add_array(val.unwrap_value(), &mut self.value) }
    }

    pub fn add_dictionary(&mut self, val: ffi::C_Dictionary) {
        unsafe { ffi::vim_array_add_dictionary(val, &mut self.value) }
    }

    pub fn get(&self, index: u64) -> Option<Object> {
        if index >= self.len() {
            return None;
        }
        unsafe { c_object_to_object(self.value.items.offset(index as int)) }
    }

    pub fn len(&self) -> u64 {
        self.value.size
    }

    #[doc(hidden)]
    pub fn unwrap_value(&self) -> ffi::C_Array {
        self.value
    }

    #[doc(hidden)]
    pub fn wrap_value(c_array: ffi::C_Array) -> Array {
        Array {
            value: c_array
        }
    }
}

impl Drop for Array {
    fn drop(&mut self) {
        unsafe { ffi::api_free_array(self.value) };
    }
}

impl fmt::Show for Array {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Array(").ok();
        for i in range(0, self.len()) {
            if let Some(obj) = self.get(i) {
                write!(f, "{}", obj).ok();
            } else {
                write!(f, "Nil").ok();
            }
            if i + 1 < self.len() {
                write!(f, ", ").ok();
            }
        }
        write!(f, ")")
    }
}

#[test]
fn test_request() {
    let mut args = Array::new();
    args.add_integer(80);
    args.add_integer(24);
    args.add_string("hello");

    let msg = serialize_message(1, "attach_ui", &args);
    let arr = deserialize_message(&msg);
    println!("LENGTH: {}", arr.len());
    for i in range(0, arr.len()) {
        println!("{}", arr.get(i));
    }
}
<commit_msg>Update for latest version of Rust<commit_after>#![crate_name = "neovim"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![allow(raw_pointer_derive)]

extern crate libc;

use std::ffi::CString;
use std::fmt;
use std::string::String;
use std::vec::Vec;

#[cfg(target_os="macos")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    #[link(name = "iconv")]
    extern{}
}

#[cfg(target_os="linux")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

#[cfg(target_os="windows")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

mod ffi;

pub enum Object {
    Buffer(ffi::C_Buffer),
    Window(ffi::C_Window),
    Tabpage(ffi::C_Tabpage),
    Boolean(ffi::C_Boolean),
    Integer(ffi::C_Integer),
    Float(ffi::C_Float),
    String(String),
    Array(ffi::C_Array),
    Dictionary(ffi::C_Dictionary),
}

impl fmt::Show for Object {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Object::Buffer(ref obj) => write!(f, "Buffer({:?})", obj),
            Object::Window(ref obj) => write!(f, "Window({:?})", obj),
            Object::Tabpage(ref obj) => write!(f, "Tabpage({:?})", obj),
            Object::Boolean(ref obj) => write!(f, "Boolean({:?})", obj),
            Object::Integer(ref obj) => write!(f, "Integer({:?})", obj),
            Object::Float(ref obj) => write!(f, "Float({:?})", obj),
            Object::String(ref obj) => write!(f, "String({:?})", obj),
            Object::Array(ref obj) => {
                write!(f, "Array(").ok();
                for i in range(0, obj.size) {
                    let inner_obj_opt = unsafe { c_object_to_object(obj.items.offset(i as isize)) };
                    if let Some(inner_obj) = inner_obj_opt {
                        write!(f, "{:?}", inner_obj).ok();
                        if i + 1 < obj.size {
                            write!(f, ", ").ok();
                        }
                    } else {
                        write!(f, "Nil ").ok();
                    }
                }
                write!(f, ")")
            },
            Object::Dictionary(ref obj) => write!(f, "Dictionary(Length: {:?})", obj.size),
        }
    }
}

unsafe fn c_object_to_object(obj: *mut ffi::C_Object) -> Option<Object> {
    match (*obj).object_type {
        ffi::ObjectType::BufferType =>
            Some(Object::Buffer((*(obj as *mut ffi::C_Object_Buffer)).data)),
        ffi::ObjectType::WindowType =>
            Some(Object::Window((*(obj as *mut ffi::C_Object_Window)).data)),
        ffi::ObjectType::TabpageType =>
            Some(Object::Tabpage((*(obj as *mut ffi::C_Object_Tabpage)).data)),
        ffi::ObjectType::NilType =>
            None,
        ffi::ObjectType::BooleanType =>
            Some(Object::Boolean((*(obj as *mut ffi::C_Object_Boolean)).data)),
        ffi::ObjectType::IntegerType =>
            Some(Object::Integer((*(obj as *mut ffi::C_Object_Integer)).data)),
        ffi::ObjectType::FloatType =>
            Some(Object::Float((*(obj as *mut ffi::C_Object_Float)).data)),
        ffi::ObjectType::StringType => {
            let vim_str: ffi::C_String = (*(obj as *mut ffi::C_Object_String)).data;
            let v = Vec::from_raw_buf(vim_str.data as *const u8, vim_str.size as usize);
            Some(Object::String(String::from_utf8_unchecked(v)))
        },
        ffi::ObjectType::ArrayType =>
            Some(Object::Array((*(obj as *mut ffi::C_Object_Array)).data)),
        ffi::ObjectType::DictionaryType =>
            Some(Object::Dictionary((*(obj as *mut ffi::C_Object_Dictionary)).data)),
    }
}

pub fn main_setup(args: Vec<String>) -> i32 {
    let v: Vec<CString> = args.iter().map(|s| CString::from_slice(s.as_bytes())).collect();
    let vp: Vec<*const ffi::c_char> = v.iter().map(|s| s.as_ptr()).collect();
    let p_vp: *const *const ffi::c_char = vp.as_ptr();

    unsafe { ffi::nvim_main_setup(vp.len() as i32, p_vp) }
}

pub fn main_loop() -> i32 {
    unsafe { ffi::nvim_main_loop() }
}

pub fn channel_from_fds(read_fd: i32, write_fd: i32) -> u64 {
    unsafe { ffi::channel_from_fds(read_fd, write_fd) }
}

pub fn serialize_message(id: u64, method: &'static str, args: &Array) -> String {
    unsafe {
        let buf = ffi::vim_msgpack_new();
        let vim_str = ffi::C_String {data: method.as_ptr() as *const i8, size: method.len() as u64};
        ffi::vim_serialize_request(id, vim_str, args.unwrap_value(), buf);
        let v = Vec::from_raw_buf((*buf).data as *const u8, (*buf).size as usize);
        ffi::vim_msgpack_free(buf);
        String::from_utf8_unchecked(v)
    }
}

pub fn deserialize_message(message: &String) -> Array {
    unsafe {
        let mut arr_raw = Array::new().unwrap_value();
        let s = ffi::C_String {
            data: message.as_slice().as_ptr() as *const i8,
            size: message.len() as u64
        };
        ffi::vim_msgpack_parse(s, &mut arr_raw);
        Array::wrap_value(arr_raw)
    }
}

pub struct Array {
    value: ffi::C_Array
}

impl Array {
    pub fn new() -> Array {
        Array {
            value: ffi::C_Array {
                items: ::std::ptr::null_mut(),
                size: 0,
                capacity: 0,
            }
        }
    }

    pub fn add_buffer(&mut self, val: ffi::C_Buffer) {
        unsafe { ffi::vim_array_add_buffer(val, &mut self.value) }
    }

    pub fn add_window(&mut self, val: ffi::C_Window) {
        unsafe { ffi::vim_array_add_window(val, &mut self.value) }
    }

    pub fn add_tabpage(&mut self, val: ffi::C_Tabpage) {
        unsafe { ffi::vim_array_add_tabpage(val, &mut self.value) }
    }

    pub fn add_nil(&mut self) {
        unsafe { ffi::vim_array_add_nil(&mut self.value) }
    }

    pub fn add_boolean(&mut self, val: ffi::C_Boolean) {
        unsafe { ffi::vim_array_add_boolean(val, &mut self.value) }
    }

    pub fn add_integer(&mut self, val: ffi::C_Integer) {
        unsafe { ffi::vim_array_add_integer(val, &mut self.value) }
    }

    pub fn add_float(&mut self, val: ffi::C_Float) {
        unsafe { ffi::vim_array_add_float(val, &mut self.value) }
    }

    pub fn add_string(&mut self, val: &str) {
        unsafe {
            // we need to copy the string into memory not managed by Rust,
            // so api_free_array can clear it
            let ptr = ffi::malloc(val.len() as u64);
            ::std::ptr::copy_memory(ptr, val.as_ptr() as *const ffi::c_void, val.len());
            let vim_str = ffi::C_String {data: ptr as *const i8, size: val.len() as u64};
            ffi::vim_array_add_string(vim_str, &mut self.value)
        }
    }

    pub fn add_array(&mut self, val: &Array) {
        unsafe { ffi::vim_array_add_array(val.unwrap_value(), &mut self.value) }
    }

    pub fn add_dictionary(&mut self, val: ffi::C_Dictionary) {
        unsafe { ffi::vim_array_add_dictionary(val, &mut self.value) }
    }

    pub fn get(&self, index: u64) -> Option<Object> {
        if index >= self.len() || index < 0 {
            return None;
        }
        unsafe { c_object_to_object(self.value.items.offset(index as isize)) }
    }

    pub fn len(&self) -> u64 {
        self.value.size
    }

    #[doc(hidden)]
    pub fn unwrap_value(&self) -> ffi::C_Array {
        self.value
    }

    #[doc(hidden)]
    pub fn wrap_value(c_array: ffi::C_Array) -> Array {
        Array {
            value: c_array
        }
    }
}

impl Drop for Array {
    fn drop(&mut self) {
        unsafe { ffi::api_free_array(self.value) };
    }
}

impl fmt::Show for Array {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Array(").ok();
        for i in range(0, self.len()) {
            if let Some(obj) = self.get(i) {
                write!(f, "{:?}", obj).ok();
            } else {
                write!(f, "Nil").ok();
            }
            if i + 1 < self.len() {
                write!(f, ", ").ok();
            }
        }
        write!(f, ")")
    }
}

#[test]
fn test_request() {
    let mut args = Array::new();
    args.add_integer(80);
    args.add_integer(24);
    args.add_string("hello");

    let msg = serialize_message(1, "attach_ui", &args);
    let arr = deserialize_message(&msg);
    println!("LENGTH: {}", arr.len());
    for i in range(0, arr.len()) {
        println!("{:?}", arr.get(i));
    }
}
<|endoftext|>


<commit_before>use std::ops::{Mul, Add};
use std::slice::Iter;

pub trait Interpolate {
    fn interpolate(&self, other: &Self, t: f32) -> Self;
}

impl<T: Mul<f32, Output = T> + Add<Output = T> + Copy> Interpolate for T {
    fn interpolate(&self, other: &Self, t: f32) -> Self {
        *self * (1.0 - t) + *other * t
    }
}

/// Structure for computing the B-spline with the given control points
/// and knots.
pub struct BSpline<T: Interpolate + Copy> {
    /// Degree of the polynomial that we use to make the curve segments
    degree: usize,
    /// Control points for the curve
    control_points: Vec<T>,
    /// TODO: What is a good description for the knots?
    knots: Vec<f32>,
}

impl<T: Interpolate + Copy> BSpline<T> {
    /// Create a new B-spline curve of the desired degree that will blend between
    /// the passed control points using the knots. The knots should be sorted in ascending
    /// order, otherwise they will be sorted for you which may lead to undesired knots
    /// for control points
    pub fn new(degree: usize, control_points: Vec<T>, mut knots: Vec<f32>) -> BSpline<T> {
        // TODO: Maybe a ctor for cardinal curves that will check we have the right number of
        // knots? Is this check correct?
        if control_points.len() < degree {
            panic!("Too few control points for curve");
        }
        knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
        BSpline { degree: degree, control_points: control_points, knots: knots }
    }
    /// Compute a point on the curve at `t`
    /// TODO: Handling of out of bounds t values? Are t values not in the domain considered
    /// out of range? The extra `degree` values are just for when we're going down the tree
    /// to find the interpolated values there right?
    pub fn point(&self, t: f32) -> T {
        // Find the first index with a knot value greater than the t we're searching for. We want
        // to find i such that: knot[i] <= t < knot[i + 1]
        let i = match upper_bounds(&self.knots[..], t) {
            Some(x) if x == 0 => self.degree,
            Some(x) => x,
            None => self.knots.len() - self.degree - 1,
        };
        //println!("Found i = {} for t = {}\n\tknots = {:?}", i, t, self.knots);
        //println!("degree = {}", self.degree);
        self.de_boors(t, self.degree, i)
    }
    /// Get an iterator over the control points
    pub fn control_points(&self) -> Iter<T> {
        self.control_points.iter()
    }
    /// Get an iterator over the knots
    pub fn knots(&self) -> Iter<f32> {
        self.knots.iter()
    }
    /// Recursively compute de Boor's B-spline algorithm. TODO: This is terrible,
    /// compute it iteratively! Recursive version is just for a simple formualation
    /// of the initial implementation.
    fn de_boors(&self, t: f32, k: usize, i: usize) -> T {
        if k == 0 {
            //println!("Returning control point {}", i);
            self.control_points[i - 1]
        } else {
            //println!("Looking at k = {}, i = {}, t = {}", k, i, t);
            //println!("\tknots[i + self.degree - k] = {}, self.knots[i - 1] = {}",
            //         self.knots[i + self.degree - k], self.knots[i - 1]);
            // TODO: This is still broken
            let alpha = (t - self.knots[i - 1]) / (self.knots[i + self.degree - k] - self.knots[i - 1]);
            self.de_boors(t, k - 1, i - 1).interpolate(&self.de_boors(t, k - 1, i), alpha)
        }
    }
}

/// Return the index of the first element greater than the value passed.
/// The data **must** be sorted.
/// If no element greater than the value passed is found the function returns None.
fn upper_bounds(data: &[f32], value: f32) -> Option<usize> {
    let mut first = 0usize;
    let mut step;
    let mut count = data.len() as isize;
    while count > 0 {
        step = count / 2;
        let it = first + step as usize;
        if !value.lt(&data[it]) {
            first = it + 1;
            count -= step + 1;
        } else {
            count = step;
        }
    }
    // If we didn't find an element greater than value
    if first == data.len() {
        None
    } else {
        Some(first)
    }
}

#[cfg(test)]
mod test {
    use std::ops::{Mul, Add};

    use super::BSpline;

    #[derive(Copy, Clone, Debug)]
    struct Point {
        x: f32,
        y: f32,
    }
    impl Point {
        fn new(x: f32, y: f32) -> Point {
            Point { x: x, y: y }
        }
    }
    impl Mul<f32> for Point {
        type Output = Point;
        fn mul(self, rhs: f32) -> Point {
            Point { x: self.x * rhs, y: self.y * rhs }
        }
    }
    impl Add for Point {
        type Output = Point;
        fn add(self, rhs: Point) -> Point {
            Point { x: self.x + rhs.x, y: self.y + rhs.y }
        }
    }

    // TODO: Test on 1D functions?
    #[test]
    fn linear_bspline() {
        let points = vec![Point::new(-1.0, 0.0), Point::new(0.0, 1.0),
                          Point::new(1.0, 1.0), Point::new(1.0, 2.0)];
        let knots = vec![0.0, 0.0, 1.0, 2.0, 3.0, 3.0];
        let spline = BSpline::new(1, points, knots);
        let x = spline.point(1.5);
        println!("spline(1.5) = {:?}", x);
        assert!(x.x == 0.5 && x.y == 1.0);
    }
    //#[test]
    fn quadratic_bspline_plot1d() {
        let points = vec![0.0, 0.0, 1.0, 0.0, 0.0];
        let knots = vec![0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 3.0];
        let t_start = knots[0];
        let t_end = knots[knots.len() - 1];
        println!("Starting at {}, ending at {}", t_start, t_end);
        let spline = BSpline::new(2, points, knots);
        let t = 0.5;
        println!("spline({}) = {}", t, spline.point(t));
    }
    //#[test]
    fn cubic_bspline_plot1d() {
        let points = vec![0.0, 0.0, 0.0, 6.0, 0.0, 0.0, 0.0];
        let knots = vec![-2.0, -2.0, -2.0, -2.0, -1.0, 0.0, 1.0, 2.0, 2.0, 2.0, 2.0];
        let t_start = knots[0];
        let t_end = knots[knots.len() - 1];
        println!("Starting at {}, ending at {}", t_start, t_end);
        let spline = BSpline::new(3, points, knots);
        let t = 0.5;
        println!("spline({}) = {}", t, spline.point(t));
    }
    //#[test]
    fn quartic_bspline_plot1d() {
        let points = vec![0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0];
        let knots = vec![0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 5.0, 5.0, 5.0];
        let t_start = knots[0];
        let t_end = knots[knots.len() - 1];
        println!("Starting at {}, ending at {}", t_start, t_end);
        let spline = BSpline::new(4, points, knots);
        let t = 3.5;
        println!("spline({}) = {}", t, spline.point(t));
    }
}

<commit_msg>Spline code works properly! Cleaning up old tests, will add new ones<commit_after>use std::ops::{Mul, Add};
use std::slice::Iter;

pub trait Interpolate {
    fn interpolate(&self, other: &Self, t: f32) -> Self;
}

impl<T: Mul<f32, Output = T> + Add<Output = T> + Copy> Interpolate for T {
    fn interpolate(&self, other: &Self, t: f32) -> Self {
        *self * (1.0 - t) + *other * t
    }
}

/// Structure for computing the B-spline with the given control points
/// and knots.
pub struct BSpline<T: Interpolate + Copy> {
    /// Degree of the polynomial that we use to make the curve segments
    degree: usize,
    /// Control points for the curve
    control_points: Vec<T>,
    /// TODO: What is a good description for the knots?
    knots: Vec<f32>,
}

impl<T: Interpolate + Copy> BSpline<T> {
    /// Create a new B-spline curve of the desired degree that will blend between
    /// the passed control points using the knots. The knots should be sorted in ascending
    /// order, otherwise they will be sorted for you which may lead to undesired knots
    /// for control points
    pub fn new(degree: usize, control_points: Vec<T>, mut knots: Vec<f32>) -> BSpline<T> {
        // TODO: Maybe a ctor for cardinal curves that will check we have the right number of
        // knots? Is this check correct?
        if control_points.len() < degree {
            panic!("Too few control points for curve");
        }
        if knots.len() != control_points.len() + degree + 1 {
            panic!(format!("Invalid number of knots, got {}, expected {}", knots.len(),
                control_points.len() + degree + 1));
        }
        knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
        BSpline { degree: degree, control_points: control_points, knots: knots }
    }
    /// Compute a point on the curve at `t`
    /// TODO: Handling of out of bounds t values? Are t values not in the domain considered
    /// out of range? The extra `degree` values are just for when we're going down the tree
    /// to find the interpolated values there right?
    pub fn point(&self, t: f32) -> T {
        // Find the first index with a knot value greater than the t we're searching for. We want
        // to find i such that: knot[i] <= t < knot[i + 1]
        let i = match upper_bounds(&self.knots[..], t) {
            Some(x) if x == 0 => self.degree,
            Some(x) => x,
            None => self.knots.len() - self.degree - 1,
        };
        self.de_boors(t, self.degree, i)
    }
    /// Get an iterator over the control points
    pub fn control_points(&self) -> Iter<T> {
        self.control_points.iter()
    }
    /// Get an iterator over the knots
    pub fn knots(&self) -> Iter<f32> {
        self.knots.iter()
    }
    /// Recursively compute de Boor's B-spline algorithm. TODO: This is terrible,
    /// compute it iteratively! Recursive version is just for a simple formualation
    /// of the initial implementation. Could we do memo-ization? If we switch to an
    /// iterative one and recursively compute the weights our interpolation at
    /// each level is no longer linear, which makes it harder to support things like
    /// Quaternions.
    fn de_boors(&self, t: f32, k: usize, i: usize) -> T {
        if k == 0 {
            self.control_points[i - 1]
        } else {
            let alpha = (t - self.knots[i - 1]) / (self.knots[i + self.degree - k] - self.knots[i - 1]);
            self.de_boors(t, k - 1, i - 1).interpolate(&self.de_boors(t, k - 1, i), alpha)
        }
    }
}

/// Return the index of the first element greater than the value passed.
/// The data **must** be sorted.
/// If no element greater than the value passed is found the function returns None.
fn upper_bounds(data: &[f32], value: f32) -> Option<usize> {
    let mut first = 0usize;
    let mut step;
    let mut count = data.len() as isize;
    while count > 0 {
        step = count / 2;
        let it = first + step as usize;
        if !value.lt(&data[it]) {
            first = it + 1;
            count -= step + 1;
        } else {
            count = step;
        }
    }
    // If we didn't find an element greater than value
    if first == data.len() {
        None
    } else {
        Some(first)
    }
}

#[cfg(test)]
mod test {
    use std::ops::{Mul, Add};

    use super::BSpline;

    #[derive(Copy, Clone, Debug)]
    struct Point {
        x: f32,
        y: f32,
    }
    impl Point {
        fn new(x: f32, y: f32) -> Point {
            Point { x: x, y: y }
        }
    }
    impl Mul<f32> for Point {
        type Output = Point;
        fn mul(self, rhs: f32) -> Point {
            Point { x: self.x * rhs, y: self.y * rhs }
        }
    }
    impl Add for Point {
        type Output = Point;
        fn add(self, rhs: Point) -> Point {
            Point { x: self.x + rhs.x, y: self.y + rhs.y }
        }
    }

    // TODO: Test on 1D functions? Re-write tests
    #[test]
    fn linear_bspline() {
        let points = vec![Point::new(-1.0, 0.0), Point::new(0.0, 1.0),
                          Point::new(1.0, 1.0), Point::new(1.0, 2.0)];
        let knots = vec![0.0, 0.0, 1.0, 2.0, 3.0, 3.0];
        let spline = BSpline::new(1, points, knots);
        let x = spline.point(1.5);
        println!("spline(1.5) = {:?}", x);
        assert!(x.x == 0.5 && x.y == 1.0);
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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.

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do Cap'n Proto code generation within a Cargo build.
//!
//! In your Cargo.toml:
//!
//! ```ignore
//!   [build-dependencies]
//!   capnpc = "0.1.5"
//! ```
//!
//! In your build.rs, call
//!
//! ```ignore
//! ::capnpc::compile(Path::new("schema"),
//!                   &[Path::new("schema/foo.capnp"),
//!                     Path::new("schema/bar.capnp")]);
//! ```
//!
//! This will be equivalent to executing the shell command
//!
//! ```ignore
//!   capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//! ```
//!

#![crate_name="capnpc"]
#![crate_type = "lib"]

extern crate capnp;

pub mod schema_capnp;
pub mod codegen;
pub mod schema;

pub fn compile(prefix : &::std::path::Path, files : &[&::std::path::Path]) -> ::capnp::Result<()> {

    // Find the absolute path of `cat`.
    //
    // TODO: Once a released version of `capnp compile` includes the '-o -' option, switch to
    //       using that. (see https://github.com/sandstorm-io/capnproto/pull/190)
    let which_output = ::std::process::Command::new("which").arg("cat").output().unwrap().stdout;

    let mut command = ::std::process::Command::new("capnp");
    command.arg("compile").arg("-o").arg(&::std::str::from_utf8(&which_output).unwrap().trim())
           .arg(&format!("--src-prefix={}", prefix.display()));

    for file in files.iter() {
        command.arg(&format!("{}", file.display()));
    }

    command.stdout(::std::process::Stdio::piped());
    command.stderr(::std::process::Stdio::inherit());

    let mut p =  try!(command.spawn());
    try!(::codegen::main(p.stdout.take().unwrap(),
                         ::std::path::Path::new(&::std::env::var("OUT_DIR").unwrap())));
    try!(p.wait());
    return Ok(());
}

<commit_msg>Workaroung for using ::capnpc::compile on Windows<commit_after>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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.

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do Cap'n Proto code generation within a Cargo build.
//!
//! In your Cargo.toml:
//!
//! ```ignore
//!   [build-dependencies]
//!   capnpc = "0.1.5"
//! ```
//!
//! In your build.rs, call
//!
//! ```ignore
//! ::capnpc::compile(Path::new("schema"),
//!                   &[Path::new("schema/foo.capnp"),
//!                     Path::new("schema/bar.capnp")]);
//! ```
//!
//! This will be equivalent to executing the shell command
//!
//! ```ignore
//!   capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//! ```
//!

#![crate_name="capnpc"]
#![crate_type = "lib"]

extern crate capnp;

pub mod schema_capnp;
pub mod codegen;
pub mod schema;

pub fn compile(prefix : &::std::path::Path, files : &[&::std::path::Path]) -> ::capnp::Result<()> {

    // Find the absolute path of `cat`.
    //
    // TODO: Once a released version of `capnp compile` includes the '-o -' option, switch to
    //       using that. (see https://github.com/sandstorm-io/capnproto/pull/190)
    let cat_file = match ::std::process::Command::new("which").arg("cat").output() {
        Ok(result) => match result.status.success() {
		true => result.stdout,
		false => vec!(b'-'),
	},
        Err(_) => vec!(b'-'),
    };

    let mut command = ::std::process::Command::new("capnp");
    command.arg("compile").arg("-o").arg(&::std::str::from_utf8(&cat_file).unwrap().trim())
           .arg(&format!("--src-prefix={}", prefix.display()));

    for file in files.iter() {
        command.arg(&format!("{}", file.display()));
    }

    command.stdout(::std::process::Stdio::piped());
    command.stderr(::std::process::Stdio::inherit());

    let mut p =  try!(command.spawn());
    try!(::codegen::main(p.stdout.take().unwrap(),
                         ::std::path::Path::new(&::std::env::var("OUT_DIR").unwrap())));
    try!(p.wait());
    return Ok(());
}

<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![feature(globs)]

extern crate router = "route-recognizer";
extern crate conduit;

use std::collections::HashMap;
use std::any::{Any, AnyRefExt};
use std::fmt::Show;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<Handler + Send + Sync>>>
}

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str)
                         -> Result<Match<&'a Box<Handler + Send + Sync>>, String>
    {
        match self.routers.find(method) {
            None => Err(format!("No router found for {}", method)),
            Some(router) => router.recognize(path)
        }
    }

    pub fn map<'a, H: Handler>(&'a mut self, method: Method, pattern: &str,
                               handler: H) -> &'a mut RouteBuilder {
        {
            let router = self.routers.find_or_insert_with(method, |_| Router::new());
            router.add(pattern, box handler as Box<Handler + Send + Sync>);
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(conduit::Get, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(conduit::Post, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(conduit::Put, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                  -> &'a mut RouteBuilder {
        self.map(conduit::Delete, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(conduit::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(box e as Box<Show>)
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert("router.params", box m.params.clone() as Box<Any>);
        }

        (*m.handler).call(request)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a Request) -> &'a router::Params {
    req.extensions().find(&"router.params")
        .and_then(|a| a.downcast_ref::<router::Params>())
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a Request {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::io::net::ip::IpAddr;
    use std::collections::HashMap;
    use std::io::MemReader;
    use super::*;

    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_string().unwrap(), "1, Get".to_string());
    }

    #[test]
    fn basic_post() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_string().unwrap(), "10, Post".to_string());
    }

    #[test]
    fn nonexistent_route() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Post, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut conduit::Request) -> Result<conduit::Response, ()> {
        let mut res = vec!();
        res.push(req.params()["id"].clone());
        res.push(format!("{}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(res.connect(", ").into_bytes())
        })
    }
}
<commit_msg>Update to master<commit_after>#![feature(macro_rules)]
#![feature(globs)]

extern crate router = "route-recognizer";
extern crate conduit;

use std::collections::HashMap;
use std::any::{Any, AnyRefExt};
use std::fmt::Show;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<Handler + Send + Sync>>>
}

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str)
                         -> Result<Match<&'a Box<Handler + Send + Sync>>, String>
    {
        match self.routers.find(method) {
            None => Err(format!("No router found for {}", method)),
            Some(router) => router.recognize(path)
        }
    }

    pub fn map<'a, H: Handler>(&'a mut self, method: Method, pattern: &str,
                               handler: H) -> &'a mut RouteBuilder {
        {
            let router = self.routers.find_or_insert_with(method, |_| Router::new());
            router.add(pattern, box handler as Box<Handler + Send + Sync>);
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(conduit::Get, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(conduit::Post, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(conduit::Put, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                  -> &'a mut RouteBuilder {
        self.map(conduit::Delete, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(conduit::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(box e as Box<Show>)
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert("router.params", box m.params.clone() as Box<Any>);
        }

        (*m.handler).call(request)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a Request) -> &'a router::Params {
    req.extensions().find(&"router.params")
        .and_then(|a| a.downcast_ref::<router::Params>())
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a Request {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::io::net::ip::IpAddr;
    use std::collections::HashMap;
    use std::io::MemReader;

    use {RouteBuilder, RequestParams};

    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_string().unwrap(), "1, Get".to_string());
    }

    #[test]
    fn basic_post() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_string().unwrap(), "10, Post".to_string());
    }

    #[test]
    fn nonexistent_route() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Post, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut conduit::Request) -> Result<conduit::Response, ()> {
        let mut res = vec!();
        res.push(req.params()["id"].clone());
        res.push(format!("{}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(res.connect(", ").into_bytes())
        })
    }
}
<|endoftext|>