<commit_before>#![desc = "Constraint Satisfaction in Rust"]
#![license = "MIT"]
#![crate_id = "csar#0.2"]
#![crate_type = "lib"]

#![feature(struct_inherit)]

use std::fmt;
use std::cell::RefCell;
use std::collections::hashmap::HashMap;
use std::rc::{Rc,Weak};

pub struct Mod {
    vars: RefCell<Vec<Rc<FDVar>>>,
    propagators: RefCell<Vec<Rc<Box<Propagator>>>>,
    waiting: RefCell<HashMap<(uint, Event), Vec<uint>>>
}

// cannot use type Model = Rc<Mod> since that would forbid using impl Model
pub struct Model;

/// Representation of finite domains as a list of intervals, maintaining
/// min and max for easy/quick access
#[deriving(Clone)]
struct Dom {
    min: int,
    max: int,
    intervals: Vec<(int, int)>
}

/// Runtime checked mutability with borrowing
#[deriving(Clone)]
struct Domain {
    dom: RefCell<Dom>
}

trait Propagator {
    fn id(&self) -> uint;
    fn model(&self) -> Weak<Mod>;

    fn events(&self) -> Vec<(uint, Event)>;
    fn propagate(&self) -> Vec<uint>;

    fn register(&self) {
        for &(var, event) in self.events().iter() {
            self.model().upgrade().unwrap().add_waiting(var, event, self.id());
        }
    }

    fn unregister(&self) {
        for &(var, event) in self.events().iter() {
            self.model().upgrade().unwrap().del_waiting(var, event, self.id());
        }
    }
}

pub virtual struct Prop {
    id: uint,
    model: Weak<Mod>
}

pub struct Var;

#[deriving(Clone)]
pub struct FDVar {
    model: Weak<Mod>,
    id: uint,
    name: String,
    dom: Domain
}

#[deriving(Show,Hash,Eq,PartialEq)]
pub enum Event {
    Min,
    Max,
    Ins
}

#[allow(dead_code)]
impl Model {
    fn new() -> Rc<Mod> {
        Rc::new(Mod {
            vars: RefCell::new(Vec::new()),
            propagators: RefCell::new(Vec::new()),
            waiting: RefCell::new(HashMap::new())
        })
    }
}

impl Mod {
    fn add_var(&self, var: Rc<FDVar>) {
        self.vars.borrow_mut().push(var);
    }

    fn add_prop(&self, prop: Rc<Box<Propagator>>) {
        self.propagators.borrow_mut().push(prop);
    }

    fn add_waiting(&self, var: uint, event: Event, propagator: uint) {
        let mut waiting = self.waiting.borrow_mut();
        if waiting.contains_key(&(var, event)) {
            waiting.get_mut(&(var, event)).push(propagator);
        } else {
            waiting.insert((var, event), vec![propagator]);
        }
    }

    fn del_waiting(&self, var: uint, event: Event, propagator: uint) {
        self.waiting.borrow_mut().get_mut(&(var, event)).remove(propagator);
    }

    fn get_waiting(&self, var: uint, event: Event) -> Vec<uint> {
        let waiting = self.waiting.borrow();
        match waiting.find_copy(&(var, event)) {
            Some(vec) => vec,
            None => Vec::new()
        }
    }
}

#[allow(dead_code)]
impl Domain {
    /// Domain created with initial bounds
    fn new(min: int, max: int) -> Domain {
        Domain {
            dom: RefCell::new(Dom {
                     min: min,
                     max: max,
                     intervals: vec![(min, max)]
                 })
        }
    }

    fn set_min(&self, min: int) {
        let mut dom = self.dom.borrow_mut();
        if min < dom.min { return; }
        if min > dom.max { return; } // TODO failure via conditions
        loop {
            match dom.intervals.get(0) {
                // note that the breaks are for the loop, not the matching
                &(x, _) if min < x => { dom.min = x; break; },
                &(_, y) if min > y => { dom.intervals.shift(); },
                &(_, y) => {
                    dom.min = min;
                    *dom.intervals.get_mut(0) = (min, y);
                    break;
                }
            }
        }
    }

    fn get_min(&self) -> int {
        self.dom.borrow().min
    }

    fn set_max(&self, max: int) {
        let mut dom = self.dom.borrow_mut();
        if max > dom.max { return; }
        if max < dom.min { return; } // TODO failure via conditions
        loop {
            match dom.intervals.last().unwrap() {
                &(_, y) if max > y => { dom.max = y; break; },
                &(x, _) if max < x => { dom.intervals.pop(); },
                &(x, _) => {
                    dom.max = max;
                    *dom.intervals.mut_last().unwrap() = (x, max);
                    break
                }
            }
        }
    }

    fn get_max(&self) -> int {
        self.dom.borrow().max
    }

    fn remove(&self, val: int) {
        let mut dom = self.dom.borrow_mut();
        if val > dom.max || val < dom.min { return; }
        let mut down = 0;
        let mut up = dom.intervals.len();
        let mut test;
        loop {
            test = down + (up - down) / 2;
            match dom.intervals.get(test) {
                &(x, _) if val < x => {
                    if test > down {
                        up = test;
                    } else {
                        break;
                    }
                },
                &(_, y) if val > y => {
                    if test < up - 1 {
                        down = test + 1;
                    } else {
                        break;
                    }
                },
                &(x, y) if val == x && val == y => {
                    dom.intervals.remove(test);
                    break;
                },
                &(x, y) if val == x => {
                    *dom.intervals.get_mut(test) = (x + 1, y);
                    break;
                },
                &(x, y) if val == y => {
                    *dom.intervals.get_mut(test) = (x, y - 1);
                    break;
                },
                &(x, y) => {
                    *dom.intervals.get_mut(test) = (x, val - 1);
                    dom.intervals.insert(test + 1, (val + 1, y));
                    break;
                }
            }
        }
        if test == 0 {
            match dom.intervals.get(test) {
                &(x, _) => dom.min = x
            }
        } else if test == dom.intervals.len() - 1 {
            match dom.intervals.get(test) {
                &(_, y) => dom.max = y
            }
        }
    }
}

impl fmt::Show for Domain {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let dom = self.dom.borrow();
        let mut s = format!("({}, {}) [", dom.min, dom.max);
        for &(min, max) in dom.intervals.iter() {
            s = s + min.to_str() + ".." + max.to_str() + ", ";
        }
        return write!(f, "{}]", s);
    }
}

impl Var {
    pub fn new(model: Rc<Mod>, min: int, max: int, name: &str) -> Rc<FDVar> {
        assert!(min <= max);
        let id = model.vars.borrow().len();
        let v = Rc::new(FDVar {
            model: model.downgrade(),
            id: id,
            name: name.to_string(),
            dom: Domain::new(min, max)
        });
        model.add_var(v.clone());
        v
    }
}

impl FDVar {
    pub fn min(&self) -> int {
        self.dom.get_min()
    }

    pub fn max(&self) -> int {
        self.dom.get_max()
    }

    fn set_min(&self, v: int) -> Vec<uint> {
        if v > self.min() {
            self.dom.set_min(v);
            if self.is_instanciated() {
                self.model.upgrade().unwrap().get_waiting(self.id, Min)
                    // + self.waitingOnIns
            } else {
                self.model.upgrade().unwrap().get_waiting(self.id, Min)
            }
        } else {
            vec![]
        }
    }

    fn set_max(&self, v: int) -> Vec<uint> {
        if v < self.max() {
            self.dom.set_max(v);
            if self.is_instanciated() {
                // self.waitingOnMax + self.waitingOnIns
                self.model.upgrade().unwrap().get_waiting(self.id, Max)
            } else {
                self.model.upgrade().unwrap().get_waiting(self.id, Max)
            }
        } else {
            vec![]
        }
    }

    fn is_instanciated(&self) -> bool {
        self.min() == self.max()
    }
}

impl fmt::Show for FDVar {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} ({})", self.name, self.dom)
    }
}

pub struct LtXYx : Prop {
    x: Rc<FDVar>,
    y: Rc<FDVar>
}

impl LtXYx {
    pub fn new(model: Rc<Mod>, x: Rc<FDVar>, y: Rc<FDVar>) -> Rc<Box<Propagator>> {
        let id = model.propagators.borrow().len();
        let this = LtXYx { model: model.downgrade(), id: id, x: x, y: y };
        this.register();
        this.propagate();
        let p = Rc::new((box this) as Box<Propagator>);
        model.add_prop(p.clone());
        p
    }
}

impl Propagator for LtXYx {
    fn id(&self) -> uint {
        self.id
    }
    fn model(&self) -> Weak<Mod> {
        self.model.clone()
    }

    fn events(&self) -> Vec<(uint, Event)> {
        vec![(self.y.id, Max)]
    }

    fn propagate(&self) -> Vec<uint> {
        if self.x.max() < self.y.min() {
            // entailed
            self.unregister();
            vec![]
        } else if self.x.max() > self.y.max() - 1 {
            //if y.is_instanciated() {
            //   self.unregister();
            //}
            let max = self.y.max() - 1;
            self.x.set_max(max)
        } else {
            vec![]
        }
    }
}

pub struct LtXYy : Prop {
    x: Rc<FDVar>,
    y: Rc<FDVar>
}

impl LtXYy {
    pub fn new(model: Rc<Mod>, x: Rc<FDVar>, y: Rc<FDVar>) -> Rc<Box<Propagator>> {
        let id = model.propagators.borrow().len();
        let this = LtXYy { model: model.downgrade(), id: id, x: x, y: y };
        this.register();
        this.propagate();
        let p = Rc::new((box this) as Box<Propagator>);
        model.add_prop(p.clone());
        p
    }
}

impl Propagator for LtXYy {
    fn id(&self) -> uint {
        self.id
    }
    fn model(&self) -> Weak<Mod> {
        self.model.clone()
    }

    fn events(&self) -> Vec<(uint, Event)> {
        vec![(self.x.id, Min)]
    }

    fn propagate(&self) -> Vec<uint> {
        if self.x.max() < self.y.min() {
            // entailed
            self.unregister();
            vec![]
        } else if self.y.min() < self.x.min() + 1 {
            //if y.is_instanciated() {
            //   self.unregister();
            //}
            let min = self.x.min() + 1;
            self.y.set_min(min)
        } else {
            vec![]
        }
    }
}

#[cfg(test)]
mod tests;
<commit_msg>making Vec<Rc<FDVar>> a field of Prop<commit_after>#![desc = "Constraint Satisfaction in Rust"]
#![license = "MIT"]
#![crate_id = "csar#0.2"]
#![crate_type = "lib"]

