<commit_before>use std::{cmp::min, fs::File, io, mem, num::Wrapping, path::PathBuf, time::Duration};

use clap::Parser;
use pgn_reader::{BufferedReader, Color, RawHeader, SanPlus, Skip, Visitor};
use rand::{distributions::OpenClosed01, rngs::SmallRng, Rng, SeedableRng};
use serde::Serialize;
use serde_with::{serde_as, DisplayFromStr, SpaceSeparator, StringWithSeparator};

const BATCH_SIZE: usize = 100;

#[derive(Debug, Serialize, Copy, Clone)]
#[serde(rename_all = "camelCase")]
enum Speed {
    UltraBullet,
    Bullet,
    Blitz,
    Rapid,
    Classical,
    Correspondence,
}

impl Speed {
    fn from_seconds_and_increment(seconds: u64, increment: u64) -> Speed {
        let total = seconds + 40 * increment;

        if total < 30 {
            Speed::UltraBullet
        } else if total < 180 {
            Speed::Bullet
        } else if total < 480 {
            Speed::Blitz
        } else if total < 1500 {
            Speed::Rapid
        } else if total < 21_600 {
            Speed::Classical
        } else {
            Speed::Correspondence
        }
    }

    fn from_bytes(bytes: &[u8]) -> Result<Speed, ()> {
        if bytes == b"-" {
            return Ok(Speed::Correspondence);
        }

        let mut parts = bytes.splitn(2, |ch| *ch == b'+');
        let seconds = btoi::btou(parts.next().ok_or(())?).map_err(|_| ())?;
        let increment = btoi::btou(parts.next().ok_or(())?).map_err(|_| ())?;
        Ok(Speed::from_seconds_and_increment(seconds, increment))
    }
}

struct Importer {
    endpoint: String,
    filename: PathBuf,
    client: reqwest::blocking::Client,
    rng: SmallRng,
    spinner_idx: Wrapping<usize>,

    current: Game,
    skip: bool,
    batch: Vec<Game>,
}

#[serde_as]
#[derive(Default, Serialize, Debug)]
struct Game {
    variant: Option<String>,
    speed: Option<Speed>,
    fen: Option<String>,
    id: Option<String>,
    date: Option<String>,
    white: Player,
    black: Player,
    #[serde_as(as = "Option<DisplayFromStr>")]
    winner: Option<Color>,
    #[serde_as(as = "StringWithSeparator<SpaceSeparator, SanPlus>")]
    moves: Vec<SanPlus>,
}

#[derive(Default, Serialize, Debug)]
struct Player {
    name: Option<String>,
    rating: Option<u16>,
}

impl Importer {
    fn new(endpoint: &str, filename: PathBuf) -> Importer {
        Importer {
            endpoint: endpoint.to_owned(),
            filename,
            client: reqwest::blocking::Client::builder()
                .timeout(Duration::from_secs(60))
                .build()
                .expect("client"),
            rng: SmallRng::from_seed([
                0x19, 0x29, 0xab, 0x17, 0xc6, 0xfa, 0xb0, 0xe9, 0x4b, 0x44, 0xd8, 0x07, 0x09, 0xbf,
                0x1d, 0x87, 0xbd, 0xd8, 0xb3, 0x2f, 0xe1, 0xe2, 0xa0, 0x1a, 0x9e, 0x30, 0x98, 0xd7,
                0xef, 0xd5, 0x7a, 0x1d,
            ]),
            spinner_idx: Wrapping(0),
            current: Game::default(),
            skip: false,
            batch: Vec::with_capacity(BATCH_SIZE),
        }
    }

    pub fn send(&mut self) {
        // println!("{}", serde_json::to_string(&self.batch).expect("serialize"));

        let res = self
            .client
            .put(format!("{}/import/lichess", self.endpoint))
            .json(&self.batch)
            .send()
            .expect("send batch");

        self.spinner_idx += Wrapping(1);
        let spinner = &['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];

        println!(
            "{} {:?}: {}: {} - {}",
            spinner[self.spinner_idx.0 % spinner.len()],
            self.filename,
            self.batch
                .last()
                .and_then(|g| g.date.as_ref())
                .unwrap_or(&String::new()),
            res.status(),
            res.text().expect("decode response")
        );

        self.batch.clear();
    }
}

impl Visitor for Importer {
    type Result = ();

    fn begin_game(&mut self) {
        self.skip = false;
        self.current = Game::default();
    }

    fn header(&mut self, key: &[u8], value: RawHeader<'_>) {
        if key == b"White" {
            self.current.white.name = Some(value.decode_utf8().expect("White").into_owned());
        } else if key == b"Black" {
            self.current.black.name = Some(value.decode_utf8().expect("Black").into_owned());
        } else if key == b"WhiteElo" {
            if value.as_bytes() != b"?" {
                self.current.white.rating = Some(btoi::btoi(value.as_bytes()).expect("WhiteElo"));
            }
        } else if key == b"BlackElo" {
            if value.as_bytes() != b"?" {
                self.current.black.rating = Some(btoi::btoi(value.as_bytes()).expect("BlackElo"));
            }
        } else if key == b"TimeControl" {
            self.current.speed = Some(Speed::from_bytes(value.as_bytes()).expect("TimeControl"));
        } else if key == b"Variant" {
            self.current.variant = Some(value.decode_utf8().expect("Variant").into_owned());
        } else if key == b"Date" || key == b"UTCDate" {
            self.current.date = Some(value.decode_utf8().expect("Date").into_owned());
        } else if key == b"WhiteTitle" || key == b"BlackTitle" {
            if value.as_bytes() == b"BOT" {
                self.skip = true;
            }
        } else if key == b"Site" {
            self.current.id = Some(
                String::from_utf8(
                    value
                        .as_bytes()
                        .rsplitn(2, |ch| *ch == b'/')
                        .next()
                        .expect("Site")
                        .to_owned(),
                )
                .expect("Site"),
            );
        } else if key == b"Result" {
            match value.as_bytes() {
                b"1-0" => self.current.winner = Some(Color::White),
                b"0-1" => self.current.winner = Some(Color::Black),
                b"1/2-1/2" => self.current.winner = None,
                _ => self.skip = true,
            }
        } else if key == b"FEN" {
            if value.as_bytes() == b"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" {
                // https://github.com/ornicar/lichess-db/issues/40
                self.current.fen = None;
            } else {
                self.current.fen = Some(value.decode_utf8().expect("FEN").into_owned());
            }
        }
    }

    fn end_headers(&mut self) -> Skip {
        let rating =
            (self.current.white.rating.unwrap_or(0) + self.current.black.rating.unwrap_or(0)) / 2;

        let standard = self
            .current
            .variant
            .as_ref()
            .map_or(true, |name| name == "Standard");

        let probability = if standard {
            match self.current.speed.unwrap_or(Speed::Correspondence) {
                Speed::Correspondence | Speed::Classical => 1.00,

                _ if rating >= 2500 => 1.00,

                Speed::Rapid if rating >= 2200 => 1.00,
                Speed::Rapid if rating >= 2000 => 0.50,
                Speed::Rapid if rating >= 1800 => 0.28,
                Speed::Rapid if rating >= 1600 => 0.24,

                Speed::Blitz if rating >= 2200 => 0.24,
                Speed::Blitz if rating >= 2000 => 0.11,
                Speed::Blitz if rating >= 1600 => 0.08,

                Speed::Bullet if rating >= 2200 => 0.30,
                Speed::Bullet if rating >= 2000 => 0.17,
                Speed::Bullet if rating >= 1600 => 0.11,

                Speed::UltraBullet => 1.00,

                _ => 0.02,
            }
        } else {
            // variant games
            if rating >= 1600 {
                1.00
            } else {
                0.50
            }
        };

        let accept = min(
            self.current.white.rating.unwrap_or(0),
            self.current.black.rating.unwrap_or(0),
        ) >= 1501
            && probability >= self.rng.sample(OpenClosed01)
            && !self.skip;

        self.skip = !accept;
        Skip(self.skip)
    }

    fn san(&mut self, san: SanPlus) {
        self.current.moves.push(san);
    }

    fn begin_variation(&mut self) -> Skip {
        Skip(true) // stay in the mainline
    }

    fn end_game(&mut self) {
        if !self.skip {
            self.batch
                .push(mem::replace(&mut self.current, Default::default()));

            if self.batch.len() >= BATCH_SIZE {
                self.send();
            }
        }
    }
}

#[derive(Parser)]
struct Args {
    #[clap(long, default_value = "http://localhost:9002")]
    endpoint: String,
    pgns: Vec<PathBuf>,
}

fn main() -> Result<(), io::Error> {
    let args = Args::parse();

    for arg in args.pgns {
        let file = File::open(&arg)?;

        let uncompressed: Box<dyn io::Read> = if arg.ends_with(".bz2") {
            Box::new(bzip2::read::MultiBzDecoder::new(file))
        } else {
            Box::new(file)
        };

        let mut reader = BufferedReader::new(uncompressed);

        let mut importer = Importer::new(&args.endpoint, arg);
        reader.read_all(&mut importer)?;
    }

    Ok(())
}
<commit_msg>also index trailing games<commit_after>use std::{cmp::min, fs::File, io, mem, num::Wrapping, path::PathBuf, time::Duration};

use clap::Parser;
use pgn_reader::{BufferedReader, Color, RawHeader, SanPlus, Skip, Visitor};
use rand::{distributions::OpenClosed01, rngs::SmallRng, Rng, SeedableRng};
use serde::Serialize;
use serde_with::{serde_as, DisplayFromStr, SpaceSeparator, StringWithSeparator};

const BATCH_SIZE: usize = 100;

#[derive(Debug, Serialize, Copy, Clone)]
#[serde(rename_all = "camelCase")]
enum Speed {
    UltraBullet,
    Bullet,
    Blitz,
    Rapid,
    Classical,
    Correspondence,
}

impl Speed {
    fn from_seconds_and_increment(seconds: u64, increment: u64) -> Speed {
        let total = seconds + 40 * increment;

        if total < 30 {
            Speed::UltraBullet
        } else if total < 180 {
            Speed::Bullet
        } else if total < 480 {
            Speed::Blitz
        } else if total < 1500 {
            Speed::Rapid
        } else if total < 21_600 {
            Speed::Classical
        } else {
            Speed::Correspondence
        }
    }

    fn from_bytes(bytes: &[u8]) -> Result<Speed, ()> {
        if bytes == b"-" {
            return Ok(Speed::Correspondence);
        }

        let mut parts = bytes.splitn(2, |ch| *ch == b'+');
        let seconds = btoi::btou(parts.next().ok_or(())?).map_err(|_| ())?;
        let increment = btoi::btou(parts.next().ok_or(())?).map_err(|_| ())?;
        Ok(Speed::from_seconds_and_increment(seconds, increment))
    }
}

struct Importer {
    endpoint: String,
    filename: PathBuf,
    client: reqwest::blocking::Client,
    rng: SmallRng,
    spinner_idx: Wrapping<usize>,

