<commit_before>#[derive(Clone, Debug, PartialEq)]
pub enum UnOp {
  Not,
  Neg,
}

#[derive(Clone, Debug, PartialEq)]
pub enum BinOp {
  Plus,
  Minus,
  Times,
  Div,
  Eq,
  Ne,
  Leq,
  Geq,
  Lt,
  Gt,
  And,
  Or,
  Mod,
  Seq,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
  Int(isize),
  Bool(bool),
  Var(String),
  BinOp(BinOp, Box<Expr>, Box<Expr>),
  UnOp(UnOp, Box<Expr>),
  Ternary(Box<Expr>, Box<Expr>, Box<Expr>),
  Let(Box<Expr>, Box<Expr>, Box<Expr>),
}

fn to_int(e: Expr) -> isize {
  match e {
    Expr::Int(n) => n,
    _ => {
      debug!("cant turn into int: {:?}", e);
      panic!()
    }
  }
}

fn to_bool(e: Expr) -> bool {
  match e {
    Expr::Bool(b) => b,
    _ => {
      debug!("cant turn into bool: {:?}", e);
      panic!()
    }
  }
}

fn sub(e: Expr, x: Expr, v: Expr) -> Expr {
  match (e.clone(), x.clone()) {
    (Expr::Var(ref s1), Expr::Var(ref s2)) if s1 == s2 => v,
    (Expr::Var(_), _) => e,
    (Expr::Int(_), _) => e,
    (Expr::Bool(_), _) => e,
    (Expr::BinOp(op, e1, e2), _) => Expr::BinOp(op, Box::new(sub(*e1, x.clone(), v.clone())), Box::new(sub(*e2, x.clone(), v.clone()))),
    (Expr::UnOp(op, e1), _) => Expr::UnOp(op, Box::new(sub(*e1, x.clone(), v.clone()))),
    (Expr::Ternary(e1, e2, e3), _) => Expr::Ternary(Box::new(sub(*e1, x.clone(), v.clone())), Box::new(sub(*e2, x.clone(), v.clone())), Box::new(sub(*e3, x.clone(), v.clone()))),
    (Expr::Let(e1, e2, e3), _) => Expr::Let(Box::new(sub(*e1, x.clone(), v.clone())), Box::new(sub(*e2, x.clone(), v.clone())), Box::new(sub(*e3, x.clone(), v.clone()))),
  }
}

pub fn eval(e: Expr) -> Expr {
  match e {
    Expr::UnOp(UnOp::Not, e1) => {
      Expr::Bool(!to_bool(eval(*e1)))
    },
    Expr::UnOp(UnOp::Neg, e1) => {
      Expr::Int(-1 * to_int(eval(*e1)))
    },
    Expr::BinOp(BinOp::And, e1, e2) => {
      Expr::Bool(to_bool(eval(*e1)) && to_bool(eval(*e2)))
    },
    Expr::BinOp(BinOp::Or, e1, e2) => {
      Expr::Bool(to_bool(eval(*e1)) || to_bool(eval(*e2)))
    },
    Expr::BinOp(BinOp::Eq, e1, e2) => {
      Expr::Bool(eval(*e1) == eval(*e2))
    },
    Expr::BinOp(BinOp::Ne, e1, e2) => {
      Expr::Bool(eval(*e1) != eval(*e2))
    },
    Expr::BinOp(BinOp::Mod, e1, e2) => {
      let n1 = to_int(eval(*e1));
      let n2 = to_int(eval(*e2));

      // rust % gives the remainder, not modulus
      let result = ((n1 % n2) + n2) % n2;

      Expr::Int(result)
    },
    Expr::BinOp(BinOp::Lt, e1, e2) => {
      Expr::Bool(to_int(eval(*e1)) < to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Gt, e1, e2) => {
      Expr::Bool(to_int(eval(*e1)) > to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Leq, e1, e2) => {
      Expr::Bool(to_int(eval(*e1)) <= to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Geq, e1, e2) => {
      Expr::Bool(to_int(eval(*e1)) >= to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Plus, e1, e2) => {
      Expr::Int(to_int(eval(*e1)) + to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Minus, e1, e2) => {
      Expr::Int(to_int(eval(*e1)) - to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Times, e1, e2) => {
      Expr::Int(to_int(eval(*e1)) * to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Div, e1, e2) => {
      Expr::Int(to_int(eval(*e1)) / to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Seq, e1, e2) => {
      eval(*e1);
      eval(*e2)
    },
    Expr::Ternary(e1, e2, e3) => {
      match to_bool(eval(*e1)) {
        true => eval(*e2),
        false => eval(*e3),
      }
    },
    Expr::Let(x, e1, e2) => {
      let v1 = eval(*e1);
      let me2 = sub(*e2, *x, v1);

      eval(me2)
    },
    Expr::Var(_) => e,
    Expr::Int(_) => e,
    Expr::Bool(_) => e,
  }
}
<commit_msg>formatting sub fn<commit_after>#[derive(Clone, Debug, PartialEq)]
pub enum UnOp {
  Not,
  Neg,
}

#[derive(Clone, Debug, PartialEq)]
pub enum BinOp {
  Plus,
  Minus,
  Times,
  Div,
  Eq,
  Ne,
  Leq,
  Geq,
  Lt,
  Gt,
  And,
  Or,
  Mod,
  Seq,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
  Int(isize),
  Bool(bool),
  Var(String),
  BinOp(BinOp, Box<Expr>, Box<Expr>),
  UnOp(UnOp, Box<Expr>),
  Ternary(Box<Expr>, Box<Expr>, Box<Expr>),
  Let(Box<Expr>, Box<Expr>, Box<Expr>),
}

fn to_int(e: Expr) -> isize {
  match e {
    Expr::Int(n) => n,
    _ => {
      debug!("cant turn into int: {:?}", e);
      panic!()
    }
  }
}

fn to_bool(e: Expr) -> bool {
  match e {
    Expr::Bool(b) => b,
    _ => {
      debug!("cant turn into bool: {:?}", e);
      panic!()
    }
  }
}

fn sub(e: Expr, x: Expr, v: Expr) -> Expr {
  match (e.clone(), x.clone()) {
    (Expr::Var(ref s1), Expr::Var(ref s2)) if s1 == s2 => v,
    (Expr::Var(_), _) => e,
    (Expr::Int(_), _) => e,
    (Expr::Bool(_), _) => e,
    (Expr::BinOp(op, e1, e2), _) => {
      Expr::BinOp(
        op,
        Box::new(sub(*e1, x.clone(), v.clone())),
        Box::new(sub(*e2, x.clone(), v.clone()))
      )
    },
    (Expr::UnOp(op, e1), _) => {
      Expr::UnOp(
        op,
        Box::new(sub(*e1, x.clone(), v.clone()))
      )
    },
    (Expr::Ternary(e1, e2, e3), _) => {
      Expr::Ternary(
        Box::new(sub(*e1, x.clone(), v.clone())),
        Box::new(sub(*e2, x.clone(), v.clone())),
        Box::new(sub(*e3, x.clone(), v.clone()))
      )
    },
    (Expr::Let(e1, e2, e3), _) => {
      Expr::Let(
        Box::new(sub(*e1, x.clone(), v.clone())),
        Box::new(sub(*e2, x.clone(), v.clone())),
        Box::new(sub(*e3, x.clone(), v.clone()))
      )
    },
  }
}

pub fn eval(e: Expr) -> Expr {
  match e {
    Expr::UnOp(UnOp::Not, e1) => {
      Expr::Bool(!to_bool(eval(*e1)))
    },
    Expr::UnOp(UnOp::Neg, e1) => {
      Expr::Int(-1 * to_int(eval(*e1)))
    },
    Expr::BinOp(BinOp::And, e1, e2) => {
      Expr::Bool(to_bool(eval(*e1)) && to_bool(eval(*e2)))
    },
    Expr::BinOp(BinOp::Or, e1, e2) => {
      Expr::Bool(to_bool(eval(*e1)) || to_bool(eval(*e2)))
    },
    Expr::BinOp(BinOp::Eq, e1, e2) => {
      Expr::Bool(eval(*e1) == eval(*e2))
    },
    Expr::BinOp(BinOp::Ne, e1, e2) => {
      Expr::Bool(eval(*e1) != eval(*e2))
    },
    Expr::BinOp(BinOp::Mod, e1, e2) => {
      let n1 = to_int(eval(*e1));
      let n2 = to_int(eval(*e2));

      // rust % gives the remainder, not modulus
      let result = ((n1 % n2) + n2) % n2;

      Expr::Int(result)
    },
    Expr::BinOp(BinOp::Lt, e1, e2) => {
      Expr::Bool(to_int(eval(*e1)) < to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Gt, e1, e2) => {
      Expr::Bool(to_int(eval(*e1)) > to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Leq, e1, e2) => {
      Expr::Bool(to_int(eval(*e1)) <= to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Geq, e1, e2) => {
      Expr::Bool(to_int(eval(*e1)) >= to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Plus, e1, e2) => {
      Expr::Int(to_int(eval(*e1)) + to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Minus, e1, e2) => {
      Expr::Int(to_int(eval(*e1)) - to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Times, e1, e2) => {
      Expr::Int(to_int(eval(*e1)) * to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Div, e1, e2) => {
      Expr::Int(to_int(eval(*e1)) / to_int(eval(*e2)))
    },
    Expr::BinOp(BinOp::Seq, e1, e2) => {
      eval(*e1);
      eval(*e2)
    },
    Expr::Ternary(e1, e2, e3) => {
      match to_bool(eval(*e1)) {
        true => eval(*e2),
        false => eval(*e3),
      }
    },
    Expr::Let(x, e1, e2) => {
      let v1 = eval(*e1);
      let me2 = sub(*e2, *x, v1);

      eval(me2)
    },
    Expr::Var(_) => e,
    Expr::Int(_) => e,
    Expr::Bool(_) => e,
  }
}
<|endoftext|>


<commit_before>use parser::{parse};
use expr::Expr::*;
use expr::UnOp::*;
use expr::BinOp::*;

#[derive(Clone, Debug, PartialEq)]
pub enum UnOp {
  Not,
  Neg,
}

#[derive(Clone, Debug, PartialEq)]
pub enum BinOp {
  Plus,
  Minus,
  Times,
  Div,
  Eq,
  Ne,
  Leq,
  Geq,
  Lt,
  Gt,
  And,
  Or,
  Mod,
  Seq,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
  Int(isize),
  Bool(bool),
  Var(String),
  Bop(BinOp, Box<Expr>, Box<Expr>),
  Uop(UnOp, Box<Expr>),
  Ternary(Box<Expr>, Box<Expr>, Box<Expr>),
  Let(Box<Expr>, Box<Expr>, Box<Expr>),
  Func(Option<Box<Expr>>, Box<Expr>, Vec<Expr>),
  FnCall(Box<Expr>, Vec<Expr>),
}

fn is_int(e: &Expr) -> bool {
  match *e {
    Int(_) => true,
    _ => false,
  }
}

fn is_bool(e: &Expr) -> bool {
  match *e {
    Bool(_) => true,
    _ => false,
  }
}

fn is_func(e: &Expr) -> bool {
  match *e {
    Func(_, _, _) => true,
    _ => false,
  }
}

fn is_value(e: &Expr) -> bool {
  match *e {
    Int(_) | Bool(_) | Var(_) | Func(_, _, _) => true,
    _ => false,
  }
}

fn to_int(e: &Expr) -> isize {
  match *e {
    Int(n) => n,
    _ => {
      debug!("cant turn into int: {:?}", e);
      panic!()
    }
  }
}

fn to_bool(e: &Expr) -> bool {
  match *e {
    Bool(b) => b,
    _ => {
      debug!("cant turn into bool: {:?}", e);
      panic!()
    }
  }
}

fn subst(e: Expr, x: Expr, v: Expr) -> Expr {
  let sub = |e1: Expr| subst(e1.clone(), x.clone(), v.clone());

  match (e.clone(), x.clone()) {
    (Var(ref s1), Var(ref s2)) if s1 == s2 => v.clone(),
    (FnCall(v1, xs), _) => {
      let xs2 = xs.iter().map(|xn| sub(xn.clone())).collect();

      if *v1 == x {
        FnCall(Box::new(v.clone()), xs2)
      } else {
        FnCall(v1, xs2)
      }
    },
    (Var(_), _) => e,
    (Int(_), _) => e,
    (Bool(_), _) => e,
    (Bop(op, e1, e2), _) => {
      Bop(
        op,
        Box::new(sub(*e1)),
        Box::new(sub(*e2))
      )
    },
    (Uop(op, e1), _) => Uop(op, Box::new(sub(*e1))),
    (Ternary(e1, e2, e3), _) => {
      Ternary(
        Box::new(sub(*e1)),
        Box::new(sub(*e2)),
        Box::new(sub(*e3))
      )
    },
    (Let(e1, e2, e3), _) => {
      let e3s = if *e1 == x {
        *e3
      } else {
        sub(*e3)
      };

      Let(
        Box::new(*e1),
        Box::new(sub(*e2)),
        Box::new(e3s)
      )
    },
    (Func(name, e1, xs), _) => {
      let xs2 = xs.iter().map(|xn| sub(xn.clone())).collect();
      Func(name, Box::new(sub(*e1)), xs2)
    },
  }
}

pub fn step(e: Expr) -> Expr {
  debug!("step(e) : {:?}", e);
  match e {
    /**
     * Values are ineligible for step
     */
    Int(_) | Bool(_) | Func(_, _, _) | Var(_) => {
      debug!("stepping on a value {:?}", e);
      panic!("stepping on a value");
    }
    /**
     * Base cases
     */
    Uop(Not, ref e1) if is_bool(e1) => {
      Bool(!to_bool(e1))
    },
    Uop(Neg, ref e1) if is_int(e1) => {
      Int(-1 * to_int(e1))
    },
    Bop(And, ref e1, ref e2) if is_bool(e1) && is_bool(e2) => {
      Bool(to_bool(e1) && to_bool(e2))
    },
    Bop(Or, ref e1, ref e2) if is_bool(e1) && is_bool(e2) => {
      Bool(to_bool(e1) || to_bool(e2))
    },
    Bop(Eq, ref e1, ref e2) if is_value(e1) && is_value(e2) => {
      Bool(*e1 == *e2)
    },
    Bop(Ne, ref e1, ref e2) if is_value(e1) && is_value(e2) => {
      Bool(*e1 != *e2)
    },
    Bop(Mod, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      let n1 = to_int(e1);
      let n2 = to_int(e2);

      // rust % gives the remainder, not modulus
      let result = ((n1 % n2) + n2) % n2;

      Int(result)
    },
    Bop(Lt, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) < to_int(e2))
    },
    Bop(Gt, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) > to_int(e2))
    },
    Bop(Leq, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) <= to_int(e2))
    },
    Bop(Geq, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) >= to_int(e2))
    },
    Bop(Plus, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) + to_int(e2))
    },
    Bop(Minus, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) - to_int(e2))
    },
    Bop(Times, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) * to_int(e2))
    },
    Bop(Div, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) / to_int(e2))
    },
    Bop(Seq, ref e1, ref e2) if is_value(e1) => {
      *e2.clone()
    },
    Ternary(ref e1, ref e2, ref e3) if is_value(e1) => {
      match to_bool(e1) {
        true => *e2.clone(),
        false => *e3.clone(),
      }
    },
    Let(ref x, ref e1, ref e2) if is_value(e1) => {
      subst(*e2.clone(), *x.clone(), *e1.clone())
    },
    FnCall(ref v1, ref es) if is_func(v1) => {
      match **v1 {
        Func(ref name, ref e1, ref xs) => {
          // sub the params
          let exp = xs.iter().zip(es.iter())
            .fold(*e1.clone(), |exp, (xn, en)| subst(exp, xn.clone(), en.clone()));

          // sub the fn body for named functions
          match *name {
            None => exp,
            Some(ref s) => subst(exp, *s.clone(), *v1.clone())
          }
        },
        _ => {
          debug!("expected a Func, got {:?}", v1);
          panic!()
        },
      }
    },
    /**
     * Search Cases
     */
    Bop(ref op, ref v1, ref e2) if is_value(v1) => {
      Bop(op.clone(), Box::new(*v1.clone()), Box::new(step(*e2.clone())))
    },
    Bop(op, e1, e2) => {
      Bop(op, Box::new(step(*e1)), e2)
    },
    Uop(op, e1) => {
      Uop(op, Box::new(step(*e1)))
    },
    Ternary(e1, e2, e3) => {
      Ternary(Box::new(step(*e1)), e2, e3)
    },
    Let(ref e1, ref e2, ref e3) if is_value(e1) => {
      Let(Box::new(*e1.clone()), Box::new(step(*e2.clone())), Box::new(*e3.clone()))
    },
    Let(e1, e2, e3) => {
      Let(Box::new(step(*e1)), e2, e3)
    },
    FnCall(e1, mut xs) => {
      let mut found_first = true;

      for x in xs.iter_mut() {
        if is_value(x) && found_first == true {
          found_first = false;
          *x = step(x.clone());
        }
      }

      FnCall(e1, xs)
    }
  }
}