#![feature(struct_inherit)]

use std::fmt;
use std::cell::RefCell;
use std::collections::hashmap::HashMap;
use std::rc::{Rc, Weak};

pub struct Mod {
    vars: RefCell<Vec<Rc<FDVar>>>,
    propagators: RefCell<Vec<Rc<Box<Propagator>>>>,
    waiting: RefCell<HashMap<(uint, Event), Vec<uint>>>
}

/// wrapping Mod in an Rc
/// cannot use type Model = Rc<Mod> since that would forbid using impl Model
pub struct Model;

/// Representation of finite domains as a list of intervals, maintaining
/// min and max for easy/quick access
#[deriving(Clone)]
struct Dom {
    min: int,
    max: int,
    intervals: Vec<(int, int)>
}

/// Runtime checked mutability with borrowing
#[deriving(Clone)]
struct Domain {
    dom: RefCell<Dom>
}

trait Propagator {
    fn id(&self) -> uint;
    fn model(&self) -> Weak<Mod>;

    fn events(&self) -> Vec<(uint, Event)>;
    fn propagate(&self) -> Vec<uint>;

    fn register(&self) {
        for &(var, event) in self.events().iter() {
            self.model().upgrade().unwrap().add_waiting(var, event, self.id());
        }
    }

    fn unregister(&self) {
        for &(var, event) in self.events().iter() {
            self.model().upgrade().unwrap().del_waiting(var, event, self.id());
        }
    }
}

pub virtual struct Prop {
    id: uint,
    model: Weak<Mod>,
    vars: Vec<Rc<FDVar>>
}

#[deriving(Clone)]
pub struct FDVar {
    model: Weak<Mod>,
    id: uint,
    name: String,
    dom: Domain
}

/// wrapping FDVar in an Rc
pub struct Var;

#[deriving(Show, Hash, Eq, PartialEq)]
pub enum Event {
    Min,
    Max,
    Ins
}

#[allow(dead_code)]
impl Model {
    fn new() -> Rc<Mod> {
        Rc::new(Mod {
            vars: RefCell::new(Vec::new()),
            propagators: RefCell::new(Vec::new()),
            waiting: RefCell::new(HashMap::new())
        })
    }
}

impl Mod {
    fn add_var(&self, var: Rc<FDVar>) {
        self.vars.borrow_mut().push(var);
    }

    fn add_prop(&self, prop: Rc<Box<Propagator>>) {
        self.propagators.borrow_mut().push(prop);
    }

    fn add_waiting(&self, var: uint, event: Event, propagator: uint) {
        let mut waiting = self.waiting.borrow_mut();
        if waiting.contains_key(&(var, event)) {
            waiting.get_mut(&(var, event)).push(propagator);
        } else {
            waiting.insert((var, event), vec![propagator]);
        }
    }

    fn del_waiting(&self, var: uint, event: Event, propagator: uint) {
        self.waiting.borrow_mut().get_mut(&(var, event)).remove(propagator);
    }

    fn get_waiting(&self, var: uint, event: Event) -> Vec<uint> {
        let waiting = self.waiting.borrow();
        match waiting.find_copy(&(var, event)) {
            Some(vec) => vec,
            None => Vec::new()
        }
    }
}

#[allow(dead_code)]
impl Domain {
    /// Domain created with initial bounds
    fn new(min: int, max: int) -> Domain {
        Domain {
            dom: RefCell::new(Dom {
                     min: min,
                     max: max,
                     intervals: vec![(min, max)]
                 })
        }
    }

    fn set_min(&self, min: int) {
        let mut dom = self.dom.borrow_mut();
        if min < dom.min { return; }
        if min > dom.max { return; } // TODO failure via conditions
        loop {
            match dom.intervals.get(0) {
                // note that the breaks are for the loop, not the matching
                &(x, _) if min < x => { dom.min = x; break; },
                &(_, y) if min > y => { dom.intervals.shift(); },
                &(_, y) => {
                    dom.min = min;
                    *dom.intervals.get_mut(0) = (min, y);
                    break;
                }
            }
        }
    }

    fn get_min(&self) -> int {
        self.dom.borrow().min
    }

    fn set_max(&self, max: int) {
        let mut dom = self.dom.borrow_mut();
        if max > dom.max { return; }
        if max < dom.min { return; } // TODO failure via conditions
        loop {
            match dom.intervals.last().unwrap() {
                &(_, y) if max > y => { dom.max = y; break; },
                &(x, _) if max < x => { dom.intervals.pop(); },
                &(x, _) => {
                    dom.max = max;
                    *dom.intervals.mut_last().unwrap() = (x, max);
                    break
                }
            }
        }
    }

    fn get_max(&self) -> int {
        self.dom.borrow().max
    }

    fn remove(&self, val: int) {
        let mut dom = self.dom.borrow_mut();
        if val > dom.max || val < dom.min { return; }
        let mut down = 0;
        let mut up = dom.intervals.len();
        let mut test;
        loop {
            test = down + (up - down) / 2;
            match dom.intervals.get(test) {
                &(x, _) if val < x => {
                    if test > down {
                        up = test;
                    } else {
                        break;
                    }
                },
                &(_, y) if val > y => {
                    if test < up - 1 {
                        down = test + 1;
                    } else {
                        break;
                    }
                },
                &(x, y) if val == x && val == y => {
                    dom.intervals.remove(test);
                    break;
                },
                &(x, y) if val == x => {
                    *dom.intervals.get_mut(test) = (x + 1, y);
                    break;
                },
                &(x, y) if val == y => {
                    *dom.intervals.get_mut(test) = (x, y - 1);
                    break;
                },
                &(x, y) => {
                    *dom.intervals.get_mut(test) = (x, val - 1);
                    dom.intervals.insert(test + 1, (val + 1, y));
                    break;
                }
            }
        }
        if test == 0 {
            match dom.intervals.get(test) {
                &(x, _) => dom.min = x
            }
        } else if test == dom.intervals.len() - 1 {
            match dom.intervals.get(test) {
                &(_, y) => dom.max = y
            }
        }
    }
}

impl fmt::Show for Domain {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let dom = self.dom.borrow();
        let mut s = format!("({}, {}) [", dom.min, dom.max);
        for &(min, max) in dom.intervals.iter() {
            s = s + min.to_str() + ".." + max.to_str() + ", ";
        }
        return write!(f, "{}]", s);
    }
}

impl Var {
    pub fn new(model: Rc<Mod>, min: int, max: int, name: &str) -> Rc<FDVar> {
        assert!(min <= max);
        let id = model.vars.borrow().len();
        let v = Rc::new(FDVar {
            model: model.downgrade(),
            id: id,
            name: name.to_string(),
            dom: Domain::new(min, max)
        });
        model.add_var(v.clone());
        v
    }
}

impl FDVar {
    pub fn min(&self) -> int {
        self.dom.get_min()
    }

    pub fn max(&self) -> int {
        self.dom.get_max()
    }

    fn set_min(&self, v: int) -> Vec<uint> {
        if v > self.min() {
            self.dom.set_min(v);
            if self.is_instanciated() {
                self.model.upgrade().unwrap().get_waiting(self.id, Min)
                    // + self.waitingOnIns
            } else {
                self.model.upgrade().unwrap().get_waiting(self.id, Min)
            }
        } else {
            vec![]
        }
    }

    fn set_max(&self, v: int) -> Vec<uint> {
        if v < self.max() {
            self.dom.set_max(v);
            if self.is_instanciated() {
                // self.waitingOnMax + self.waitingOnIns
                self.model.upgrade().unwrap().get_waiting(self.id, Max)
            } else {
                self.model.upgrade().unwrap().get_waiting(self.id, Max)
            }
        } else {
            vec![]
        }
    }

    fn is_instanciated(&self) -> bool {
        self.min() == self.max()
    }
}

impl fmt::Show for FDVar {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} ({})", self.name, self.dom)
    }
}

pub struct LtXYx : Prop;

impl LtXYx {
    pub fn new(model: Rc<Mod>, x: Rc<FDVar>, y: Rc<FDVar>) -> Rc<Box<Propagator>> {
        let id = model.propagators.borrow().len();
        let this = LtXYx { model: model.downgrade(), id: id, vars: vec![x, y]};
        this.register();
        this.propagate();
        let p = Rc::new((box this) as Box<Propagator>);
        model.add_prop(p.clone());
        p
    }

    fn x(&self) -> Rc<FDVar> {
        self.vars.get(0).clone()
    }

    fn y(&self) -> Rc<FDVar> {
        self.vars.get(1).clone()
    }
}

impl Propagator for LtXYx {
    fn id(&self) -> uint {
        self.id
    }
    fn model(&self) -> Weak<Mod> {
        self.model.clone()
    }

    fn events(&self) -> Vec<(uint, Event)> {
        vec![(self.y().id, Max)]
    }

    fn propagate(&self) -> Vec<uint> {
        if self.x().max() < self.y().min() {
            // entailed
            self.unregister();
            vec![]
        } else if self.x().max() > self.y().max() - 1 {
            //if y.is_instanciated() {
            //   self.unregister();
            //}
            let max = self.y().max() - 1;
            self.x().set_max(max)
        } else {
            vec![]
        }
    }
}

pub struct LtXYy : Prop;

impl LtXYy {
    pub fn new(model: Rc<Mod>, x: Rc<FDVar>, y: Rc<FDVar>) -> Rc<Box<Propagator>> {
        let id = model.propagators.borrow().len();
        let this = LtXYy { model: model.downgrade(), id: id, vars: vec![x, y]};
        this.register();
        this.propagate();
        let p = Rc::new((box this) as Box<Propagator>);
        model.add_prop(p.clone());
        p
    }

    fn x(&self) -> Rc<FDVar> {
        self.vars.get(0).clone()
    }

    fn y(&self) -> Rc<FDVar> {
        self.vars.get(1).clone()
    }
}

impl Propagator for LtXYy {
    fn id(&self) -> uint {
        self.id
    }
    fn model(&self) -> Weak<Mod> {
        self.model.clone()
    }

    fn events(&self) -> Vec<(uint, Event)> {
        vec![(self.x().id, Min)]
    }

    fn propagate(&self) -> Vec<uint> {
        if self.x().max() < self.y().min() {
            // entailed
            self.unregister();
            vec![]
        } else if self.y().min() < self.x().min() + 1 {
            //if y.is_instanciated() {
            //   self.unregister();
            //}
            let min = self.x().min() + 1;
            self.y().set_min(min)
        } else {
            vec![]
        }
    }
}

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


<commit_before>// Copyright 2017 Dave Goodell <dave@goodell.io>
// See LICENSE file for license terms (MIT license)