    current: Game,
    skip: bool,
    batch: Vec<Game>,
}

#[serde_as]
#[derive(Default, Serialize, Debug)]
struct Game {
    variant: Option<String>,
    speed: Option<Speed>,
    fen: Option<String>,
    id: Option<String>,
    date: Option<String>,
    white: Player,
    black: Player,
    #[serde_as(as = "Option<DisplayFromStr>")]
    winner: Option<Color>,
    #[serde_as(as = "StringWithSeparator<SpaceSeparator, SanPlus>")]
    moves: Vec<SanPlus>,
}

#[derive(Default, Serialize, Debug)]
struct Player {
    name: Option<String>,
    rating: Option<u16>,
}

impl Importer {
    fn new(endpoint: &str, filename: PathBuf) -> Importer {
        Importer {
            endpoint: endpoint.to_owned(),
            filename,
            client: reqwest::blocking::Client::builder()
                .timeout(Duration::from_secs(60))
                .build()
                .expect("client"),
            rng: SmallRng::from_seed([
                0x19, 0x29, 0xab, 0x17, 0xc6, 0xfa, 0xb0, 0xe9, 0x4b, 0x44, 0xd8, 0x07, 0x09, 0xbf,
                0x1d, 0x87, 0xbd, 0xd8, 0xb3, 0x2f, 0xe1, 0xe2, 0xa0, 0x1a, 0x9e, 0x30, 0x98, 0xd7,
                0xef, 0xd5, 0x7a, 0x1d,
            ]),
            spinner_idx: Wrapping(0),
            current: Game::default(),
            skip: false,
            batch: Vec::with_capacity(BATCH_SIZE),
        }
    }

    pub fn send(&mut self) {
        // println!("{}", serde_json::to_string(&self.batch).expect("serialize"));

        let res = self
            .client
            .put(format!("{}/import/lichess", self.endpoint))
            .json(&self.batch)
            .send()
            .expect("send batch");

        self.spinner_idx += Wrapping(1);
        let spinner = &['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];

        println!(
            "{} {:?}: {}: {} - {}",
            spinner[self.spinner_idx.0 % spinner.len()],
            self.filename,
            self.batch
                .last()
                .and_then(|g| g.date.as_ref())
                .unwrap_or(&String::new()),
            res.status(),
            res.text().expect("decode response")
        );

        self.batch.clear();
    }
}

impl Visitor for Importer {
    type Result = ();

    fn begin_game(&mut self) {
        self.skip = false;
        self.current = Game::default();
    }

    fn header(&mut self, key: &[u8], value: RawHeader<'_>) {
        if key == b"White" {
            self.current.white.name = Some(value.decode_utf8().expect("White").into_owned());
        } else if key == b"Black" {
            self.current.black.name = Some(value.decode_utf8().expect("Black").into_owned());
        } else if key == b"WhiteElo" {
            if value.as_bytes() != b"?" {
                self.current.white.rating = Some(btoi::btoi(value.as_bytes()).expect("WhiteElo"));
            }
        } else if key == b"BlackElo" {
            if value.as_bytes() != b"?" {
                self.current.black.rating = Some(btoi::btoi(value.as_bytes()).expect("BlackElo"));
            }
        } else if key == b"TimeControl" {
            self.current.speed = Some(Speed::from_bytes(value.as_bytes()).expect("TimeControl"));
        } else if key == b"Variant" {
            self.current.variant = Some(value.decode_utf8().expect("Variant").into_owned());
        } else if key == b"Date" || key == b"UTCDate" {
            self.current.date = Some(value.decode_utf8().expect("Date").into_owned());
        } else if key == b"WhiteTitle" || key == b"BlackTitle" {
            if value.as_bytes() == b"BOT" {
                self.skip = true;
            }
        } else if key == b"Site" {
            self.current.id = Some(
                String::from_utf8(
                    value
                        .as_bytes()
                        .rsplitn(2, |ch| *ch == b'/')
                        .next()
                        .expect("Site")
                        .to_owned(),
                )
                .expect("Site"),
            );
        } else if key == b"Result" {
            match value.as_bytes() {
                b"1-0" => self.current.winner = Some(Color::White),
                b"0-1" => self.current.winner = Some(Color::Black),
                b"1/2-1/2" => self.current.winner = None,
                _ => self.skip = true,
            }
        } else if key == b"FEN" {
            if value.as_bytes() == b"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" {
                // https://github.com/ornicar/lichess-db/issues/40
                self.current.fen = None;
            } else {
                self.current.fen = Some(value.decode_utf8().expect("FEN").into_owned());
            }
        }
    }

    fn end_headers(&mut self) -> Skip {
        let rating =
            (self.current.white.rating.unwrap_or(0) + self.current.black.rating.unwrap_or(0)) / 2;

        let standard = self
            .current
            .variant
            .as_ref()
            .map_or(true, |name| name == "Standard");

        let probability = if standard {
            match self.current.speed.unwrap_or(Speed::Correspondence) {
                Speed::Correspondence | Speed::Classical => 1.00,

                _ if rating >= 2500 => 1.00,

                Speed::Rapid if rating >= 2200 => 1.00,
                Speed::Rapid if rating >= 2000 => 0.50,
                Speed::Rapid if rating >= 1800 => 0.28,
                Speed::Rapid if rating >= 1600 => 0.24,

                Speed::Blitz if rating >= 2200 => 0.24,
                Speed::Blitz if rating >= 2000 => 0.11,
                Speed::Blitz if rating >= 1600 => 0.08,

                Speed::Bullet if rating >= 2200 => 0.30,
                Speed::Bullet if rating >= 2000 => 0.17,
                Speed::Bullet if rating >= 1600 => 0.11,

                Speed::UltraBullet => 1.00,

                _ => 0.02,
            }
        } else {
            // variant games
            if rating >= 1600 {
                1.00
            } else {
                0.50
            }
        };

        let accept = min(
            self.current.white.rating.unwrap_or(0),
            self.current.black.rating.unwrap_or(0),
        ) >= 1501
            && probability >= self.rng.sample(OpenClosed01)
            && !self.skip;

        self.skip = !accept;
        Skip(self.skip)
    }

    fn san(&mut self, san: SanPlus) {
        self.current.moves.push(san);
    }

    fn begin_variation(&mut self) -> Skip {
        Skip(true) // stay in the mainline
    }