pub fn boxx(input: &str) -> Expr {
  let mut exp = parse(input);

  loop {
    if is_value(&exp) {
      return exp
    } else {
      exp = step(exp);
    }
  }
}
<commit_msg>starting mutable state<commit_after>use parser::{parse};
use expr::Expr::*;
use expr::UnOp::*;
use expr::BinOp::*;

#[derive(Clone, Debug, PartialEq)]
pub enum UnOp {
  Not,
  Neg,
}

#[derive(Clone, Debug, PartialEq)]
pub enum BinOp {
  Plus,
  Minus,
  Times,
  Div,
  Eq,
  Ne,
  Leq,
  Geq,
  Lt,
  Gt,
  And,
  Or,
  Mod,
  Seq,
}

pub struct State {
  expr: Expr
}

impl State {
  fn wrap(e: Expr) -> State {
    return State {
      expr: e
    }
  }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
  Int(isize),
  Bool(bool),
  Var(String),
  Bop(BinOp, Box<Expr>, Box<Expr>),
  Uop(UnOp, Box<Expr>),
  Ternary(Box<Expr>, Box<Expr>, Box<Expr>),
  Let(Box<Expr>, Box<Expr>, Box<Expr>),
  Func(Option<Box<Expr>>, Box<Expr>, Vec<Expr>),
  FnCall(Box<Expr>, Vec<Expr>),
}

fn is_int(e: &Expr) -> bool {
  match *e {
    Int(_) => true,
    _ => false,
  }
}

fn is_bool(e: &Expr) -> bool {
  match *e {
    Bool(_) => true,
    _ => false,
  }
}

fn is_func(e: &Expr) -> bool {
  match *e {
    Func(_, _, _) => true,
    _ => false,
  }
}

fn is_value(e: &Expr) -> bool {
  match *e {
    Int(_) | Bool(_) | Var(_) | Func(_, _, _) => true,
    _ => false,
  }
}

fn to_int(e: &Expr) -> isize {
  match *e {
    Int(n) => n,
    _ => {
      debug!("cant turn into int: {:?}", e);
      panic!()
    }
  }
}

fn to_bool(e: &Expr) -> bool {
  match *e {
    Bool(b) => b,
    _ => {
      debug!("cant turn into bool: {:?}", e);
      panic!()
    }
  }
}

fn subst(e: Expr, x: Expr, v: Expr) -> Expr {
  let sub = |e1: Expr| subst(e1.clone(), x.clone(), v.clone());

  match (e.clone(), x.clone()) {
    (Var(ref s1), Var(ref s2)) if s1 == s2 => v.clone(),
    (FnCall(v1, xs), _) => {
      let xs2 = xs.iter().map(|xn| sub(xn.clone())).collect();

      if *v1 == x {
        FnCall(Box::new(v.clone()), xs2)
      } else {
        FnCall(v1, xs2)
      }
    },
    (Var(_), _) => e,
    (Int(_), _) => e,
    (Bool(_), _) => e,
    (Bop(op, e1, e2), _) => {
      Bop(
        op,
        Box::new(sub(*e1)),
        Box::new(sub(*e2))
      )
    },
    (Uop(op, e1), _) => Uop(op, Box::new(sub(*e1))),
    (Ternary(e1, e2, e3), _) => {
      Ternary(
        Box::new(sub(*e1)),
        Box::new(sub(*e2)),
        Box::new(sub(*e3))
      )
    },
    (Let(e1, e2, e3), _) => {
      let e3s = if *e1 == x {
        *e3
      } else {
        sub(*e3)
      };

      Let(
        Box::new(*e1),
        Box::new(sub(*e2)),
        Box::new(e3s)
      )
    },
    (Func(name, e1, xs), _) => {
      let xs2 = xs.iter().map(|xn| sub(xn.clone())).collect();
      Func(name, Box::new(sub(*e1)), xs2)
    },
  }
}

pub fn step1(state: State) -> State {
  let step = |e1: Expr| step1(State::wrap(e1)).expr;

  //debug!("step(e) : {:?}", e);
  let e1 = match state.expr {
    /**
     * Values are ineligible for step
     */
    Int(_) | Bool(_) | Func(_, _, _) | Var(_) => {
      debug!("stepping on a value {:?}", state.expr);
      panic!("stepping on a value");
    }
    /**
     * Base cases
     */
    Uop(Not, ref e1) if is_bool(e1) => {
      Bool(!to_bool(e1))
    },
    Uop(Neg, ref e1) if is_int(e1) => {
      Int(-1 * to_int(e1))
    },
    Bop(And, ref e1, ref e2) if is_bool(e1) && is_bool(e2) => {
      Bool(to_bool(e1) && to_bool(e2))
    },
    Bop(Or, ref e1, ref e2) if is_bool(e1) && is_bool(e2) => {
      Bool(to_bool(e1) || to_bool(e2))
    },
    Bop(Eq, ref e1, ref e2) if is_value(e1) && is_value(e2) => {
      Bool(*e1 == *e2)
    },
    Bop(Ne, ref e1, ref e2) if is_value(e1) && is_value(e2) => {
      Bool(*e1 != *e2)
    },
    Bop(Mod, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      let n1 = to_int(e1);
      let n2 = to_int(e2);

      // rust % gives the remainder, not modulus
      let result = ((n1 % n2) + n2) % n2;

      Int(result)
    },
    Bop(Lt, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) < to_int(e2))
    },
    Bop(Gt, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) > to_int(e2))
    },
    Bop(Leq, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) <= to_int(e2))
    },
    Bop(Geq, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) >= to_int(e2))
    },
    Bop(Plus, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) + to_int(e2))
    },
    Bop(Minus, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) - to_int(e2))
    },
    Bop(Times, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) * to_int(e2))
    },
    Bop(Div, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) / to_int(e2))
    },
    Bop(Seq, ref e1, ref e2) if is_value(e1) => {
      *e2.clone()
    },
    Ternary(ref e1, ref e2, ref e3) if is_value(e1) => {
      match to_bool(e1) {
        true => *e2.clone(),
        false => *e3.clone(),
      }
    },
    Let(ref x, ref e1, ref e2) if is_value(e1) => {
      subst(*e2.clone(), *x.clone(), *e1.clone())
    },
    FnCall(ref v1, ref es) if is_func(v1) => {
      match **v1 {
        Func(ref name, ref e1, ref xs) => {
          // sub the params
          let exp = xs.iter().zip(es.iter())
            .fold(*e1.clone(), |exp, (xn, en)| subst(exp, xn.clone(), en.clone()));

          // sub the fn body for named functions
          match *name {
            None => exp,
            Some(ref s) => subst(exp, *s.clone(), *v1.clone())
          }
        },
        _ => {
          debug!("expected a Func, got {:?}", v1);
          panic!()
        },
      }
    },
    /**
     * Search Cases
     */
    Bop(ref op, ref v1, ref e2) if is_value(v1) => {
      Bop(op.clone(), Box::new(*v1.clone()), Box::new(step(*e2.clone())))
    },
    Bop(op, e1, e2) => {
      Bop(op, Box::new(step(*e1)), e2)
    },
    Uop(op, e1) => {
      Uop(op, Box::new(step(*e1)))
    },
    Ternary(e1, e2, e3) => {
      Ternary(Box::new(step(*e1)), e2, e3)
    },
    Let(ref e1, ref e2, ref e3) if is_value(e1) => {
      Let(Box::new(*e1.clone()), Box::new(step(*e2.clone())), Box::new(*e3.clone()))
    },
    Let(e1, e2, e3) => {
      Let(Box::new(step(*e1)), e2, e3)
    },
    FnCall(e1, mut xs) => {
      let mut found_first = true;

      for x in xs.iter_mut() {
        if is_value(x) && found_first == true {
          found_first = false;
          *x = step(x.clone());
        }
      }

      FnCall(e1, xs)
    }
  };

  State::wrap(e1)
}

pub fn boxx(input: &str) -> Expr {
  let mut state = State {
    expr: parse(input)
  };

  let mut num_iterations = 0;

  loop {
    num_iterations += 1;
    if is_value(&state.expr) {
      debug!("--- iterations: {}", num_iterations);
      return state.expr
    } else {
      state = step1(state);
    }
  }
}
<|endoftext|>


<commit_before>use std;
use hb;
use std::marker::PhantomData;

use blob::Blob;
use font::Font;
use common::{Tag, HarfbuzzObject};

/// A wrapper around the harfbuzz `hb_face_t`.
pub struct Face<'a> {
    hb_face: *mut hb::hb_face_t,
    _marker: PhantomData<&'a [u8]>,
}

use std::path::Path;