// TODO:
// - package the Alfred workflow properly, including icon
// - add a README.md
// - add "<icon>hex.png</icon>" (etc.) to xml output
// - add tests for the binary's behavior
// - convert all signed integer arithmetic to use "wrapping_add()" and friends to avoid
//   undefined behavior?
// - toggle type width/signedness with shift/option/ctrl/cmd modifier keys?

extern crate rustc_serialize;
extern crate docopt;

use std::process;
use docopt::Docopt;

const USAGE: &'static str = "
Usage: alfred-rust-calc [--alfred2] [--] <expr>...
       alfred-rust-calc (-h | --help)

Options:
    -h,--help    Show this screen.
    --alfred2    Emit Alfred2-style workflow XML.
";

mod calc {
    include!(concat!(env!("OUT_DIR"), "/calc.rs"));
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_alfred2: bool,
    arg_expr: Vec<String>,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let expr_str = args.arg_expr.join(" ");

    if args.flag_alfred2 {
        match calc::expr(&*expr_str) {
            Ok(expr) => {
                // the Alfred2 Script Filter XML output format is documented here:
                // https://www.alfredapp.com/help/workflows/inputs/script-filter/xml/
        print!("\
<?xml version=\"1.0\"?>
<items>
  <item arg=\"{0}\" valid=\"YES\" autocomplete=\"{0}\" type=\"default\">
    <title>{0}</title>
    <subtitle>(decimal)</subtitle>
  </item>
  <item arg=\"0x{0:x}\" valid=\"YES\" autocomplete=\"0x{0:x}\" type=\"default\">
    <title>0x{0:x}</title>
    <subtitle>(hexadecimal)</subtitle>
  </item>
  <item arg=\"0o{0:o}\" valid=\"YES\" autocomplete=\"0o{0:o}\" type=\"default\">
    <title>0o{0:o}</title>
    <subtitle>(octal)</subtitle>
  </item>
  <item arg=\"0b{0:b}\" valid=\"YES\" autocomplete=\"0b{0:b}\" type=\"default\">
    <title>0b{0:o}</title>
    <subtitle>(binary)</subtitle>
  </item>
</items>
", expr);
            },
            Err(err) => {
                println!("Error: {}", err);
                process::exit(1);
            }
        }
    } else {
        match calc::expr(&*expr_str) {
            Ok(expr) => {
                println!("{:}", expr);
            },
            Err(err) => {
                println!("Error: {}", err);
                process::exit(1);
            }
        }
    }
}
<commit_msg>emit valid XML for parse errors in --alfred2 mode<commit_after>// Copyright 2017 Dave Goodell <dave@goodell.io>
// See LICENSE file for license terms (MIT license)

// TODO:
// - package the Alfred workflow properly, including icon
// - add a README.md
// - add "<icon>hex.png</icon>" (etc.) to xml output
// - add tests for the binary's behavior
// - convert all signed integer arithmetic to use "wrapping_add()" and friends to avoid
//   undefined behavior?
// - toggle type width/signedness with shift/option/ctrl/cmd modifier keys?

extern crate rustc_serialize;
extern crate docopt;

use std::process;
use docopt::Docopt;

const USAGE: &'static str = "
Usage: alfred-rust-calc [--alfred2] [--] <expr>...
       alfred-rust-calc (-h | --help)

Options:
    -h,--help    Show this screen.
    --alfred2    Emit Alfred2-style workflow XML.
";

mod calc {
    include!(concat!(env!("OUT_DIR"), "/calc.rs"));
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_alfred2: bool,
    arg_expr: Vec<String>,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let expr_str = args.arg_expr.join(" ");