    fn end_game(&mut self) {
        if !self.skip {
            self.batch
                .push(mem::replace(&mut self.current, Default::default()));

            if self.batch.len() >= BATCH_SIZE {
                self.send();
            }
        }
    }
}

#[derive(Parser)]
struct Args {
    #[clap(long, default_value = "http://localhost:9002")]
    endpoint: String,
    pgns: Vec<PathBuf>,
}

fn main() -> Result<(), io::Error> {
    let args = Args::parse();

    for arg in args.pgns {
        let file = File::open(&arg)?;

        let uncompressed: Box<dyn io::Read> = if arg.ends_with(".bz2") {
            Box::new(bzip2::read::MultiBzDecoder::new(file))
        } else {
            Box::new(file)
        };

        let mut reader = BufferedReader::new(uncompressed);

        let mut importer = Importer::new(&args.endpoint, arg);
        reader.read_all(&mut importer)?;
        importer.send();
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::io::prelude::*;

use term::terminfo::TermInfo;
use unicode_width::UnicodeWidthStr;

use std::sync::mpsc::{Receiver, Sender};
use std::borrow::{Cow, Borrow};
use std::collections::HashMap;
use std::iter::FromIterator;

use std::sync::mpsc;
use std::io;
use std::env;
use std::thread;

use bis_c::{TermTrack, TermSize};
use error::StringError;
use search::SearchBase;

// TermControl contains utility funcitons for terminfo
#[derive(Debug)]
struct TermControl {
    strings: HashMap<String, String>
}

#[derive(PartialEq, Clone, Debug)]
enum TermStack {
    // here for correctness
    #[allow(dead_code)]
    Str(String),
    Int(isize),
    // here for correctness
    #[allow(dead_code)]
    Bool(bool)
}

// our user interface instance
pub struct UI {
    // track is a guard, we never touch it manually
    #[allow(dead_code)]
    track: TermTrack,
    size: TermSize,
    control: TermControl,
    query: Sender<String>,
    matches: Receiver<Vec<Cow<'static, str>>>,
    chars: Receiver<char>,
    stop: Receiver<()>
}

impl Drop for UI {
    fn drop(&mut self) {
        debug!("Clearing screen on exit");
        let mut output = io::stdout();
        match write!(output, "{}", self.control.get_string("clr_eos".to_owned(), vec![]).unwrap_or(format!(""))) {
            Ok(_) => {
                trace!("Cleared screen successfully");
            },
            Err(e) => {
                error!("Failed to clear screen: {}", e);
            }
        }
        debug!("Flushing output");
        match output.flush() {
            Ok(_) => {
                trace!("Flushed screen successfully");
            },
            Err(e) => {
                error!("Failed to flush screen: {}", e);
            }
        }
    }
}

impl TermControl {
    pub fn create() -> Result<TermControl, StringError> {
        debug!("Getting terminal info");
        let info = match TermInfo::from_env() {
            Ok(info) => info,
            Err(e) => return Err(StringError::new("Failed to get TermInfo", Some(Box::new(e))))
        };

        trace!("Got terminfo: {:?}", info);

        let mut strings = HashMap::default();

        for (name, value) in info.strings.into_iter() {
            strings.insert(name, match String::from_utf8(value) {
                Ok(s) => s,
                Err(e) => return Err(StringError::new("Failed to convert value into an OsString", Some(Box::new(e))))
            });
        }

        // right now all we care about are the strings
        Ok(TermControl {
            strings: strings
        })
    }

    pub fn get_string<T: Borrow<String>>(&mut self, name: T, params: Vec<TermStack>) -> Option<String> {
        // only implement what we're actually using in the UI
        let sequence = match self.strings.get(name.borrow()) {
            None => {
                trace!("No match for string: {:?}", name.borrow());
                return None;
            },
            Some(s) => {
                trace!("Matched string: {:?}", s);
                s.clone()
            }
        };

        let mut escaped = false;
        let mut stack: Vec<TermStack> = vec![];
        let mut result = String::default();
        let mut escape = String::default();

        // only implement the sequences we care about

        for c in sequence.chars() {
            if !escaped {
                if c == '%' {
                    escaped = true;
                } else {
                    result.push(c);
                }
            } else if escape.is_empty() {
                if c == 'd' {
                    match stack.pop() {
                        Some(TermStack::Int(c)) => {
                            result.push_str(format!("{}", c).as_ref());
                        },
                        Some(o) => {
                            error!("Numeric print on non-numeric type: {:?}", o);
                        },
                        None => {
                            error!("Stack was empty on print");
                        }
                    }

                    escaped = false;
                } else if c == 'p' {
                    escape.push('p');
                } else {
                    error!("Unknown escape character: {:?}", c);
                    escaped = false;
                }
            } else {
                if escape == "p" {
                    match c.to_digit(10) {
                        Some(idx) => {
                            if idx != 0 {
                                match params.get(idx as usize - 1) {
                                    Some(item) => {
                                        stack.push(item.clone())
                                    },
                                    None => {
                                        error!("There was no parameter {}", idx);
                                    }
                                }
                            } else {
                                error!("Tried to print 0th paramater");
                            }
                        },
                        None => {
                            error!("Paramater number was not a digit");
                        }
                    }

                    escape.clear();
                    escaped = false;
                } else {
                    error!("Unknown escape sequence: {:?}", escape);
                    escape.clear();
                    escaped = false;
                }
            }
        }

        trace!("Returning result: {:?}", result);

        // return result
        Some(result)
    }
}

impl UI {
    pub fn create() -> Result<UI, StringError> {
        debug!("Creating TermControl");
        let control = try!(TermControl::create());

        trace!("Got TermControl: {:?}", control);

        let mut track = TermTrack::default();

        debug!("Getting terminal size");
        let size = match track.get_size() {
            Err(e) => return Err(StringError::new("Failed to get terminal size", Some(Box::new(e)))),
            Ok(s) => {
                trace!("Terminal size: {:?}", s);
                s
            }
        };

        debug!("Preparing terminal");
        match track.prepare() {
            Err(e) => return Err(StringError::new("Failed to prepare terminal", Some(Box::new(e)))),
            Ok(_) => {
                trace!("Terminal prepared successfully");
            }
        }

        debug!("Masking sigint on main thread");

        match ::bis_c::mask_sigint() {
            Ok(_) => {
                trace!("Set signal mask successfully");
            },
            Err(e) => return Err(StringError::new("Failed to mask signal", Some(Box::new(e))))
        }

        debug!("Starting search thread");

        trace!("Creating thread primitives");
        let (query_tx, query_rx) = mpsc::channel();
        let (matches_tx, matches_rx) = mpsc::channel();

        trace!("Starting thread");
        thread::spawn(move || {
            search_thread(query_rx, matches_tx);
        });

        debug!("Starting input thread");

        trace!("Creating thread primitives");
        let (chars_tx, chars_rx) = mpsc::channel();

        trace!("Starting thread");
        thread::spawn(move || {
            input_thread(chars_tx);
        });

        debug!("Starting signal thread");

        trace!("Creating thread primitives");
        let (stop_tx, stop_rx) = mpsc::channel();

        trace!("Starting thread");
        thread::spawn(move || {
            signal_thread(stop_tx);
        });

        debug!("Creating UI instance");
        let instance = UI {
            track: track,
            size: size,
            control: control,
            query: query_tx,
            matches: matches_rx,
            chars: chars_rx,
            stop: stop_rx
        };

        trace!("Instance creation successful");
        Ok(instance)
    }

    pub fn start(&mut self) -> Result<(), StringError> {
        // assume start on a new line
        // get handles for io
        let stdout = io::stdout();
        let mut output = stdout.lock();

        let mut query = String::new();

        // make space for our matches
        match write!(output, "{}{}", String::from_iter(vec!['\n'; 10].into_iter()),
                     self.control.get_string("cuu".to_owned(), vec![TermStack::Int(10)]).unwrap_or(format!(""))) {
            Err(e) => return Err(StringError::new("Failed to create space", Some(Box::new(e)))),
            Ok(_) => {
                trace!("Successfully created space on terminal");
            }
        }

        // draw our prompt and save the cursor
        debug!("Drawing prompt");
        match write!(output, "Match: {}",
                     self.control.get_string("sc".to_owned(), vec![]).unwrap_or(format!(""))) {
            Err(e) => return Err(StringError::new("Failed to draw prompt", Some(Box::new(e)))),
            Ok(_) => {
                trace!("Drew prompt successfully");
            }
        }

        // flush the output
        debug!("Flushing output");
        match output.flush() {
            Ok(_) => {
                trace!("Successfully flushed output");
            },
            Err(e) => {
                return Err(StringError::new("Failed to flush output", Some(Box::new(e))));
            }
        }

        // are you kidding me with this stupid macro bullshit
        let matches_chan = &self.matches;
        let chars_chan = &self.chars;
        let stop_chan = &self.stop;

        loop {
            // this macro is bad and the rust people should feel bad
            // on the other hand, multi-threaded UI! Yay!
            select! {
                _ = stop_chan.recv() => {
                    // any event on this channel means stop
                    debug!("Event on stop thread, exiting");
                    break;
                },
                maybe_matches = matches_chan.recv() => {
                    let matches = match maybe_matches {
                        Ok(m) => m,
                        Err(e) => return Err(StringError::new("Query thread hung up", Some(Box::new(e))))
                    };
                    debug!("Got matches: {:?}", matches);

                    // draw the matches
                    for item in matches.into_iter() {
                        if UnicodeWidthStr::width(item.as_ref()) > self.size.cols {
                            let mut owned = item.into_owned();
                            while UnicodeWidthStr::width((&owned as &AsRef<str>).as_ref()) > self.size.cols {
                                // truncate long lines
                                owned.pop();
                            }
                            // draw the truncated item
                            match write!(output, "\n{}", owned) {
                                Err(e) => return Err(StringError::new("Failed to draw match", Some(Box::new(e)))),
                                Ok(_) => {
                                    trace!("Drew match successfully");
                                }
                            }
                        } else {
                            // draw the match after a newline
                            match write!(output, "\n{}", item) {
                                Err(e) => return Err(StringError::new("Failed to draw match", Some(Box::new(e)))),
                                Ok(_) => {
                                    trace!("Drew match successfully");
                                }
                            }
                        }
                    }

                    // restore the cursor
                    match write!(output, "{}", self.control.get_string("rc".to_owned(), vec![]).unwrap_or(format!(""))) {
                        Err(e) => return Err(StringError::new("Failed to restore cursor", Some(Box::new(e)))),
                        Ok(_) => {
                            trace!("Restored cursor successfully");
                        }
                    }
                },
                maybe_chr = chars_chan.recv() => {
                    let chr = match maybe_chr {
                        Ok(c) => c,
                        Err(e) => {
                            // io hung up, exit
                            debug!("IO thread hung up: {:?}", e);
                            break;
                        }
                    };
                    debug!("Got character: {:?}", chr);

                    // push the character onto the query string
                    query.push(chr);

                    // draw the character, save the cursor position, clear the screen after us
                    match write!(output, "{}{}{}", chr,
                                 self.control.get_string("sc".to_owned(), vec![]).unwrap_or(format!("")),
                                 self.control.get_string("clr_eos".to_owned(), vec![]).unwrap_or(format!(""))) {
                        Err(e) => return Err(StringError::new("Failed to output character", Some(Box::new(e)))),
                        Ok(_) => {
                            trace!("Outputted character successfully");
                        }
                    }

                    // send the search thread our query
                    debug!("Sending {} to search thread", &query);
                    match self.query.send(query.clone()) {
                        Ok(_) => {
                            trace!("Send successful");
                        },
                        Err(e) => {
                            return Err(StringError::new("Failed to send to search thread", Some(Box::new(e))));
                        }
                    }
                }
            }

            // flush the output
            match output.flush() {
                Ok(_) => {
                    trace!("Successfully flushed output");
                },
                Err(e) => {
                    return Err(StringError::new("Failed to flush output", Some(Box::new(e))));
                }
            }
        }

        // Return success
        Ok(())
    }
}

// this thread waits for queries, and responds with search matches
pub fn search_thread(query: Receiver<String>,
                     matches: Sender<Vec<Cow<'static, str>>>) {
    debug!("Starting query thread");

    debug!("Getting history path");
    let history_path = match env::var("HISTFILE") {
        Ok(p) => {
            trace!("Got history path: {:?}", p);
            p
        },
        Err(e) => panic!("Failed to get bash history file: {}", e)
    };

    let mut base = SearchBase::default();

    // read the history
    info!("Reading history");
    match base.read_history(history_path) {
        Ok(_) => {
            // success
        },
        Err(e) => {
            panic!("Failed to read history: {}", e)
        }
    }

    debug!("Starting query loop");

    loop {
        trace!("Waiting for a query");
        match query.recv() {
            Err(e) => {
                debug!("Search thread exiting: {}", e);
                break;
            },
            Ok(q) => {
                debug!("Got query: {:?}", q);
                let result = base.query(q);
                debug!("Got result: {:?}", result);
                match matches.send(result) {
                    Err(e) => {
                        debug!("Search thread exiting: {}", e);
                        break;
                    },
                    Ok(_) => {
                        trace!("Matches sent successfully");
                    }
                }
            }
        }
    }
}

// this thread waits for input on stdin and sends that input back
fn input_thread(chars: Sender<char>) {
    debug!("Starting input thread");

    debug!("Getting stdin lock");
    let input = io::stdin();

    for maybe_chr in input.chars() {
        match maybe_chr {
            Err(e) => {
                debug!("Input thread exiting: {}", e);
                break;
            },
            Ok(c) => {
                debug!("Got character: {:?}", c);
                match chars.send(c) {
                    Err(e) => {
                        debug!("Search thread exiting: {:?}", e);
                    },
                    Ok(_) => {
                        trace!("Character sent successfully");
                    }
                }
            }
        }
    }

    debug!("Input thread ran out of input");
}

// this thread waits for interrupt signals so we can exit cleanly
fn signal_thread(stop: Sender<()>) {
    debug!("Starting signal thread");

    match ::bis_c::mask_sigint() {
        Ok(_) => {
            trace!("Set signal mask successfully");
        },
        Err(e) => {
            panic!("Error setting signal mask: {:?}", e);
        }
    }

    match ::bis_c::wait_sigint() {
        Ok(_) => {
            trace!("Waited for signal successfully");
        },
        Err(e) => {
            panic!("Error waiting for signal: {:?}", e);
        }
    }

    match stop.send(()) {
        Ok(_) => {
            trace!("Sent stop signal successfully");
        },
        Err(e) => {
            // this doesn't necessarily mean an error
            debug!("Stop thread failed to send: {:?}", e);
        }
    }

    debug!("Thread got interrupt signal, exiting");
}
<commit_msg>Print best match on exit<commit_after>use std::io::prelude::*;

use term::terminfo::TermInfo;
use unicode_width::UnicodeWidthStr;

use std::sync::mpsc::{Receiver, Sender};
use std::borrow::{Cow, Borrow};
use std::collections::HashMap;
use std::iter::FromIterator;

use std::sync::mpsc;
use std::io;
use std::env;
use std::thread;

use bis_c::{TermTrack, TermSize};
use error::StringError;
use search::SearchBase;

// TermControl contains utility funcitons for terminfo
#[derive(Debug)]
struct TermControl {
    strings: HashMap<String, String>
}

#[derive(PartialEq, Clone, Debug)]
enum TermStack {
    // here for correctness
    #[allow(dead_code)]
    Str(String),
    Int(isize),
    // here for correctness
    #[allow(dead_code)]
    Bool(bool)
}

// our user interface instance
pub struct UI {
    // track is a guard, we never touch it manually
    #[allow(dead_code)]
    track: TermTrack,
    size: TermSize,
    control: TermControl,
    query: Sender<String>,
    matches: Receiver<Vec<Cow<'static, str>>>,
    chars: Receiver<char>,
    stop: Receiver<()>
}

impl TermControl {
    pub fn create() -> Result<TermControl, StringError> {
        debug!("Getting terminal info");
        let info = match TermInfo::from_env() {
            Ok(info) => info,
            Err(e) => return Err(StringError::new("Failed to get TermInfo", Some(Box::new(e))))
        };

        trace!("Got terminfo: {:?}", info);

        let mut strings = HashMap::default();

        for (name, value) in info.strings.into_iter() {
            strings.insert(name, match String::from_utf8(value) {
                Ok(s) => s,
                Err(e) => return Err(StringError::new("Failed to convert value into an OsString", Some(Box::new(e))))
            });
        }

        // right now all we care about are the strings
        Ok(TermControl {
            strings: strings
        })
    }

    pub fn get_string<T: Borrow<String>>(&mut self, name: T, params: Vec<TermStack>) -> Option<String> {
        // only implement what we're actually using in the UI
        let sequence = match self.strings.get(name.borrow()) {
            None => {
                trace!("No match for string: {:?}", name.borrow());
                return None;
            },
            Some(s) => {
                trace!("Matched string: {:?}", s);
                s.clone()
            }
        };

        let mut escaped = false;
        let mut stack: Vec<TermStack> = vec![];
        let mut result = String::default();
        let mut escape = String::default();

        // only implement the sequences we care about

        for c in sequence.chars() {
            if !escaped {
                if c == '%' {
                    escaped = true;
                } else {
                    result.push(c);
                }
            } else if escape.is_empty() {
                if c == 'd' {
                    match stack.pop() {
                        Some(TermStack::Int(c)) => {
                            result.push_str(format!("{}", c).as_ref());
                        },
                        Some(o) => {
                            error!("Numeric print on non-numeric type: {:?}", o);
                        },
                        None => {
                            error!("Stack was empty on print");
                        }
                    }

                    escaped = false;
                } else if c == 'p' {
                    escape.push('p');
                } else {
                    error!("Unknown escape character: {:?}", c);
                    escaped = false;
                }
            } else {
                if escape == "p" {
                    match c.to_digit(10) {
                        Some(idx) => {
                            if idx != 0 {
                                match params.get(idx as usize - 1) {
                                    Some(item) => {
                                        stack.push(item.clone())
                                    },
                                    None => {
                                        error!("There was no parameter {}", idx);
                                    }
                                }
                            } else {
                                error!("Tried to print 0th paramater");
                            }
                        },
                        None => {
                            error!("Paramater number was not a digit");
                        }
                    }

                    escape.clear();
                    escaped = false;
                } else {
                    error!("Unknown escape sequence: {:?}", escape);
                    escape.clear();
                    escaped = false;
                }
            }
        }

        trace!("Returning result: {:?}", result);

        // return result
        Some(result)
    }
}

impl UI {
    pub fn create() -> Result<UI, StringError> {
        debug!("Creating TermControl");
        let control = try!(TermControl::create());

        trace!("Got TermControl: {:?}", control);

        let mut track = TermTrack::default();

        debug!("Getting terminal size");
        let size = match track.get_size() {
            Err(e) => return Err(StringError::new("Failed to get terminal size", Some(Box::new(e)))),
            Ok(s) => {
                trace!("Terminal size: {:?}", s);
                s
            }
        };

        debug!("Preparing terminal");
        match track.prepare() {
            Err(e) => return Err(StringError::new("Failed to prepare terminal", Some(Box::new(e)))),
            Ok(_) => {
                trace!("Terminal prepared successfully");
            }
        }

        debug!("Masking sigint on main thread");

        match ::bis_c::mask_sigint() {
            Ok(_) => {
                trace!("Set signal mask successfully");
            },
            Err(e) => return Err(StringError::new("Failed to mask signal", Some(Box::new(e))))
        }

        debug!("Starting search thread");

        trace!("Creating thread primitives");
        let (query_tx, query_rx) = mpsc::channel();
        let (matches_tx, matches_rx) = mpsc::channel();

        trace!("Starting thread");
        thread::spawn(move || {
            search_thread(query_rx, matches_tx);
        });

        debug!("Starting input thread");

        trace!("Creating thread primitives");
        let (chars_tx, chars_rx) = mpsc::channel();

        trace!("Starting thread");
        thread::spawn(move || {
            input_thread(chars_tx);
        });

        debug!("Starting signal thread");

        trace!("Creating thread primitives");
        let (stop_tx, stop_rx) = mpsc::channel();

        trace!("Starting thread");
        thread::spawn(move || {
            signal_thread(stop_tx);
        });

        debug!("Creating UI instance");
        let instance = UI {
            track: track,
            size: size,
            control: control,
            query: query_tx,
            matches: matches_rx,
            chars: chars_rx,
            stop: stop_rx
        };

        trace!("Instance creation successful");
        Ok(instance)
    }

    pub fn start(&mut self) -> Result<(), StringError> {
        // assume start on a new line
        // get handles for io
        let stdout = io::stdout();
        let mut output = stdout.lock();

        let mut query = String::new();

        // make space for our matches
        match write!(output, "{}{}", String::from_iter(vec!['\n'; 10].into_iter()),
                     self.control.get_string("cuu".to_owned(), vec![TermStack::Int(10)]).unwrap_or(format!(""))) {
            Err(e) => return Err(StringError::new("Failed to create space", Some(Box::new(e)))),
            Ok(_) => {
                trace!("Successfully created space on terminal");
            }
        }

        // draw our prompt and save the cursor
        debug!("Drawing prompt");
        match write!(output, "Match: {}",
                     self.control.get_string("sc".to_owned(), vec![]).unwrap_or(format!(""))) {
            Err(e) => return Err(StringError::new("Failed to draw prompt", Some(Box::new(e)))),
            Ok(_) => {
                trace!("Drew prompt successfully");
            }
        }

        // flush the output
        debug!("Flushing output");
        match output.flush() {
            Ok(_) => {
                trace!("Successfully flushed output");
            },
            Err(e) => {
                return Err(StringError::new("Failed to flush output", Some(Box::new(e))));
            }
        }

        // are you kidding me with this stupid macro bullshit
        let matches_chan = &self.matches;
        let chars_chan = &self.chars;
        let stop_chan = &self.stop;

        let mut best_match = None;

        loop {
            // this macro is bad and the rust people should feel bad
            // on the other hand, multi-threaded UI! Yay!
            select! {
                _ = stop_chan.recv() => {
                    // any event on this channel means stop
                    debug!("Event on stop thread, exiting");
                    match best_match {
                        Some(m) => {
                            // redraw the best match
                            match write!(output, "\r{}", m) {
                                Err(e) => return Err(StringError::new("Failed to write best match", Some(Box::new(e)))),
                                Ok(_) => {
                                    trace!("Drew best match successfully");
                                }
                            }
                        },
                        None => {
                            trace!("Not redrawing best match");
                        }
                    }

                    // clear the screen and move to a new line
                    match write!(output, "{}\n",
                                 self.control.get_string("clr_eos".to_owned(), vec![]).unwrap_or(format!(""))) {
                        Err(e) => return Err(StringError::new("Failed to clear screen", Some(Box::new(e)))),
                        Ok(_) => {
                            trace!("Cleared screen successfully");
                        }
                    }

                    // exit
                    break;
                },
                maybe_matches = matches_chan.recv() => {
                    let matches = match maybe_matches {
                        Ok(m) => m,
                        Err(e) => return Err(StringError::new("Query thread hung up", Some(Box::new(e))))
                    };
                    debug!("Got matches: {:?}", matches);

                    // update the best match if we have one
                    match matches.first() {
                        Some(m) => {
                            best_match = Some(m.clone());
                        },
                        None => {
                            best_match = None;
                        }
                    }

                    // draw the matches
                    for item in matches.into_iter() {
                        if UnicodeWidthStr::width(item.as_ref()) > self.size.cols {
                            let mut owned = item.into_owned();
                            while UnicodeWidthStr::width((&owned as &AsRef<str>).as_ref()) > self.size.cols {
                                // truncate long lines
                                owned.pop();
                            }
                            // draw the truncated item
                            match write!(output, "\n{}", owned) {
                                Err(e) => return Err(StringError::new("Failed to draw match", Some(Box::new(e)))),
                                Ok(_) => {
                                    trace!("Drew match successfully");
                                }
                            }
                        } else {
                            // draw the match after a newline
                            match write!(output, "\n{}", item) {
                                Err(e) => return Err(StringError::new("Failed to draw match", Some(Box::new(e)))),
                                Ok(_) => {
                                    trace!("Drew match successfully");
                                }
                            }
                        }
                    }

                    // restore the cursor
                    match write!(output, "{}", self.control.get_string("rc".to_owned(), vec![]).unwrap_or(format!(""))) {
                        Err(e) => return Err(StringError::new("Failed to restore cursor", Some(Box::new(e)))),
                        Ok(_) => {
                            trace!("Restored cursor successfully");
                        }
                    }
                },
                maybe_chr = chars_chan.recv() => {
                    let chr = match maybe_chr {
                        Ok(c) => c,
                        Err(e) => {
                            // io hung up, exit
                            debug!("IO thread hung up: {:?}", e);
                            break;
                        }
                    };
                    debug!("Got character: {:?}", chr);

                    // push the character onto the query string
                    query.push(chr);

                    // draw the character, save the cursor position, clear the screen after us
                    match write!(output, "{}{}{}", chr,
                                 self.control.get_string("sc".to_owned(), vec![]).unwrap_or(format!("")),
                                 self.control.get_string("clr_eos".to_owned(), vec![]).unwrap_or(format!(""))) {
                        Err(e) => return Err(StringError::new("Failed to output character", Some(Box::new(e)))),
                        Ok(_) => {
                            trace!("Outputted character successfully");
                        }
                    }

                    // send the search thread our query
                    debug!("Sending {} to search thread", &query);
                    match self.query.send(query.clone()) {
                        Ok(_) => {
                            trace!("Send successful");
                        },
                        Err(e) => {
                            return Err(StringError::new("Failed to send to search thread", Some(Box::new(e))));
                        }
                    }
                }
            }

            // flush the output
            match output.flush() {
                Ok(_) => {
                    trace!("Successfully flushed output");
                },
                Err(e) => {
                    return Err(StringError::new("Failed to flush output", Some(Box::new(e))));
                }
            }
        }

        // flush the output
        match output.flush() {
            Ok(_) => {
                trace!("Successfully flushed output");
            },
            Err(e) => {
                return Err(StringError::new("Failed to flush output", Some(Box::new(e))));
            }
        }

        // Return success
        Ok(())
    }
}

// this thread waits for queries, and responds with search matches
pub fn search_thread(query: Receiver<String>,
                     matches: Sender<Vec<Cow<'static, str>>>) {
    debug!("Starting query thread");

    debug!("Getting history path");
    let history_path = match env::var("HISTFILE") {
        Ok(p) => {
            trace!("Got history path: {:?}", p);
            p
        },
        Err(e) => panic!("Failed to get bash history file: {}", e)
    };

    let mut base = SearchBase::default();

    // read the history
    info!("Reading history");
    match base.read_history(history_path) {
        Ok(_) => {
            // success
        },
        Err(e) => {
            panic!("Failed to read history: {}", e)
        }
    }

    debug!("Starting query loop");

    loop {
        trace!("Waiting for a query");
        match query.recv() {
            Err(e) => {
                debug!("Search thread exiting: {}", e);
                break;
            },
            Ok(q) => {
                debug!("Got query: {:?}", q);
                let result = base.query(q);
                debug!("Got result: {:?}", result);
                match matches.send(result) {
                    Err(e) => {
                        debug!("Search thread exiting: {}", e);
                        break;
                    },
                    Ok(_) => {
                        trace!("Matches sent successfully");
                    }
                }
            }
        }
    }
}

// this thread waits for input on stdin and sends that input back
fn input_thread(chars: Sender<char>) {
    debug!("Starting input thread");

    debug!("Getting stdin lock");
    let input = io::stdin();

    for maybe_chr in input.chars() {
        match maybe_chr {
            Err(e) => {
                debug!("Input thread exiting: {}", e);
                break;
            },
            Ok(c) => {
                debug!("Got character: {:?}", c);
                match chars.send(c) {
                    Err(e) => {
                        debug!("Search thread exiting: {:?}", e);
                    },
                    Ok(_) => {
                        trace!("Character sent successfully");
                    }
                }
            }
        }
    }

    debug!("Input thread ran out of input");
}

// this thread waits for interrupt signals so we can exit cleanly
fn signal_thread(stop: Sender<()>) {
    debug!("Starting signal thread");

    match ::bis_c::mask_sigint() {
        Ok(_) => {
            trace!("Set signal mask successfully");
        },
        Err(e) => {
            panic!("Error setting signal mask: {:?}", e);
        }
    }

    match ::bis_c::wait_sigint() {
        Ok(_) => {
            trace!("Waited for signal successfully");
        },
        Err(e) => {
            panic!("Error waiting for signal: {:?}", e);
        }
    }

    match stop.send(()) {
        Ok(_) => {
            trace!("Sent stop signal successfully");
        },
        Err(e) => {
            // this doesn't necessarily mean an error
            debug!("Stop thread failed to send: {:?}", e);
        }
    }

    debug!("Thread got interrupt signal, exiting");
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use error::*;
use bytecode;

pub struct VM {
    ip: usize,
    sp: usize,
    globals: Vec<u64>,
    stack: Vec<u64>,
}

impl VM {
    pub fn new() -> VM {
        VM {
            ip: 0,
            sp: 0,
            globals: Vec::new(),
            stack: Vec::new(),
        }
    }

    pub fn exec<P: AsRef<Path>>(&mut self, path: P) -> VMResult<()> {
        let mut image_file = File::open(path).chain_err(|| "unable to open game image")?;
        let mut image_string = String::new();
        image_file.read_to_string(&mut image_string).chain_err(|| "unable to read image")?;

        let mut byte_iter = image_string.bytes();
        let mut outer_byte = byte_iter.next();
        while let Some(byte) = outer_byte {
            match byte {
                bytecode::HALT => break,
                bytecode::ADD => self.add().chain_err(|| "unable to execute 'add' instruction")?,
                bytecode::SUB => self.sub().chain_err(|| "unable to execute 'sub' instruction")?,
                bytecode::PRINT => {
                    self.print().chain_err(|| "unable to execute 'print' instruction")?
                }
                bytecode::PUSH => {
                    // Build a u32 from single bytes
                    let mut res: u32 = 0;
                    for _ in 0..4 {
                        res <<= 8;
                        res |= byte_iter.next().unwrap() as u32;
                    }

                    self.push(res).chain_err(|| "unable to push value to the stack")?;
                }
                _ => bail!("unexpected opcode: {:08x}", byte),
            }

            outer_byte = byte_iter.next();
        }

        Ok(())
    }

    fn push(&mut self, value: u32) -> VMResult<()> {
        if !self.stack.is_empty() {
            self.sp += 1;
        }

        self.stack.push(value as u64);

        Ok(())
    }

    fn pop(&mut self) -> VMResult<u64> {
        if self.stack.is_empty() {
            bail!("unable to pop value off an empty Stack");
        }

        let res = self.stack.remove(self.sp);
        if !self.stack.is_empty() {
            self.sp -= 1;
        }

        Ok(res)
    }

    fn add(&mut self) -> VMResult<()> {
        let b = self.pop().chain_err(|| "unable to pop value off the stack")?;
        let a = self.pop().chain_err(|| "unable to pop value off the stack")?;
        self.push((a + b) as u32).chain_err(|| "unable to push value to the stack")?;
        Ok(())
    }

    fn sub(&mut self) -> VMResult<()> {
        let b = self.pop().chain_err(|| "unable to pop value off the stack")?;
        let a = self.pop().chain_err(|| "unable to pop value off the stack")?;
        self.push((a - b) as u32).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn print(&mut self) -> VMResult<()> {
        println!("{:?}", self.stack[self.sp]);
        Ok(())
    }
}
<commit_msg>Added mul and div handling<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use error::*;
use bytecode;

pub struct VM {
    ip: usize,
    sp: usize,
    globals: Vec<u64>,
    stack: Vec<u64>,
}

impl VM {
    pub fn new() -> VM {
        VM {
            ip: 0,
            sp: 0,
            globals: Vec::new(),
            stack: Vec::new(),
        }
    }

    pub fn exec<P: AsRef<Path>>(&mut self, path: P) -> VMResult<()> {
        let mut image_file = File::open(path).chain_err(|| "unable to open game image")?;
        let mut image_string = String::new();
        image_file.read_to_string(&mut image_string).chain_err(|| "unable to read image")?;

        let mut byte_iter = image_string.bytes();
        let mut outer_byte = byte_iter.next();
        while let Some(byte) = outer_byte {
            match byte {
                bytecode::HALT => break,
                bytecode::ADD => self.add().chain_err(|| "unable to execute 'add' instruction")?,
                bytecode::SUB => self.sub().chain_err(|| "unable to execute 'sub' instruction")?,
                bytecode::MUL => self.mul().chain_err(|| "unable to execute 'mul' instruction")?,
                bytecode::DIV => self.div().chain_err(|| "unable to execute 'div' instruction")?,
                bytecode::PRINT => {
                    self.print().chain_err(|| "unable to execute 'print' instruction")?
                }
                bytecode::PUSH => {
                    // Build a u32 from single bytes
                    let mut res: u32 = 0;
                    for _ in 0..4 {
                        res <<= 8;
                        res |= byte_iter.next().unwrap() as u32;
                    }

                    self.push(res).chain_err(|| "unable to push value to the stack")?;
                }
                _ => bail!("unexpected opcode: {:08x}", byte),
            }

            outer_byte = byte_iter.next();
        }

        Ok(())
    }

    fn push(&mut self, value: u32) -> VMResult<()> {
        if !self.stack.is_empty() {
            self.sp += 1;
        }

        self.stack.push(value as u64);

        Ok(())
    }

    fn pop(&mut self) -> VMResult<u64> {
        if self.stack.is_empty() {
            bail!("unable to pop value off an empty Stack");
        }

        let res = self.stack.remove(self.sp);
        if !self.stack.is_empty() {
            self.sp -= 1;
        }

        Ok(res)
    }

    fn add(&mut self) -> VMResult<()> {
        let b = self.pop().chain_err(|| "unable to pop value off the stack")?;
        let a = self.pop().chain_err(|| "unable to pop value off the stack")?;
        self.push((a + b) as u32).chain_err(|| "unable to push value to the stack")?;
        Ok(())
    }

    fn sub(&mut self) -> VMResult<()> {
        let b = self.pop().chain_err(|| "unable to pop value off the stack")?;
        let a = self.pop().chain_err(|| "unable to pop value off the stack")?;
        self.push((a - b) as u32).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn mul(&mut self) -> VMResult<()> {
        let b = self.pop().chain_err(|| "unable to pop value off the stack")?;
        let a = self.pop().chain_err(|| "unable to pop value off the stack")?;
        self.push((a * b) as u32).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn div(&mut self) -> VMResult<()> {
        let b = self.pop().chain_err(|| "unable to pop value off the stack")?;
        let a = self.pop().chain_err(|| "unable to pop value off the stack")?;
        self.push((a / b) as u32).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn print(&mut self) -> VMResult<()> {
        println!("{:?}", self.stack[self.sp]);
        Ok(())
    }
}
<|endoftext|>


<commit_before>pub fn perin_version() -> f32{
	0.1
}

#[deriving(FromPrimitive)]
enum Instruction {
	INTEGER = 0x00,
	STRING = 0x01,
	ADD = 0x02,
	SHOWINTEGER = 0x0A,
	SHOWVERSION = 0x0E,
	EXITVM = 0x0F
}

pub struct PerinVM{
	push: bool,
	stack: Vec<u8>
}

impl PerinVM{
	pub fn new() -> PerinVM{
		println!("Starting PerinVM instance");
		PerinVM{push: false, stack: vec![]}
	}
	pub fn interpreter(&mut self,bytecode: &'static str) -> (){
		for execbyte in bytecode.chars() {
			self.execute(execbyte as u8);
		}
	}
	fn execute(&mut self, execbyte: u8) -> () {
		if self.push {
			self.push(execbyte);
			self.push=false;
		}else{
			let op: Option<Instruction> = FromPrimitive::from_u8(execbyte);
			match op{
				None => {
					println!("Unknown instruction, skipping...");
				},
				Some(bc) => {
					match bc{
						INTEGER => {
							self.push=true;
						},
						ADD => {
							let a=self.pop() as int;
							let b=self.pop() as int;
							let c=a+b;
							self.push(c as u8);
						},
						SHOWINTEGER => {
							println!("Integer value {}",self.pop() as int);
						},
						SHOWVERSION => {
							println!("PerinVM v0.1.0");
						},
						EXITVM => {
							println!("Exit VM");
						},
						STRING => {
							println!("Unsupported instruction 'STRING' ");
						}
					}
				}
			}

		}
	}
	fn push(&mut self, value: u8) -> (){
		self.stack.push(value);
	}
	fn pop(&mut self) -> u8{
		let a: Option<u8>=self.stack.pop();
		match a{
			None => {
				println!("Failed to pop");
				0
			},
			Some(result) => {
				result
			}
		}
	}
}
<commit_msg>Namespaced enums - Rust breaking change<commit_after>#[deriving(FromPrimitive)]
pub enum Instruction {
	INTEGER = 0x00,
	STRING = 0x01,
	ADD = 0x02,
	SHOWINTEGER = 0x0A,
	SHOWVERSION = 0x0E,
	EXITVM = 0x0F
}

pub fn perin_version() -> f32{
	0.1
}

pub struct PerinVM{
	push: bool,
	stack: Vec<u8>
}

impl PerinVM{
	pub fn new() -> PerinVM{
		println!("Starting PerinVM instance");
		PerinVM{push: false, stack: vec![]}
	}
	pub fn interpreter(&mut self,bytecode: &'static str) -> (){
		for execbyte in bytecode.chars() {
			self.execute(execbyte as u8);
		}
	}
	fn execute(&mut self, execbyte: u8) -> () {
		if self.push {
			self.push(execbyte);
			self.push=false;
		}else{
			let op: Option<Instruction> = FromPrimitive::from_u8(execbyte);
			match op{
				None => {
					println!("Unknown instruction, skipping...");
				},
				Some(bc) => {
					match bc{
						Instruction::INTEGER => {
							self.push=true;
						},
						Instruction::ADD => {
							let a=self.pop() as int;
							let b=self.pop() as int;
							let c=a+b;
							self.push(c as u8);
						},
						Instruction::SHOWINTEGER => {
							println!("Integer value {}",self.pop() as int);
						},
						Instruction::SHOWVERSION => {
							println!("PerinVM v0.1.0");
						},
						Instruction::EXITVM => {
							println!("Exit VM");
						},
						Instruction::STRING => {
							println!("Unsupported instruction 'STRING' ");
						}
					}
				}
			}

		}
	}
	fn push(&mut self, value: u8) -> (){
		self.stack.push(value);
	}
	fn pop(&mut self) -> u8{
		let a: Option<u8>=self.stack.pop();
		match a{
			None => {
				println!("Failed to pop");
				0
			},
			Some(result) => {
				result
			}
		}
	}
}
<|endoftext|>


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

/*!

Functions for the unit type.

*/

#[cfg(not(test))]
use prelude::*;
#[cfg(not(test))]
use num::Zero;

#[cfg(not(test))]
impl Eq for () {
    #[inline]
    fn eq(&self, _other: &()) -> bool { true }
    #[inline]
    fn ne(&self, _other: &()) -> bool { false }
}

#[cfg(not(test))]
impl Ord for () {
    #[inline]
    fn lt(&self, _other: &()) -> bool { false }
    #[inline]
    fn le(&self, _other: &()) -> bool { true }
    #[inline]
    fn ge(&self, _other: &()) -> bool { true }
    #[inline]
    fn gt(&self, _other: &()) -> bool { false }
}

#[cfg(not(test))]
impl TotalOrd for () {
    #[inline]
    fn cmp(&self, _other: &()) -> Ordering { Equal }
}

#[cfg(not(test))]
impl TotalEq for () {
    #[inline]
    fn equals(&self, _other: &()) -> bool { true }
}

#[cfg(not(test))]
impl Zero for () {
    fn zero() -> () { () }
    fn is_zero(&self) -> bool { true }
}

<commit_msg>Add #[inline] to impl Zero for ()<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Functions for the unit type.

*/

#[cfg(not(test))]
use prelude::*;
#[cfg(not(test))]
use num::Zero;

#[cfg(not(test))]
impl Eq for () {
    #[inline]
    fn eq(&self, _other: &()) -> bool { true }
    #[inline]
    fn ne(&self, _other: &()) -> bool { false }
}

#[cfg(not(test))]
impl Ord for () {
    #[inline]
    fn lt(&self, _other: &()) -> bool { false }
    #[inline]
    fn le(&self, _other: &()) -> bool { true }
    #[inline]
    fn ge(&self, _other: &()) -> bool { true }
    #[inline]
    fn gt(&self, _other: &()) -> bool { false }
}

#[cfg(not(test))]
impl TotalOrd for () {
    #[inline]
    fn cmp(&self, _other: &()) -> Ordering { Equal }
}

#[cfg(not(test))]
impl TotalEq for () {
    #[inline]
    fn equals(&self, _other: &()) -> bool { true }
}

#[cfg(not(test))]
impl Zero for () {
    #[inline]
    fn zero() -> () { () }
    #[inline]
    fn is_zero(&self) -> bool { true }
}

<|endoftext|>


<commit_before>extern crate rand;
use rand::Rng;

pub struct Continent {
    pub id: u8,
    pub diseases: DiceHolder,
}

impl Continent {
    pub fn new(id: u8) -> Continent {
        Continent {
            id: id,
            diseases: DiceHolder::new(),
        }
    }
    // adds Disease d to the DiceHolder
    pub fn add(&mut self, d: Disease) {
        self.diseases.add(d);
    }
    pub fn total_count(&self) -> [u8; 4] {
        self.diseases.total_count()
    }
}

pub struct DiceHolder {
    dice: Vec<Disease>,
}

impl DiceHolder {
    pub fn new() -> DiceHolder {
        DiceHolder { dice: Vec::new() }
    }
    // add a Disease to the holder
    pub fn add(&mut self, d: Disease) {
        self.dice.push(d);
    }
    // return number of given color
    pub fn count(&self, color: &str) -> u8 {
        let mut count = 0;
        match color {
            "red" | "Red" => {
                for i in self.dice.iter() {
                    match i {
                        &Disease::Red => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            "yellow" | "Yellow" => {
                for i in self.dice.iter() {
                    match i {
                        &Disease::Yellow => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            "blue" | "Blue" => {
                for i in self.dice.iter() {
                    match i {
                        &Disease::Blue => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            "black" | "Black" => {
                for i in self.dice.iter() {
                    match i {
                        &Disease::Black => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            _ => 0,
        }
    }
    // grab random die, remove and return it
    pub fn grab(&mut self) -> Option<Disease> {
        if self.size() <= 0 {
            None
        } else {
            // try randomly until we hit a color that exists
            loop {
                let color = match rand::thread_rng().gen_range(0, 4) {
                    0 => Disease::Red,
                    1 => Disease::Yellow,
                    2 => Disease::Blue,
                    3 => Disease::Black,
                    _ => panic!("Check disease.grab() something's fucked"),
                };
                match self.remove(color) {
                    Some(color) => return Some(color),
                    None => continue,
                }
            }
        }
    }
    // remove and return an Option with the Disease specified - TODO: make this less gross
    // i'm fighting the borrow checker, not working with it
    pub fn remove(&mut self, d: Disease) -> Option<Disease> {
        // grab first die that matches
        let mut found: bool = false;
        let mut index: usize = 0;
        for (i, elem) in self.dice.iter_mut().enumerate() {
            if elem == &d {
                // TODO: cont. i'd like to be able to just return the Option from here
                // but already have a mutable reference to iterate in the first place
                found = true;
                index = i;
                break;
            }
        }
        if found {
            Some(self.dice.remove(index))
        } else {
            None
        }
    }
    // size of holder
    pub fn size(&self) -> usize {
        self.dice.len()
    }
    // returns an array with the counts [red, yellow, blue, black]
    pub fn total_count(&self) -> [u8; 4] {
        [self.count("red"), self.count("yellow"), self.count("blue"), self.count("black")]
    }
}

// partialeq to compare variants
#[derive(PartialEq)]
pub enum Disease {
    Red,
    Yellow,
    Blue,
    Black,
}

impl Disease {
    // returns result of die roll - die weights from rule book
    // 0 signifies a CDC token
    pub fn roll(&self) -> u8 {
        let roll = rand::thread_rng().gen_range(0, 6);
        match self {
            &Disease::Red => {
                match roll {
                    0 => 0,
                    1 | 2 => 1,
                    3 => 4,
                    4 | 5 => 6,
                    _ => panic!("invalid random roll"),
                }
            }
            &Disease::Yellow => {
                match roll {
                    0 => 0,
                    1 | 2 => 2,
                    3 => 4,
                    4 | 5 => 5,
                    _ => panic!("invalid random roll"),
                }
            }
            &Disease::Blue => {
                match roll {
                    0 => 0,
                    1 => 1,
                    2 => 2,
                    3 => 3,
                    4 | 5 => 6,
                    _ => panic!("invalid random roll"),
                }
            }
            &Disease::Black => {
                match roll {
                    0 => 0,
                    1 | 2 | 3 => 3,
                    4 => 4,
                    5 => 5,
                    _ => panic!("invalid random roll"),
                }
            }
        }
    }
}

pub struct GameModel {
    pub continents: Vec<Continent>,
    pub cdc: DiceHolder,
    pub treatment_center: DiceHolder,
    pub infection_bag: DiceHolder,
}

impl GameModel {
    pub fn new() -> GameModel {
        let mut ret = GameModel {
            continents: Vec::new(),
            cdc: DiceHolder::new(),
            treatment_center: DiceHolder::new(),
            infection_bag: DiceHolder::new(),
        };
        // 6 continents
        for i in 1..7 {
            ret.continents.push(Continent::new(i));
        }
        // 12 of each color in bag
        for _ in 0..12 {
            ret.infection_bag.add(Disease::Red);
            ret.infection_bag.add(Disease::Yellow);
            ret.infection_bag.add(Disease::Blue);
            ret.infection_bag.add(Disease::Black);
        }
        ret
    }
    pub fn initial_infect(&mut self) {
        let mut dice: Vec<Disease> = Vec::new();
        // grab 12 random
        for _ in 0..12 {
            dice.push(match self.infection_bag.grab() {
                Some(color) => color,
                None => panic!("grab failed, but its the beginning of the game!"),
            });
        }
        // roll and place
        for i in dice.iter() {
            let mut roll = 0;
            // roll until we don't get a zero
            while roll == 0 {
                roll = i.roll();
            }
            // TODO: we're fighting the borrow checker again here
            let result = match i {
                &Disease::Red => Disease::Red,
                &Disease::Yellow => Disease::Yellow,
                &Disease::Blue => Disease::Blue,
                &Disease::Black => Disease::Black,
            };
            self.continents[roll as usize - 1].add(result);
        }
    }
}<commit_msg>use expect for Option<commit_after>extern crate rand;
use rand::Rng;

pub struct Continent {
    pub id: u8,
    pub diseases: DiceHolder,
}

impl Continent {
    pub fn new(id: u8) -> Continent {
        Continent {
            id: id,
            diseases: DiceHolder::new(),
        }
    }
    // adds Disease d to the DiceHolder
    pub fn add(&mut self, d: Disease) {
        self.diseases.add(d);
    }
    pub fn total_count(&self) -> [u8; 4] {
        self.diseases.total_count()
    }
}

pub struct DiceHolder {
    dice: Vec<Disease>,
}

impl DiceHolder {
    pub fn new() -> DiceHolder {
        DiceHolder { dice: Vec::new() }
    }
    // add a Disease to the holder
    pub fn add(&mut self, d: Disease) {
        self.dice.push(d);
    }
    // return number of given color
    pub fn count(&self, color: &str) -> u8 {
        let mut count = 0;
        match color {
            "red" | "Red" => {
                for i in self.dice.iter() {
                    match i {
                        &Disease::Red => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            "yellow" | "Yellow" => {
                for i in self.dice.iter() {
                    match i {
                        &Disease::Yellow => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            "blue" | "Blue" => {
                for i in self.dice.iter() {
                    match i {
                        &Disease::Blue => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            "black" | "Black" => {
                for i in self.dice.iter() {
                    match i {
                        &Disease::Black => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            _ => 0,
        }
    }
    // grab random die, remove and return it
    pub fn grab(&mut self) -> Option<Disease> {
        if self.size() <= 0 {
            None
        } else {
            // try randomly until we hit a color that exists
            loop {
                let color = match rand::thread_rng().gen_range(0, 4) {
                    0 => Disease::Red,
                    1 => Disease::Yellow,
                    2 => Disease::Blue,
                    3 => Disease::Black,
                    _ => panic!("Check disease.grab() something's fucked"),
                };
                match self.remove(color) {
                    Some(color) => return Some(color),
                    None => continue,
                }
            }
        }
    }
    // remove and return an Option with the Disease specified - TODO: make this less gross
    // i'm fighting the borrow checker, not working with it
    pub fn remove(&mut self, d: Disease) -> Option<Disease> {
        // grab first die that matches
        let mut found: bool = false;
        let mut index: usize = 0;
        for (i, elem) in self.dice.iter_mut().enumerate() {
            if elem == &d {
                // TODO: cont. i'd like to be able to just return the Option from here
                // but already have a mutable reference to iterate in the first place
                found = true;
                index = i;
                break;
            }
        }
        if found {
            Some(self.dice.remove(index))
        } else {
            None
        }
    }
    // size of holder
    pub fn size(&self) -> usize {
        self.dice.len()
    }
    // returns an array with the counts [red, yellow, blue, black]
    pub fn total_count(&self) -> [u8; 4] {
        [self.count("red"), self.count("yellow"), self.count("blue"), self.count("black")]
    }
}

// partialeq to compare variants
#[derive(PartialEq)]
pub enum Disease {
    Red,
    Yellow,
    Blue,
    Black,
}

impl Disease {
    // returns result of die roll - die weights from rule book
    // 0 signifies a CDC token
    pub fn roll(&self) -> u8 {
        let roll = rand::thread_rng().gen_range(0, 6);
        match self {
            &Disease::Red => {
                match roll {
                    0 => 0,
                    1 | 2 => 1,
                    3 => 4,
                    4 | 5 => 6,
                    _ => panic!("invalid random roll"),
                }
            }
            &Disease::Yellow => {
                match roll {
                    0 => 0,
                    1 | 2 => 2,
                    3 => 4,
                    4 | 5 => 5,
                    _ => panic!("invalid random roll"),
                }
            }
            &Disease::Blue => {
                match roll {
                    0 => 0,
                    1 => 1,
                    2 => 2,
                    3 => 3,
                    4 | 5 => 6,
                    _ => panic!("invalid random roll"),
                }
            }
            &Disease::Black => {
                match roll {
                    0 => 0,
                    1 | 2 | 3 => 3,
                    4 => 4,
                    5 => 5,
                    _ => panic!("invalid random roll"),
                }
            }
        }
    }
}

pub struct GameModel {
    pub continents: Vec<Continent>,
    pub cdc: DiceHolder,
    pub treatment_center: DiceHolder,
    pub infection_bag: DiceHolder,
}

impl GameModel {
    pub fn new() -> GameModel {
        let mut ret = GameModel {
            continents: Vec::new(),
            cdc: DiceHolder::new(),
            treatment_center: DiceHolder::new(),
            infection_bag: DiceHolder::new(),
        };
        // 6 continents
        for i in 1..7 {
            ret.continents.push(Continent::new(i));
        }
        // 12 of each color in bag
        for _ in 0..12 {
            ret.infection_bag.add(Disease::Red);
            ret.infection_bag.add(Disease::Yellow);
            ret.infection_bag.add(Disease::Blue);
            ret.infection_bag.add(Disease::Black);
        }
        ret
    }
    pub fn initial_infect(&mut self) {
        let mut dice: Vec<Disease> = Vec::new();
        // grab 12 random
        for _ in 0..12 {
            dice.push(self.infection_bag.grab().expect("grab failed during initial_infect"));
        }
        // roll and place
        for i in dice.iter() {
            let mut roll = 0;
            // roll until we don't get a zero
            while roll == 0 {
                roll = i.roll();
            }
            // TODO: we're fighting the borrow checker again here
            let result = match i {
                &Disease::Red => Disease::Red,
                &Disease::Yellow => Disease::Yellow,
                &Disease::Blue => Disease::Blue,
                &Disease::Black => Disease::Black,
            };
            self.continents[roll as usize - 1].add(result);
        }
    }
}<|endoftext|>


<commit_before>use core::ops::{Div, Rem};
pub trait DivRemEuclid: Sized + Div<Self, Output = Self> + Rem<Self, Output = Self> {
    /// Calculates Euclidean division, the matching method for `rem_euclid`.
    ///
    /// This computes the integer `n` such that
    /// `self = n * rhs + self.rem_euclid(rhs)`.
    /// In other words, the result is `self / rhs` rounded to the integer `n`
    /// such that `self >= n * rhs`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::DivRemEuclid;
    ///
    /// let a: i32 = 7;
    /// let b: i32 = 4;
    /// assert_eq!(DivRemEuclid::div_euclid(&a,&b), 1); // 7 > 4 * 1
    /// assert_eq!(DivRemEuclid::div_euclid(&-a,&b), -2); // -7 >= 4 * -2
    /// assert_eq!(DivRemEuclid::div_euclid(&a,&-b), -1); // 7 >= -4 * -1
    /// assert_eq!(DivRemEuclid::div_euclid(&-a,&-b), 2); // -7 >= -4 * 2
    /// ```
    fn div_euclid(&self, v: &Self) -> Self;

    /// Calculates the least nonnegative remainder of `self (mod rhs)`.
    ///
    /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in
    /// most cases. However, due to a floating point round-off error it can
    /// result in `r == rhs.abs()`, violating the mathematical definition, if
    /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`.
    /// This result is not an element of the function's codomain, but it is the
    /// closest floating point number in the real numbers and thus fulfills the
    /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)`
    /// approximatively.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::DivRemEuclid;
    ///
    /// let a: f32 = 7.0;
    /// let b: f32 = 4.0;
    /// assert_eq!(DivRemEuclid::rem_euclid(&a,&b), 3.0);
    /// assert_eq!(DivRemEuclid::rem_euclid(&-a,&b), 1.0);
    /// assert_eq!(DivRemEuclid::rem_euclid(&a,&-b), 3.0);
    /// assert_eq!(DivRemEuclid::rem_euclid(&-a,&-b), 1.0);
    /// ```
    fn rem_euclid(&self, v: &Self) -> Self;
}
macro_rules! div_rem_euclid_impl {
    ($trait_name:ident for $($t:ty)*) => {$(
        impl $trait_name for $t {
            #[inline]
            fn div_euclid(&self, v: &$t) -> Self {
                <$t>::div_euclid(*self, *v)
            }

            #[inline]
            fn rem_euclid(&self, v: &$t) -> Self {
                <$t>::rem_euclid(*self, *v)
            }

        }
    )*}
}
div_rem_euclid_impl!(DivRemEuclid for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
#[cfg(has_i128)]
div_rem_euclid_impl!(DivRemEuclid for i128 u128);

#[cfg(any(feature = "std", feature = "libm"))]
impl DivRemEuclid for f32 {
    fn div_euclid(&self, rhs: &f32) -> f32 {
        let q = <f32 as ::Float>::trunc(self / rhs);
        if self % rhs < 0.0 {
            return if *rhs > 0.0 { q - 1.0 } else { q + 1.0 };
        }
        q
    }

    fn rem_euclid(&self, rhs: &f32) -> f32 {
        let r = self % rhs;
        if r < 0.0 {
            r + <f32 as ::Float>::abs(*rhs)
        } else {
            r
        }
    }
}

#[cfg(any(feature = "std", feature = "libm"))]
impl DivRemEuclid for f64 {
    fn div_euclid(&self, rhs: &f64) -> f64 {
        let q = <f64 as ::Float>::trunc(self / rhs);
        if self % rhs < 0.0 {
            return if *rhs > 0.0 { q - 1.0 } else { q + 1.0 };
        }
        q
    }

    fn rem_euclid(&self, rhs: &f64) -> f64 {
        let r = self % rhs;
        if r < 0.0 {
            r + <f64 as ::Float>::abs(*rhs)
        } else {
            r
        }
    }
}

pub trait CheckedDivRemEuclid: Sized + Div<Self, Output = Self> + Rem<Self, Output = Self> {
    /// Performs euclid division that returns `None` instead of panicking on division by zero
    /// and instead of wrapping around on underflow and overflow.
    fn checked_div_euclid(&self, v: &Self) -> Option<Self>;

    /// Finds the euclid remainder of dividing two numbers, checking for underflow, overflow and
    /// division by zero. If any of that happens, `None` is returned.
    fn checked_rem_euclid(&self, v: &Self) -> Option<Self>;
}

macro_rules! checked_div_rem_euclid_impl {
    ($trait_name:ident for $($t:ty)*) => {$(
        impl $trait_name for $t {
            #[inline]
            fn checked_div_euclid(&self, v: &$t) -> Option<$t> {
                <$t>::checked_div_euclid(*self, *v)
            }

            #[inline]
            fn checked_rem_euclid(&self, v: &$t) -> Option<$t> {
                <$t>::checked_rem_euclid(*self, *v)
            }
        }
    )*}
}
checked_div_rem_euclid_impl!(CheckedDivRemEuclid for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
#[cfg(has_i128)]
checked_div_rem_euclid_impl!(CheckedDivRemEuclid for i128 u128);

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

    #[test]
    fn euclid_unsigned() {
        macro_rules! test_euclid {
            ($($t:ident)+) => {
                $(
                    {
                        let x: $t = 10;
                        let y: $t = 3;
                        assert_eq!(DivRemEuclid::div_euclid(&x,&y),3);
                        assert_eq!(DivRemEuclid::rem_euclid(&x,&y),1);
                    }
                )+
            };
        }

        test_euclid!(usize u8 u16 u32 u64 isize);
    }

    #[test]
    fn euclid_signed() {
        macro_rules! test_euclid {
            ($($t:ident)+) => {
                $(
                    {
                        let x: $t = 10;
                        let y: $t = -3;
                        assert_eq!(DivRemEuclid::div_euclid(&x,&y),-3);
                        assert_eq!(DivRemEuclid::div_euclid(&-x,&y),4);
                        assert_eq!(DivRemEuclid::rem_euclid(&x,&y),1);
                        assert_eq!(DivRemEuclid::rem_euclid(&-x,&y),2);
                        let x: $t = $t::MIN+1;
                        let y: $t = -1;
                        assert_eq!(DivRemEuclid::div_euclid(&x,&y),$t::MAX);
                    }
                )+
            };
        }

        test_euclid!(i8 i16 i32 i64);
    }

    #[test]
    #[cfg(any(feature = "std", feature = "libm"))]
    fn euclid_float() {
        macro_rules! test_euclid {
            ($($t:ident)+) => {
                $(
                    {
                        let x: $t = 12.1;
                        let y: $t = 3.2;
                        assert!(DivRemEuclid::div_euclid(&x,&y)*y+DivRemEuclid::rem_euclid(&x,&y)-x
                        <=46.4 * $t::EPSILON);
                        assert!(DivRemEuclid::div_euclid(&x,&-y)*-y+DivRemEuclid::rem_euclid(&x,&-y)-x
                        <= 46.4 * $t::EPSILON);
                        assert!(DivRemEuclid::div_euclid(&-x,&y)*y+DivRemEuclid::rem_euclid(&-x,&y)-(-x)
                        <= 46.4 * $t::EPSILON);
                        assert!(DivRemEuclid::div_euclid(&-x,&-y)*-y+DivRemEuclid::rem_euclid(&-x,&-y)-(-x)
                        <= 46.4 * $t::EPSILON);
                    }
                )+
            };
        }

        test_euclid!(f32 f64);
    }

    #[test]
    fn euclid_checked() {
        macro_rules! test_euclid_checked {
            ($($t:ident)+) => {
                $(
                    {
                        assert_eq!(CheckedDivRemEuclid::checked_div_euclid(&$t::MIN,&-1),None);
                        assert_eq!(CheckedDivRemEuclid::checked_rem_euclid(&$t::MIN,&-1),None);
                        assert_eq!(CheckedDivRemEuclid::checked_div_euclid(&1,&0),None);
                        assert_eq!(CheckedDivRemEuclid::checked_rem_euclid(&1,&0),None);
                    }
                )+
            };
        }

        test_euclid_checked!(i8 i16 i32 i64);
    }
}
<commit_msg>fixes example<commit_after>use core::ops::{Div, Rem};
pub trait DivRemEuclid: Sized + Div<Self, Output = Self> + Rem<Self, Output = Self> {
    /// Calculates Euclidean division, the matching method for `rem_euclid`.
    ///
    /// This computes the integer `n` such that
    /// `self = n * rhs + self.rem_euclid(rhs)`.
    /// In other words, the result is `self / rhs` rounded to the integer `n`
    /// such that `self >= n * rhs`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::DivRemEuclid;
    ///
    /// let a: i32 = 7;
    /// let b: i32 = 4;
    /// assert_eq!(DivRemEuclid::div_euclid(&a,&b), 1); // 7 > 4 * 1
    /// assert_eq!(DivRemEuclid::div_euclid(&-a,&b), -2); // -7 >= 4 * -2
    /// assert_eq!(DivRemEuclid::div_euclid(&a,&-b), -1); // 7 >= -4 * -1
    /// assert_eq!(DivRemEuclid::div_euclid(&-a,&-b), 2); // -7 >= -4 * 2
    /// ```
    fn div_euclid(&self, v: &Self) -> Self;

    /// Calculates the least nonnegative remainder of `self (mod rhs)`.
    ///
    /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in
    /// most cases. However, due to a floating point round-off error it can
    /// result in `r == rhs.abs()`, violating the mathematical definition, if
    /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`.
    /// This result is not an element of the function's codomain, but it is the
    /// closest floating point number in the real numbers and thus fulfills the
    /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)`
    /// approximatively.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::DivRemEuclid;
    ///
    /// let a: i32 = 7;
    /// let b: i32 = 4;
    /// assert_eq!(DivRemEuclid::rem_euclid(&a,&b), 3);
    /// assert_eq!(DivRemEuclid::rem_euclid(&-a,&b), 1);
    /// assert_eq!(DivRemEuclid::rem_euclid(&a,&-b), 3);
    /// assert_eq!(DivRemEuclid::rem_euclid(&-a,&-b), 1);
    /// ```
    fn rem_euclid(&self, v: &Self) -> Self;
}
macro_rules! div_rem_euclid_impl {
    ($trait_name:ident for $($t:ty)*) => {$(
        impl $trait_name for $t {
            #[inline]
            fn div_euclid(&self, v: &$t) -> Self {
                <$t>::div_euclid(*self, *v)
            }

            #[inline]
            fn rem_euclid(&self, v: &$t) -> Self {
                <$t>::rem_euclid(*self, *v)
            }

        }
    )*}
}
div_rem_euclid_impl!(DivRemEuclid for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
#[cfg(has_i128)]
div_rem_euclid_impl!(DivRemEuclid for i128 u128);

#[cfg(any(feature = "std", feature = "libm"))]
impl DivRemEuclid for f32 {
    fn div_euclid(&self, rhs: &f32) -> f32 {
        let q = <f32 as ::Float>::trunc(self / rhs);
        if self % rhs < 0.0 {
            return if *rhs > 0.0 { q - 1.0 } else { q + 1.0 };
        }
        q
    }

    fn rem_euclid(&self, rhs: &f32) -> f32 {
        let r = self % rhs;
        if r < 0.0 {
            r + <f32 as ::Float>::abs(*rhs)
        } else {
            r
        }
    }
}

#[cfg(any(feature = "std", feature = "libm"))]
impl DivRemEuclid for f64 {
    fn div_euclid(&self, rhs: &f64) -> f64 {
        let q = <f64 as ::Float>::trunc(self / rhs);
        if self % rhs < 0.0 {
            return if *rhs > 0.0 { q - 1.0 } else { q + 1.0 };
        }
        q
    }

    fn rem_euclid(&self, rhs: &f64) -> f64 {
        let r = self % rhs;
        if r < 0.0 {
            r + <f64 as ::Float>::abs(*rhs)
        } else {
            r
        }
    }
}

pub trait CheckedDivRemEuclid: Sized + Div<Self, Output = Self> + Rem<Self, Output = Self> {
    /// Performs euclid division that returns `None` instead of panicking on division by zero
    /// and instead of wrapping around on underflow and overflow.
    fn checked_div_euclid(&self, v: &Self) -> Option<Self>;

    /// Finds the euclid remainder of dividing two numbers, checking for underflow, overflow and
    /// division by zero. If any of that happens, `None` is returned.
    fn checked_rem_euclid(&self, v: &Self) -> Option<Self>;
}

macro_rules! checked_div_rem_euclid_impl {
    ($trait_name:ident for $($t:ty)*) => {$(
        impl $trait_name for $t {
            #[inline]
            fn checked_div_euclid(&self, v: &$t) -> Option<$t> {
                <$t>::checked_div_euclid(*self, *v)
            }

            #[inline]
            fn checked_rem_euclid(&self, v: &$t) -> Option<$t> {
                <$t>::checked_rem_euclid(*self, *v)
            }
        }
    )*}
}
checked_div_rem_euclid_impl!(CheckedDivRemEuclid for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
#[cfg(has_i128)]
checked_div_rem_euclid_impl!(CheckedDivRemEuclid for i128 u128);

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

    #[test]
    fn euclid_unsigned() {
        macro_rules! test_euclid {
            ($($t:ident)+) => {
                $(
                    {
                        let x: $t = 10;
                        let y: $t = 3;
                        assert_eq!(DivRemEuclid::div_euclid(&x,&y),3);
                        assert_eq!(DivRemEuclid::rem_euclid(&x,&y),1);
                    }
                )+
            };
        }

        test_euclid!(usize u8 u16 u32 u64 isize);
    }

    #[test]
    fn euclid_signed() {
        macro_rules! test_euclid {
            ($($t:ident)+) => {
                $(
                    {
                        let x: $t = 10;
                        let y: $t = -3;
                        assert_eq!(DivRemEuclid::div_euclid(&x,&y),-3);
                        assert_eq!(DivRemEuclid::div_euclid(&-x,&y),4);
                        assert_eq!(DivRemEuclid::rem_euclid(&x,&y),1);
                        assert_eq!(DivRemEuclid::rem_euclid(&-x,&y),2);
                        let x: $t = $t::MIN+1;
                        let y: $t = -1;
                        assert_eq!(DivRemEuclid::div_euclid(&x,&y),$t::MAX);
                    }
                )+
            };
        }

        test_euclid!(i8 i16 i32 i64);
    }

    #[test]
    #[cfg(any(feature = "std", feature = "libm"))]
    fn euclid_float() {
        macro_rules! test_euclid {
            ($($t:ident)+) => {
                $(
                    {
                        use core::$t;

                        let x: $t = 12.1;
                        let y: $t = 3.2;
                        assert!(DivRemEuclid::div_euclid(&x,&y)*y+DivRemEuclid::rem_euclid(&x,&y)-x
                        <=46.4 * $t::EPSILON);
                        assert!(DivRemEuclid::div_euclid(&x,&-y)*-y+DivRemEuclid::rem_euclid(&x,&-y)-x
                        <= 46.4 * $t::EPSILON);
                        assert!(DivRemEuclid::div_euclid(&-x,&y)*y+DivRemEuclid::rem_euclid(&-x,&y)-(-x)
                        <= 46.4 * $t::EPSILON);
                        assert!(DivRemEuclid::div_euclid(&-x,&-y)*-y+DivRemEuclid::rem_euclid(&-x,&-y)-(-x)
                        <= 46.4 * $t::EPSILON);
                    }
                )+
            };
        }

        test_euclid!(f32 f64);
    }

    #[test]
    fn euclid_checked() {
        macro_rules! test_euclid_checked {
            ($($t:ident)+) => {
                $(
                    {
                        assert_eq!(CheckedDivRemEuclid::checked_div_euclid(&$t::MIN,&-1),None);
                        assert_eq!(CheckedDivRemEuclid::checked_rem_euclid(&$t::MIN,&-1),None);
                        assert_eq!(CheckedDivRemEuclid::checked_div_euclid(&1,&0),None);
                        assert_eq!(CheckedDivRemEuclid::checked_rem_euclid(&1,&0),None);
                    }
                )+
            };
        }

        test_euclid_checked!(i8 i16 i32 i64);
    }
}
<|endoftext|>