impl<'a> Face<'a> {
    /// Create a new `Face` from the data in `bytes`.
    pub fn new<'b, T: Into<Blob<'b>>>(bytes: T, index: u32) -> Face<'b> {
        let blob = bytes.into();
        let hb_face = unsafe { hb::hb_face_create(blob.into_raw(), index) };
        Face {
            hb_face: hb_face,
            _marker: PhantomData,
        }
    }

    /// Create a new face from the contents of the file at `path`.
    pub fn from_file<P: AsRef<Path>>(path: P, index: u32) -> std::io::Result<Face<'static>> {
        let blob = Blob::from_file(path)?;
        Ok(Face::new(blob, index))
    }

    pub fn from_table_func<'b, F>(func: F) -> Face<'b>
        where F: FnMut(Tag) -> Option<Blob<'b>>
    {
        extern "C" fn destroy_box<U>(ptr: *mut std::os::raw::c_void) {
            unsafe { Box::from_raw(ptr as *mut U) };
        }
        extern "C" fn table_func<'b, F>(_: *mut hb::hb_face_t,
                                        tag: hb::hb_tag_t,
                                        user_data: *mut std::os::raw::c_void)
                                        -> *mut hb::hb_blob_t
            where F: FnMut(Tag) -> Option<Blob<'b>>
        {
            let tag = Tag(tag);
            let closure = unsafe { &mut *(user_data as *mut F) };
            let blob = closure(tag);
            match blob {
                Some(blob) => blob.as_raw(),
                None => std::ptr::null_mut(),
            }
        }
        let boxed_closure = Box::new(func);
        unsafe {
            let face = hb::hb_face_create_for_tables(Some(table_func::<'b, F>),
                                                     Box::into_raw(boxed_closure) as *mut _,
                                                     Some(destroy_box::<F>));
            Face::from_raw(face)
        }
    }

    /// Create a `Font` of this face. By default this will use harfbuzz' included opentype font
    /// funcs for shaping and have no scale value set so that the returned values will be in font
    /// space.
    pub fn create_font(&self) -> Font<'a> {
        unsafe {
            let raw_font = hb::hb_font_create(self.hb_face);
            hb::hb_ot_font_set_funcs(raw_font);
            Font::from_raw(raw_font)
        }
    }

    pub fn face_data(&self) -> &'a [u8] {
        unsafe {
            let raw_blob = hb::hb_face_reference_blob(self.hb_face);
            Blob::from_raw(raw_blob).get_data()
        }
    }

    pub fn table_with_tag(&self, tag: Tag) -> Option<&[u8]> {
        unsafe {
            let raw_blob = hb::hb_face_reference_table(self.hb_face, tag.0);
            if raw_blob.is_null() {
                None
            } else {
                let blob = Blob::from_raw(raw_blob);
                if blob.is_empty() { None } else { Some(blob.get_data()) }
            }
        }
    }

    pub fn index(&self) -> u32 {
        unsafe { hb::hb_face_get_index(self.hb_face) }
    }

    pub fn set_upem(&mut self, upem: u32) {
        unsafe { hb::hb_face_set_upem(self.hb_face, upem) };
    }

    pub fn upem(&self) -> u32 {
        unsafe { hb::hb_face_get_upem(self.hb_face) }
    }

    pub fn set_glyph_count(&mut self, count: u32) {
        unsafe { hb::hb_face_set_glyph_count(self.hb_face, count) };
    }

    pub fn glyph_count(&self) -> u32 {
        unsafe { hb::hb_face_get_glyph_count(self.hb_face) }
    }
}

impl<'a> HarfbuzzObject for Face<'a> {
    type Raw = *mut hb::hb_face_t;

    unsafe fn from_raw(raw: *mut hb::hb_face_t) -> Self {
        Face {
            hb_face: raw,
            _marker: PhantomData,
        }
    }

    fn as_raw(&self) -> *mut hb::hb_face_t {
        self.hb_face
    }
}

impl<'a> Clone for Face<'a> {
    fn clone(&self) -> Self {
        let hb_face = unsafe { hb::hb_face_reference(self.hb_face) };
        Face {
            hb_face: hb_face,
            _marker: PhantomData,
        }
    }
}

impl<'a> Drop for Face<'a> {
    fn drop(&mut self) {
        unsafe { hb::hb_face_destroy(self.hb_face) }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::FromStr;
    use common::Tag;

    #[test]
    fn test_face_wrapper() {
        let font_bytes = include_bytes!("../testfiles/MinionPro-Regular.otf");
        let face = Face::new(&font_bytes[..], 0);
        let blob = face.face_data();
        let maxp_table = face.table_with_tag(Tag::from_str("maxp").unwrap()).unwrap();

        assert_eq!(maxp_table, [0x00, 0x00, 0x50, 0x00, 0x06, 0x96]);
        assert_eq!(blob, &font_bytes[..]);
        assert_eq!(face.upem(), 1000);
        assert_eq!(face.glyph_count(), 1686);
    }
}
<commit_msg>Fix Use-after-free bug during Face creation from closure<commit_after>use std;
use hb;
use std::marker::PhantomData;

use blob::Blob;
use font::Font;
use common::{Tag, HarfbuzzObject};

/// A wrapper around the harfbuzz `hb_face_t`.
pub struct Face<'a> {
    hb_face: *mut hb::hb_face_t,
    _marker: PhantomData<&'a [u8]>,
}

use std::path::Path;

impl<'a> Face<'a> {
    /// Create a new `Face` from the data in `bytes`.
    pub fn new<'b, T: Into<Blob<'b>>>(bytes: T, index: u32) -> Face<'b> {
        let blob = bytes.into();
        let hb_face = unsafe { hb::hb_face_create(blob.into_raw(), index) };
        Face {
            hb_face: hb_face,
            _marker: PhantomData,
        }
    }

    /// Create a new face from the contents of the file at `path`.
    pub fn from_file<P: AsRef<Path>>(path: P, index: u32) -> std::io::Result<Face<'static>> {
        let blob = Blob::from_file(path)?;
        Ok(Face::new(blob, index))
    }

    pub fn from_table_func<'b, F>(func: F) -> Face<'b>
        where F: FnMut(Tag) -> Option<Blob<'b>>
    {
        extern "C" fn destroy_box<U>(ptr: *mut std::os::raw::c_void) {
            unsafe { Box::from_raw(ptr as *mut U) };
        }
        extern "C" fn table_func<'b, F>(_: *mut hb::hb_face_t,
                                        tag: hb::hb_tag_t,
                                        user_data: *mut std::os::raw::c_void)
                                        -> *mut hb::hb_blob_t
            where F: FnMut(Tag) -> Option<Blob<'b>>
        {
            let tag = Tag(tag);
            let closure = unsafe { &mut *(user_data as *mut F) };
            let blob = closure(tag);
            match blob {
                Some(blob) => blob.into_raw(),
                None => std::ptr::null_mut(),
            }
        }
        let boxed_closure = Box::new(func);
        unsafe {
            let face = hb::hb_face_create_for_tables(Some(table_func::<'b, F>),
                                                     Box::into_raw(boxed_closure) as *mut _,
                                                     Some(destroy_box::<F>));
            Face::from_raw(face)
        }
    }

    /// Create a `Font` of this face. By default this will use harfbuzz' included opentype font
    /// funcs for shaping and have no scale value set so that the returned values will be in font
    /// space.
    pub fn create_font(&self) -> Font<'a> {
        unsafe {
            let raw_font = hb::hb_font_create(self.hb_face);
            hb::hb_ot_font_set_funcs(raw_font);
            Font::from_raw(raw_font)
        }
    }

    pub fn face_data(&self) -> &'a [u8] {
        unsafe {
            let raw_blob = hb::hb_face_reference_blob(self.hb_face);
            Blob::from_raw(raw_blob).get_data()
        }
    }

    pub fn table_with_tag(&self, tag: Tag) -> Option<&[u8]> {
        unsafe {
            let raw_blob = hb::hb_face_reference_table(self.hb_face, tag.0);
            if raw_blob.is_null() {
                None
            } else {
                let blob = Blob::from_raw(raw_blob);
                if blob.is_empty() { None } else { Some(blob.get_data()) }
            }
        }
    }

    pub fn index(&self) -> u32 {
        unsafe { hb::hb_face_get_index(self.hb_face) }
    }

    pub fn set_upem(&mut self, upem: u32) {
        unsafe { hb::hb_face_set_upem(self.hb_face, upem) };
    }

    pub fn upem(&self) -> u32 {
        unsafe { hb::hb_face_get_upem(self.hb_face) }
    }

    pub fn set_glyph_count(&mut self, count: u32) {
        unsafe { hb::hb_face_set_glyph_count(self.hb_face, count) };
    }

    pub fn glyph_count(&self) -> u32 {
        unsafe { hb::hb_face_get_glyph_count(self.hb_face) }
    }
}

impl<'a> HarfbuzzObject for Face<'a> {
    type Raw = *mut hb::hb_face_t;

    unsafe fn from_raw(raw: *mut hb::hb_face_t) -> Self {
        Face {
            hb_face: raw,
            _marker: PhantomData,
        }
    }

    fn as_raw(&self) -> *mut hb::hb_face_t {
        self.hb_face
    }
}

impl<'a> Clone for Face<'a> {
    fn clone(&self) -> Self {
        let hb_face = unsafe { hb::hb_face_reference(self.hb_face) };
        Face {
            hb_face: hb_face,
            _marker: PhantomData,
        }
    }
}