    if args.flag_alfred2 {
        match calc::expr(&*expr_str) {
            Ok(expr) => {
                // the Alfred2 Script Filter XML output format is documented here:
                // https://www.alfredapp.com/help/workflows/inputs/script-filter/xml/
                print!("\
<?xml version=\"1.0\"?>
<items>
  <item arg=\"{0}\" valid=\"YES\" autocomplete=\"{0}\" type=\"default\">
    <title>{0}</title>
    <subtitle>(decimal)</subtitle>
  </item>
  <item arg=\"0x{0:x}\" valid=\"YES\" autocomplete=\"0x{0:x}\" type=\"default\">
    <title>0x{0:x}</title>
    <subtitle>(hexadecimal)</subtitle>
  </item>
  <item arg=\"0o{0:o}\" valid=\"YES\" autocomplete=\"0o{0:o}\" type=\"default\">
    <title>0o{0:o}</title>
    <subtitle>(octal)</subtitle>
  </item>
  <item arg=\"0b{0:b}\" valid=\"YES\" autocomplete=\"0b{0:b}\" type=\"default\">
    <title>0b{0:o}</title>
    <subtitle>(binary)</subtitle>
  </item>
</items>
", expr);
            },
            Err(err) => {
                print!("\
<?xml version=\"1.0\"?>
<items>
  <item arg=\"{0}\" valid=\"NO\" autocomplete=\"{0}\" type=\"default\">
    <title>{0}</title>
    <subtitle><![CDATA[{1}]]></subtitle>
  </item>
</items>
", "...", err);
                // don't "process::exit(1)" here, it makes Alfred mildly angry
            }
        }
    } else {
        match calc::expr(&*expr_str) {
            Ok(expr) => {
                println!("{:}", expr);
            },
            Err(err) => {
                println!("Error: {}", err);
                process::exit(1);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::ffi::OsStr;

fn exec_runner<S: AsRef<OsStr>>(args: &[S]) {
    use std::os::unix::process::CommandExt;
    let err = std::process::Command::new(&args[0]).args(&args[1..]).exec();
    println!("error: {}", err);
    if let Some(err) = err.raw_os_error() {
        std::process::exit(err);
    }
    std::process::exit(-1)
}

fn main() {
    let home = std::env::home_dir().unwrap();

    let mut sbt_jar = std::path::PathBuf::from(home);
    sbt_jar.push(".sbt/launchers/0.13.13/sbt-launch.jar");
    let sbt_jar = sbt_jar;

    let java_cmd = OsStr::new("java");
    let extra_jvm_opts = [OsStr::new("-Xms512m"), OsStr::new("-Xmx1536m"), OsStr::new("-Xss2m")];
    let java_args: [&OsStr; 0] = [];
    let sbt_commands: [&OsStr; 0] = [];
    let residual_args = [OsStr::new("shell")];

    let mut exec_args: Vec<&OsStr> = Vec::new();
    exec_args.push(java_cmd);
    exec_args.extend_from_slice(&extra_jvm_opts);
    exec_args.extend_from_slice(&java_args);
    exec_args.extend_from_slice(&[OsStr::new("-jar"), sbt_jar.as_os_str()]);
    exec_args.extend_from_slice(&sbt_commands);
    exec_args.extend_from_slice(&residual_args);
    let exec_args = exec_args;

    exec_runner(&exec_args)
}
<commit_msg>Start defining sbt_launch_dir/jar_file/etc<commit_after>use std::ffi::OsStr;
use std::path::PathBuf;

fn home() -> PathBuf {
    std::env::home_dir().unwrap()
}

fn sbt_launch_dir() -> PathBuf {
    let mut p = PathBuf::from(home());
    p.push(".sbt/launchers");
    p
}

fn jar_file(sbt_version: &str) -> PathBuf {
    let mut p = PathBuf::from(sbt_launch_dir());
    p.push(sbt_version);
    p.push("sbt-launch.jar");
    p
}

fn sbt_version() -> String {
    "0.13.13".to_string()
}

fn sbt_jar() -> PathBuf {
    jar_file(&sbt_version())
}

fn exec_runner<S: AsRef<OsStr>>(args: &[S]) {
    use std::os::unix::process::CommandExt;
    let err = std::process::Command::new(&args[0]).args(&args[1..]).exec();
    println!("error: {}", err);
    if let Some(err) = err.raw_os_error() {
        std::process::exit(err);
    }
    std::process::exit(-1)
}

fn main() {
    let sbt_jar = sbt_jar();

    let java_cmd = OsStr::new("java");
    let extra_jvm_opts = [OsStr::new("-Xms512m"), OsStr::new("-Xmx1536m"), OsStr::new("-Xss2m")];
    let java_args: [&OsStr; 0] = [];
    let sbt_commands: [&OsStr; 0] = [];
    let residual_args = [OsStr::new("shell")];

    let mut exec_args: Vec<&OsStr> = Vec::new();
    exec_args.push(java_cmd);
    exec_args.extend_from_slice(&extra_jvm_opts);
    exec_args.extend_from_slice(&java_args);
    exec_args.extend_from_slice(&[OsStr::new("-jar"), sbt_jar.as_os_str()]);
    exec_args.extend_from_slice(&sbt_commands);
    exec_args.extend_from_slice(&residual_args);
    let exec_args = exec_args;

    exec_runner(&exec_args)
}
<|endoftext|>


<commit_before>#![feature(convert, test, core, core_str_ext)]
extern crate test;
extern crate core;

use core::str::StrExt;

#[derive(Clone)]
pub struct Entity {
    start: usize,
	end: usize,
    html: String
}

fn render(text: &str, entities: &mut Vec<Entity>) -> String {
	let mut sb = String::new();
	entities.sort_by(|e1, e2| e1.start.cmp(&e2.start) );

  let mut pos = 0 as usize;
	for entity in entities {
		sb.push_str(text.slice_chars(pos, entity.start));
		sb.push_str(entity.html.as_str());
		pos = entity.end;
	}
	sb.push_str(text.slice_chars(pos, text.len()));
	sb
}

fn main() {
	let result = classic(&mut entities());
	println!("Result: {}", result);
}

pub fn classic(entities: &mut Vec<Entity>) -> String {
    render("Attend to hear 6 stellar #mobile #startups at #OF12 Entrepreneur Idol show 2day,  http://t.co/HtzEMgAC @TiEcon @sv_entrepreneur @500!", entities)
}

pub fn entities() -> Vec<Entity> {
	let entities = vec![
	Entity {start: 82, end: 102, html:"<http://t.co/HtzEMgAC>".to_string()},
	Entity {start: 128, end: 132, html:"<@500>".to_string()},
	Entity {start: 25, end: 32, html:"<#mobile>".to_string()},
	Entity {start: 33, end: 42, html:"<#startups>".to_string()},
	Entity {start: 111, end: 127, html:"<@sv_entrepreneur>".to_string()},
	Entity {start: 46, end: 51, html:"<#OF12>".to_string()},
	Entity {start: 103, end: 110, html:"<@TiEcon>".to_string()},
	];
	entities
}

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

    #[test]
	fn correctness() {
		let result = "Attend to hear 6 stellar <#mobile> <#startups> at <#OF12> Entrepreneur Idol show 2day,  <http://t.co/HtzEMgAC> <@TiEcon> <@sv_entrepreneur> <@500>!";
		assert_eq!(result, classic(&mut entities()))
	}

    #[bench]
	fn bench_replacement(b: &mut Bencher) {
	   	let entities = &mut entities();
		b.iter(|| {
		    classic(entities)
		});
	}
}
<commit_msg>Ascii optimization. Support codepoints. Tweak benchmarking.<commit_after>#![feature(convert, test, core, core_str_ext, vec_push_all)]
extern crate test;
extern crate core;

use core::str::StrExt;

pub static ASCII_TEXT: &'static str = "Attend to hear 6 stellar #mobile #startups at #OF12 Entrepreneur Idol show 2day,  http://t.co/HtzEMgAC @TiEcon @sv_entrepreneur @500!";
pub static UNICODE_TEXT: &'static str = "Attend 次次 hear 6 stellar #mobile #startups at #OF12 Entrepreneur Idol show 2day,  http://t.co/HtzEMgAC @TiEcon @sv_entrepreneur @500!";

#[derive(Clone)]
pub struct Entity {
    start: usize,
    end: usize,
    html: String
}

#[derive(Clone)]
pub struct DecodedEntity {
    start: usize,
    end: usize,
    html: Vec<char>,
}

unsafe fn render_ascii(text: &str, entities: &mut Vec<Entity>) -> String {
    let mut sb = String::new();
    entities.sort_by(|e1, e2| e1.start.cmp(&e2.start) );

    let mut pos = 0 as usize;
    for entity in entities {
        sb.push_str(text.slice_unchecked(pos, entity.start));
        sb.push_str(entity.html.as_str());
        pos = entity.end;
    }
    sb.push_str(text.slice_unchecked(pos, text.len()));
    sb
}

fn render(text: &Vec<char>, entities: &mut Vec<DecodedEntity>) -> String {
    // Initial capacity based on observation that entities tend to add just 2 chars
    let mut sb: Vec<char> = Vec::with_capacity(text.len()+entities.len()*2);
    entities.sort_by(|e1, e2| e1.start.cmp(&e2.start) );

    let mut pos = 0 as usize;
    for entity in entities {
        sb.push_all(&text[pos..entity.start]);
        sb.push_all(&*entity.html);
        pos = entity.end;
    }
    sb.push_all(&text[pos..text.len()]);
    sb.into_iter().collect()
}

fn main() {
    let result = classic(&ASCII_TEXT.chars().collect(), &mut decoded_entities());
    println!("Result: {}", result);
}

pub fn classic_ascii(text: &str, entities: &mut Vec<Entity>) -> String {
    unsafe {
        render_ascii(text, entities)
    }
}

pub fn classic(text: &Vec<char>, entities: &mut Vec<DecodedEntity>) -> String {
    render(&text, entities)
}

pub fn entities() -> Vec<Entity> {
    let entities = vec![
    Entity {start: 82, end: 102, html:"<http://t.co/HtzEMgAC>".to_string()},
    Entity {start: 128, end: 132, html:"<@500>".to_string()},
    Entity {start: 25, end: 32, html:"<#mobile>".to_string()},
    Entity {start: 33, end: 42, html:"<#startups>".to_string()},
    Entity {start: 111, end: 127, html:"<@sv_entrepreneur>".to_string()},
    Entity {start: 46, end: 51, html:"<#OF12>".to_string()},
    Entity {start: 103, end: 110, html:"<@TiEcon>".to_string()},
    ];
    entities
}

pub fn decoded_entities() -> Vec<DecodedEntity> {
    entities().into_iter().map( |e: Entity|
        DecodedEntity {start: e.start, end: e.end, html: e.html.chars().collect()}
    ).collect()
}

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

    #[test]
    fn correctness_ascii() {
        let result = "Attend to hear 6 stellar <#mobile> <#startups> at <#OF12> Entrepreneur Idol show 2day,  <http://t.co/HtzEMgAC> <@TiEcon> <@sv_entrepreneur> <@500>!";
        assert_eq!(result, classic_ascii(ASCII_TEXT, &mut entities()))
    }

    #[test]
    fn correctness() {
        let result = "Attend 次次 hear 6 stellar <#mobile> <#startups> at <#OF12> Entrepreneur Idol show 2day,  <http://t.co/HtzEMgAC> <@TiEcon> <@sv_entrepreneur> <@500>!";
        assert_eq!(result, classic(&UNICODE_TEXT.chars().collect(), &mut decoded_entities()))
    }

    #[bench]
    fn bench_replacement_ascii(b: &mut Bencher) {
        let entities = &mut entities();
        b.iter(|| {
            classic_ascii(ASCII_TEXT, entities)
        });
    }

    #[bench]
    fn bench_replacement(b: &mut Bencher) {
        let entities = &mut decoded_entities();
        let decoded_text = UNICODE_TEXT.chars().collect();
        b.iter(|| {
            classic(&decoded_text, entities)
        });
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate git2;

use git2::{Repository, Remote, Error, Index, Commit};
use git2::build::CheckoutBuilder;
use clap::{Arg, App};
use std::path::Path;
use std::collections::{HashMap, HashSet};

const E_NO_GIT_REPO : i32 = 1;

fn main() {
    let exit_code = real_main();
    std::process::exit(exit_code);
}

fn real_main() -> i32 {
    let options = App::new("git-submerge")
                          .version("0.1")
                          .author("Alexander Batischev <eual.jp@gmail.com>")
                          .about("Merges git submodule into the repo as if it was that way from the start")
                          .arg(Arg::with_name("SUBMODULE_DIR")
                               .help("The submodule to merge")
                               .required(true)
                               .index(1))
                          .get_matches();
    // We can safely use unwrap() here because if the option is empty, Clap would've already shown
    // the error message and aborted.
    let submodule_dir = options.value_of("SUBMODULE_DIR").unwrap();
    println!("Merging {}...", submodule_dir);

    let repo = match Repository::open(".") {
        Ok(repo) => repo,
        Err(e) => {
            eprintln!("Couldn't find Git repo in the current directory: {}", e.message());
            return E_NO_GIT_REPO;
        },
    };

    // 1. Add submodule as a remote
    let mut remote = add_remote(&repo, submodule_dir).expect("Couldn't add a remote");
    // 2. Fetch submodule's history
    remote.fetch(&[], None, None).expect("Couldn't fetch submodule's history");
    // 3. Find out submodule's HEAD commit id
    let submodules = repo.submodules().expect("Couldn't obtain a list of submodules");
    let submodule_path = Path::new(submodule_dir);
    // TODO: use repo.find_submodule() here
    let submodule = submodules.iter().find(|s| s.path() == submodule_path)
        .expect("Couldn't find the submodule with expected path");
    let submodule_head = submodule.head_id()
        .expect("Couldn't obtain submodule's HEAD");
    // 4. Rewrite submodule branch's history, moving everything under a single directory named
    //    after the submodule
    let mut revwalk = repo.revwalk().expect("Couldn't obtain RevWalk object for the repo");
    // TODO: make sure "topological" here means "parents are always visited before their children".
    // We need that in order to be sure that our old-to-new-ids map always contains everything we
    // need it to contain.
    revwalk.set_sorting(git2::SORT_REVERSE | git2::SORT_TOPOLOGICAL);
    // TODO: push all branches and tags, not just HEAD
    revwalk.push(submodule_head).expect("Couldn't add submodule's HEAD to RevWalk list");

    let mut old_id_to_new = HashMap::new();

    for maybe_oid in revwalk {
        match maybe_oid {
            Ok(oid) => {
                // 4.1. Extract the tree
                let commit = repo.find_commit(oid).expect(&format!("Couldn't get a commit with ID {}", oid));
                let tree = commit.tree().expect(&format!("Couldn't obtain the tree of a commit with ID {}", oid));
                let mut old_index = Index::new().expect("Couldn't create an in-memory index for commit");
                let mut new_index = Index::new().expect("Couldn't create an in-memory index");
                old_index.read_tree(&tree).expect(&format!("Couldn't read the commit {} into index", oid));
                // 4.2. Obtain the new tree, where everything from the old one is moved under
                //   a directory named after the submodule
                for entry in old_index.iter() {
                    let mut new_entry = entry;

                    // TODO: what mode, owner, mtime etc. does the newly created dir get?
                    let mut new_path = String::from(submodule_dir);
                    new_path += "/";
                    new_path += &String::from_utf8(new_entry.path).expect("Failed to convert a path to str");

                    new_entry.path = new_path.into_bytes();
                    new_index.add(&new_entry).expect("Couldn't add an entry to the index");
                }
                let tree_id = new_index.write_tree_to(&repo).expect("Couldn't write the index into a tree");
                old_id_to_new.insert(tree.id(), tree_id);
                let tree = repo.find_tree(tree_id).expect("Couldn't retrieve the tree we just created");
                // 4.3. Create new commit with the new tree
                let parents = {
                    let mut p: Vec<Commit> = Vec::new();
                    for parent_id in commit.parent_ids() {
                        let new_parent_id = old_id_to_new[&parent_id];
                        let parent = repo.find_commit(new_parent_id).expect("Couldn't find parent commit by its id");
                        p.push(parent);
                    };
                    p
                };

                let mut parents_refs: Vec<&Commit> = Vec::new();
                for i in 0 .. parents.len() {
                    parents_refs.push(&parents[i]);
                }
                let new_commit_id = repo.commit(
                    None,
                    &commit.author(),
                    &commit.committer(),
                    &commit.message().expect("Couldn't retrieve commit's message"),
                    &tree,
                    &parents_refs[..])
                    .expect("Failed to commit");
                // 4.4. Update the map with the new commit's ID
                old_id_to_new.insert(oid, new_commit_id);
            },
            Err(e) =>
                eprintln!("Error walking the submodule's history: {:?}", e),
        }
    };
    // 7. Remove submodule's remote
    repo.remote_delete(submodule_dir).expect("Couldn't remove submodule's remote");
    // 8. Run through master's history, doing two things:
    revwalk = repo.revwalk().expect("Couldn't obtain RevWalk object for the repo");
    revwalk.set_sorting(git2::SORT_REVERSE | git2::SORT_TOPOLOGICAL);
    let head = repo.head().expect("Couldn't obtain repo's HEAD");
    let head_id = head.target().expect("Couldn't resolve repo's HEAD to a commit ID");
    // TODO: push all branches and tags, not just HEAD
    revwalk.push(head_id).expect("Couldn't add repo's HEAD to RevWalk list");

    for maybe_oid in revwalk {
        match maybe_oid {
            Ok(oid) => {
                // 8.1 updating the tree to contain the relevant tree from submodule
                let commit = repo.find_commit(oid).expect(&format!("Couldn't get a commit with ID {}", oid));
                let tree = commit.tree().expect(&format!("Couldn't obtain the tree of a commit with ID {}", oid));

                let submodule_subdir = match tree.get_path(submodule_path) {
                    Ok(tree) => tree,
                    Err(e) => {
                        if e.code() == git2::ErrorCode::NotFound
                            && e.class() == git2::ErrorClass::Tree
                        {
                            // It's okay. The tree lacks the subtree corresponding to the
                            // submodule. In other words, the commit doesn't include the submodule.
                            // That's totally fine. Let's map it into itself and move on.
                            old_id_to_new.insert(oid, oid);
                            continue;
                        } else {
                            // Unexpected error; let's report it and abort the program
                            // TODO: clean things up before aborting
                            panic!("Error getting submodule's subdir from the tree: {:?}", e);
                        };
                    },
                };

                // **INVARIANT**: if we got this far, current commit contains a submodule and
                // should be rewritten

                let submodule_commit_id = submodule_subdir.id();
                let new_submodule_commit_id = old_id_to_new[&submodule_commit_id];
                let submodule_commit = repo.find_commit(new_submodule_commit_id).expect("Couldn't obtain submodule's commit");
                let subtree_id = submodule_commit.tree()
                    .and_then(|t| t.get_path(submodule_path))
                    .and_then(|te| Ok(te.id()))
                    .expect("Couldn't obtain submodule's subtree ID");

                let mut treebuilder = repo.treebuilder(Some(&tree)).expect("Couldn't create TreeBuilder");
                treebuilder.remove(submodule_path).expect("Couldn't remove submodule path from TreeBuilder");
                treebuilder.insert(submodule_path, subtree_id, 0o040000).expect("Couldn't add submodule as a subdir to TreeBuilder");
                let new_tree_id = treebuilder.write().expect("Couldn't write TreeBuilder into a Tree");
                let new_tree = repo.find_tree(new_tree_id).expect("Couldn't read back the Tree we just wrote");

                // 8.2 in commits that used to update the submodule, add a parent pointing to
                //   appropriate commit in new submodule history
                let mut parent_subtree_ids = HashSet::new();
                for parent in commit.parents() {
                    let parent_tree = parent.tree().expect("Couldn't obtain parent's tree");
                    let parent_subdir_tree_id = parent_tree.get_path(submodule_path).and_then(|x| Ok(x.id()));

                    match parent_subdir_tree_id {
                        Ok(id) => {
                            parent_subtree_ids.insert(id);
                            ()
                        },
                        Err(e) => {
                            if e.code() == git2::ErrorCode::NotFound
                                && e.class() == git2::ErrorClass::Tree
                            {
                                // It's okay; carry on.
                                continue;
                            } else {
                                panic!("Error getting submodule's subdir from the tree: {:?}", e);
                            };
                        },
                    }
                };
                // true if
                //
                // o--o--o--A--
                //             `,-C
                //  o--o--o--B-
                //
                //  or
                //
                // o--o--o--o--A--B
                //
                // false if
                //
                // o--o--o--A--
                //             `,-A
                //  o--o--o--B-
                //
                //  or
                //
                // o--o--o--A--
                //             `,-B
                //  o--o--o--B-
                let submodule_updated: bool = !parent_subtree_ids.contains(&submodule_commit_id);

                // rewrite the parents if the submodule was updated
                let parents = {
                    let mut p: Vec<Commit> = Vec::new();
                    for parent_id in commit.parent_ids() {
                        let actual_parent_id = old_id_to_new[&parent_id];
                        let parent = repo.find_commit(actual_parent_id).expect("Couldn't find parent commit by its id");
                        p.push(parent);
                    };

                    if submodule_updated {
                        p.push(submodule_commit);
                    }

                    p
                };

                let mut parents_refs: Vec<&Commit> = Vec::new();
                for i in 0 .. parents.len() {
                    parents_refs.push(&parents[i]);
                }
                let new_commit_id = repo.commit(
                    None,
                    &commit.author(),
                    &commit.committer(),
                    &commit.message().expect("Couldn't retrieve commit's message"),
                    &new_tree,
                    &parents_refs[..])
                    .expect("Failed to commit");

                old_id_to_new.insert(oid, new_commit_id);
            },
            Err(e) =>
                eprintln!("Error walking the submodule's history: {:?}", e),
        }
    };

    // It's safe to do force-reset because we checked at the beginning and the repo was clean
    let mut checkoutbuilder = CheckoutBuilder::new();
    checkoutbuilder.force();

    let updated_id = old_id_to_new[&head_id];
    let object = repo.find_object(updated_id, None).expect("Couldn't look up an object at which HEAD points");
    repo.reset(&object, git2::ResetType::Hard, Some(&mut checkoutbuilder)).expect("Couldn't run force-reset");

    0 // An exit code indicating success
}

fn add_remote<'a>(repo : &'a Repository, submodule_name : &str) -> Result<Remote<'a>, Error> {
    // TODO: randomize remote's name or at least check that it doesn't exist already
    // Maybe use remote_anonymous()
    let url = String::from("./") + submodule_name;
    repo.remote(submodule_name, &url)
}
<commit_msg>Add one more TODO<commit_after>extern crate clap;
extern crate git2;

use git2::{Repository, Remote, Error, Index, Commit};
use git2::build::CheckoutBuilder;
use clap::{Arg, App};
use std::path::Path;
use std::collections::{HashMap, HashSet};

const E_NO_GIT_REPO : i32 = 1;

fn main() {
    let exit_code = real_main();
    std::process::exit(exit_code);
}

fn real_main() -> i32 {
    let options = App::new("git-submerge")
                          .version("0.1")
                          .author("Alexander Batischev <eual.jp@gmail.com>")
                          // TODO: get this in synch with Cargo.toml and README
                          .about("Merges git submodule into the repo as if it was that way from the start")
                          .arg(Arg::with_name("SUBMODULE_DIR")
                               .help("The submodule to merge")
                               .required(true)
                               .index(1))
                          .get_matches();
    // We can safely use unwrap() here because if the option is empty, Clap would've already shown
    // the error message and aborted.
    let submodule_dir = options.value_of("SUBMODULE_DIR").unwrap();
    println!("Merging {}...", submodule_dir);

    let repo = match Repository::open(".") {
        Ok(repo) => repo,
        Err(e) => {
            eprintln!("Couldn't find Git repo in the current directory: {}", e.message());
            return E_NO_GIT_REPO;
        },
    };

    // 1. Add submodule as a remote
    let mut remote = add_remote(&repo, submodule_dir).expect("Couldn't add a remote");
    // 2. Fetch submodule's history
    remote.fetch(&[], None, None).expect("Couldn't fetch submodule's history");
    // 3. Find out submodule's HEAD commit id
    let submodules = repo.submodules().expect("Couldn't obtain a list of submodules");
    let submodule_path = Path::new(submodule_dir);
    // TODO: use repo.find_submodule() here
    let submodule = submodules.iter().find(|s| s.path() == submodule_path)
        .expect("Couldn't find the submodule with expected path");
    let submodule_head = submodule.head_id()
        .expect("Couldn't obtain submodule's HEAD");
    // 4. Rewrite submodule branch's history, moving everything under a single directory named
    //    after the submodule
    let mut revwalk = repo.revwalk().expect("Couldn't obtain RevWalk object for the repo");
    // TODO: make sure "topological" here means "parents are always visited before their children".
    // We need that in order to be sure that our old-to-new-ids map always contains everything we
    // need it to contain.
    revwalk.set_sorting(git2::SORT_REVERSE | git2::SORT_TOPOLOGICAL);
    // TODO: push all branches and tags, not just HEAD
    revwalk.push(submodule_head).expect("Couldn't add submodule's HEAD to RevWalk list");

    let mut old_id_to_new = HashMap::new();

    for maybe_oid in revwalk {
        match maybe_oid {
            Ok(oid) => {
                // 4.1. Extract the tree
                let commit = repo.find_commit(oid).expect(&format!("Couldn't get a commit with ID {}", oid));
                let tree = commit.tree().expect(&format!("Couldn't obtain the tree of a commit with ID {}", oid));
                let mut old_index = Index::new().expect("Couldn't create an in-memory index for commit");
                let mut new_index = Index::new().expect("Couldn't create an in-memory index");
                old_index.read_tree(&tree).expect(&format!("Couldn't read the commit {} into index", oid));
                // 4.2. Obtain the new tree, where everything from the old one is moved under
                //   a directory named after the submodule
                for entry in old_index.iter() {
                    let mut new_entry = entry;

                    // TODO: what mode, owner, mtime etc. does the newly created dir get?
                    let mut new_path = String::from(submodule_dir);
                    new_path += "/";
                    new_path += &String::from_utf8(new_entry.path).expect("Failed to convert a path to str");

                    new_entry.path = new_path.into_bytes();
                    new_index.add(&new_entry).expect("Couldn't add an entry to the index");
                }
                let tree_id = new_index.write_tree_to(&repo).expect("Couldn't write the index into a tree");
                old_id_to_new.insert(tree.id(), tree_id);
                let tree = repo.find_tree(tree_id).expect("Couldn't retrieve the tree we just created");
                // 4.3. Create new commit with the new tree
                let parents = {
                    let mut p: Vec<Commit> = Vec::new();
                    for parent_id in commit.parent_ids() {
                        let new_parent_id = old_id_to_new[&parent_id];
                        let parent = repo.find_commit(new_parent_id).expect("Couldn't find parent commit by its id");
                        p.push(parent);
                    };
                    p
                };

                let mut parents_refs: Vec<&Commit> = Vec::new();
                for i in 0 .. parents.len() {
                    parents_refs.push(&parents[i]);
                }
                let new_commit_id = repo.commit(
                    None,
                    &commit.author(),
                    &commit.committer(),
                    &commit.message().expect("Couldn't retrieve commit's message"),
                    &tree,
                    &parents_refs[..])
                    .expect("Failed to commit");
                // 4.4. Update the map with the new commit's ID
                old_id_to_new.insert(oid, new_commit_id);
            },
            Err(e) =>
                eprintln!("Error walking the submodule's history: {:?}", e),
        }
    };
    // 7. Remove submodule's remote
    repo.remote_delete(submodule_dir).expect("Couldn't remove submodule's remote");
    // 8. Run through master's history, doing two things:
    revwalk = repo.revwalk().expect("Couldn't obtain RevWalk object for the repo");
    revwalk.set_sorting(git2::SORT_REVERSE | git2::SORT_TOPOLOGICAL);
    let head = repo.head().expect("Couldn't obtain repo's HEAD");
    let head_id = head.target().expect("Couldn't resolve repo's HEAD to a commit ID");
    // TODO: push all branches and tags, not just HEAD
    revwalk.push(head_id).expect("Couldn't add repo's HEAD to RevWalk list");

    for maybe_oid in revwalk {
        match maybe_oid {
            Ok(oid) => {
                // 8.1 updating the tree to contain the relevant tree from submodule
                let commit = repo.find_commit(oid).expect(&format!("Couldn't get a commit with ID {}", oid));
                let tree = commit.tree().expect(&format!("Couldn't obtain the tree of a commit with ID {}", oid));

                let submodule_subdir = match tree.get_path(submodule_path) {
                    Ok(tree) => tree,
                    Err(e) => {
                        if e.code() == git2::ErrorCode::NotFound
                            && e.class() == git2::ErrorClass::Tree
                        {
                            // It's okay. The tree lacks the subtree corresponding to the
                            // submodule. In other words, the commit doesn't include the submodule.
                            // That's totally fine. Let's map it into itself and move on.
                            old_id_to_new.insert(oid, oid);
                            continue;
                        } else {
                            // Unexpected error; let's report it and abort the program
                            // TODO: clean things up before aborting
                            panic!("Error getting submodule's subdir from the tree: {:?}", e);
                        };
                    },
                };

                // **INVARIANT**: if we got this far, current commit contains a submodule and
                // should be rewritten

                let submodule_commit_id = submodule_subdir.id();
                let new_submodule_commit_id = old_id_to_new[&submodule_commit_id];
                let submodule_commit = repo.find_commit(new_submodule_commit_id).expect("Couldn't obtain submodule's commit");
                let subtree_id = submodule_commit.tree()
                    .and_then(|t| t.get_path(submodule_path))
                    .and_then(|te| Ok(te.id()))
                    .expect("Couldn't obtain submodule's subtree ID");

                let mut treebuilder = repo.treebuilder(Some(&tree)).expect("Couldn't create TreeBuilder");
                treebuilder.remove(submodule_path).expect("Couldn't remove submodule path from TreeBuilder");
                treebuilder.insert(submodule_path, subtree_id, 0o040000).expect("Couldn't add submodule as a subdir to TreeBuilder");
                let new_tree_id = treebuilder.write().expect("Couldn't write TreeBuilder into a Tree");
                let new_tree = repo.find_tree(new_tree_id).expect("Couldn't read back the Tree we just wrote");

                // 8.2 in commits that used to update the submodule, add a parent pointing to
                //   appropriate commit in new submodule history
                let mut parent_subtree_ids = HashSet::new();
                for parent in commit.parents() {
                    let parent_tree = parent.tree().expect("Couldn't obtain parent's tree");
                    let parent_subdir_tree_id = parent_tree.get_path(submodule_path).and_then(|x| Ok(x.id()));

                    match parent_subdir_tree_id {
                        Ok(id) => {
                            parent_subtree_ids.insert(id);
                            ()
                        },
                        Err(e) => {
                            if e.code() == git2::ErrorCode::NotFound
                                && e.class() == git2::ErrorClass::Tree
                            {
                                // It's okay; carry on.
                                continue;
                            } else {
                                panic!("Error getting submodule's subdir from the tree: {:?}", e);
                            };
                        },
                    }
                };
                // true if
                //
                // o--o--o--A--
                //             `,-C
                //  o--o--o--B-
                //
                //  or
                //
                // o--o--o--o--A--B
                //
                // false if
                //
                // o--o--o--A--
                //             `,-A
                //  o--o--o--B-
                //
                //  or
                //
                // o--o--o--A--
                //             `,-B
                //  o--o--o--B-
                let submodule_updated: bool = !parent_subtree_ids.contains(&submodule_commit_id);

                // rewrite the parents if the submodule was updated
                let parents = {
                    let mut p: Vec<Commit> = Vec::new();
                    for parent_id in commit.parent_ids() {
                        let actual_parent_id = old_id_to_new[&parent_id];
                        let parent = repo.find_commit(actual_parent_id).expect("Couldn't find parent commit by its id");
                        p.push(parent);
                    };

                    if submodule_updated {
                        p.push(submodule_commit);
                    }

                    p
                };

                let mut parents_refs: Vec<&Commit> = Vec::new();
                for i in 0 .. parents.len() {
                    parents_refs.push(&parents[i]);
                }
                let new_commit_id = repo.commit(
                    None,
                    &commit.author(),
                    &commit.committer(),
                    &commit.message().expect("Couldn't retrieve commit's message"),
                    &new_tree,
                    &parents_refs[..])
                    .expect("Failed to commit");

                old_id_to_new.insert(oid, new_commit_id);
            },
            Err(e) =>
                eprintln!("Error walking the submodule's history: {:?}", e),
        }
    };

    // It's safe to do force-reset because we checked at the beginning and the repo was clean
    let mut checkoutbuilder = CheckoutBuilder::new();
    checkoutbuilder.force();

    let updated_id = old_id_to_new[&head_id];
    let object = repo.find_object(updated_id, None).expect("Couldn't look up an object at which HEAD points");
    repo.reset(&object, git2::ResetType::Hard, Some(&mut checkoutbuilder)).expect("Couldn't run force-reset");

    0 // An exit code indicating success
}

fn add_remote<'a>(repo : &'a Repository, submodule_name : &str) -> Result<Remote<'a>, Error> {
    // TODO: randomize remote's name or at least check that it doesn't exist already
    // Maybe use remote_anonymous()
    let url = String::from("./") + submodule_name;
    repo.remote(submodule_name, &url)
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate getopts;

use getopts::Options;
use rustc_serialize::json;

use std::env;
use std::process;
use std::io::{self, Write};

mod error;
use error::Error;

mod gist;
use gist::{Gist, GistFile};

const DEFAULT_GIST_NAME: &'static str = "Untitled";
const E_HELP: i32  = 1;
const E_FATAL: i32 = 2;

#[derive(RustcDecodable)]
struct GistResponse {
    html_url: String,
}

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

fn fatal(err: error::Error) {
    io::stderr().write(format!("Error: {}", err).as_bytes()).ok();
    process::exit(E_FATAL);
}

fn parse_args(args : Vec<String>) -> getopts::Matches {
    let mut opts = Options::new();
    opts.optopt("f", "file", "set file name", "NAME");
    opts.optflag("p", "public", "make public");
    opts.optflag("a", "anonymous", "make anonymous");
    opts.optflag("h", "help", "print this");

    let params = match opts.parse(&args[1..]) {
        Ok(m)  => m,
        Err(f) => panic!(f.to_string())
    };
    if params.opt_present("h") {
        print_usage(&args[0].clone(), opts);
    }

    params
}

fn main() {
    let params = parse_args(env::args().collect());
    let is_public = params.opt_present("p");
    let is_anonymous = params.opt_present("a");
    let filename = match params.opt_str("f") {
        Some(name) => name,
        None       => DEFAULT_GIST_NAME.to_string(),
    };
    let mut gist = Gist::new(is_public, is_anonymous);

    // Read from stdin, unless we receive a bunch of filenames.
    if params.free.is_empty() {
        let mut g = GistFile::new(filename);
        if g.read_stdin().is_ok() { gist.add_file(g); }
    } else {
        for file_param in params.free {
            let mut g = GistFile::new(file_param);
            match g.read_file() {
                Ok(_)  => gist.add_file(g),
                Err(e) => fatal(e)
            }
        }
    }

    if !gist.is_empty() {
        match gist.create() {
            Ok(r) => {
                let gist: GistResponse = json::decode(&r).unwrap();
                println!("{}", gist.html_url);
            },
            Err(e) => fatal(e)
        }
    }
}
<commit_msg>Use getopts.short_usage<commit_after>extern crate rustc_serialize;
extern crate getopts;

use getopts::Options;
use rustc_serialize::json;

use std::env;
use std::process;
use std::io::{self, Write};

mod error;
use error::Error;

mod gist;
use gist::{Gist, GistFile};

const DEFAULT_GIST_NAME: &'static str = "Untitled";
const E_HELP: i32  = 1;
const E_FATAL: i32 = 2;

#[derive(RustcDecodable)]
struct GistResponse {
    html_url: String,
}

fn print_usage(program: &str, opts: Options) {
    let brief = opts.short_usage(program);
    print!("{}", opts.usage(&brief));
    process::exit(E_HELP);
}

fn fatal(err: error::Error) {
    io::stderr().write(format!("Error: {}", err).as_bytes()).ok();
    process::exit(E_FATAL);
}

fn parse_args(args : Vec<String>) -> getopts::Matches {
    let mut opts = Options::new();
    opts.optopt("f", "file", "set file name", "NAME");
    opts.optflag("p", "public", "make public");
    opts.optflag("a", "anonymous", "make anonymous");
    opts.optflag("h", "help", "print this");

    let params = opts.parse(&args[1..]).ok().expect("Unknown flag.");
    if params.opt_present("h") {
        print_usage(&args[0].clone(), opts);
    }

    params
}

fn main() {
    let params = parse_args(env::args().collect());
    let is_public = params.opt_present("p");
    let is_anonymous = params.opt_present("a");
    let filename = match params.opt_str("f") {
        Some(name) => name,
        None       => DEFAULT_GIST_NAME.to_string(),
    };
    let mut gist = Gist::new(is_public, is_anonymous);

    // Read from stdin, unless we receive a bunch of filenames.
    if params.free.is_empty() {
        let mut g = GistFile::new(filename);
        if g.read_stdin().is_ok() { gist.add_file(g); }
    } else {
        for file_param in params.free {
            let mut g = GistFile::new(file_param);
            match g.read_file() {
                Ok(_)  => gist.add_file(g),
                Err(e) => fatal(e)
            }
        }
    }

    if !gist.is_empty() {
        match gist.create() {
            Ok(r) => {
                let gist: GistResponse = json::decode(&r).unwrap();
                println!("{}", gist.html_url);
            },
            Err(e) => fatal(e)
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;
#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate enum_primitive;
extern crate num_traits;
#[macro_use]
extern crate clap;
use clap::{Arg, App};

use num_traits::FromPrimitive;

use std::fs::File;
use std::io::Read;
use std::io;

// Needed because of https://github.com/Geal/nom/issues/345
use nom::{alpha, multispace, digit, IResult};

#[derive(Debug,PartialEq,Eq)]
struct Word {
    word: String,
    score: u8
}

#[derive(Debug,PartialEq,Eq)]
enum RawWord {
    Junk,
    Word(Word)
}

fn score(word: &str) -> u8 {
    let mut result = 0;
    for letter in word.chars() {
        result += match letter {
            // Scrabble scores from https://en.wikipedia.org/wiki/Scrabble_letter_distributions#English
            'a'|'e'|'i'|'o'|'u'|'n'|'r'|'t'|'l'|'s' => 1,
            'd'|'g' => 2,
            'b'|'c'|'m'|'p' => 3,
            'f'|'h'|'v'|'w'|'y' => 4,
            'k' => 5,
            'j'|'x' => 8,
            'q'|'z' => 10,
            _ => 0
        }
    }
    return result;
}

named!(get_word<RawWord>,
    alt!(
        alpha => { |word| {
                let word = String::from(std::str::from_utf8(word).unwrap());
                let sc = score(&word);
                RawWord::Word(Word{word:word, score:sc})
            }
        } |
        alt!(multispace | digit | is_a!(", !;:.()\"'-?|&"))  => { |_| RawWord::Junk }
    )
);

fn io_str_error<T: std::error::Error + std::marker::Send + std::marker::Sync + 'static>(se: T) -> std::io::Error {
    return io::Error::new(io::ErrorKind::Other, se);
}

fn get_words(filename: &str) -> Result<Vec<Word>, io::Error> {
    let mut f = try!(File::open(filename));
    let mut buffer = Vec::new();
    try!(f.read_to_end(&mut buffer));
    let mut result = Vec::new();
    let mut remaining = buffer.as_slice();
    loop {
        match get_word(remaining) {
            IResult::Done(further, word) => {
                if let RawWord::Word(x) = word {
                    result.push(x);
                }
                remaining = further;
            }
            rest => {
                match rest {
                    nom::IResult::Error(nom::verbose_errors::Err::Position(_, characters)) => {
                        let location = std::str::from_utf8(characters).map_err(io_str_error)?;
                        return Err(io::Error::new(io::ErrorKind::InvalidData, format!("Don't know how to parse: {}", location.chars().take(50).collect::<String>())));
                    },
                    _ => {}
                };

                //rest.to_result().map_err(io_str_error)?;
            }
        }
        if remaining.len() == 0 {
            break;
        }
    }
    return Ok(result);
}

enum_from_primitive! {
    #[allow(non_camel_case_types)]
    #[derive(Debug, PartialEq)]
    enum Command {
        PUSH = 5,
        DISCARD = 6,
        ADD = 7,
        INPUT = 8,
        OUTPUT = 9,
        SUBTRACT = 10,
        SWAP = 11,
        DUP = 12,
        SKIP_AHEAD_ZERO = 13,
        SKIP_AHEAD_NONZERO = 14,
        SKIP_BACK_ZERO = 15,
        SKIP_BACK_NONZERO = 16,
        STOP = 17,
        NOP,
    }
}

fn action(act: u8) -> Command {
    return match Command::from_u8(act) {
        Some(val) => val,
        None => Command::NOP
    }
}

fn run_beatnik(words: Vec<Word>) {
    let mut stack: Vec<u8> = Vec::new();
    let mut pc: usize = 0;
    loop {
        debug!("'{}' = {} ({:?})", words[pc].word, words[pc].score, action(words[pc].score));
        match action(words[pc].score) {
            Command::PUSH => {
                pc +=1;
                debug!("Pushing {} to stack", words[pc].score);
                stack.push(words[pc].score);
            }
            Command::DISCARD => {stack.pop().expect("stack value");},
            Command::ADD => {
                let x = stack.pop().expect("first value");
                let y = stack.pop().expect("second value");
                stack.push(x.wrapping_add(y));
            }
            Command::INPUT => {
                // FIXME: read from stdin
                stack.push('a' as u8);
            }
            Command::OUTPUT => print!("{}", stack.pop().expect("character on stack") as char),
            Command::SUBTRACT => {
                let x = stack.pop().expect("first value");
                let y = stack.pop().expect("second value");
                stack.push(y.wrapping_sub(x));
            }
            Command::SWAP => {
                let x = stack.pop().expect("first value");
                let y = stack.pop().expect("second value");
                stack.push(x);
                stack.push(y);
            }
            Command::DUP => {
                let x = stack.pop().expect("first value");
                stack.push(x);
                stack.push(x);
            }
            Command::SKIP_AHEAD_NONZERO => {
                let check = stack.pop().expect("check value");
                pc +=1;
                if check != 0 {
                    pc += words[pc].score as usize;
                }
            }
            Command::SKIP_AHEAD_ZERO => {
                let check = stack.pop().expect("check value");
                pc +=1;
                if check == 0 {
                    pc += words[pc].score as usize;
                }
            }
            Command::SKIP_BACK_ZERO => {
                let check = stack.pop().expect("check value");
                if check == 0 {
                    pc -= words[pc+1].score as usize;
                }
            }
            Command::SKIP_BACK_NONZERO => {
                let check = stack.pop().expect("check value");
                if check != 0 {
                    pc -= words[pc+1].score as usize;
                }
            }
            Command::STOP => break,
            Command::NOP => {}
        }
        pc += 1;
        if pc == words.len() {
            break;
        }
    }
    debug!("Stack: {:?}", stack);
}

fn output_wottasquare(words: Vec<Word>) {
    for word in words {
        println!("[{}:{:?}]", word.score, action(word.score));
    }
}

fn main() {
    env_logger::init().unwrap();
    let matches = App::new("peacenik")
                          .version("1.0")
                          .author("Tom Parker <palfrey@tevp.net>")
                          .about("Beatnik interpreter")
                          .arg(Arg::with_name("output-wottasquare")
                               .short("w")
                               .long("output-wottasquare")
                               .help("Switches into wottasquare output mode"))
                          .arg(Arg::with_name("input-wottasquare")
                               .short("i")
                               .long("input-wottasquare")
                               .help("Switches into wottasquare input mode"))
                          .arg(Arg::with_name("INPUT")
                               .help("Sets the input file to use")
                               .required(true)
                               .index(1))
                          .get_matches();
    let words = if matches.is_present("input-wottasquare") {
        (Vec::new())
    }
    else {
        match get_words(matches.value_of("INPUT").unwrap()) {
            Ok(val) => val,
            Err(err) => {
                if err.kind() == io::ErrorKind::InvalidData {
                    println!("{}", err.get_ref().unwrap());
                    std::process::exit(-1);
                }
                else {
                    panic!("Error during parsing: {}", err);
                }
            }
        }
    };
    if matches.is_present("output-wottasquare") {
        output_wottasquare(words);
    }
    else {
        run_beatnik(words);
    }
}<commit_msg>Wottasquare import support<commit_after>#[macro_use]
extern crate nom;
#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate enum_primitive;
extern crate num_traits;
#[macro_use]
extern crate clap;
use clap::{Arg, App};

use num_traits::FromPrimitive;

use std::fs::File;
use std::io::Read;
use std::io;
use std::str::FromStr;

// Needed because of https://github.com/Geal/nom/issues/345
use nom::{alpha, multispace, digit, IResult, newline};

#[derive(Debug,PartialEq,Eq)]
struct Word {
    word: String,
    score: u8
}

#[derive(Debug,PartialEq,Eq)]
enum RawWord {
    Junk,
    Word(Word)
}

fn score(word: &str) -> u8 {
    let mut result = 0;
    for letter in word.chars() {
        result += match letter {
            // Scrabble scores from https://en.wikipedia.org/wiki/Scrabble_letter_distributions#English
            'a'|'e'|'i'|'o'|'u'|'n'|'r'|'t'|'l'|'s' => 1,
            'd'|'g' => 2,
            'b'|'c'|'m'|'p' => 3,
            'f'|'h'|'v'|'w'|'y' => 4,
            'k' => 5,
            'j'|'x' => 8,
            'q'|'z' => 10,
            _ => 0
        }
    }
    return result;
}

named!(get_word<RawWord>,
    alt!(
        alpha => { |word| {
                let word = String::from(std::str::from_utf8(word).unwrap());
                let sc = score(&word);
                RawWord::Word(Word{word:word, score:sc})
            }
        } |
        alt!(multispace | digit | is_a!(", !;:.()\"'-?|&"))  => { |_| RawWord::Junk }
    )
);

named!(get_wotta<RawWord>,
    map!(tuple!(
        tag!("["),
        digit,
        opt!(
            tuple!(
                tag!(":"),
                is_not!("]")
            )
        ),
        tag!("]"),
        opt!(newline)
    ), |(_, raw_score, comment_opt, _, _)|{
        let word = String::from(std::str::from_utf8((comment_opt as Option<(&[u8], &[u8])>).unwrap().1).unwrap());
        RawWord::Word(Word{word: word, score: u8::from_str(std::str::from_utf8(raw_score).unwrap()).unwrap()})
        })
);

fn io_str_error<T: std::error::Error + std::marker::Send + std::marker::Sync + 'static>(se: T) -> std::io::Error {
    return io::Error::new(io::ErrorKind::Other, se);
}

fn get_words_core<F>(filename: &str, mut function: F) -> Result<Vec<Word>, io::Error>
    where F: FnMut(&[u8]) -> nom::IResult<&[u8], RawWord>
{
    let mut f = try!(File::open(filename));
    let mut buffer = Vec::new();
    try!(f.read_to_end(&mut buffer));
    let mut result = Vec::new();
    let mut remaining = buffer.as_slice();
    loop {
        match function(remaining) {
            IResult::Done(further, word) => {
                if let RawWord::Word(x) = word {
                    result.push(x);
                }
                remaining = further;
            }
            rest => {
                match rest {
                    nom::IResult::Error(nom::verbose_errors::Err::Position(_, characters)) => {
                        let location = std::str::from_utf8(characters).map_err(io_str_error)?;
                        return Err(io::Error::new(io::ErrorKind::InvalidData, format!("Don't know how to parse: {}", location.chars().take(50).collect::<String>())));
                    },
                    _ => {}
                };
            }
        }
        if remaining.len() == 0 {
            break;
        }
    }
    return Ok(result);
}

fn get_words(filename: &str) -> Result<Vec<Word>, io::Error> {
    return get_words_core(filename, get_word);
}

fn get_wottas(filename: &str) -> Result<Vec<Word>, io::Error> {
    return get_words_core(filename, get_wotta);
}

enum_from_primitive! {
    #[allow(non_camel_case_types)]
    #[derive(Debug, PartialEq)]
    enum Command {
        PUSH = 5,
        DISCARD = 6,
        ADD = 7,
        INPUT = 8,
        OUTPUT = 9,
        SUBTRACT = 10,
        SWAP = 11,
        DUP = 12,
        SKIP_AHEAD_ZERO = 13,
        SKIP_AHEAD_NONZERO = 14,
        SKIP_BACK_ZERO = 15,
        SKIP_BACK_NONZERO = 16,
        STOP = 17,
        NOP,
    }
}

fn action(act: u8) -> Command {
    return match Command::from_u8(act) {
        Some(val) => val,
        None => Command::NOP
    }
}

fn run_beatnik(words: Vec<Word>) {
    let mut stack: Vec<u8> = Vec::new();
    let mut pc: usize = 0;
    loop {
        debug!("'{}' = {} ({:?})", words[pc].word, words[pc].score, action(words[pc].score));
        match action(words[pc].score) {
            Command::PUSH => {
                pc +=1;
                debug!("Pushing {} to stack", words[pc].score);
                stack.push(words[pc].score);
            }
            Command::DISCARD => {stack.pop().expect("stack value");},
            Command::ADD => {
                let x = stack.pop().expect("first value");
                let y = stack.pop().expect("second value");
                stack.push(x.wrapping_add(y));
            }
            Command::INPUT => {
                // FIXME: read from stdin
                stack.push('a' as u8);
            }
            Command::OUTPUT => print!("{}", stack.pop().expect("character on stack") as char),
            Command::SUBTRACT => {
                let x = stack.pop().expect("first value");
                let y = stack.pop().expect("second value");
                stack.push(y.wrapping_sub(x));
            }
            Command::SWAP => {
                let x = stack.pop().expect("first value");
                let y = stack.pop().expect("second value");
                stack.push(x);
                stack.push(y);
            }
            Command::DUP => {
                let x = stack.pop().expect("first value");
                stack.push(x);
                stack.push(x);
            }
            Command::SKIP_AHEAD_NONZERO => {
                let check = stack.pop().expect("check value");
                pc +=1;
                if check != 0 {
                    pc += words[pc].score as usize;
                }
            }
            Command::SKIP_AHEAD_ZERO => {
                let check = stack.pop().expect("check value");
                pc +=1;
                if check == 0 {
                    pc += words[pc].score as usize;
                }
            }
            Command::SKIP_BACK_ZERO => {
                let check = stack.pop().expect("check value");
                if check == 0 {
                    pc -= words[pc+1].score as usize;
                }
            }
            Command::SKIP_BACK_NONZERO => {
                let check = stack.pop().expect("check value");
                if check != 0 {
                    pc -= words[pc+1].score as usize;
                }
            }
            Command::STOP => break,
            Command::NOP => {}
        }
        pc += 1;
        if pc == words.len() {
            break;
        }
    }
    debug!("Stack: {:?}", stack);
}

fn output_wottasquare(words: Vec<Word>) {
    for word in words {
        println!("[{}:{:?}]", word.score, action(word.score));
    }
}

fn main() {
    env_logger::init().unwrap();
    let matches = App::new("peacenik")
                          .version("1.0")
                          .author("Tom Parker <palfrey@tevp.net>")
                          .about("Beatnik interpreter")
                          .arg(Arg::with_name("output-wottasquare")
                               .short("w")
                               .long("output-wottasquare")
                               .help("Switches into wottasquare output mode"))
                          .arg(Arg::with_name("input-wottasquare")
                               .short("i")
                               .long("input-wottasquare")
                               .help("Switches into wottasquare input mode"))
                          .arg(Arg::with_name("INPUT")
                               .help("Sets the input file to use")
                               .required(true)
                               .index(1))
                          .get_matches();
    let items = if matches.is_present("input-wottasquare") {
        get_wottas(matches.value_of("INPUT").unwrap())
    }
    else {
        get_words(matches.value_of("INPUT").unwrap())
    };
    let words = match items {
        Ok(val) => val,
        Err(err) => {
            if err.kind() == io::ErrorKind::InvalidData {
                println!("{}", err.get_ref().unwrap());
                std::process::exit(-1);
            }
            else {
                panic!("Error during parsing: {}", err);
            }
        }
    };
    if matches.is_present("output-wottasquare") {
        output_wottasquare(words);
    }
    else {
        run_beatnik(words);
    }
}<|endoftext|>


<commit_before>#![feature(tuple_indexing)]
#![feature(phase)]
#[phase(plugin, link)] extern crate log;
extern crate native;

use memory::Memory;
use cpu::Cpu;

mod memory;
mod ops;
mod extensions;
mod cpu;

fn main() {
    let mut memory = Memory::new(65536);
    let mut cpu = Cpu::new(&mut memory);

    loop {
        let clock_cycle = cpu.tick();
    }

}
<commit_msg>Fix for lastest rust<commit_after>#![feature(tuple_indexing)]
#![feature(phase)]
#[phase(plugin, link)] extern crate log;

use memory::Memory;
use cpu::Cpu;

mod memory;
mod ops;
mod extensions;
mod cpu;

fn main() {
    let mut memory = Memory::new(65536);
    let mut cpu = Cpu::new(&mut memory);

    loop {
        let clock_cycle = cpu.tick();
    }

}
<|endoftext|>


<commit_before>use std::slice;

extern crate rustfft;

use rustfft::num_complex::Complex;

struct Color {
    r: u8,
    g: u8,
    b: u8,
    a: u8
}

struct Surface<'a> {
    pub buf: &'a mut [u8],
    pub width: usize,
    pub height: usize
}

impl<'a> Surface<'a> {
    pub unsafe fn new(buf: *mut u8, width: usize, height: usize) -> Surface<'a> {
        Surface {
            buf: slice::from_raw_parts_mut(buf, width * height * 4),
            width: width,
            height: height
        }
    }

    pub fn clear(&mut self, color: Color) {
        let mut i = 0;
        for _ in 0..(self.width * self.height) {
            self.buf[i+0] = color.r;
            self.buf[i+1] = color.g;
            self.buf[i+2] = color.b;
            self.buf[i+3] = color.a;
            i += 4;
        }
    }
}

#[no_mangle]
pub unsafe fn add_one(ptr: *const u32) -> u32 {
    *ptr + 1
}

#[no_mangle]
pub unsafe fn draw_spectro(audio_buf: *const f32, audio_len: usize,
                           gfx_buf: *mut u8,
                           gfx_width: usize, gfx_height: usize) {
    analyze_internal(slice::from_raw_parts(audio_buf, audio_len));

    let mut surface = Surface::new(gfx_buf, gfx_width, gfx_height);
    surface.clear(Color { r: 0, g: 0, b: 0, a: 255 });
}

fn analyze_internal(buf: &[f32]) {
    println!("{} of {} samples has energy",
             buf.iter().fold(0, |count, sample| if *sample == 0.0 { count } else { count + 1 } ),
             buf.len());

    let mut input = Vec::new();
    for sample in buf {
        input.push(Complex { re: *sample, im: 0.0 });
    }
    let mut output = vec![Complex { re: 0.0, im: 0.0 }; buf.len()];

    let mut planner = rustfft::FFTplanner::new(false);
    let fft = planner.plan_fft(buf.len());
    fft.process(&mut input, &mut output);
}

// When exporting other functions explicitly, main is not exported at all.
fn main() {
    println!("rust: main. NO CALLS HERE");
}
<commit_msg>Very simple and wrong frequency spectrum drawing.<commit_after>use std::f32;
use std::slice;

extern crate rustfft;

use rustfft::num_complex::Complex;

struct Color {
    r: u8,
    g: u8,
    b: u8,
    a: u8
}

struct Surface<'a> {
    pub buf: &'a mut [u8],
    pub width: usize,
    pub height: usize
}

impl<'a> Surface<'a> {
    pub unsafe fn new(buf: *mut u8, width: usize, height: usize) -> Surface<'a> {
        Surface {
            buf: slice::from_raw_parts_mut(buf, width * height * 4),
            width: width,
            height: height
        }
    }