impl<'a> Drop for Face<'a> {
    fn drop(&mut self) {
        unsafe { hb::hb_face_destroy(self.hb_face) }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::FromStr;
    use common::Tag;

    #[test]
    fn test_face_wrapper() {
        let font_bytes = include_bytes!("../testfiles/MinionPro-Regular.otf");
        let face = Face::new(&font_bytes[..], 0);
        let blob = face.face_data();
        let maxp_table = face.table_with_tag(Tag::from_str("maxp").unwrap()).unwrap();

        assert_eq!(maxp_table, [0x00, 0x00, 0x50, 0x00, 0x06, 0x96]);
        assert_eq!(blob, &font_bytes[..]);
        assert_eq!(face.upem(), 1000);
        assert_eq!(face.glyph_count(), 1686);
    }

    #[test]
    fn test_face_from_table_func() {
        let face = Face::from_table_func(|table_tag| {
            let content = format!("{}-table", table_tag);
            Some(content.into_bytes().into())
        });

        let maxp_table = face.table_with_tag(Tag::new('m', 'a', 'x', 'p')).unwrap();
        assert_eq!(maxp_table, b"maxp-table");

        let maxp_table = face.table_with_tag(Tag::new('h', 'h', 'e', 'a')).unwrap();
        assert_eq!(maxp_table, b"hhea-table");
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::result::Result as StdResult;
use std::time::Instant;
use uuid::Uuid;
use futures::{Future, Stream, future, stream};
use futures::sync::oneshot;

#[derive(Debug, PartialEq)]
pub enum Error {
    Invalid,
    NotFound,
    Dropped,
    NotReady,
    Other,
}

pub type Result<T> = StdResult<T, Error>;

pub const MAX_SIZE: usize = 65536;

#[derive(Clone, Debug)]
struct Chunk {
    data: Vec<u8>,
}

pub struct Flow {
    pub id: String,
    pub size: Option<u64>,
    active_stamp: Instant,
    next_index: u64,
    tail_index: u64,
    chunk_bucket: HashMap<u64, Chunk>,
    wait_list: HashMap<u64, Vec<oneshot::Sender<Chunk>>>,
    stat_size: u64,
}

type FlowFuture<T> = future::BoxFuture<T, Error>;

impl Flow {
    pub fn new(size: Option<u64>) -> Self {
        Flow {
            id: Uuid::new_v4().simple().to_string(),
            size: size,
            active_stamp: Instant::now(),
            next_index: 0,
            tail_index: 0,
            chunk_bucket: HashMap::new(),
            wait_list: HashMap::new(),
            stat_size: 0,
        }
    }

    pub fn push(&mut self, data: &[u8]) -> FlowFuture<u64> {
        if data.len() > MAX_SIZE {
            return future::err(Error::Invalid).boxed();
        }
        if let Some(size) = self.size {
            if (data.len() as u64) + self.stat_size > size {
                return future::err(Error::Invalid).boxed();
            }
        }

        let chunk_index = self.next_index;
        self.next_index += 1;
        let chunk = Chunk { data: data.to_vec() };
        // Wake up the waiting fetch.
        if let Some(waits) = self.wait_list.remove(&chunk_index) {
            for wait in waits {
                wait.send(chunk.clone()).unwrap();
            }
        }
        // Insert the chunk.
        self.chunk_bucket.insert(chunk_index, chunk);

        self.stat_size += data.len() as u64;
        future::ok(chunk_index).boxed()
    }

    pub fn fetch(&self, chunk_index: u64) -> Result<&[u8]> {
        if let Some(chunk) = self.chunk_bucket.get(&chunk_index) {
            Ok(&chunk.data)
        } else {
            Err(Error::NotFound)
        }
    }

    pub fn pull(&mut self, chunk_index: u64, timeout: Option<u64>) -> FlowFuture<Vec<u8>> {
        if let Some(chunk) = self.chunk_bucket.get(&chunk_index) {
            return future::ok(chunk.data.clone()).boxed();
        } else if chunk_index < self.next_index {
            return future::err(Error::Dropped).boxed();
        } else if let Some(0) = timeout {
            return future::err(Error::NotReady).boxed();
        }
        let (tx, rx) = oneshot::channel();
        let waits = self.wait_list.entry(chunk_index).or_insert(Vec::new());
        waits.push(tx);
        rx.and_then(|chunk| {
            future::ok(chunk.data)
        }).or_else(|_| {
            future::err(Error::Other)
        }).boxed()
    }
}

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

    #[test]
    fn basic_flow_operations() {
        let mut flow = Flow::new(None);

        assert_eq!(flow.push(&[1u8; 1234]).wait(), Ok(0));
        assert_eq!(flow.push(&[2u8; MAX_SIZE]).wait(), Ok(1));
        assert_eq!(flow.push(b"hello").wait(), Ok(2));
        assert_eq!(flow.push(&[2u8; MAX_SIZE + 1]).wait(), Err(Error::Invalid));

        assert_eq!(flow.pull(2, Some(0)).wait(), Ok(Vec::from(b"hello" as &[u8])));
        assert_eq!(flow.pull(100, Some(0)).wait(), Err(Error::NotReady));
    }

    #[test]
    fn fixed_size_flow() {
        let mut flow = Flow::new(Some(10));

        assert_eq!(flow.push(b"hello").wait(), Ok(0));
        assert_eq!(flow.push(b"world").wait(), Ok(1));
        assert_eq!(flow.push(b"!").wait(), Err(Error::Invalid));
    }

    #[test]
    fn pull_chunk() {
        let mut flow = Flow::new(None);

        assert_eq!(flow.pull(0, Some(0)).wait(), Err(Error::NotReady));
    }
}
<commit_msg>Add flow pull<commit_after>use futures::{Future, Stream, future, stream};
use futures::sync::oneshot;
use std::collections::HashMap;
use std::result::Result as StdResult;
use std::time::Instant;
use uuid::Uuid;

#[derive(Debug, PartialEq)]
pub enum Error {
    Invalid,
    NotFound,
    Dropped,
    NotReady,
    Other,
}

pub type Result<T> = StdResult<T, Error>;

pub const MAX_SIZE: usize = 65536;

#[derive(Clone, Debug)]
struct Chunk {
    data: Vec<u8>,
}

pub struct Flow {
    pub id: String,
    pub size: Option<u64>,
    active_stamp: Instant,
    next_index: u64,
    tail_index: u64,
    chunk_bucket: HashMap<u64, Chunk>,
    wait_list: HashMap<u64, Vec<oneshot::Sender<Chunk>>>,
    stat_size: u64,
}

type FlowFuture<T> = future::BoxFuture<T, Error>;

impl Flow {
    pub fn new(size: Option<u64>) -> Self {
        Flow {
            id: Uuid::new_v4().simple().to_string(),
            size: size,
            active_stamp: Instant::now(),
            next_index: 0,
            tail_index: 0,
            chunk_bucket: HashMap::new(),
            wait_list: HashMap::new(),
            stat_size: 0,
        }
    }

    pub fn push(&mut self, data: &[u8]) -> FlowFuture<u64> {
        if data.len() > MAX_SIZE {
            return future::err(Error::Invalid).boxed();
        }
        if let Some(size) = self.size {
            if (data.len() as u64) + self.stat_size > size {
                return future::err(Error::Invalid).boxed();
            }
        }

        let chunk_index = self.next_index;
        self.next_index += 1;
        let chunk = Chunk { data: data.to_vec() };
        // Wake up the waiting fetch.
        if let Some(waits) = self.wait_list.remove(&chunk_index) {
            for wait in waits {
                wait.send(chunk.clone()).unwrap();
            }
        }
        // Insert the chunk.
        self.chunk_bucket.insert(chunk_index, chunk);

        self.stat_size += data.len() as u64;
        future::ok(chunk_index).boxed()
    }

    pub fn fetch(&self, chunk_index: u64) -> Result<&[u8]> {
        if let Some(chunk) = self.chunk_bucket.get(&chunk_index) {
            Ok(&chunk.data)
        } else {
            Err(Error::NotFound)
        }
    }

    pub fn pull(&mut self, chunk_index: u64, timeout: Option<u64>) -> FlowFuture<Vec<u8>> {
        if let Some(chunk) = self.chunk_bucket.get(&chunk_index) {
            return future::ok(chunk.data.clone()).boxed();
        } else if chunk_index < self.next_index {
            return future::err(Error::Dropped).boxed();
        } else if let Some(0) = timeout {
            return future::err(Error::NotReady).boxed();
        }
        let (tx, rx) = oneshot::channel();
        let waits = self.wait_list.entry(chunk_index).or_insert(Vec::new());
        waits.push(tx);
        rx.and_then(|chunk| future::ok(chunk.data)).or_else(|_| future::err(Error::Other)).boxed()
    }
}

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

    #[test]
    fn basic_flow_operations() {
        let mut flow = Flow::new(None);

        assert_eq!(flow.push(&[1u8; 1234]).wait(), Ok(0));
        assert_eq!(flow.push(&[2u8; MAX_SIZE]).wait(), Ok(1));
        assert_eq!(flow.push(b"hello").wait(), Ok(2));
        assert_eq!(flow.push(&[2u8; MAX_SIZE + 1]).wait(), Err(Error::Invalid));

        assert_eq!(flow.pull(2, Some(0)).wait(), Ok(Vec::from(b"hello" as &[u8])));
        assert_eq!(flow.pull(100, Some(0)).wait(), Err(Error::NotReady));
    }

    #[test]
    fn fixed_size_flow() {
        let mut flow = Flow::new(Some(10));

        assert_eq!(flow.push(b"hello").wait(), Ok(0));
        assert_eq!(flow.push(b"world").wait(), Ok(1));
        assert_eq!(flow.push(b"!").wait(), Err(Error::Invalid));
    }

    #[test]
    fn pull_chunk() {
        let mut flow = Flow::new(None);

        assert_eq!(flow.pull(0, Some(0)).wait(), Err(Error::NotReady));
        assert_eq!(flow.pull(1, None).join3(flow.push(b"ello"), flow.push(b"hello")).wait(),
                   Ok((Vec::from(b"hello" as &[u8]), 0, 1)));
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::fs;
use std::path::Path;
use std::process::Command;

use core::PackageIdSpec;
use core::source::Source;
use ops;
use sources::PathSource;
use util::{CargoResult, human};

pub struct DocOptions<'a, 'b: 'a> {
    pub open_result: bool,
    pub compile_opts: ops::CompileOptions<'a, 'b>,
}

pub fn doc(manifest_path: &Path,
           options: &DocOptions) -> CargoResult<()> {
    let mut source = try!(PathSource::for_path(manifest_path.parent().unwrap(),
                                               options.compile_opts.config));
    try!(source.update());
    let package = try!(source.root_package());

    let mut lib_names = HashSet::new();
    let mut bin_names = HashSet::new();
    if options.compile_opts.spec.is_none() {
        for target in package.targets().iter().filter(|t| t.documented()) {
            if target.is_lib() {
                assert!(lib_names.insert(target.name()));
            } else {
                assert!(bin_names.insert(target.name()));
            }
        }
        for bin in bin_names.iter() {
            if lib_names.contains(bin) {
                return Err(human("Cannot document a package where a library \
                                  and a binary have the same name. Consider \
                                  renaming one or marking the target as \
                                  `doc = false`"))
            }
        }
    }

    try!(ops::compile(manifest_path, &options.compile_opts));

    if options.open_result {
        let name = match options.compile_opts.spec {
            Some(spec) => try!(PackageIdSpec::parse(spec)).name().to_string(),
            None => {
                match lib_names.iter().chain(bin_names.iter()).nth(0) {
                    Some(s) => s.to_string(),
                    None => return Ok(())
                }
            }
        };

        let path = package.absolute_target_dir().join("doc").join(&name)
                                                    .join("index.html");
        if fs::metadata(&path).is_ok() {
            open_docs(&path);
        }
    }

    Ok(())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) {
    // trying xdg-open
    match Command::new("xdg-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };

    // trying gnome-open
    match Command::new("gnome-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };

    // trying kde-open
    match Command::new("kde-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}

#[cfg(target_os = "windows")]
fn open_docs(path: &Path) {
    match Command::new("cmd").arg("/C").arg("start").arg("").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}

#[cfg(target_os = "macos")]
fn open_docs(path: &Path) {
    match Command::new("open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}
<commit_msg>Fix `doc --open` crate name.<commit_after>use std::collections::HashSet;
use std::fs;
use std::path::Path;
use std::process::Command;

use core::PackageIdSpec;
use core::source::Source;
use ops;
use sources::PathSource;
use util::{CargoResult, human};

pub struct DocOptions<'a, 'b: 'a> {
    pub open_result: bool,
    pub compile_opts: ops::CompileOptions<'a, 'b>,
}

pub fn doc(manifest_path: &Path,
           options: &DocOptions) -> CargoResult<()> {
    let mut source = try!(PathSource::for_path(manifest_path.parent().unwrap(),
                                               options.compile_opts.config));
    try!(source.update());
    let package = try!(source.root_package());

    let mut lib_names = HashSet::new();
    let mut bin_names = HashSet::new();
    if options.compile_opts.spec.is_none() {
        for target in package.targets().iter().filter(|t| t.documented()) {
            if target.is_lib() {
                assert!(lib_names.insert(target.name()));
            } else {
                assert!(bin_names.insert(target.name()));
            }
        }
        for bin in bin_names.iter() {
            if lib_names.contains(bin) {
                return Err(human("Cannot document a package where a library \
                                  and a binary have the same name. Consider \
                                  renaming one or marking the target as \
                                  `doc = false`"))
            }
        }
    }

    try!(ops::compile(manifest_path, &options.compile_opts));

    if options.open_result {
        let name = match options.compile_opts.spec {
            Some(spec) => try!(PackageIdSpec::parse(spec)).name().to_string(),
            None => {
                match lib_names.iter().chain(bin_names.iter()).nth(0) {
                    Some(s) => s.to_string(),
                    None => return Ok(())
                }
            }
        };
        let name = name.replace("-", "_");

        let path = package.absolute_target_dir().join("doc").join(&name)
                                                    .join("index.html");
        if fs::metadata(&path).is_ok() {
            open_docs(&path);
        }
    }

    Ok(())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) {
    // trying xdg-open
    match Command::new("xdg-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };

    // trying gnome-open
    match Command::new("gnome-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };

    // trying kde-open
    match Command::new("kde-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}

#[cfg(target_os = "windows")]
fn open_docs(path: &Path) {
    match Command::new("cmd").arg("/C").arg("start").arg("").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}

#[cfg(target_os = "macos")]
fn open_docs(path: &Path) {
    match Command::new("open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}
<|endoftext|>


<commit_before>//! Implementation of a complete Reversi match.

use std::marker::{PhantomData, Sized};
use board::*;
use turn::*;
use ::Result;

pub enum PlayerAction {
    Move(Coord),
    Undo,
    Other(A),
}

/// Being able to make moves is the trait characterizing players.
pub trait IsPlayer {
    fn make_move(&self, turn: &Turn) -> Result<PlayerAction>;
}

/// A game is given by a list of past turns (with the successive move), a current turn, and the two players.
pub struct Game<'a, A, D: 'a + ?Sized + IsPlayer, L: 'a + ?Sized + IsPlayer> {
    current_turn: Turn,
    turns_history: Vec<(Turn, Coord)>,
    dark:  &'a D,
    light: &'a L,
    phantom: PhantomData
}

impl<'a, A, D: 'a + ?Sized + IsPlayer, L: 'a + ?Sized + IsPlayer> Game<'a, A, D, L> {

    /// Creates a new game, with first turn already set and empty turns' history.
    /// It requires the two players as input.
    pub fn new(dark: &'a D, light: &'a L) -> Game<'a, A, D, L> where D: IsPlayer, L: IsPlayer {
        Game {
            current_turn: Turn::first_turn(),
            turns_history: vec![],
            dark: dark,
            light: light,
            phantom: PhantomData,
        }
    }

    /// Gets the board of the current turn.
    pub fn get_current_board(&self) -> &Board {
        self.current_turn.get_board()
    }

    /// Gets the board of the current turn.
    pub fn get_current_turn(&self) -> &Turn {
        &self.current_turn
    }

    /// Gets the state of the current turn.
    pub fn get_current_state(&self) -> State {
        self.current_turn.get_state()
    }

    /// Returns true if the game is ended.
    pub fn is_ended(&self) -> bool {
        self.get_current_state().is_none()
    }

    /// It has the correct player return an action and applies its effects.
    pub fn play_turn(&mut self) -> Result<PlayerAction> {
        let action = match self.current_turn.get_state() {
            None => return Err(::ReversiError::EndedGame),
            Some(::Side::Dark)  => try!(self.dark.make_move(&self.current_turn)),
            Some(::Side::Light) => try!(self.light.make_move(&self.current_turn)),
        };

        match action {
            // If that move is legal, it is applied and the turns' history is updated.
            PlayerAction::Move(coord) => try!(self.make_move(coord)),
            PlayerAction::Undo => try!(self.undo()),
            _ => {}
        }

        Ok(action)
    }

    /// A move (given by `coord`) is applied. If that move is legal, game's history is updated.
    fn make_move(&mut self, coord: Coord) -> Result<()> {
        let new_turn = try!(self.current_turn.make_move(coord));
        self.turns_history.push((self.current_turn.clone(), coord));
        self.current_turn = new_turn;
        Ok(())
    }

    /// Undo last move(s) till the player asking for undoing can play again.
    fn undo(&mut self) -> Result<()> {
        let backup = self.turns_history.clone();
        match self.get_current_state() {
            None => {
                self.current_turn = try!(self.turns_history.pop().ok_or(::ReversiError::NoUndo)).0;
                let last_side = self.get_current_state().unwrap();
                while let Some((previous_turn, _)) = self.turns_history.pop() {
                    if last_side.opposite() == previous_turn.get_state().unwrap() {
                        self.current_turn = previous_turn;
                        return Ok(());
                    }
                }
                self.turns_history = backup;
                return Err(::ReversiError::NoUndo);
            },
            Some(current_side) => {
                while let Some((previous_turn, _)) = self.turns_history.pop() {
                    if current_side == previous_turn.get_state().unwrap() {
                        self.current_turn = previous_turn;
                        return Ok(());
                    }
                }
                self.turns_history = backup;
                return Err(::ReversiError::NoUndo);
            }
        }
    }
}
<commit_msg>Add `get_current_score` method<commit_after>//! Implementation of a complete Reversi match.

use std::marker::{PhantomData, Sized};
use board::*;
use turn::*;
use ::Result;

pub enum PlayerAction {
    Move(Coord),
    Undo,
    Other(A),
}

/// Being able to make moves is the trait characterizing players.
pub trait IsPlayer {
    fn make_move(&self, turn: &Turn) -> Result<PlayerAction>;
}

/// A game is given by a list of past turns (with the successive move), a current turn, and the two players.
pub struct Game<'a, A, D: 'a + ?Sized + IsPlayer, L: 'a + ?Sized + IsPlayer> {
    current_turn: Turn,
    turns_history: Vec<(Turn, Coord)>,
    dark:  &'a D,
    light: &'a L,
    phantom: PhantomData
}

impl<'a, A, D: 'a + ?Sized + IsPlayer, L: 'a + ?Sized + IsPlayer> Game<'a, A, D, L> {

    /// Creates a new game, with first turn already set and empty turns' history.
    /// It requires the two players as input.
    pub fn new(dark: &'a D, light: &'a L) -> Game<'a, A, D, L> where D: IsPlayer, L: IsPlayer {
        Game {
            current_turn: Turn::first_turn(),
            turns_history: vec![],
            dark: dark,
            light: light,
            phantom: PhantomData,
        }
    }

    /// Gets the board of the current turn.
    pub fn get_current_board(&self) -> &Board {
        self.current_turn.get_board()
    }

    /// Gets current turn.
    pub fn get_current_turn(&self) -> &Turn {
        &self.current_turn
    }

    /// Gets current score.
    pub fn get_current_score(&self) -> (u8, u8) {
        self.current_turn.get_score()
    }

    /// Gets the state of the current turn.
    pub fn get_current_state(&self) -> State {
        self.current_turn.get_state()
    }

    /// Returns true if the game is ended.
    pub fn is_ended(&self) -> bool {
        self.get_current_state().is_none()
    }

    /// It has the correct player return an action and applies its effects.
    pub fn play_turn(&mut self) -> Result<PlayerAction> {
        let action = match self.current_turn.get_state() {
            None => return Err(::ReversiError::EndedGame),
            Some(::Side::Dark)  => try!(self.dark.make_move(&self.current_turn)),
            Some(::Side::Light) => try!(self.light.make_move(&self.current_turn)),
        };

        match action {
            // If that move is legal, it is applied and the turns' history is updated.
            PlayerAction::Move(coord) => try!(self.make_move(coord)),
            PlayerAction::Undo => try!(self.undo()),
            _ => {}
        }

        Ok(action)
    }

    /// A move (given by `coord`) is applied. If that move is legal, game's history is updated.
    fn make_move(&mut self, coord: Coord) -> Result<()> {
        let new_turn = try!(self.current_turn.make_move(coord));
        self.turns_history.push((self.current_turn.clone(), coord));
        self.current_turn = new_turn;
        Ok(())
    }

    /// Undo last move(s) till the player asking for undoing can play again.
    fn undo(&mut self) -> Result<()> {
        let backup = self.turns_history.clone();
        match self.get_current_state() {
            None => {
                self.current_turn = try!(self.turns_history.pop().ok_or(::ReversiError::NoUndo)).0;
                let last_side = self.get_current_state().unwrap();
                while let Some((previous_turn, _)) = self.turns_history.pop() {
                    if last_side.opposite() == previous_turn.get_state().unwrap() {
                        self.current_turn = previous_turn;
                        return Ok(());
                    }
                }
                self.turns_history = backup;
                return Err(::ReversiError::NoUndo);
            },
            Some(current_side) => {
                while let Some((previous_turn, _)) = self.turns_history.pop() {
                    if current_side == previous_turn.get_state().unwrap() {
                        self.current_turn = previous_turn;
                        return Ok(());
                    }
                }
                self.turns_history = backup;
                return Err(::ReversiError::NoUndo);
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate gtk;

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
                move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
                move |$(clone!(@param $p),)+| $body
        }
    );
}

#[cfg(feature = "gtk_3_10")]
mod example {
    use gtk;
    use gtk::prelude::*;
    use gtk::{
        Builder, Button, Grid, Window,
    };

    pub fn main() {
        if gtk::init().is_err() {
            println!("Failed to initialize GTK.");
            return;
        }
        let glade_src = include_str!("grid.glade");
        let builder = Builder::new_from_string(glade_src);

        let window: Window = builder.get_object("window").unwrap();
        let grid: Grid = builder.get_object("grid").unwrap();
        let button6: Button = builder.get_object("button6").unwrap();
        button6.connect_clicked(clone!(grid, button6 => move |_| {
            let height = grid.get_child_height(&button6);
            let new_height = if height == 2 { 1 } else { 2 };
            grid.set_child_height(&button6, new_height);
        }));
        let button7: Button = builder.get_object("button7").unwrap();
        button7.connect_clicked(clone!(grid, button7 => move |_| {
            let left_attach = grid.get_child_left_attach(&button7);
            let new_left_attach = if left_attach == 2 { 0 } else { left_attach + 1 };
            grid.set_child_left_attach(&button7, new_left_attach);
        }));

        window.connect_delete_event(|_, _| {
            gtk::main_quit();
            Inhibit(false)
        });

        window.show_all();
        gtk::main();
    }
}

#[cfg(feature = "gtk_3_10")]
fn main() {
    example::main()
}

#[cfg(not(feature = "gtk_3_10"))]
fn main() {
    println!("This example only work with GTK 3.10 and later");
    println!("Did you forget to build with `--features gtk_3_10`?");
}
<commit_msg>Rename grid child properties to "cell"<commit_after>extern crate gtk;

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
                move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
                move |$(clone!(@param $p),)+| $body
        }
    );
}

#[cfg(feature = "gtk_3_10")]
mod example {
    use gtk;
    use gtk::prelude::*;
    use gtk::{
        Builder, Button, Grid, Window,
    };

    pub fn main() {
        if gtk::init().is_err() {
            println!("Failed to initialize GTK.");
            return;
        }
        let glade_src = include_str!("grid.glade");
        let builder = Builder::new_from_string(glade_src);

        let window: Window = builder.get_object("window").unwrap();
        let grid: Grid = builder.get_object("grid").unwrap();
        let button6: Button = builder.get_object("button6").unwrap();
        button6.connect_clicked(clone!(grid, button6 => move |_| {
            let height = grid.get_cell_height(&button6);
            let new_height = if height == 2 { 1 } else { 2 };
            grid.set_cell_height(&button6, new_height);
        }));
        let button7: Button = builder.get_object("button7").unwrap();
        button7.connect_clicked(clone!(grid, button7 => move |_| {
            let left_attach = grid.get_cell_left_attach(&button7);
            let new_left_attach = if left_attach == 2 { 0 } else { left_attach + 1 };
            grid.set_cell_left_attach(&button7, new_left_attach);
        }));

        window.connect_delete_event(|_, _| {
            gtk::main_quit();
            Inhibit(false)
        });

        window.show_all();
        gtk::main();
    }
}

#[cfg(feature = "gtk_3_10")]
fn main() {
    example::main()
}

#[cfg(not(feature = "gtk_3_10"))]
fn main() {
    println!("This example only work with GTK 3.10 and later");
    println!("Did you forget to build with `--features gtk_3_10`?");
}
<|endoftext|>


<commit_before>use super::cell::*;
use super::fluid::*;
use itertools::Itertools;
use std::mem;
use rand::{Isaac64Rng, Rng};

#[derive(Default, Debug)]
pub struct Hex {
    pub solution: Solution,
}

impl Hex {
    pub fn color(&self) -> [f32; 4] {
        [self.solution.fluids[0] as f32, self.solution.fluids[1] as f32, 0.0, 1.0]
    }
}

pub struct Grid {
    width: usize,
    height: usize,
    tiles: Vec<Hex>,
}

impl Grid {
    pub fn new(width: usize, height: usize, rng: &mut Isaac64Rng) -> Self {
        Grid {
            width: width,
            height: height,
            tiles: (0..(width * height))
                .map(|_| Hex { solution: Solution::new([rng.next_f64(), rng.next_f64()]) })
                .collect_vec(),
        }
    }

    pub fn randomize(&mut self, rng: &mut Isaac64Rng) {
        for hex in &mut self.tiles {
            hex.solution = Solution::new([rng.next_f64(), rng.next_f64()]);
        }
    }

    pub fn get_hex(&self, x: usize, y: usize) -> &Hex {
        &self.tiles[x + y * self.width]
    }

    pub fn size(&self) -> usize {
        self.width * self.height
    }

    pub fn cycle(&mut self) {
        // Then update diffusion.
        for x in 0..self.width {
            for y in 0..self.height {
                let mut this: &'static mut Hex =
                    unsafe { mem::transmute(&mut self.tiles[x + y * self.width]) };
                // Right
                this.solution.diffuse_from(&self.get_hex((x + self.width + 1) % self.width, y)
                    .solution);
                // Left
                this.solution.diffuse_from(&self.get_hex((x + self.width - 1) % self.width, y)
                    .solution);
                // UpRight
                this.solution
                    .diffuse_from(&self.get_hex(x, (y + self.height - 1) % self.height).solution);
                // DownLeft
                this.solution.diffuse_from(&self.get_hex((x + self.width - 1) % self.width,
                             (y + self.height + 1) % self.height)
                    .solution);
                // UpLeft
                this.solution.diffuse_from(&self.get_hex((x + self.width - 1) % self.width,
                             (y + self.height - 1) % self.height)
                    .solution);
                // DownRight
                this.solution.diffuse_from(&self.get_hex(x, (y + self.height + 1) % self.height)
                    .solution);
            }
        }

        // Finish cycle.
        for hex in &mut self.tiles {
            hex.solution.end_cycle();
        }
    }
}
<commit_msg>make some stuff simpler and reorder operations<commit_after>use super::cell::*;
use super::fluid::*;
use itertools::Itertools;
use std::mem;
use rand::{Isaac64Rng, Rng};

#[derive(Default, Debug)]
pub struct Hex {
    pub solution: Solution,
}

impl Hex {
    pub fn color(&self) -> [f32; 4] {
        [self.solution.fluids[0] as f32, self.solution.fluids[1] as f32, 0.0, 1.0]
    }
}

pub struct Grid {
    width: usize,
    height: usize,
    tiles: Vec<Hex>,
}

impl Grid {
    pub fn new(width: usize, height: usize, rng: &mut Isaac64Rng) -> Self {
        Grid {
            width: width,
            height: height,
            tiles: (0..(width * height))
                .map(|_| Hex { solution: Solution::new([rng.next_f64(), rng.next_f64()]) })
                .collect_vec(),
        }
    }

    pub fn randomize(&mut self, rng: &mut Isaac64Rng) {
        for hex in &mut self.tiles {
            hex.solution = Solution::new([rng.next_f64(), rng.next_f64()]);
        }
    }

    pub fn get_hex(&self, x: usize, y: usize) -> &Hex {
        &self.tiles[x + y * self.width]
    }

    pub fn get_hex_mut(&mut self, x: usize, y: usize) -> &mut Hex {
        &mut self.tiles[x + y * self.width]
    }

    pub fn cycle(&mut self) {
        // Then update diffusion.
        for x in 0..self.width {
            for y in 0..self.height {
                let mut this: &mut Hex = unsafe { mem::transmute(self.get_hex_mut(x, y)) };
                // UpRight
                this.solution
                    .diffuse_from(&self.get_hex(x, (y + self.height - 1) % self.height).solution);
                // UpLeft
                this.solution.diffuse_from(&self.get_hex((x + self.width - 1) % self.width,
                             (y + self.height - 1) % self.height)
                    .solution);
                // Left
                this.solution.diffuse_from(&self.get_hex((x + self.width - 1) % self.width, y)
                    .solution);
                // DownLeft
                this.solution.diffuse_from(&self.get_hex((x + self.width - 1) % self.width,
                             (y + self.height + 1) % self.height)
                    .solution);
                // DownRight
                this.solution.diffuse_from(&self.get_hex(x, (y + self.height + 1) % self.height)
                    .solution);
                // Right
                this.solution.diffuse_from(&self.get_hex((x + self.width + 1) % self.width, y)
                    .solution);
            }
        }

        // Finish the cycle.
        for hex in &mut self.tiles {
            hex.solution.end_cycle();
        }
    }
}
<|endoftext|>


<commit_before>//! GC heap allocator.

use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::{fmt, mem, ptr};
use bit_vec::BitVec;

// What does this do? You'll never guess!
type HeapId<'a> = PhantomData<::std::cell::Cell<&'a mut ()>>;

/// Total number of Pair objects that can be allocated in a Heap at once.
///
/// XXX BOGUS: At present, this is number is carefully selected (with insider
/// knowledge of both `size_of::<PairStorage>()` on my platform and the `Box`
/// allocator's behavior) so that a HeapStorage object fits in a page and thus
/// the assertions below about HEAP_STORAGE_ALIGN pass.
pub const HEAP_SIZE: usize = 125;

/// We rely on all bits to the right of this bit being 0 in addresses of
/// HeapStorage instances.
const HEAP_STORAGE_ALIGN: usize = 0x1000;

// The heap is (for now) just a big array of Pairs
struct HeapStorage<'a> {
    mark_bits: BitVec,
    mark_entry_point: unsafe fn(*mut ()),
    freelist: *mut PairStorage<'a>,
    objects: [PairStorage<'a>; HEAP_SIZE]
}

impl<'a> HeapStorage<'a> {
    unsafe fn new() -> Box<HeapStorage<'a>> {
        let mut storage = Box::new(HeapStorage {
            mark_bits: BitVec::from_elem(HEAP_SIZE, false),
            mark_entry_point: mark_entry_point::<PairStorage>,
            freelist: ptr::null_mut(),
            objects: mem::uninitialized()
        });

        // These assertions will likely fail on 32-bit platforms or if someone
        // is somehow using a custom Box allocator. If either one fails, this
        // GC will not work.
        assert_eq!(&mut *storage as *mut HeapStorage<'a> as usize & (HEAP_STORAGE_ALIGN - 1), 0);
        assert!(mem::size_of::<HeapStorage<'a>>() <= HEAP_STORAGE_ALIGN);

        for i in 0 .. HEAP_SIZE {
            let p = &mut storage.objects[i] as *mut PairStorage<'a>;
            storage.add_to_free_list(p);
        }
        storage
    }

    unsafe fn add_to_free_list(&mut self, p: *mut PairStorage<'a>) {
        let listp = p as *mut *mut PairStorage<'a>;
        *listp = self.freelist;
        assert_eq!(*listp, self.freelist);
        self.freelist = p;
    }

    unsafe fn try_alloc(&mut self) -> Option<*mut PairStorage<'a>> {
        let p = self.freelist;
        if p.is_null() {
            None
        } else {
            let listp = p as *mut *mut PairStorage<'a>;
            self.freelist = *listp;
            Some(p)
        }
    }

    unsafe fn sweep(&mut self) {
        self.freelist = ptr::null_mut();
        for i in 0 .. HEAP_SIZE {
            let p = &mut self.objects[i] as *mut PairStorage<'a>;
            if !self.mark_bits[i] {
                self.add_to_free_list(p);
            }
        }
    }
}

pub struct Heap<'a> {
    id: HeapId<'a>,
    storage: Box<HeapStorage<'a>>,
    pins: RefCell<HashMap<*mut (), usize>>
}

/// Create a heap, pass it to a callback, then destroy the heap.
///
/// The heap's lifetime is directly tied to this function call, for safety. (So
/// the API is a little wonky --- but how many heaps were you planning on
/// creating?)
pub fn with_heap<F, O>(f: F) -> O
    where F: for<'a> FnOnce(&mut Heap<'a>) -> O
{
    f(&mut Heap::new())
}

/// Trait implemented by all types that can be stored directly in the GC heap:
/// the `Storage` types associated with any `HeapInline` or `HeapRef` type.
///
/// XXX maybe this should not be its own trait - fold into HeapInline?
///
pub unsafe trait Mark<'a> {
    unsafe fn mark(ptr: *mut Self);
}

/// Non-inlined function that serves as an entry point to marking. This is used
/// for marking root set entries.
unsafe fn mark_entry_point<'a, T: Mark<'a>>(addr: *mut ()) {
    Mark::mark(addr as *mut T);
}

/// Trait implemented by all types that can be stored in fields of structs (or,
/// eventually, elements of GCVecs) that are stored in the GC heap.
pub unsafe trait HeapInline<'a> {
    /// The type of the value when it is physically stored in the heap.
    type Storage;

    /// Extract the value from the heap. Do not under any circumstances call
    /// this.  It is for macro-generated code to call; it is impossible for
    /// ordinary users to call this safely, because `ptr` must be a direct,
    /// unwrapped reference to a value stored in the GC heap, which ordinary
    /// users cannot obtain.
    ///
    /// This turns any raw pointers in the `Storage` value into safe
    /// references, so while it's a dangerous function, the result of a correct
    /// call can be safely handed out to user code.
    ///
    unsafe fn from_heap(heap: &Heap<'a>, ptr: &Self::Storage) -> Self;

    /// Convert the value to the form it should have in the heap.
    /// This is for macro-generated code to call.
    fn to_heap(self) -> Self::Storage;
}

impl<'a> Heap<'a> {
    fn new() -> Heap<'a> {
        Heap {
            id: PhantomData,
            storage: unsafe { HeapStorage::new() },
            pins: RefCell::new(HashMap::new())
        }
    }

    /// Add the object `*p` to the root set, protecting it from GC.
    ///
    /// An object that has been pinned *n* times stays in the root set
    /// until it has been unpinned *n* times.
    ///
    /// (Unsafe because if the argument is garbage, a later GC will
    /// crash. Called only from `impl PinnedRef`.)
    unsafe fn pin<T: Mark<'a>>(&self, p: *mut T) {
        let p = p as *mut ();
        let mut pins = self.pins.borrow_mut();
        let entry = pins.entry(p).or_insert(0);
        *entry += 1;
    }

    /// Unpin an object (see `pin`).
    ///
    /// (Unsafe because unpinning an object that other code is still using
    /// causes dangling pointers. Called only from `impl PinnedRef`.)
    unsafe fn unpin<T: Mark<'a>>(&self, p: *mut T) {
        let p = p as *mut ();
        let mut pins = self.pins.borrow_mut();
        if {
            let entry = pins.entry(p as *mut ()).or_insert(0);
            assert!(*entry != 0);
            *entry -= 1;
            *entry == 0
        } {
            pins.remove(&p);
        }
    }

    pub fn try_alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Option<Pair<'a>> {
        unsafe {
            self.storage.try_alloc()
                .or_else(|| {
                    self.gc();
                    self.storage.try_alloc()
                })
                .map(move |p| {
                    *p = PairStorage {
                        head: pair.0.to_heap(),
                        tail: pair.1.to_heap()
                    };
                    Pair(PinnedRef::new(self, p))
                })
        }
    }

    unsafe fn find_header<T>(_ptr: *const T) -> *mut HeapStorage<'a> {
        let storage_addr = _ptr as usize & !(HEAP_STORAGE_ALIGN - 1);
        storage_addr as *mut HeapStorage<'a>
    }

    unsafe fn find_mark_bit<T>(_ptr: *const T) -> (*mut BitVec, usize) {
        assert_eq!(mem::size_of::<T>(), mem::size_of::<PairStorage<'a>>());
        let storage = Heap::find_header(_ptr);
        let objects_addr = &mut (*storage).objects[0] as *mut PairStorage<'a> as usize;
        let index = (_ptr as usize - objects_addr) / mem::size_of::<PairStorage<'a>>();
        (&mut (*storage).mark_bits as *mut BitVec, index)
    }

    pub unsafe fn get_mark_bit<T>(_ptr: *const T) -> bool {
        let (bits, index) = Heap::find_mark_bit(_ptr);
        (*bits)[index]
    }

    pub unsafe fn set_mark_bit<T>(_ptr: *const T) {
        let (bits, index) = Heap::find_mark_bit(_ptr);
        (*bits).set(index, true);
    }

    pub fn alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Pair<'a> {
        self.try_alloc(pair).expect("out of memory (gc did not collect anything)")
    }

    pub fn alloc_null(&mut self) -> Pair<'a> {
        self.alloc((Value::Null, Value::Null))
    }

    unsafe fn mark(ptr: *mut ()) {
        let storage = Heap::find_header(ptr);
        let mark_fn = (*storage).mark_entry_point;
        mark_fn(ptr);
    }

    unsafe fn gc(&mut self) {
        // mark phase
        self.storage.mark_bits.clear();
        for (&p, _) in self.pins.borrow().iter() {
            Heap::mark(p);
        }

        // sweep phase
        self.storage.sweep();
    }

    #[cfg(test)]
    pub fn force_gc(&mut self) {
        unsafe { self.gc(); }
    }
}