    pub fn clear(&mut self, color: Color) {
        let mut i = 0;
        for _ in 0..(self.width * self.height) {
            self.buf[i+0] = color.r;
            self.buf[i+1] = color.g;
            self.buf[i+2] = color.b;
            self.buf[i+3] = color.a;
            i += 4;
        }
    }

    pub fn point(&mut self, x: usize, y: usize, color: Color) {
        let i = y * self.width + x;
        self.buf[i+0] = color.r;
        self.buf[i+1] = color.g;
        self.buf[i+2] = color.b;
        self.buf[i+3] = color.a;
    }
}

#[no_mangle]
pub unsafe fn add_one(ptr: *const u32) -> u32 {
    *ptr + 1
}

#[no_mangle]
pub unsafe fn draw_spectro(audio_buf: *const f32, audio_len: usize,
                           gfx_buf: *mut u8, gfx_width: usize, gfx_height: usize) {
    let mut surface = Surface::new(gfx_buf, gfx_width, gfx_height);
    draw_spectro_internal(slice::from_raw_parts(audio_buf, audio_len),
                          &mut surface);
}

fn draw_spectro_internal(buf: &[f32], surface: &mut Surface) {
    println!("{} of {} samples has energy",
             buf.iter().fold(0, |count, sample| if *sample == 0.0 { count } else { count + 1 } ),
             buf.len());

    let mut input = Vec::new();
    for sample in buf {
        input.push(Complex { re: *sample, im: 0.0 });
    }
    let mut output = vec![Complex { re: 0.0, im: 0.0 }; buf.len()];

    let mut planner = rustfft::FFTplanner::new(false);
    let fft = planner.plan_fft(buf.len());
    fft.process(&mut input, &mut output);

    let mut dbs = Vec::new();

    for value in &output {
        dbs.push(10f32 * (value.re * value.re + value.im * value.im).log10() / 10f32.log10());
    }

    let min_db = dbs.iter().cloned().fold(f32::NAN, f32::min);
    let max_db = dbs.iter().cloned().fold(f32::NAN, f32::max);

    surface.clear(Color { r: 0, g: 0, b: 0, a: 255 });

    for x in 0..surface.width {
        let db = dbs[((x as f64 / surface.width as f64) * output.len() as f64) as usize];
        let scaled = (db - min_db) / (max_db - min_db);
        let y = (scaled * surface.height as f32) as usize;

        surface.point(x, y, Color { r: 255, g: 255, b: 255, a: 255 });
    }
}

// When exporting other functions explicitly, main is not exported at all.
fn main() {
    println!("rust: main. NO CALLS HERE");
}
<|endoftext|>