pub struct PinnedRef<'a, T: Mark<'a>> {
    ptr: *mut T,
    heap: *const Heap<'a>,
    heap_id: HeapId<'a>
}

impl<'a, T: Mark<'a>> PinnedRef<'a, T> {
    /// Pin an object, returning a new `PinnedRef` that will unpin it when
    /// dropped. Unsafe because if `p` is not a pointer to a live allocation of
    /// type `T` --- and a complete allocation, not a sub-object of one --- then
    /// later unsafe code will explode.
    unsafe fn new(heap: &Heap<'a>, p: *mut T) -> PinnedRef<'a, T> {
        heap.pin(p);
        PinnedRef {
            ptr: p,
            heap: heap as *const Heap<'a>,
            heap_id: heap.id
        }
    }
}

impl<'a, T: Mark<'a>> Drop for PinnedRef<'a, T> {
    fn drop(&mut self) {
        unsafe {
            (*self.heap).unpin(self.ptr);
        }
    }
}

impl<'a, T: Mark<'a>> Clone for PinnedRef<'a, T> {
    fn clone(&self) -> PinnedRef<'a, T> {
        let &PinnedRef { ptr, heap, heap_id } = self;
        unsafe {
            (*heap).pin(ptr);
        }
        PinnedRef {
            ptr: ptr,
            heap: heap,
            heap_id: heap_id
        }
    }
}

impl<'a, T: Mark<'a>> fmt::Debug for PinnedRef<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PinnedRef {{ ptr: {:p} }}", self.ptr)
    }
}

impl<'a, T: Mark<'a>> PartialEq for PinnedRef<'a, T> {
    fn eq(&self, other: &PinnedRef<'a, T>) -> bool {
        self.ptr == other.ptr
    }
}

impl<'a, T: Mark<'a>> Eq for PinnedRef<'a, T> {}

pub trait GCRef {
    #[cfg(test)]
    fn address(&self) -> usize;
}

// === Pair, the reference type

gc_ref_type! {
    pub struct Pair / PairStorage<'a> {
        head / set_head: Value<'a>,
        tail / set_tail: Value<'a>
    }
}

// === Values (a heap-inline enum)

use std::rc::Rc;

// Values inside the heap (GC heap-to-heap cross-references) (private)
enum ValueStorage<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),
    Pair(*mut PairStorage<'a>)
}

unsafe impl<'a> Mark<'a> for ValueStorage<'a> {
    unsafe fn mark(ptr: *mut ValueStorage<'a>) {
        match *ptr {
            ValueStorage::Pair(p) => Mark::mark(p),
            _ => {}
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),  // <-- equality is by value
    Pair(Pair<'a>)  // <-- equality is by pointer
}

unsafe impl<'a> HeapInline<'a> for Value<'a> {
    type Storage = ValueStorage<'a>;

    fn to_heap(self) -> ValueStorage<'a> {
        match self {
            Value::Null => ValueStorage::Null,
            Value::Int(n) => ValueStorage::Int(n),
            Value::Str(rcstr) => ValueStorage::Str(rcstr),
            Value::Pair(pair) => ValueStorage::Pair(HeapInline::<'a>::to_heap(pair))
        }
    }

    unsafe fn from_heap(heap: &Heap<'a>, v: &ValueStorage<'a>) -> Value<'a> {
        match v {
            &ValueStorage::Null => Value::Null,
            &ValueStorage::Int(n) => Value::Int(n),
            &ValueStorage::Str(ref rcstr) => Value::Str(rcstr.clone()),
            &ValueStorage::Pair(ref ptr) => Value::Pair(HeapInline::<'a>::from_heap(heap, ptr))
        }
    }
}

unsafe impl<'a, T: Copy + 'static> Mark<'a> for T {
    unsafe fn mark(_ptr: *mut T) {}
}

unsafe impl<'a, T: Copy + 'static> HeapInline<'a> for T {
    type Storage = Self;

    fn to_heap(self) -> T { self }

    unsafe fn from_heap(_heap: &Heap<'a>, v: &T) -> T { *v }
}
<commit_msg>Move stuff around.<commit_after>//! GC heap allocator.

use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::{fmt, mem, ptr};
use bit_vec::BitVec;

// What does this do? You'll never guess!
type HeapId<'a> = PhantomData<::std::cell::Cell<&'a mut ()>>;

/// Total number of Pair objects that can be allocated in a Heap at once.
///
/// XXX BOGUS: At present, this is number is carefully selected (with insider
/// knowledge of both `size_of::<PairStorage>()` on my platform and the `Box`
/// allocator's behavior) so that a HeapStorage object fits in a page and thus
/// the assertions below about HEAP_STORAGE_ALIGN pass.
pub const HEAP_SIZE: usize = 125;

/// We rely on all bits to the right of this bit being 0 in addresses of
/// HeapStorage instances.
const HEAP_STORAGE_ALIGN: usize = 0x1000;

// The heap is (for now) just a big array of Pairs
struct HeapStorage<'a> {
    mark_bits: BitVec,
    mark_entry_point: unsafe fn(*mut ()),
    freelist: *mut PairStorage<'a>,
    objects: [PairStorage<'a>; HEAP_SIZE]
}

impl<'a> HeapStorage<'a> {
    unsafe fn new() -> Box<HeapStorage<'a>> {
        let mut storage = Box::new(HeapStorage {
            mark_bits: BitVec::from_elem(HEAP_SIZE, false),
            mark_entry_point: mark_entry_point::<PairStorage>,
            freelist: ptr::null_mut(),
            objects: mem::uninitialized()
        });

        // These assertions will likely fail on 32-bit platforms or if someone
        // is somehow using a custom Box allocator. If either one fails, this
        // GC will not work.
        assert_eq!(&mut *storage as *mut HeapStorage<'a> as usize & (HEAP_STORAGE_ALIGN - 1), 0);
        assert!(mem::size_of::<HeapStorage<'a>>() <= HEAP_STORAGE_ALIGN);

        for i in 0 .. HEAP_SIZE {
            let p = &mut storage.objects[i] as *mut PairStorage<'a>;
            storage.add_to_free_list(p);
        }
        storage
    }

    unsafe fn add_to_free_list(&mut self, p: *mut PairStorage<'a>) {
        let listp = p as *mut *mut PairStorage<'a>;
        *listp = self.freelist;
        assert_eq!(*listp, self.freelist);
        self.freelist = p;
    }

    unsafe fn try_alloc(&mut self) -> Option<*mut PairStorage<'a>> {
        let p = self.freelist;
        if p.is_null() {
            None
        } else {
            let listp = p as *mut *mut PairStorage<'a>;
            self.freelist = *listp;
            Some(p)
        }
    }

    unsafe fn sweep(&mut self) {
        self.freelist = ptr::null_mut();
        for i in 0 .. HEAP_SIZE {
            let p = &mut self.objects[i] as *mut PairStorage<'a>;
            if !self.mark_bits[i] {
                self.add_to_free_list(p);
            }
        }
    }
}

pub struct Heap<'a> {
    id: HeapId<'a>,
    storage: Box<HeapStorage<'a>>,
    pins: RefCell<HashMap<*mut (), usize>>
}

/// Create a heap, pass it to a callback, then destroy the heap.
///
/// The heap's lifetime is directly tied to this function call, for safety. (So
/// the API is a little wonky --- but how many heaps were you planning on
/// creating?)
pub fn with_heap<F, O>(f: F) -> O
    where F: for<'a> FnOnce(&mut Heap<'a>) -> O
{
    f(&mut Heap::new())
}

/// Trait implemented by all types that can be stored directly in the GC heap:
/// the `Storage` types associated with any `HeapInline` or `HeapRef` type.
///
/// XXX maybe this should not be its own trait - fold into HeapInline?
///
pub unsafe trait Mark<'a> {
    unsafe fn mark(ptr: *mut Self);
}

/// Non-inlined function that serves as an entry point to marking. This is used
/// for marking root set entries.
unsafe fn mark_entry_point<'a, T: Mark<'a>>(addr: *mut ()) {
    Mark::mark(addr as *mut T);
}

/// Trait implemented by all types that can be stored in fields of structs (or,
/// eventually, elements of GCVecs) that are stored in the GC heap.
pub unsafe trait HeapInline<'a> {
    /// The type of the value when it is physically stored in the heap.
    type Storage;

    /// Extract the value from the heap. Do not under any circumstances call
    /// this.  It is for macro-generated code to call; it is impossible for
    /// ordinary users to call this safely, because `ptr` must be a direct,
    /// unwrapped reference to a value stored in the GC heap, which ordinary
    /// users cannot obtain.
    ///
    /// This turns any raw pointers in the `Storage` value into safe
    /// references, so while it's a dangerous function, the result of a correct
    /// call can be safely handed out to user code.
    ///
    unsafe fn from_heap(heap: &Heap<'a>, ptr: &Self::Storage) -> Self;

    /// Convert the value to the form it should have in the heap.
    /// This is for macro-generated code to call.
    fn to_heap(self) -> Self::Storage;
}

impl<'a> Heap<'a> {
    fn new() -> Heap<'a> {
        Heap {
            id: PhantomData,
            storage: unsafe { HeapStorage::new() },
            pins: RefCell::new(HashMap::new())
        }
    }

    /// Add the object `*p` to the root set, protecting it from GC.
    ///
    /// An object that has been pinned *n* times stays in the root set
    /// until it has been unpinned *n* times.
    ///
    /// (Unsafe because if the argument is garbage, a later GC will
    /// crash. Called only from `impl PinnedRef`.)
    unsafe fn pin<T: Mark<'a>>(&self, p: *mut T) {
        let p = p as *mut ();
        let mut pins = self.pins.borrow_mut();
        let entry = pins.entry(p).or_insert(0);
        *entry += 1;
    }

    /// Unpin an object (see `pin`).
    ///
    /// (Unsafe because unpinning an object that other code is still using
    /// causes dangling pointers. Called only from `impl PinnedRef`.)
    unsafe fn unpin<T: Mark<'a>>(&self, p: *mut T) {
        let p = p as *mut ();
        let mut pins = self.pins.borrow_mut();
        if {
            let entry = pins.entry(p as *mut ()).or_insert(0);
            assert!(*entry != 0);
            *entry -= 1;
            *entry == 0
        } {
            pins.remove(&p);
        }
    }

    pub fn try_alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Option<Pair<'a>> {
        unsafe {
            self.storage.try_alloc()
                .or_else(|| {
                    self.gc();
                    self.storage.try_alloc()
                })
                .map(move |p| {
                    *p = PairStorage {
                        head: pair.0.to_heap(),
                        tail: pair.1.to_heap()
                    };
                    Pair(PinnedRef::new(self, p))
                })
        }
    }

    unsafe fn find_header<T>(_ptr: *const T) -> *mut HeapStorage<'a> {
        let storage_addr = _ptr as usize & !(HEAP_STORAGE_ALIGN - 1);
        storage_addr as *mut HeapStorage<'a>
    }

    unsafe fn find_mark_bit<T>(_ptr: *const T) -> (*mut BitVec, usize) {
        assert_eq!(mem::size_of::<T>(), mem::size_of::<PairStorage<'a>>());
        let storage = Heap::find_header(_ptr);
        let objects_addr = &mut (*storage).objects[0] as *mut PairStorage<'a> as usize;
        let index = (_ptr as usize - objects_addr) / mem::size_of::<PairStorage<'a>>();
        (&mut (*storage).mark_bits as *mut BitVec, index)
    }

    pub unsafe fn get_mark_bit<T>(_ptr: *const T) -> bool {
        let (bits, index) = Heap::find_mark_bit(_ptr);
        (*bits)[index]
    }

    pub unsafe fn set_mark_bit<T>(_ptr: *const T) {
        let (bits, index) = Heap::find_mark_bit(_ptr);
        (*bits).set(index, true);
    }

    pub fn alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Pair<'a> {
        self.try_alloc(pair).expect("out of memory (gc did not collect anything)")
    }

    pub fn alloc_null(&mut self) -> Pair<'a> {
        self.alloc((Value::Null, Value::Null))
    }

    unsafe fn mark(ptr: *mut ()) {
        let storage = Heap::find_header(ptr);
        let mark_fn = (*storage).mark_entry_point;
        mark_fn(ptr);
    }

    unsafe fn gc(&mut self) {
        // mark phase
        self.storage.mark_bits.clear();
        for (&p, _) in self.pins.borrow().iter() {
            Heap::mark(p);
        }

        // sweep phase
        self.storage.sweep();
    }

    #[cfg(test)]
    pub fn force_gc(&mut self) {
        unsafe { self.gc(); }
    }
}

pub struct PinnedRef<'a, T: Mark<'a>> {
    ptr: *mut T,
    heap: *const Heap<'a>,
    heap_id: HeapId<'a>
}

impl<'a, T: Mark<'a>> PinnedRef<'a, T> {
    /// Pin an object, returning a new `PinnedRef` that will unpin it when
    /// dropped. Unsafe because if `p` is not a pointer to a live allocation of
    /// type `T` --- and a complete allocation, not a sub-object of one --- then
    /// later unsafe code will explode.
    unsafe fn new(heap: &Heap<'a>, p: *mut T) -> PinnedRef<'a, T> {
        heap.pin(p);
        PinnedRef {
            ptr: p,
            heap: heap as *const Heap<'a>,
            heap_id: heap.id
        }
    }
}

impl<'a, T: Mark<'a>> Drop for PinnedRef<'a, T> {
    fn drop(&mut self) {
        unsafe {
            (*self.heap).unpin(self.ptr);
        }
    }
}

impl<'a, T: Mark<'a>> Clone for PinnedRef<'a, T> {
    fn clone(&self) -> PinnedRef<'a, T> {
        let &PinnedRef { ptr, heap, heap_id } = self;
        unsafe {
            (*heap).pin(ptr);
        }
        PinnedRef {
            ptr: ptr,
            heap: heap,
            heap_id: heap_id
        }
    }
}

impl<'a, T: Mark<'a>> fmt::Debug for PinnedRef<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PinnedRef {{ ptr: {:p} }}", self.ptr)
    }
}

impl<'a, T: Mark<'a>> PartialEq for PinnedRef<'a, T> {
    fn eq(&self, other: &PinnedRef<'a, T>) -> bool {
        self.ptr == other.ptr
    }
}

impl<'a, T: Mark<'a>> Eq for PinnedRef<'a, T> {}

pub trait GCRef {
    #[cfg(test)]
    fn address(&self) -> usize;
}

unsafe impl<'a, T: Copy + 'static> Mark<'a> for T {
    unsafe fn mark(_ptr: *mut T) {}
}

unsafe impl<'a, T: Copy + 'static> HeapInline<'a> for T {
    type Storage = Self;

    fn to_heap(self) -> T { self }

    unsafe fn from_heap(_heap: &Heap<'a>, v: &T) -> T { *v }
}

// === Pair, the reference type

gc_ref_type! {
    pub struct Pair / PairStorage<'a> {
        head / set_head: Value<'a>,
        tail / set_tail: Value<'a>
    }
}

// === Values (a heap-inline enum)

use std::rc::Rc;

// Values inside the heap (GC heap-to-heap cross-references) (private)
enum ValueStorage<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),
    Pair(*mut PairStorage<'a>)
}

unsafe impl<'a> Mark<'a> for ValueStorage<'a> {
    unsafe fn mark(ptr: *mut ValueStorage<'a>) {
        match *ptr {
            ValueStorage::Pair(p) => Mark::mark(p),
            _ => {}
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),  // <-- equality is by value
    Pair(Pair<'a>)  // <-- equality is by pointer
}

unsafe impl<'a> HeapInline<'a> for Value<'a> {
    type Storage = ValueStorage<'a>;

    fn to_heap(self) -> ValueStorage<'a> {
        match self {
            Value::Null => ValueStorage::Null,
            Value::Int(n) => ValueStorage::Int(n),
            Value::Str(rcstr) => ValueStorage::Str(rcstr),
            Value::Pair(pair) => ValueStorage::Pair(HeapInline::<'a>::to_heap(pair))
        }
    }

    unsafe fn from_heap(heap: &Heap<'a>, v: &ValueStorage<'a>) -> Value<'a> {
        match v {
            &ValueStorage::Null => Value::Null,
            &ValueStorage::Int(n) => Value::Int(n),
            &ValueStorage::Str(ref rcstr) => Value::Str(rcstr.clone()),
            &ValueStorage::Pair(ref ptr) => Value::Pair(HeapInline::<'a>::from_heap(heap, ptr))
        }
    }
}

<|endoftext|>


<commit_before>use std::{
    convert::TryFrom,
    fmt,
    hash::{Hash, Hasher},
    ops::Deref,
    sync::Arc,
};

const CUTOFF: usize = 22;

type Inner = [u8; CUTOFF];

/// A buffer that may either be inline or remote and protected
/// by an Arc
#[derive(Clone)]
pub struct IVec(IVecInner);

impl Default for IVec {
    fn default() -> Self {
        Self::from(&[])
    }
}

#[derive(Clone)]
enum IVecInner {
    Inline(u8, Inner),
    Remote(Arc<[u8]>),
}

impl Hash for IVec {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.deref().hash(state);
    }
}

const fn is_inline_candidate(length: usize) -> bool {
    length <= CUTOFF
}

impl IVec {
    fn inline(slice: &[u8]) -> Self {
        assert!(is_inline_candidate(slice.len()));

        let mut data = Inner::default();

        #[allow(unsafe_code)]
        unsafe {
            std::ptr::copy_nonoverlapping(
                slice.as_ptr(),
                data.as_mut_ptr(),
                slice.len(),
            );
        }

        Self(IVecInner::Inline(u8::try_from(slice.len()).unwrap(), data))
    }

    fn remote(arc: Arc<[u8]>) -> Self {
        Self(IVecInner::Remote(arc))
    }
}

impl From<Box<[u8]>> for IVec {
    fn from(b: Box<[u8]>) -> Self {
        if is_inline_candidate(b.len()) {
            Self::inline(&b)
        } else {
            // rely on the Arc From specialization
            // for Box<T>, which may improve
            // over time
            Self::remote(Arc::from(b))
        }
    }
}

impl From<&[u8]> for IVec {
    fn from(slice: &[u8]) -> Self {
        if is_inline_candidate(slice.len()) {
            Self::inline(slice)
        } else {
            Self::remote(Arc::from(slice))
        }
    }
}

impl From<Arc<[u8]>> for IVec {
    fn from(arc: Arc<[u8]>) -> Self {
        Self::remote(arc)
    }
}

impl From<&str> for IVec {
    fn from(s: &str) -> Self {
        Self::from(s.as_bytes())
    }
}

impl From<&IVec> for IVec {
    fn from(v: &Self) -> Self {
        v.clone()
    }
}

impl From<Vec<u8>> for IVec {
    fn from(v: Vec<u8>) -> Self {
        if is_inline_candidate(v.len()) {
            Self::inline(&v)
        } else {
            // rely on the Arc From specialization
            // for Vec<T>, which may improve
            // over time
            Self::remote(Arc::from(v))
        }
    }
}

impl std::borrow::Borrow<[u8]> for IVec {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

impl std::borrow::Borrow<[u8]> for &IVec {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

macro_rules! from_array {
    ($($s:expr),*) => {
        $(
            impl From<&[u8; $s]> for IVec {
                fn from(v: &[u8; $s]) -> Self {
                    Self::from(&v[..])
                }
            }
        )*
    }
}

from_array!(
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
);

impl Into<Arc<[u8]>> for IVec {
    fn into(self) -> Arc<[u8]> {
        match self.0 {
            IVecInner::Inline(..) => Arc::from(self.as_ref()),
            IVecInner::Remote(arc) => arc,
        }
    }
}

impl Deref for IVec {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}

impl AsRef<[u8]> for IVec {
    #[inline]
    #[allow(unsafe_code)]
    fn as_ref(&self) -> &[u8] {
        match &self.0 {
            IVecInner::Inline(sz, buf) => unsafe {
                buf.get_unchecked(..*sz as usize)
            },
            IVecInner::Remote(buf) => buf,
        }
    }
}

impl Ord for IVec {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

impl PartialOrd for IVec {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: AsRef<[u8]>> PartialEq<T> for IVec {
    fn eq(&self, other: &T) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl PartialEq<[u8]> for IVec {
    fn eq(&self, other: &[u8]) -> bool {
        self.as_ref() == other
    }
}

impl Eq for IVec {}

impl fmt::Debug for IVec {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.as_ref().fmt(f)
    }
}

#[test]
fn ivec_usage() {
    let iv1 = IVec::from(vec![1, 2, 3]);
    assert_eq!(iv1, vec![1, 2, 3]);
    let iv2 = IVec::from(&[4; 128][..]);
    assert_eq!(iv2, vec![4; 128]);
}
<commit_msg>Implement FromIterator<u8> for IVec<commit_after>use std::{
    convert::TryFrom,
    fmt,
    hash::{Hash, Hasher},
    iter::FromIterator,
    ops::Deref,
    sync::Arc,
};

const CUTOFF: usize = 22;

type Inner = [u8; CUTOFF];

/// A buffer that may either be inline or remote and protected
/// by an Arc
#[derive(Clone)]
pub struct IVec(IVecInner);

impl Default for IVec {
    fn default() -> Self {
        Self::from(&[])
    }
}

#[derive(Clone)]
enum IVecInner {
    Inline(u8, Inner),
    Remote(Arc<[u8]>),
}

impl Hash for IVec {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.deref().hash(state);
    }
}

const fn is_inline_candidate(length: usize) -> bool {
    length <= CUTOFF
}

impl IVec {
    fn inline(slice: &[u8]) -> Self {
        assert!(is_inline_candidate(slice.len()));

        let mut data = Inner::default();

        #[allow(unsafe_code)]
        unsafe {
            std::ptr::copy_nonoverlapping(
                slice.as_ptr(),
                data.as_mut_ptr(),
                slice.len(),
            );
        }

        Self(IVecInner::Inline(u8::try_from(slice.len()).unwrap(), data))
    }

    fn remote(arc: Arc<[u8]>) -> Self {
        Self(IVecInner::Remote(arc))
    }
}

impl FromIterator<u8> for IVec {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = u8>,
    {
        let bs: Box<[u8]> = iter.into_iter().collect();
        bs.into()
    }
}

impl From<Box<[u8]>> for IVec {
    fn from(b: Box<[u8]>) -> Self {
        if is_inline_candidate(b.len()) {
            Self::inline(&b)
        } else {
            // rely on the Arc From specialization
            // for Box<T>, which may improve
            // over time
            Self::remote(Arc::from(b))
        }
    }
}

impl From<&[u8]> for IVec {
    fn from(slice: &[u8]) -> Self {
        if is_inline_candidate(slice.len()) {
            Self::inline(slice)
        } else {
            Self::remote(Arc::from(slice))
        }
    }
}

impl From<Arc<[u8]>> for IVec {
    fn from(arc: Arc<[u8]>) -> Self {
        Self::remote(arc)
    }
}

impl From<&str> for IVec {
    fn from(s: &str) -> Self {
        Self::from(s.as_bytes())
    }
}

impl From<&IVec> for IVec {
    fn from(v: &Self) -> Self {
        v.clone()
    }
}

impl From<Vec<u8>> for IVec {
    fn from(v: Vec<u8>) -> Self {
        if is_inline_candidate(v.len()) {
            Self::inline(&v)
        } else {
            // rely on the Arc From specialization
            // for Vec<T>, which may improve
            // over time
            Self::remote(Arc::from(v))
        }
    }
}

impl std::borrow::Borrow<[u8]> for IVec {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

impl std::borrow::Borrow<[u8]> for &IVec {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

macro_rules! from_array {
    ($($s:expr),*) => {
        $(
            impl From<&[u8; $s]> for IVec {
                fn from(v: &[u8; $s]) -> Self {
                    Self::from(&v[..])
                }
            }
        )*
    }
}

from_array!(
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
);

impl Into<Arc<[u8]>> for IVec {
    fn into(self) -> Arc<[u8]> {
        match self.0 {
            IVecInner::Inline(..) => Arc::from(self.as_ref()),
            IVecInner::Remote(arc) => arc,
        }
    }
}

impl Deref for IVec {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}

impl AsRef<[u8]> for IVec {
    #[inline]
    #[allow(unsafe_code)]
    fn as_ref(&self) -> &[u8] {
        match &self.0 {
            IVecInner::Inline(sz, buf) => unsafe {
                buf.get_unchecked(..*sz as usize)
            },
            IVecInner::Remote(buf) => buf,
        }
    }
}

impl Ord for IVec {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

impl PartialOrd for IVec {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: AsRef<[u8]>> PartialEq<T> for IVec {
    fn eq(&self, other: &T) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl PartialEq<[u8]> for IVec {
    fn eq(&self, other: &[u8]) -> bool {
        self.as_ref() == other
    }
}

impl Eq for IVec {}

impl fmt::Debug for IVec {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.as_ref().fmt(f)
    }
}

#[test]
fn ivec_usage() {
    let iv1 = IVec::from(vec![1, 2, 3]);
    assert_eq!(iv1, vec![1, 2, 3]);
    let iv2 = IVec::from(&[4; 128][..]);
    assert_eq!(iv2, vec![4; 128]);
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::iter::{Iterator, FromIterator, IntoIterator};
use data::{Value, List, Cons, Scope, RuntimeError};

impl List
{
    pub fn cons(car: Value, cdr: List) -> List
    {
        List::Node(Rc::new(Cons{ car: car, cdr: cdr }))
    }

    pub fn from_vec(vec: Vec<Value>) -> List
    {
        vec.into_iter().rev().fold(List::End, |cdr, car| List::cons(car, cdr))
    }

    pub fn iter(&self) -> ListIter
    {
        ListIter(self)
    }

    pub fn eval(&self, env: &mut Scope) -> Result<List, RuntimeError>
    {
        self.iter().map(|val| val.eval(env)).collect()
    }

    pub fn eval_to_value(&self, env: &mut Scope) -> Result<Value, RuntimeError>
    {
        self.iter().map(|val| val.eval(env)).last().unwrap_or(Ok(Value::Nil))
    }

    pub fn call(&self, env: &mut Scope) -> Result<Value, RuntimeError>
    {
        match *self {
            List::Node(ref cons) => match try!(cons.car.eval(env)) {
                Value::Function(ref func) => func.call(&cons.cdr, env, true),
                other => Err(RuntimeError::InvalidCall(other.type_name())),
            },
            List::End => Ok(Value::Nil),
        }
    }

    pub fn fold<T, F>(&self, mut acc: T, mut f: F) -> Result<T, RuntimeError>
        where F: FnMut(T, Value) -> Result<T, RuntimeError>
    {
        let mut iter = self.iter();
        while let Some(val) = iter.next()
        {
            acc = try!(f(acc, val))
        }
        Ok(acc)
    }
}

impl FromIterator<Value> for List
{
    fn from_iter<T>(iterator: T) -> Self
        where T: IntoIterator<Item=Value>
    {
        List::from_vec(iterator.into_iter().collect())
    }
}

#[derive(Clone)]
pub struct ListIter<'a>(&'a List);

impl<'a> Iterator for ListIter<'a>
{
    type Item = Value;

    fn next(&mut self) -> Option<Self::Item>
    {
        match *self.0 {
            List::Node(ref cons) => {
                self.0 = &cons.cdr;
                Some(cons.car.clone())
            },
            List::End => None,
        }
    }
}
<commit_msg>evaluation should stop on error<commit_after>use std::rc::Rc;
use std::iter::{Iterator, FromIterator, IntoIterator};
use data::{Value, List, Cons, Scope, RuntimeError};

impl List
{
    pub fn cons(car: Value, cdr: List) -> List
    {
        List::Node(Rc::new(Cons{ car: car, cdr: cdr }))
    }

    pub fn from_vec(vec: Vec<Value>) -> List
    {
        vec.into_iter().rev().fold(List::End, |cdr, car| List::cons(car, cdr))
    }

    pub fn iter(&self) -> ListIter
    {
        ListIter(self)
    }

    pub fn eval(&self, env: &mut Scope) -> Result<List, RuntimeError>
    {
        self.iter().map(|val| val.eval(env)).collect()
    }

    pub fn eval_to_value(&self, env: &mut Scope) -> Result<Value, RuntimeError>
    {
        self.fold(Value::Nil, |_, val| val.eval(env))
    }

    pub fn call(&self, env: &mut Scope) -> Result<Value, RuntimeError>
    {
        match *self {
            List::Node(ref cons) => match try!(cons.car.eval(env)) {
                Value::Function(ref func) => func.call(&cons.cdr, env, true),
                other => Err(RuntimeError::InvalidCall(other.type_name())),
            },
            List::End => Ok(Value::Nil),
        }
    }

    pub fn fold<T, F>(&self, mut acc: T, mut f: F) -> Result<T, RuntimeError>
        where F: FnMut(T, Value) -> Result<T, RuntimeError>
    {
        let mut iter = self.iter();
        while let Some(val) = iter.next()
        {
            acc = try!(f(acc, val))
        }
        Ok(acc)
    }
}

impl FromIterator<Value> for List
{
    fn from_iter<T>(iterator: T) -> Self
        where T: IntoIterator<Item=Value>
    {
        List::from_vec(iterator.into_iter().collect())
    }
}

#[derive(Clone)]
pub struct ListIter<'a>(&'a List);

impl<'a> Iterator for ListIter<'a>
{
    type Item = Value;

    fn next(&mut self) -> Option<Self::Item>
    {
        match *self.0 {
            List::Node(ref cons) => {
                self.0 = &cons.cdr;
                Some(cons.car.clone())
            },
            List::End => None,
        }
    }
}
<|endoftext|>