<commit_before>use std::cmp;
use std::mem;
use std::fmt;
use std::collections::BTreeMap;
use mio;

use lmdb_rs::{self, EnvBuilder, Environment, DbFlags, MdbError};
use tempdir::TempDir;
use byteorder::{ByteOrder, BigEndian};
use spki_sexp;

use super::{Operation,OpResp};
use event_handler::EventHandler;

const REPLICATION_CREDIT : u64 = 1024;

#[derive(Debug)]
struct Forwarder {
    last_sent_downstream: Option<u64>,
    last_acked_downstream: Option<u64>,
    pending_operations: BTreeMap<u64, mio::Token>,
}

#[derive(Debug)]
struct Terminus {
    state: String,
}

#[derive(Debug)]
enum Role {
    Forwarder(Forwarder),
    Terminus(Terminus),
}

struct Log {
    dir: TempDir,
    env: Environment,
}

impl Log {
    fn new() -> Log {
        let d = TempDir::new("lmdb-log").expect("new log");
        info!("DB path: {:?}", d.path());
        let env = EnvBuilder::new().open(d.path(), 0o777).expect("open db");

        Log { dir: d, env: env }
    }

    fn tokey(seq: u64) -> [u8; 8] {
        let mut buf : [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
        BigEndian::write_u64(&mut buf, seq);
        buf
    }

    fn fromkey(key: &[u8]) -> u64 {
        BigEndian::read_u64(&key)
    }

    pub fn seqno(&self) -> u64 {
        let mut dbh = self.env.get_default_db(DbFlags::empty()).expect("open-db");
        let mut rdr = self.env.get_reader().expect("get_reader");
        let mut db = rdr.bind(&dbh);
        let mut cur = db.new_cursor().expect("cursor");
        match cur.to_last() {
            Ok(()) => {
                let last_key = cur.get_key::<&[u8]>().expect("get_key");
                let current = Self::fromkey(last_key);
                let next = current + 1;
                debug!("Last exisiting current: {:?}; key: {:?}; next: {:?}", last_key, current, next);
                next
            },
            Err(MdbError::NotFound) => 0,
            Err(e) => panic!("Unexpected error getting last item: {:?}", e),
        }
    }

    fn read(&self, seqno: u64) -> Option<Operation> {
        let mut dbh = self.env.get_default_db(DbFlags::empty()).expect("open-db");
        let mut rdr = self.env.get_reader().expect("get_reader");
        let mut db = rdr.bind(&dbh);
        let key = Self::tokey(seqno);
        let ret = match db.get(&key.as_ref()) {
            Ok(val) => Some(spki_sexp::from_bytes(val).expect("decode operation")),
            Err(MdbError::NotFound) => None,
            Err(e) => panic!("Unexpected error reading index: {:?}: {:?}", seqno, e),
        };
        debug!("Read: {:?} => {:?}", seqno, ret);
        ret
    }

    fn verify_sequential(&self, seqno: u64) -> bool {
        let current = self.seqno();
        if !(seqno == 0 || current <= seqno) {
            warn!("Hole in history: saw {}; have: {:?}", seqno, current);
            false
        } else {
            true
        }
    }

    fn insert_at(&mut self, seqno: u64, op: &Operation) {
        let bytes = spki_sexp::as_bytes(op).expect("encode operation");
        let mut dbh = self.env.get_default_db(DbFlags::empty()).expect("open-db");
        let txn = self.env.new_transaction().expect("new_transaction");
        debug!("Checking {:?}", seqno);
        let key = Self::tokey(seqno);
        match txn.bind(&dbh).get::<&[u8]>(&key.as_ref()) {
            Err(MdbError::NotFound) => (),
            Err(e) => panic!("Unexpected error reading index: {:?}: {:?}", seqno, e),
            Ok(_) => panic!("Unexpected entry at seqno: {:?}", seqno),
        };

        txn.bind(&dbh).set(&key.as_ref(), &bytes).expect("Persist operation");
        txn.commit().expect("txn commit");
        debug!("Wrote as {:?}/{:?}: {:?}", seqno, key, bytes.len());
    }
}

#[derive(Debug)]
pub struct ReplModel {
    next: Role,
    log: Log,
    current_epoch: u64,
}
impl fmt::Debug for Log {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Log").field("dir", &self.dir.path()).finish()
    }
}

impl Role {
    fn process_operation(&mut self, channel: &mut EventHandler, epoch: u64, seqno: u64, op: Operation) {
        match self {
            &mut Role::Forwarder(ref mut f) => f.process_operation(channel, epoch, seqno, op),
            &mut Role::Terminus(ref mut t) => t.process_operation(channel, epoch, seqno, op),
        }
    }
    pub fn process_downstream_response(&mut self, reply: &OpResp) -> Option<mio::Token> {
        match self {
            &mut Role::Forwarder(ref mut f) => f.process_downstream_response(reply),
            _ => None,
        }
    }

    pub fn process_replication<F: FnMut(u64, Operation)>(&mut self, log: &Log, forward: F) -> bool {
        match self {
            &mut Role::Forwarder(ref mut f) => f.process_replication(log, forward),
            _ => false,
        }
    }
    fn has_pending(&self, token: mio::Token) -> bool {
        match self {
            &Role::Forwarder(ref f) => f.has_pending(token),
            _ => false,
        }
    }
    fn reset(&mut self) {
        match self {
            &mut Role::Forwarder(ref mut f) => f.reset(),
            _ => (),
        }
    }
}

impl Forwarder {
    fn new() -> Forwarder {
        Forwarder {
            last_sent_downstream: None,
            last_acked_downstream: None,
            pending_operations: BTreeMap::new(),
        }
    }

    fn process_operation(&mut self, channel: &mut EventHandler, epoch: u64, seqno: u64, op: Operation) {
        self.pending_operations.insert(seqno, channel.token());
    }

    fn process_downstream_response(&mut self, reply: &OpResp) -> Option<mio::Token> {
        match reply {
            &OpResp::Ok(epoch, seqno, _) | &OpResp::Err(epoch, seqno, _) => {
                self.last_acked_downstream = Some(seqno);
                if let Some(token) = self.pending_operations.remove(&seqno) {
                    info!("Found in-flight op {:?} for client token {:?}", seqno, token);
                    Some(token)
                } else {
                    warn!("Unexpected response for seqno: {:?}", seqno);
                    None
                }
            },
            &OpResp::HelloIWant(last_sent_downstream) => {
                info!("Downstream has {:?}", last_sent_downstream);
                // assert!(last_sent_downstream <= self.seqno());
                self.last_acked_downstream = Some(last_sent_downstream);
                self.last_sent_downstream = Some(last_sent_downstream);
                None
            },
        }
    }

    pub fn process_replication<F: FnMut(u64, Operation)>(&mut self, log: &Log, mut forward: F) -> bool {
        let mut changed = false;
        debug!("pre  Repl: Ours: {:?}; downstream sent: {:?}; acked: {:?}",
            log.seqno(), self.last_sent_downstream, self.last_acked_downstream);

        let mut changed = false;
        if let Some(send_next) = self.last_sent_downstream {
            if send_next < log.seqno() {
                let max_to_push_now = cmp::min(self.last_acked_downstream.unwrap_or(0) + REPLICATION_CREDIT, log.seqno());
                debug!("Window push {:?} - {:?}; waiting: {:?}", send_next, max_to_push_now, log.seqno() - max_to_push_now);
                for i in send_next..max_to_push_now {
                    if let Some(op) = log.read(i) {
                        debug!("Queueing seq:{:?}/{:?}; ds/seqno: {:?}", i, op, self.last_sent_downstream);
                        forward(i, op);
                        self.last_sent_downstream = Some(i+1);
                        changed = true
                    } else {
                        panic!("Attempted to replicate item not in log: {:?}", self);
                    }
                }
            }
            debug!("post Repl: Ours: {:?}; downstream sent: {:?}; acked: {:?}",
                log.seqno(), self.last_sent_downstream, self.last_acked_downstream);
        }
        changed
    }

    fn has_pending(&self, token: mio::Token) -> bool {
        self.pending_operations.values().all(|tok| tok != &token)
    }

    fn reset(&mut self) {
        self.last_sent_downstream = None
    }
}

impl Terminus {
    fn new() -> Terminus {
        Terminus {
            state: "".to_string()
        }
    }

    fn process_operation(&mut self, channel: &mut EventHandler, epoch: u64, seqno: u64, op: Operation) {
        info!("Terminus! {:?}/{:?}", seqno, op);
        let resp = match op {
            Operation::Set(s) => {
                self.state = s;
                OpResp::Ok(epoch, seqno, None)
            },
                Operation::Get => OpResp::Ok(epoch, seqno, Some(self.state.clone()))
        };
        channel.response(resp)
    }
}

impl ReplModel {
    pub fn new() -> ReplModel {
        ReplModel {
            log: Log::new(),
            current_epoch: Default::default(),
            next: Role::Terminus(Terminus::new()),
        }
    }

    pub fn seqno(&self) -> u64 {
        self.log.seqno()
    }

    fn next_seqno(&self) -> u64 {
        self.log.seqno()
    }

    pub fn process_operation(&mut self, channel: &mut EventHandler, seqno: Option<u64>, epoch: Option<u64>, op: Operation) {
        let seqno = seqno.unwrap_or_else(|| self.next_seqno());
        let epoch = epoch.unwrap_or_else(|| self.current_epoch);

       if epoch != self.current_epoch {
            warn!("Operation epoch ({}) differers from our last observed configuration: ({})",
                epoch, self.current_epoch);
            let resp = OpResp::Err(epoch, seqno, format!("BadEpoch: {}; last seen config: {}", epoch, self.current_epoch));
            channel.response(resp);
            return;
        }

        if !self.log.verify_sequential(seqno) {
            let resp = OpResp::Err(epoch, seqno, format!("Bad sequence number; saw: {:?}", seqno));
            channel.response(resp);
            return;
        }

        self.log.insert_at(seqno, &op);
        self.next.process_operation(channel, epoch, seqno, op)
    }

    pub fn process_downstream_response(&mut self, reply: &OpResp) -> Option<mio::Token> {
        self.next.process_downstream_response(reply)
    }

    pub fn process_replication<F: FnMut(u64, u64, Operation)>(&mut self, mut forward: F) -> bool {
        let epoch = self.current_epoch;
        self.next.process_replication(&self.log, |i, op| forward(epoch, i, op))
    }

    pub fn epoch_changed(&mut self, epoch: u64) {
        self.current_epoch = epoch;
    }

    pub fn has_pending(&self, token: mio::Token) -> bool {
        self.next.has_pending(token)
    }

    pub fn reset(&mut self) {
        self.next.reset()
    }

    pub fn set_has_downstream(&mut self, is_forwarder: bool) {
        // XXX: Replays?
        match (is_forwarder, &mut self.next) {
            (true, role @ &mut Role::Terminus(_)) => {
                let prev = mem::replace(role, Role::Forwarder(Forwarder::new()));
                info!("Switched to forwarding from {:?}", prev);
            },

            (false, role @ &mut Role::Forwarder(_)) => {
                let prev = mem::replace(role, Role::Terminus(Terminus::new()));
                info!("Switched to terminating from {:?}", prev);
            },
            _ => { info!("No change of config"); }
        }
    }
}
<commit_msg>Use seperate data space for metadata.<commit_after>use std::cmp;
use std::mem;
use std::fmt;
use std::collections::BTreeMap;
use mio;

use lmdb_rs::{self, EnvBuilder, Environment, DbFlags, MdbError};
use tempdir::TempDir;
use byteorder::{ByteOrder, BigEndian};
use spki_sexp;

use super::{Operation,OpResp};
use event_handler::EventHandler;

const REPLICATION_CREDIT : u64 = 1024;

#[derive(Debug)]
struct Forwarder {
    last_sent_downstream: Option<u64>,
    last_acked_downstream: Option<u64>,
    pending_operations: BTreeMap<u64, mio::Token>,
}

#[derive(Debug)]
struct Terminus {
    state: String,
}

#[derive(Debug)]
enum Role {
    Forwarder(Forwarder),
    Terminus(Terminus),
}

struct Log {
    dir: TempDir,
    env: Environment,
}

const META : &'static str = "meta";
const DATA : &'static str = "data";
const META_COMMITTED : &'static str = "committed";

impl Log {
    fn new() -> Log {
        let d = TempDir::new("lmdb-log").expect("new log");
        info!("DB path: {:?}", d.path());
        let env = EnvBuilder::new().max_dbs(2).open(d.path(), 0o777).expect("open db");

        Log { dir: d, env: env }
    }

    fn tokey(seq: u64) -> [u8; 8] {
        let mut buf : [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
        BigEndian::write_u64(&mut buf, seq);
        buf
    }

    fn fromkey(key: &[u8]) -> u64 {
        BigEndian::read_u64(&key)
    }

    pub fn seqno(&self) -> u64 {
        let mut data = self.env.create_db(META, DbFlags::empty()).expect("open-db");
        let mut rdr = self.env.get_reader().expect("get_reader");

        match rdr.bind(&data).get(&META_COMMITTED) {
            Ok(val) => {
                let current = Self::fromkey(val);
                let next = current + 1;
                debug!("Last exisiting current: {:?}; next: {:?}", current, next);
                next
            },
            Err(MdbError::NotFound) => 0,
            Err(e) => panic!("Unexpected error getting last item: {:?}", e),
        }
    }

    fn read(&self, seqno: u64) -> Option<Operation> {
        let mut data = self.env.create_db(DATA, DbFlags::empty()).expect("open-db");
        let mut rdr = self.env.get_reader().expect("get_reader");
        let mut db = rdr.bind(&data);
        let key = Self::tokey(seqno);
        let ret = match db.get(&key.as_ref()) {
            Ok(val) => Some(spki_sexp::from_bytes(val).expect("decode operation")),
            Err(MdbError::NotFound) => None,
            Err(e) => panic!("Unexpected error reading index: {:?}: {:?}", seqno, e),
        };
        debug!("Read: {:?} => {:?}", seqno, ret);
        ret
    }

    fn verify_sequential(&self, seqno: u64) -> bool {
        let current = self.seqno();
        if !(seqno == 0 || current <= seqno) {
            warn!("Hole in history: saw {}; have: {:?}", seqno, current);
            false
        } else {
            true
        }
    }

    fn insert_at(&mut self, seqno: u64, op: &Operation) {
        let data_bytes = spki_sexp::as_bytes(op).expect("encode operation");
        let mut data = self.env.create_db(DATA, DbFlags::empty()).expect("open-db");
        let mut meta = self.env.create_db(META, DbFlags::empty()).expect("open-db");
        let txn = self.env.new_transaction().expect("new_transaction");
        debug!("Checking {:?}", seqno);
        let key = Self::tokey(seqno);
        match txn.bind(&data).get::<&[u8]>(&key.as_ref()) {
            Err(MdbError::NotFound) => (),
            Err(e) => panic!("Unexpected error reading index: {:?}: {:?}", seqno, e),
            Ok(_) => panic!("Unexpected entry at seqno: {:?}", seqno),
        };

        txn.bind(&data).set(&key.as_ref(), &data_bytes).expect("Persist operation");
        txn.bind(&meta).set(&META_COMMITTED, &key.as_ref()).expect("Persist operation");
        txn.commit().expect("txn commit");
        debug!("Wrote as {:?}/{:?}: {:?}", seqno, key, data_bytes.len());
    }
}

#[derive(Debug)]
pub struct ReplModel {
    next: Role,
    log: Log,
    current_epoch: u64,
}
impl fmt::Debug for Log {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Log").field("dir", &self.dir.path()).finish()
    }
}

impl Role {
    fn process_operation(&mut self, channel: &mut EventHandler, epoch: u64, seqno: u64, op: Operation) {
        match self {
            &mut Role::Forwarder(ref mut f) => f.process_operation(channel, epoch, seqno, op),
            &mut Role::Terminus(ref mut t) => t.process_operation(channel, epoch, seqno, op),
        }
    }
    pub fn process_downstream_response(&mut self, reply: &OpResp) -> Option<mio::Token> {
        match self {
            &mut Role::Forwarder(ref mut f) => f.process_downstream_response(reply),
            _ => None,
        }
    }

    pub fn process_replication<F: FnMut(u64, Operation)>(&mut self, log: &Log, forward: F) -> bool {
        match self {
            &mut Role::Forwarder(ref mut f) => f.process_replication(log, forward),
            _ => false,
        }
    }
    fn has_pending(&self, token: mio::Token) -> bool {
        match self {
            &Role::Forwarder(ref f) => f.has_pending(token),
            _ => false,
        }
    }
    fn reset(&mut self) {
        match self {
            &mut Role::Forwarder(ref mut f) => f.reset(),
            _ => (),
        }
    }
}

impl Forwarder {
    fn new() -> Forwarder {
        Forwarder {
            last_sent_downstream: None,
            last_acked_downstream: None,
            pending_operations: BTreeMap::new(),
        }
    }

    fn process_operation(&mut self, channel: &mut EventHandler, epoch: u64, seqno: u64, op: Operation) {
        self.pending_operations.insert(seqno, channel.token());
    }

    fn process_downstream_response(&mut self, reply: &OpResp) -> Option<mio::Token> {
        match reply {
            &OpResp::Ok(epoch, seqno, _) | &OpResp::Err(epoch, seqno, _) => {
                self.last_acked_downstream = Some(seqno);
                if let Some(token) = self.pending_operations.remove(&seqno) {
                    info!("Found in-flight op {:?} for client token {:?}", seqno, token);
                    Some(token)
                } else {
                    warn!("Unexpected response for seqno: {:?}", seqno);
                    None
                }
            },
            &OpResp::HelloIWant(last_sent_downstream) => {
                info!("Downstream has {:?}", last_sent_downstream);
                // assert!(last_sent_downstream <= self.seqno());
                self.last_acked_downstream = Some(last_sent_downstream);
                self.last_sent_downstream = Some(last_sent_downstream);
                None
            },
        }
    }

    pub fn process_replication<F: FnMut(u64, Operation)>(&mut self, log: &Log, mut forward: F) -> bool {
        let mut changed = false;
        debug!("pre  Repl: Ours: {:?}; downstream sent: {:?}; acked: {:?}",
            log.seqno(), self.last_sent_downstream, self.last_acked_downstream);

        let mut changed = false;
        if let Some(send_next) = self.last_sent_downstream {
            if send_next < log.seqno() {
                let max_to_push_now = cmp::min(self.last_acked_downstream.unwrap_or(0) + REPLICATION_CREDIT, log.seqno());
                debug!("Window push {:?} - {:?}; waiting: {:?}", send_next, max_to_push_now, log.seqno() - max_to_push_now);
                for i in send_next..max_to_push_now {
                    if let Some(op) = log.read(i) {
                        debug!("Queueing seq:{:?}/{:?}; ds/seqno: {:?}", i, op, self.last_sent_downstream);
                        forward(i, op);
                        self.last_sent_downstream = Some(i+1);
                        changed = true
                    } else {
                        panic!("Attempted to replicate item not in log: {:?}", self);
                    }
                }
            }
            debug!("post Repl: Ours: {:?}; downstream sent: {:?}; acked: {:?}",
                log.seqno(), self.last_sent_downstream, self.last_acked_downstream);
        }
        changed
    }

    fn has_pending(&self, token: mio::Token) -> bool {
        self.pending_operations.values().all(|tok| tok != &token)
    }

    fn reset(&mut self) {
        self.last_sent_downstream = None
    }
}

impl Terminus {
    fn new() -> Terminus {
        Terminus {
            state: "".to_string()
        }
    }

    fn process_operation(&mut self, channel: &mut EventHandler, epoch: u64, seqno: u64, op: Operation) {
        info!("Terminus! {:?}/{:?}", seqno, op);
        let resp = match op {
            Operation::Set(s) => {
                self.state = s;
                OpResp::Ok(epoch, seqno, None)
            },
                Operation::Get => OpResp::Ok(epoch, seqno, Some(self.state.clone()))
        };
        channel.response(resp)
    }
}

impl ReplModel {
    pub fn new() -> ReplModel {
        ReplModel {
            log: Log::new(),
            current_epoch: Default::default(),
            next: Role::Terminus(Terminus::new()),
        }
    }

    pub fn seqno(&self) -> u64 {
        self.log.seqno()
    }

    fn next_seqno(&self) -> u64 {
        self.log.seqno()
    }

    pub fn process_operation(&mut self, channel: &mut EventHandler, seqno: Option<u64>, epoch: Option<u64>, op: Operation) {
        let seqno = seqno.unwrap_or_else(|| self.next_seqno());
        let epoch = epoch.unwrap_or_else(|| self.current_epoch);

       if epoch != self.current_epoch {
            warn!("Operation epoch ({}) differers from our last observed configuration: ({})",
                epoch, self.current_epoch);
            let resp = OpResp::Err(epoch, seqno, format!("BadEpoch: {}; last seen config: {}", epoch, self.current_epoch));
            channel.response(resp);
            return;
        }

        if !self.log.verify_sequential(seqno) {
            let resp = OpResp::Err(epoch, seqno, format!("Bad sequence number; saw: {:?}", seqno));
            channel.response(resp);
            return;
        }

        self.log.insert_at(seqno, &op);
        self.next.process_operation(channel, epoch, seqno, op)
    }

    pub fn process_downstream_response(&mut self, reply: &OpResp) -> Option<mio::Token> {
        self.next.process_downstream_response(reply)
    }

    pub fn process_replication<F: FnMut(u64, u64, Operation)>(&mut self, mut forward: F) -> bool {
        let epoch = self.current_epoch;
        self.next.process_replication(&self.log, |i, op| forward(epoch, i, op))
    }

    pub fn epoch_changed(&mut self, epoch: u64) {
        self.current_epoch = epoch;
    }

    pub fn has_pending(&self, token: mio::Token) -> bool {
        self.next.has_pending(token)
    }

    pub fn reset(&mut self) {
        self.next.reset()
    }

    pub fn set_has_downstream(&mut self, is_forwarder: bool) {
        // XXX: Replays?
        match (is_forwarder, &mut self.next) {
            (true, role @ &mut Role::Terminus(_)) => {
                let prev = mem::replace(role, Role::Forwarder(Forwarder::new()));
                info!("Switched to forwarding from {:?}", prev);
            },

            (false, role @ &mut Role::Forwarder(_)) => {
                let prev = mem::replace(role, Role::Terminus(Terminus::new()));
                info!("Switched to terminating from {:?}", prev);
            },
            _ => { info!("No change of config"); }
        }
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use turn::Turn;
use superregion::SuperRegion;
use region::Region;

#[derive(Debug,Clone,PartialEq)]
pub struct ParseRequestError;

#[derive(Debug,Clone,PartialEq,Eq,PartialOrd,Ord)]
pub enum Request
{
	ListSuperRegions(Vec<SuperRegion>),
	ListRegions(Vec<Region>),
	ListNeighbours(Vec<(usize,Vec<usize>)>),
	RequestStartingRegions(Vec<usize>),
	SettingNameYou(String),
	SettingNameOther(String),
	SettingArmies(usize),
	UpdateMap(Vec<(usize,String,usize)>),
	TurnOther(Vec<Turn>),
	TurnPlace,
	TurnArmies,
}

impl FromStr for Request
{
	type Err = ParseRequestError;

	fn from_str(s: &str) -> Result<Self,Self::Err>
	{
		use self::Request::*;

		//FIXME: slice pattern matching
		let mut args = s.split_whitespace();
		match (args.next(),args.next())
		{
			(Some("setup_map"),Some("super_regions")) =>
			{
				let v = args.collect::<Vec<_>>();
				let v = v
					.chunks(2)
					.map(|s|s.join(" "))
					.map(|s|s.parse::<SuperRegion>())
					.map(Result::unwrap)
					.collect::<Vec<_>>();
				Ok(ListSuperRegions(v))
			},
			(Some("setup_map"),Some("regions")) =>
			{
				let v = args.collect::<Vec<_>>();
				let v = v
					.chunks(2)
					.map(|s|s.join(" "))
					.map(|s|s.parse::<Region>())
					.map(Result::unwrap)
					.collect::<Vec<_>>();
				Ok(ListRegions(v))
			},
			(Some("setup_map"),Some("neighbors")) =>
			{
				let v = args
					.collect::<Vec<_>>();
				let v = v
					.chunks(2)
					.map(|c|
						(c[0].parse::<usize>().unwrap(),c[1]
							.split("r")
							.map(|s|s.parse::<usize>())
							.map(Result::unwrap)
							.collect::<Vec<_>>()
						)
					)
					.collect::<Vec<_>>();
				Ok(ListNeighbours(v))
			},
			(Some("pick_starting_regions"),Some(_)) =>
			{
				Ok(RequestStartingRegions(
					args
						.map(|s|s.parse::<usize>())
						.map(Result::unwrap)
						.collect::<Vec<_>>()
				))
			},
			(Some("settings"),Some("your_bot")) => Ok(SettingNameYou(args.next().unwrap().to_owned())),
			(Some("settings"),Some("opponent_bot")) => Ok(SettingNameOther(args.next().unwrap().to_owned())),
			(Some("settings"),Some("starting_armies")) => Ok(SettingArmies(args.next().unwrap().parse().unwrap())),
			(Some("update_map"),Some(x)) =>
			{
				let mut v = vec![x];
				v.extend(args);
				let v = v
					.chunks(3)
					.map(|s|(s[0].parse::<usize>().unwrap(),s[1].to_owned(),s[2].parse::<usize>().unwrap()))
					.collect::<Vec<_>>();
				Ok(UpdateMap(v))
			},
			(Some("opponent_moves"),Some(_)) =>
			{
				Ok(TurnOther(s.split_at(s.find(' ').unwrap()).1
					.split(',')
					.map(|s|s.parse::<Turn>())
					.map(|r|r.unwrap_or(Turn::Noop))
					.collect::<Vec<_>>()
				))
			},
			(Some("go"),Some("place_armies")) => Ok(TurnPlace),
			(Some("go"),Some("attack/transfer")) => Ok(TurnArmies),
			_ => Err(ParseRequestError),
		}
	}
}

<commit_msg>fix typo<commit_after>use std::str::FromStr;
use turn::Turn;
use superregion::SuperRegion;
use region::Region;

#[derive(Debug,Clone,PartialEq)]
pub struct ParseRequestError;

#[derive(Debug,Clone,PartialEq,Eq,PartialOrd,Ord)]
pub enum Request
{
	ListSuperRegions(Vec<SuperRegion>),
	ListRegions(Vec<Region>),
	ListNeighbours(Vec<(usize,Vec<usize>)>),
	RequestStartingRegions(Vec<usize>),
	SettingNameYou(String),
	SettingNameOther(String),
	SettingArmies(usize),
	UpdateMap(Vec<(usize,String,usize)>),
	TurnOther(Vec<Turn>),
	TurnPlace,
	TurnArmies,
}

impl FromStr for Request
{
	type Err = ParseRequestError;

	fn from_str(s: &str) -> Result<Self,Self::Err>
	{
		use self::Request::*;

		//FIXME: slice pattern matching
		let mut args = s.split_whitespace();
		match (args.next(),args.next())
		{
			(Some("setup_map"),Some("super_regions")) =>
			{
				let v = args.collect::<Vec<_>>();
				let v = v
					.chunks(2)
					.map(|s|s.join(" "))
					.map(|s|s.parse::<SuperRegion>())
					.map(Result::unwrap)
					.collect::<Vec<_>>();
				Ok(ListSuperRegions(v))
			},
			(Some("setup_map"),Some("regions")) =>
			{
				let v = args.collect::<Vec<_>>();
				let v = v
					.chunks(2)
					.map(|s|s.join(" "))
					.map(|s|s.parse::<Region>())
					.map(Result::unwrap)
					.collect::<Vec<_>>();
				Ok(ListRegions(v))
			},
			(Some("setup_map"),Some("neighbors")) =>
			{
				let v = args
					.collect::<Vec<_>>();
				let v = v
					.chunks(2)
					.map(|c|
						(c[0].parse::<usize>().unwrap(),c[1]
							.split(',')
							.map(|s|s.parse::<usize>())
							.map(Result::unwrap)
							.collect::<Vec<_>>()
						)
					)
					.collect::<Vec<_>>();
				Ok(ListNeighbours(v))
			},
			(Some("pick_starting_regions"),Some(_)) =>
			{
				Ok(RequestStartingRegions(
					args
						.map(|s|s.parse::<usize>())
						.map(Result::unwrap)
						.collect::<Vec<_>>()
				))
			},
			(Some("settings"),Some("your_bot")) => Ok(SettingNameYou(args.next().unwrap().to_owned())),
			(Some("settings"),Some("opponent_bot")) => Ok(SettingNameOther(args.next().unwrap().to_owned())),
			(Some("settings"),Some("starting_armies")) => Ok(SettingArmies(args.next().unwrap().parse().unwrap())),
			(Some("update_map"),Some(x)) =>
			{
				let mut v = vec![x];
				v.extend(args);
				let v = v
					.chunks(3)
					.map(|s|(s[0].parse::<usize>().unwrap(),s[1].to_owned(),s[2].parse::<usize>().unwrap()))
					.collect::<Vec<_>>();
				Ok(UpdateMap(v))
			},
			(Some("opponent_moves"),Some(_)) =>
			{
				Ok(TurnOther(s.split_at(s.find(' ').unwrap()).1
					.split(',')
					.map(|s|s.parse::<Turn>())
					.map(|r|r.unwrap_or(Turn::Noop))
					.collect::<Vec<_>>()
				))
			},
			(Some("go"),Some("place_armies")) => Ok(TurnPlace),
			(Some("go"),Some("attack/transfer")) => Ok(TurnArmies),
			_ => Err(ParseRequestError),
		}
	}
}

<|endoftext|>


<commit_before>#[crate_id = "rsa#0.1.0-pre"];

#[comment = "Totally for-fun completely unusable RSA implementation"];
#[crate_type = "rlib"];

extern crate bignum;
extern crate serialize;

use std::num::ToStrRadix;
use bignum::{BigUint, ToBigUint};
use serialize::hex::{ToHex, FromHex};

pub mod primes;

pub enum KeySizeT {
  DefaultKeySize,
  KeySize(uint)
}

pub enum PublicExponentT {
  DefaultExponent,
  Exponent(uint)
}

#[deriving(Show)]
pub struct PublicKey {
  e: BigUint,
  n: BigUint,
  key_size: uint
}

#[deriving(Show)]
pub struct PrivateKey {
  d: BigUint,
  n: BigUint
}

/// Generate RSA key-pair with default size and exponent.
pub fn gen_keys_default() -> (PublicKey, PrivateKey) {
  gen_keys(DefaultKeySize, DefaultExponent)
}

/// Generate RSA key-pair with given size and exponent.
pub fn gen_keys(key_size: KeySizeT, e: PublicExponentT) -> (PublicKey, PrivateKey) {
  let key_size = match key_size {
    KeySize(key_size) => key_size,
    _                 => 1024
  };
  let prime_size = key_size / 2;

  let e = match e {
    Exponent(e) => e,
    _           => 3u
  }.to_biguint().unwrap();

  let p = primes::rsa_prime(prime_size, &e);
  let q = primes::rsa_prime(prime_size, &e);
  let n = p * q;
  let one = 1u.to_biguint().unwrap();
  let et = (p - one) * (q - one);
  let d = primes::invmod(&e, &et).unwrap();

  let public_key = PublicKey{ e: e, n: n.clone(), key_size: key_size };
  let private_key = PrivateKey{ d: d, n: n };
  (public_key, private_key)
}

impl PublicKey {
  fn encrypt_biguint(&self, m: &BigUint) -> BigUint {
    primes::mod_exp(m, &self.e, &self.n)
  }

  /// Encrypt a message using this public key
  pub fn encrypt(&self, m: ~str) -> ~str {
    let max_len = self.key_size / 8;
    assert!( m.char_len() < max_len,
      "Message must be less than {} bytes for RSA with key size {}",
      max_len, self.key_size);

    to_hex(&self.encrypt_biguint(&from_plaintext(m)))
  }
}

impl PrivateKey {
  fn decrypt_biguint(&self, c: &BigUint) -> BigUint {
    primes::mod_exp(c, &self.d, &self.n)
  }

  /// Decrypt a message using this private key
  pub fn decrypt(&self, m: ~str) -> ~str {
    to_plaintext(&self.decrypt_biguint(&from_hex(m)))
  }
}

/// Encoding helper functions

fn to_hex(m: &BigUint) -> ~str {
  m.to_str_radix(16)
}

fn to_plaintext(m: &BigUint) -> ~str {
  m.to_str_radix(16).from_hex().unwrap().into_ascii().into_str()
}

fn from_plaintext(m: ~str) -> BigUint {
  BigUint::from_str_radix(m.as_bytes().to_hex(), 16).unwrap()
}

fn from_hex(m: ~str) -> BigUint {
  BigUint::from_str_radix(m, 16).unwrap()
}

#[cfg(test)]
mod test_rsa {
  use super::{Exponent, KeySize, gen_keys_default, gen_keys,
              from_hex, to_hex, from_plaintext, to_plaintext};
  use bignum::ToBigUint;
  use std::{str,vec};

  #[test]
  fn test_conversions() {
    assert_eq!(from_plaintext(~"abcd"), 1633837924u.to_biguint().unwrap())
    assert_eq!(from_hex(~"61626364"), 1633837924u.to_biguint().unwrap())
    assert_eq!(to_plaintext(&1633837924u.to_biguint().unwrap()), ~"abcd")
    assert_eq!(to_hex(&1633837924u.to_biguint().unwrap()), ~"61626364")
  }

  #[test]
  fn test_encrypt_decrypt_default() {
    let (public, private) = gen_keys_default();
    let m = ~"super secret message";
    let encrypted = public.encrypt(m.clone());
    let decrypted = private.decrypt(encrypted);
    assert_eq!(m, decrypted);
  }

  #[test]
  fn test_encrypt_decrypt_five() {
    let (public, private) = gen_keys(KeySize(2048), Exponent(5u));
    let m = ~"super secret message";
    let encrypted = public.encrypt(m.clone());
    let decrypted = private.decrypt(encrypted);
    assert_eq!(m, decrypted);
  }

  #[test]
  #[should_fail]
  fn test_message_too_long() {
    let (public, _) = gen_keys_default();
    let m = str::from_chars(vec::from_elem(128, 'a'));
    public.encrypt(m.clone());
  }
}
<commit_msg>Make encrypt/decrypt biguint public<commit_after>#[crate_id = "rsa#0.1.0-pre"];

#[comment = "Totally for-fun completely unusable RSA implementation"];
#[crate_type = "rlib"];

extern crate bignum;
extern crate serialize;

use std::num::ToStrRadix;
use bignum::{BigUint, ToBigUint};
use serialize::hex::{ToHex, FromHex};

pub mod primes;

pub enum KeySizeT {
  DefaultKeySize,
  KeySize(uint)
}

pub enum PublicExponentT {
  DefaultExponent,
  Exponent(uint)
}

#[deriving(Show)]
pub struct PublicKey {
  e: BigUint,
  n: BigUint,
  key_size: uint
}

#[deriving(Show)]
pub struct PrivateKey {
  d: BigUint,
  n: BigUint
}

/// Generate RSA key-pair with default size and exponent.
pub fn gen_keys_default() -> (PublicKey, PrivateKey) {
  gen_keys(DefaultKeySize, DefaultExponent)
}

/// Generate RSA key-pair with given size and exponent.
pub fn gen_keys(key_size: KeySizeT, e: PublicExponentT) -> (PublicKey, PrivateKey) {
  let key_size = match key_size {
    KeySize(key_size) => key_size,
    _                 => 1024
  };
  let prime_size = key_size / 2;

  let e = match e {
    Exponent(e) => e,
    _           => 3u
  }.to_biguint().unwrap();

  let p = primes::rsa_prime(prime_size, &e);
  let q = primes::rsa_prime(prime_size, &e);
  let n = p * q;
  let one = 1u.to_biguint().unwrap();
  let et = (p - one) * (q - one);
  let d = primes::invmod(&e, &et).unwrap();

  let public_key = PublicKey{ e: e, n: n.clone(), key_size: key_size };
  let private_key = PrivateKey{ d: d, n: n };
  (public_key, private_key)
}

impl PublicKey {
  pub fn encrypt_biguint(&self, m: &BigUint) -> BigUint {
    primes::mod_exp(m, &self.e, &self.n)
  }

  /// Encrypt a message using this public key
  pub fn encrypt(&self, m: ~str) -> ~str {
    let max_len = self.key_size / 8;
    assert!( m.char_len() < max_len,
      "Message must be less than {} bytes for RSA with key size {}",
      max_len, self.key_size);

    to_hex(&self.encrypt_biguint(&from_plaintext(m)))
  }
}

impl PrivateKey {
  pub fn decrypt_biguint(&self, c: &BigUint) -> BigUint {
    primes::mod_exp(c, &self.d, &self.n)
  }

  /// Decrypt a message using this private key
  pub fn decrypt(&self, m: ~str) -> ~str {
    to_plaintext(&self.decrypt_biguint(&from_hex(m)))
  }
}

/// Encoding helper functions

fn to_hex(m: &BigUint) -> ~str {
  m.to_str_radix(16)
}

fn to_plaintext(m: &BigUint) -> ~str {
  m.to_str_radix(16).from_hex().unwrap().into_ascii().into_str()
}

fn from_plaintext(m: ~str) -> BigUint {
  BigUint::from_str_radix(m.as_bytes().to_hex(), 16).unwrap()
}

fn from_hex(m: ~str) -> BigUint {
  BigUint::from_str_radix(m, 16).unwrap()
}

#[cfg(test)]
mod test_rsa {
  use super::{Exponent, KeySize, gen_keys_default, gen_keys,
              from_hex, to_hex, from_plaintext, to_plaintext};
  use bignum::ToBigUint;
  use std::{str,vec};

  #[test]
  fn test_conversions() {
    assert_eq!(from_plaintext(~"abcd"), 1633837924u.to_biguint().unwrap())
    assert_eq!(from_hex(~"61626364"), 1633837924u.to_biguint().unwrap())
    assert_eq!(to_plaintext(&1633837924u.to_biguint().unwrap()), ~"abcd")
    assert_eq!(to_hex(&1633837924u.to_biguint().unwrap()), ~"61626364")
  }

  #[test]
  fn test_encrypt_decrypt_biguint() {
    let (public, private) = gen_keys_default();
    let m = 1633837924u.to_biguint().unwrap();
    let encrypted = public.encrypt_biguint(&m);
    let decrypted = private.decrypt_biguint(&encrypted);
    assert_eq!(m, decrypted);
  }

  #[test]
  fn test_encrypt_decrypt_default() {
    let (public, private) = gen_keys_default();
    let m = ~"super secret message";
    let encrypted = public.encrypt(m.clone());
    let decrypted = private.decrypt(encrypted);
    assert_eq!(m, decrypted);
  }

  #[test]
  fn test_encrypt_decrypt_five() {
    let (public, private) = gen_keys(KeySize(2048), Exponent(5u));
    let m = ~"super secret message";
    let encrypted = public.encrypt(m.clone());
    let decrypted = private.decrypt(encrypted);
    assert_eq!(m, decrypted);
  }

  #[test]
  #[should_fail]
  fn test_message_too_long() {
    let (public, _) = gen_keys_default();
    let m = str::from_chars(vec::from_elem(128, 'a'));
    public.encrypt(m.clone());
  }
}
<|endoftext|>


<commit_before>#[derive(Debug, PartialEq)]
pub enum Token {
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    Bang,
    BangEqual,
    Equal,
    EqualEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    Identifier(String),
    StringLiteral(String),
    NumberLiteral(f64),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,

    Eof,
    /*
     * The book doesn't have tokens for comments and
     * whitespaces. Introducing them the scanner can
     * deal with them uniformly and in a more
     * functional way.
     */
    Comment,
    Whitespace,
}

#[derive(Debug)]
pub struct TokenWithContext {
    token: Token,
    lexeme: String, // TODO: make a reference
    line: usize,
}

struct Scanner {
    start: usize,
    current: usize,
    line: usize,
    source: String, // TODO: make a reference
}

fn is_digit(c: char) -> bool {
    c >= '0' && c <= '9'
}

fn is_alpha(c: char) -> bool {
    (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
}

fn is_alphanumeric(c: char) -> bool {
    is_digit(c) || is_alpha(c)
}

fn is_whitespace(c: char) -> bool{
    match c {
        ' ' => true,
        '\r' => true,
        '\t' => true,
        '\n' => true,
        _ => false
    }
}

impl Scanner {
    fn initialize(source: &String) -> Scanner {
        Scanner {
            start: 0,
            current: 0,
            line: 1, // 1-indexed,
            source: source.clone(),
        }
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    fn char_at(&self, index: usize) -> char {
        // TODO: there must be a better way
        self.source.chars().nth(index).unwrap()
    }

    fn substring(&self, start: usize, end: usize) -> String {
        self.source.chars().skip(start).take(end - start).collect()
    }

    fn peek(&self) -> char() {
        if self.is_at_end() {
            '\0'
        } else {
            self.char_at(self.current)
        }
    }

    fn peek_next(&self) -> char() {
        if self.current + 1 >= self.source.len() {
            '\0'
        } else {
            self.char_at(self.current + 1)
        }
    }

    fn advance(&mut self) -> char {
        self.current += 1;
        let c = self.char_at(self.current - 1);
        if c == '\n' {
            self.line += 1;
        }
        c
    }

    fn is_match(&mut self, expected: char) -> bool {
        if self.is_at_end() {
            return false;
        }
        if self.char_at(self.current) != expected {
            return false;
        }
        self.current += 1;
        return true;
    }

    fn add_context(&self, token: Token) -> TokenWithContext {
        TokenWithContext {
            token: token,
            lexeme: self.substring(self.start, self.current),
            line: self.line,
        }
    }

    fn string(&mut self) -> Result<Token, String> {
        let initial_line = self.line;
        while self.peek() != '"' && !self.is_at_end() {
            self.advance();
        }
        if self.is_at_end() {
            return Err(format!("Unterminated string at line {}", initial_line));
        }
        self.advance();
        Ok(Token::StringLiteral(self.substring(self.start + 1, self.current - 1)))
    }

    fn number(&mut self) -> Token {
        while is_digit(self.peek()) {
            self.advance();
        }
        if self.peek() == '.' && is_digit(self.peek_next()) {
            self.advance(); // Consume the .
            while is_digit(self.peek()) {
                self.advance();
            }
        }
        let literal = self.substring(self.start, self.current);
        let value = literal.parse::<f64>().unwrap();
        Token::NumberLiteral(value)
    }

    fn identifier(&mut self) -> Token {
        while is_alphanumeric(self.peek()) {
            self.advance();
        }
        // TODO: take a ref in the first place
        match self.substring(self.start, self.current).as_ref() {
            "and" => Token::And,
            "class" => Token::Class,
            "else" => Token::Else,
            "false" => Token::False,
            "for" => Token::For,
            "fun" => Token::Fun,
            "if" => Token::If,
            "nil" => Token::Nil,
            "or" => Token::Or,
            "print" => Token::Print,
            "return" => Token::Return,
            "super" => Token::Super,
            "this" => Token::This,
            "true" => Token::True,
            "var" => Token::Var,
            "while" => Token::While,
            identifier => Token::Identifier(identifier.into()),
        }

    }

    fn scan_next(&mut self) -> Result<TokenWithContext, String> {
        self.start = self.current;
        let token = match self.advance() {
            '(' => Token::LeftParen,
            ')' => Token::RightParen,
            '{' => Token::LeftBrace,
            '}' => Token::RightBrace,
            ',' => Token::Comma,
            '.' => Token::Dot,
            '-' => Token::Minus,
            '+' => Token::Plus,
            ';' => Token::Semicolon,
            '*' => Token::Star,
            '!' => {
                if self.is_match('=') {
                    Token::BangEqual
                } else {
                    Token::Bang
                }
            }
            '=' => {
                if self.is_match('=') {
                    Token::EqualEqual
                } else {
                    Token::Equal
                }
            }
            '<' => {
                if self.is_match('=') {
                    Token::LessEqual
                } else {
                    Token::Less
                }
            }
            '>' => {
                if self.is_match('=') {
                    Token::GreaterEqual
                } else {
                    Token::Greater
                }
            }
            '/' => {
                if self.is_match('/') {
                    // Comments go on till the end of the line
                    while self.peek() != '\n' && !self.is_at_end() {
                        self.advance();
                    }
                    Token::Comment
                } else {
                    Token::Slash
                }
            },
            '"' => try!(self.string()),
            c if is_whitespace(c) => Token::Whitespace,
            c if is_digit(c) => self.number(),
            c if is_alpha(c) => self.identifier(),
            c => {
                return Err(format!("Unexpected character {} at line {}, pos {}",
                                   c,
                                   self.line,
                                   self.current - 1));
            }
        };
        Ok(self.add_context(token))
    }
}

pub fn scan(source: &String) -> Result<Vec<TokenWithContext>, String> {
    let mut scanner = Scanner::initialize(source);
    let mut tokens = Vec::new();
    while !scanner.is_at_end() {
        let token_with_context = try!(scanner.scan_next());
        match token_with_context.token {
            // Ignoring tokens we don't care about
            Token::Comment => {}
            Token::Whitespace => {}
            _ => tokens.push(token_with_context),
        }
    }
    tokens.push(TokenWithContext {
        token: Token::Eof,
        lexeme: "".into(),
        line: scanner.line,
    });
    Ok(tokens)
}

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

    #[test]
    fn single_token() {
        let tokens = scan(&"+".into()).unwrap();
        assert_eq!(tokens[0].token, Token::Plus);
    }

    #[test]
    fn expression() {
        let tokens = scan(&"1+2".into()).unwrap();
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(tokens[3].token, Token::Eof);
    }

    #[test]
    fn expression_with_whitespaces() {
        let tokens = scan(&"1 + 2".into()).unwrap();
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(tokens[3].token, Token::Eof);
    }

    #[test]
    fn assignement_with_comment() {
        let tokens = scan(&"var a = 1.0; // A comment".into()).unwrap();
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Eof);
    }

    #[test]
    fn multiline_statements(){
        let tokens = scan(&r#"var a = 1.0;
                              var b = "Hello";"#.into()).unwrap();
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Var);
        assert_eq!(tokens[6].token, Token::Identifier("b".into()));
        assert_eq!(tokens[7].token, Token::Equal);
        assert_eq!(tokens[8].token, Token::StringLiteral("Hello".into()));
        assert_eq!(tokens[9].token, Token::Semicolon);
        assert_eq!(tokens[10].token, Token::Eof);
        assert_eq!(tokens[1].line, 1);
        assert_eq!(tokens[9].line, 2);
    }
}<commit_msg>cargo fmt<commit_after>#[derive(Debug, PartialEq)]
pub enum Token {
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    Bang,
    BangEqual,
    Equal,
    EqualEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    Identifier(String),
    StringLiteral(String),
    NumberLiteral(f64),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,

    Eof,
    // The book doesn't have tokens for comments and
    // whitespaces. Introducing them the scanner can
    // deal with them uniformly and in a more
    // functional way.
    Comment,
    Whitespace,
}

#[derive(Debug)]
pub struct TokenWithContext {
    token: Token,
    lexeme: String, // TODO: make a reference
    line: usize,
}

struct Scanner {
    start: usize,
    current: usize,
    line: usize,
    source: String, // TODO: make a reference
}

fn is_digit(c: char) -> bool {
    c >= '0' && c <= '9'
}

fn is_alpha(c: char) -> bool {
    (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
}

fn is_alphanumeric(c: char) -> bool {
    is_digit(c) || is_alpha(c)
}

fn is_whitespace(c: char) -> bool {
    match c {
        ' ' => true,
        '\r' => true,
        '\t' => true,
        '\n' => true,
        _ => false,
    }
}

impl Scanner {
    fn initialize(source: &String) -> Scanner {
        Scanner {
            start: 0,
            current: 0,
            line: 1, // 1-indexed,
            source: source.clone(),
        }
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    fn char_at(&self, index: usize) -> char {
        // TODO: there must be a better way
        self.source.chars().nth(index).unwrap()
    }

    fn substring(&self, start: usize, end: usize) -> String {
        self.source.chars().skip(start).take(end - start).collect()
    }

    fn peek(&self) -> char() {
        if self.is_at_end() {
            '\0'
        } else {
            self.char_at(self.current)
        }
    }

    fn peek_next(&self) -> char() {
        if self.current + 1 >= self.source.len() {
            '\0'
        } else {
            self.char_at(self.current + 1)
        }
    }

    fn advance(&mut self) -> char {
        self.current += 1;
        let c = self.char_at(self.current - 1);
        if c == '\n' {
            self.line += 1;
        }
        c
    }

    fn is_match(&mut self, expected: char) -> bool {
        if self.is_at_end() {
            return false;
        }
        if self.char_at(self.current) != expected {
            return false;
        }
        self.current += 1;
        return true;
    }

    fn add_context(&self, token: Token) -> TokenWithContext {
        TokenWithContext {
            token: token,
            lexeme: self.substring(self.start, self.current),
            line: self.line,
        }
    }

    fn string(&mut self) -> Result<Token, String> {
        let initial_line = self.line;
        while self.peek() != '"' && !self.is_at_end() {
            self.advance();
        }
        if self.is_at_end() {
            return Err(format!("Unterminated string at line {}", initial_line));
        }
        self.advance();
        Ok(Token::StringLiteral(self.substring(self.start + 1, self.current - 1)))
    }

    fn number(&mut self) -> Token {
        while is_digit(self.peek()) {
            self.advance();
        }
        if self.peek() == '.' && is_digit(self.peek_next()) {
            self.advance(); // Consume the .
            while is_digit(self.peek()) {
                self.advance();
            }
        }
        let literal = self.substring(self.start, self.current);
        let value = literal.parse::<f64>().unwrap();
        Token::NumberLiteral(value)
    }

    fn identifier(&mut self) -> Token {
        while is_alphanumeric(self.peek()) {
            self.advance();
        }
        // TODO: take a ref in the first place
        match self.substring(self.start, self.current).as_ref() {
            "and" => Token::And,
            "class" => Token::Class,
            "else" => Token::Else,
            "false" => Token::False,
            "for" => Token::For,
            "fun" => Token::Fun,
            "if" => Token::If,
            "nil" => Token::Nil,
            "or" => Token::Or,
            "print" => Token::Print,
            "return" => Token::Return,
            "super" => Token::Super,
            "this" => Token::This,
            "true" => Token::True,
            "var" => Token::Var,
            "while" => Token::While,
            identifier => Token::Identifier(identifier.into()),
        }

    }

    fn scan_next(&mut self) -> Result<TokenWithContext, String> {
        self.start = self.current;
        let token = match self.advance() {
            '(' => Token::LeftParen,
            ')' => Token::RightParen,
            '{' => Token::LeftBrace,
            '}' => Token::RightBrace,
            ',' => Token::Comma,
            '.' => Token::Dot,
            '-' => Token::Minus,
            '+' => Token::Plus,
            ';' => Token::Semicolon,
            '*' => Token::Star,
            '!' => {
                if self.is_match('=') {
                    Token::BangEqual
                } else {
                    Token::Bang
                }
            }
            '=' => {
                if self.is_match('=') {
                    Token::EqualEqual
                } else {
                    Token::Equal
                }
            }
            '<' => {
                if self.is_match('=') {
                    Token::LessEqual
                } else {
                    Token::Less
                }
            }
            '>' => {
                if self.is_match('=') {
                    Token::GreaterEqual
                } else {
                    Token::Greater
                }
            }
            '/' => {
                if self.is_match('/') {
                    // Comments go on till the end of the line
                    while self.peek() != '\n' && !self.is_at_end() {
                        self.advance();
                    }
                    Token::Comment
                } else {
                    Token::Slash
                }
            }
            '"' => try!(self.string()),
            c if is_whitespace(c) => Token::Whitespace,
            c if is_digit(c) => self.number(),
            c if is_alpha(c) => self.identifier(),
            c => {
                return Err(format!("Unexpected character {} at line {}, pos {}",
                                   c,
                                   self.line,
                                   self.current - 1));
            }
        };
        Ok(self.add_context(token))
    }
}

pub fn scan(source: &String) -> Result<Vec<TokenWithContext>, String> {
    let mut scanner = Scanner::initialize(source);
    let mut tokens = Vec::new();
    while !scanner.is_at_end() {
        let token_with_context = try!(scanner.scan_next());
        match token_with_context.token {
            // Ignoring tokens we don't care about
            Token::Comment => {}
            Token::Whitespace => {}
            _ => tokens.push(token_with_context),
        }
    }
    tokens.push(TokenWithContext {
        token: Token::Eof,
        lexeme: "".into(),
        line: scanner.line,
    });
    Ok(tokens)
}

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

    #[test]
    fn single_token() {
        let tokens = scan(&"+".into()).unwrap();
        assert_eq!(tokens[0].token, Token::Plus);
    }

    #[test]
    fn expression() {
        let tokens = scan(&"1+2".into()).unwrap();
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(tokens[3].token, Token::Eof);
    }

    #[test]
    fn expression_with_whitespaces() {
        let tokens = scan(&"1 + 2".into()).unwrap();
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(tokens[3].token, Token::Eof);
    }

    #[test]
    fn assignement_with_comment() {
        let tokens = scan(&"var a = 1.0; // A comment".into()).unwrap();
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Eof);
    }

    #[test]
    fn multiline_statements() {
        let tokens = scan(&r#"var a = 1.0;
                              var b = "Hello";"#
                .into())
            .unwrap();
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Var);
        assert_eq!(tokens[6].token, Token::Identifier("b".into()));
        assert_eq!(tokens[7].token, Token::Equal);
        assert_eq!(tokens[8].token, Token::StringLiteral("Hello".into()));
        assert_eq!(tokens[9].token, Token::Semicolon);
        assert_eq!(tokens[10].token, Token::Eof);
        assert_eq!(tokens[1].line, 1);
        assert_eq!(tokens[9].line, 2);
    }
}
<|endoftext|>


<commit_before>//!
//! A session runs a filesystem implementation while it is being mounted
//! to a specific mount point. A session begins by mounting the filesystem
//! and ends by unmounting it. While the filesystem is mounted, the session
//! loop receives, dispatches and replies to kernel requests for filesystem
//! operations under its mount point.
//!

use std::io;
use std::ffi::OsStr;
use std::path::{PathBuf, Path};
use std::thread::{Builder, JoinGuard};
use libc::{EAGAIN, EINTR, ENODEV, ENOENT};
use channel;
use channel::Channel;
use Filesystem;
use request::{request, dispatch};

/// The max size of write requests from the kernel. The absolute minimum is 4k,
/// FUSE recommends at least 128k, max 16M. The FUSE default is 16M on OS X
/// and 128k on other systems.
pub const MAX_WRITE_SIZE: usize = 16*1024*1024;

/// Size of the buffer for reading a request from the kernel. Since the kernel may send
/// up to MAX_WRITE_SIZE bytes in a write request, we use that value plus some extra space.
const BUFFER_SIZE: usize = MAX_WRITE_SIZE + 4096;

/// The session data structure
pub struct Session<FS> {
    /// Filesystem operation implementations
    pub filesystem: FS,
    /// Communication channel to the kernel driver
    ch: Channel,
    /// FUSE protocol major version
    pub proto_major: u32,
    /// FUSE protocol minor version
    pub proto_minor: u32,
    /// True if the filesystem is initialized (init operation done)
    pub initialized: bool,
    /// True if the filesystem was destroyed (destroy operation done)
    pub destroyed: bool,
}

impl<FS: Filesystem> Session<FS> {
    /// Create a new session by mounting the given filesystem to the given mountpoint
    pub fn new (filesystem: FS, mountpoint: &Path, options: &[&OsStr]) -> Session<FS> {
        info!("Mounting {}", mountpoint.display());
        let ch = match Channel::new(mountpoint, options) {
            Ok(ch) => ch,
            Err(err) => panic!("Unable to mount filesystem. Error {}", err),
        };
        Session {
            filesystem: filesystem,
            ch: ch,
            proto_major: 0,
            proto_minor: 0,
            initialized: false,
            destroyed: false,
        }
    }

    /// Return path of the mounted filesystem
    pub fn mountpoint (&self) -> &Path {
        &self.ch.mountpoint()
    }

    /// Run the session loop that receives kernel requests and dispatches them to method
    /// calls into the filesystem. This read-dispatch-loop is non-concurrent to prevent
    /// having multiple buffers (which take up much memory), but the filesystem methods
    /// may run concurrent by spawning threads.
    pub fn run (&mut self) {
        // Buffer for receiving requests from the kernel. Only one is allocated and
        // it is reused immediately after dispatching to conserve memory and allocations.
        let mut buffer: Vec<u8> = Vec::with_capacity(BUFFER_SIZE);
        loop {
            // Read the next request from the given channel to kernel driver
            // The kernel driver makes sure that we get exactly one request per read
            match self.ch.receive(&mut buffer) {
                Ok(()) => match request(self.ch.sender(), &buffer) {
                    // Dispatch request
                    Some(req) => dispatch(&req, self),
                    // Quit loop on illegal request
                    None => break,
                },
                Err(ref err) => match err.raw_os_error() {
                    // Operation interrupted. Accordingly to FUSE, this is safe to retry
                    Some(ENOENT) => continue,
                    // Interrupted system call, retry
                    Some(EINTR) => continue,
                    // Explicitly try again
                    Some(EAGAIN) => continue,
                    // Filesystem was unmounted, quit the loop
                    Some(ENODEV) => break,
                    // Unhandled error
                    _ => panic!("Lost connection to FUSE device. Error: {}", err),
                },
            }
        }
    }
}

impl<FS: Filesystem+Send+'static> Session<FS> {
    /// Run the session loop in a background thread
    pub fn spawn<'a> (self) -> io::Result<BackgroundSession<'a>> {
        BackgroundSession::new(self)
    }
}

#[unsafe_destructor]
impl<FS: Filesystem> Drop for Session<FS> {
    fn drop (&mut self) {
        info!("Unmounted {}", self.mountpoint().display());
    }
}

/// The background session data structure
pub struct BackgroundSession<'a> {
    /// Path of the mounted filesystem
    pub mountpoint: PathBuf,
    /// Thread guard of the background session
    pub guard: JoinGuard<'a ()>,
}

impl<'a> BackgroundSession<'a> {
    /// Create a new background session for the given session by running its
    /// session loop in a background thread. If the returned handle is dropped,
    /// the filesystem is unmounted and the given session ends.
    pub fn new<FS: Filesystem+Send+'static> (se: Session<FS>) -> io::Result<BackgroundSession<'a>> {
        let mountpoint = se.mountpoint().to_path_buf();
        let builder = Builder::new().name(format!("FUSE {}", mountpoint.display()));
        let guard = try!(builder.scoped(move || {
            let mut se = se;
            se.run();
        }));
        Ok(BackgroundSession { mountpoint: mountpoint, guard: guard })
    }
}

#[unsafe_destructor]
impl<'a> Drop for BackgroundSession<'a> {
    fn drop (&mut self) {
        info!("Unmounting {}", self.mountpoint.display());
        // Unmounting the filesystem will eventually end the session loop,
        // drop the session and hence end the background thread.
        match channel::unmount(&self.mountpoint) {
            Ok(()) => (),
            Err(err) => error!("Failed to unmount {}: {}", self.mountpoint.display(), err),
        }
    }
}
<commit_msg>add a restriction to Session's parameter FS because latest rust rejects specialized Drop impl.<commit_after>//!
//! A session runs a filesystem implementation while it is being mounted
//! to a specific mount point. A session begins by mounting the filesystem
//! and ends by unmounting it. While the filesystem is mounted, the session
//! loop receives, dispatches and replies to kernel requests for filesystem
//! operations under its mount point.
//!

use std::io;
use std::ffi::OsStr;
use std::path::{PathBuf, Path};
use std::thread::{Builder, JoinGuard};
use libc::{EAGAIN, EINTR, ENODEV, ENOENT};
use channel;
use channel::Channel;
use Filesystem;
use request::{request, dispatch};

/// The max size of write requests from the kernel. The absolute minimum is 4k,
/// FUSE recommends at least 128k, max 16M. The FUSE default is 16M on OS X
/// and 128k on other systems.
pub const MAX_WRITE_SIZE: usize = 16*1024*1024;

/// Size of the buffer for reading a request from the kernel. Since the kernel may send
/// up to MAX_WRITE_SIZE bytes in a write request, we use that value plus some extra space.
const BUFFER_SIZE: usize = MAX_WRITE_SIZE + 4096;

/// The session data structure
pub struct Session<FS: Filesystem> {
    /// Filesystem operation implementations
    pub filesystem: FS,
    /// Communication channel to the kernel driver
    ch: Channel,
    /// FUSE protocol major version
    pub proto_major: u32,
    /// FUSE protocol minor version
    pub proto_minor: u32,
    /// True if the filesystem is initialized (init operation done)
    pub initialized: bool,
    /// True if the filesystem was destroyed (destroy operation done)
    pub destroyed: bool,
}

impl<FS: Filesystem> Session<FS> {
    /// Create a new session by mounting the given filesystem to the given mountpoint
    pub fn new (filesystem: FS, mountpoint: &Path, options: &[&OsStr]) -> Session<FS> {
        info!("Mounting {}", mountpoint.display());
        let ch = match Channel::new(mountpoint, options) {
            Ok(ch) => ch,
            Err(err) => panic!("Unable to mount filesystem. Error {}", err),
        };
        Session {
            filesystem: filesystem,
            ch: ch,
            proto_major: 0,
            proto_minor: 0,
            initialized: false,
            destroyed: false,
        }
    }

    /// Return path of the mounted filesystem
    pub fn mountpoint (&self) -> &Path {
        &self.ch.mountpoint()
    }

    /// Run the session loop that receives kernel requests and dispatches them to method
    /// calls into the filesystem. This read-dispatch-loop is non-concurrent to prevent
    /// having multiple buffers (which take up much memory), but the filesystem methods
    /// may run concurrent by spawning threads.
    pub fn run (&mut self) {
        // Buffer for receiving requests from the kernel. Only one is allocated and
        // it is reused immediately after dispatching to conserve memory and allocations.
        let mut buffer: Vec<u8> = Vec::with_capacity(BUFFER_SIZE);
        loop {
            // Read the next request from the given channel to kernel driver
            // The kernel driver makes sure that we get exactly one request per read
            match self.ch.receive(&mut buffer) {
                Ok(()) => match request(self.ch.sender(), &buffer) {
                    // Dispatch request
                    Some(req) => dispatch(&req, self),
                    // Quit loop on illegal request
                    None => break,
                },
                Err(ref err) => match err.raw_os_error() {
                    // Operation interrupted. Accordingly to FUSE, this is safe to retry
                    Some(ENOENT) => continue,
                    // Interrupted system call, retry
                    Some(EINTR) => continue,
                    // Explicitly try again
                    Some(EAGAIN) => continue,
                    // Filesystem was unmounted, quit the loop
                    Some(ENODEV) => break,
                    // Unhandled error
                    _ => panic!("Lost connection to FUSE device. Error: {}", err),
                },
            }
        }
    }
}

impl<FS: Filesystem+Send+'static> Session<FS> {
    /// Run the session loop in a background thread
    pub fn spawn<'a> (self) -> io::Result<BackgroundSession<'a>> {
        BackgroundSession::new(self)
    }
}

#[unsafe_destructor]
impl<FS: Filesystem> Drop for Session<FS> {
    fn drop (&mut self) {
        info!("Unmounted {}", self.mountpoint().display());
    }
}

/// The background session data structure
pub struct BackgroundSession<'a> {
    /// Path of the mounted filesystem
    pub mountpoint: PathBuf,
    /// Thread guard of the background session
    pub guard: JoinGuard<'a ()>,
}

impl<'a> BackgroundSession<'a> {
    /// Create a new background session for the given session by running its
    /// session loop in a background thread. If the returned handle is dropped,
    /// the filesystem is unmounted and the given session ends.
    pub fn new<FS: Filesystem+Send+'static> (se: Session<FS>) -> io::Result<BackgroundSession<'a>> {
        let mountpoint = se.mountpoint().to_path_buf();
        let builder = Builder::new().name(format!("FUSE {}", mountpoint.display()));
        let guard = try!(builder.scoped(move || {
            let mut se = se;
            se.run();
        }));
        Ok(BackgroundSession { mountpoint: mountpoint, guard: guard })
    }
}

#[unsafe_destructor]
impl<'a> Drop for BackgroundSession<'a> {
    fn drop (&mut self) {
        info!("Unmounting {}", self.mountpoint.display());
        // Unmounting the filesystem will eventually end the session loop,
        // drop the session and hence end the background thread.
        match channel::unmount(&self.mountpoint) {
            Ok(()) => (),
            Err(err) => error!("Failed to unmount {}: {}", self.mountpoint.display(), err),
        }
    }
}
<|endoftext|>


<commit_before>//imports
use std::collections::TreeMap;
use std::io::BufferedReader;
use std::io::File;

///rust all this set's challenges
fn main(){
	println!("set one ::");
	challenge_one();
	challenge_two();
	challenge_three();
	challenge_four();
	challenge_five();
	//challenge_six();
	//challenge_seven();
	//challenge_eight();
	println!("done set one");}

//challenges
/// solution for challenge one
fn challenge_one(){
	println!("challenge one ::");
	//params
	let input = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d";
	let desired = "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t";
	//get result
	let result = hexstr_tob64str( input);
	//print info
	//println!("input: {}", input);
	println!("result: {}", result);
	println!("result == desired: {}", result.as_slice() == desired);
	println!("done challenge one");}

/// solution for challenge two
fn challenge_two(){
	println!("challenge two ::");
	//params
	let input_a = "1c0111001f010100061a024b53535009181c";
	let input_b = "686974207468652062756c6c277320657965";
	let desired = "746865206b696420646f6e277420706c6179";
	//convert to bytes
	let a_bytes = hexstr_tobytes( input_a);
	let b_bytes = hexstr_tobytes( input_b);
	//apply xor
	let result_bytes = xor_bytes(
		a_bytes.as_slice(), b_bytes.as_slice());
	//convert to string
	let result = bytes_tohexstr( result_bytes.as_slice());
	//print info
	println!("result: {}", result);
	println!("result == desired: {}", result.as_slice() == desired);
	println!("done challenge two");}

/// solution for challenge three
fn challenge_three(){
	println!("challenge three ::");
	//params
	let input =
		"1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736";
	let extractions = crack_xor_cipher( input);
	println!("extractions:");
	println!("cipher :: message :: rating");
	for ( &cipher, &( ref message, ref rating)) in extractions.iter() {
		println!("{:02x} :: {} :: {:.2f}", cipher, message, *rating);}
	println!("done challenge three");}

/// solution for challenge four
fn challenge_four(){
	println!("challenge four ::");
	let lines = read_lines( "data/4.txt");
	let mut i : int = 0;
	for ref line in lines.iter() {
		let extractions = crack_xor_cipher( line.as_slice());
		if ! extractions.is_empty() {
			println!("extractions for line {}:", i);
			for ( &cipher, &( ref message, ref rating)) in extractions.iter() {
				println!("{:02x} :: {} :: {:.2f}", cipher, message, *rating);}}
		i += 1;}
	println!("done challenge four");}

/// solution for challenge five
fn challenge_five(){
	println!("challenge five ::");
	println!("done challenge five");}

/// solution for challenge six
fn challenge_six(){
	println!("challenge six ::");
	println!("done challenge six");}

/// solution for challenge seven
fn challenge_seven(){
	println!("challenge seven ::");
	println!("done challenge seven");}

/// solution for challenge eight
fn challenge_eight(){
	println!("challenge eight ::");
	println!("done challenge eight");}

//conversion functions
/// convert a hex string into base64
fn hexstr_tob64str( input: &str) -> String {
	//vars
	let bytes = hexstr_tobytes( input);
	let b64_codes : Vec<u8> = bytes_tob64codes( bytes.as_slice());
	return b64codes_tob64str( b64_codes.as_slice());
	}

/// convert a hex string into a byte vector
fn hexstr_tobytes( input: &str) -> Vec<u8> {
	let mut i = 0;
	let mut bytes : Vec<u8> = Vec::new();
	//parse bytes
	while i < input.len() {
		//current byte we're parsing
		let mut byte = 0u8;
		//parse first half
		byte += hex_toi( input.char_at( i));
		byte <<= 4;
		i += 1;
		//break if byte is \nincomplete
		if i == input.len() {
			bytes.push( byte);
			break;}
		//parse second half
		byte += hex_toi( input.char_at( i));
		//add byte
		bytes.push( byte);
		i += 1;}
	return bytes;}

fn bytes_tohexstr( bytes : &[u8]) -> String {
	let mut result = String::new();
	for &byte in bytes.iter() {
		let half1 = ( byte >> 4) & 0b1111;
		let half2 = byte & 0b1111;
		result.push_char( hexcode_tochar( half1));
		result.push_char( hexcode_tochar( half2));}
	return result;}

/// convert a byte string into b64 codes
fn bytes_tob64codes( bytes : &[u8]) -> Vec<u8> {
	let mut codes : Vec<u8> = Vec::new();
	//write bytes into b64 codes
	let mut leftover: u8 = 0;
	for i in range( 0, bytes.len()) {
		let byte = bytes[ i];
		match i % 3 {
			0 => {
				codes.push( ( byte >> 2));
				leftover = byte & 0b11;}
			1 => {
				codes.push( ( (leftover << 4) + (byte >> 4)));
				leftover = byte & 0b1111;}
			_ => {
				codes.push( ( (leftover << 2) + (byte >> 6)));
				codes.push( ( byte & 0b111111));}}}
	return codes;}

fn b64codes_tob64str( codes : &[u8]) -> String {
	let mut result = String::new();
	//convert b64 codes into string
	for i in range( 0, codes.len()) {
		result.push_char( b64code_tochar( codes[ i]));}
	return result;}

/// convert a hex char its corresponding int
fn hex_toi( character : char) -> u8 {
	match character {
		'0'..'9' => (character as u8) - ('0' as u8) + 0,
		'a'..'f' => (character as u8) - ('a' as u8) + 10,
		_ => fail!("error: input contained non-hex chars")}}

/// convert a base64 code into its corresponding char
fn b64code_tochar( code : u8) -> char {
	match code {
		00..25 => ( code - 00 + ('A' as u8)) as char,
		26..51 => ( code - 26 + ('a' as u8)) as char,
		52..61 => ( code - 52 + ('0' as u8)) as char,
		62 => '+',
		63 => '/',
		_ => fail!("error: code out of range")}}

/// convert a hec
fn hexcode_tochar( code : u8) -> char {
	match code {
		00..09 => ( code - 00 + ('0' as u8)) as char,
		10..15 => ( code - 10 + ('a' as u8)) as char,
		_ => fail!("error: code out of range")}}

//utilities
/// xor two byte arrays
fn xor_bytes( a : &[u8], b : &[u8]) -> Vec<u8> {
	let size = std::cmp::min( a.len(), b.len());
	let mut result = Vec::new();
	for i in range( 0, size) {
		result.push( a[i] ^ b[i]);}
	return result;}

fn score_bytes( bytes : &[u8]) -> TreeMap<u8, u8> {
	let mut table : TreeMap<u8, u8> = TreeMap::new();
	for &byte in bytes.iter() {
		let new_count =
			match table.find( &byte) {
				Some( count) => count + 1,
				None => 1};
		table.insert( byte, new_count);}
	return table;}

/// single byte xor cipher
fn byte_cipher( original : &[u8], cipher : u8) -> Vec<u8> {
	let mut result = Vec::new();
	for &byte in original.iter() {
		result.push( byte ^ cipher);}
	return result;}

fn crack_xor_cipher( input : &str) -> TreeMap< u8, (String, f32)> {
	//convert input to bytes
	let input_bytes = hexstr_tobytes( input);
	//create score table
	let input_scores = score_bytes( input_bytes.as_slice());
	//println!("score table: {}", input_scores);
	//find top scores
	let mut top_scores : Vec<u8> = Vec::new();
	let scores_cap = 3;
	for &value in input_scores.values() {
		top_scores.push( value);}
	top_scores.sort();
	top_scores.reverse();
	let top_scores = top_scores.slice_to( scores_cap);
	//println!("top {} scores: {}", scores_cap, top_scores);
	//find bytes that match top scores
	let mut common_bytes : Vec<u8> = Vec::new();
	for ( &byte, score) in input_scores.iter() {
		if top_scores.contains( score) {
			common_bytes.push( byte);}}
	//result of above:
	//  most common bytes in input_bytes: { 120: 6, 55: 5, 54: 3 }
	let common_bytes = common_bytes.as_slice();
	//println!("common bytes: {}", common_bytes);
	//let common_chars = [' ','e','t','a','o','i','n','s','h','r','d','l','u'];
	let common_chars = [' ', 'e', 't', 'a', 'o', 'i'];
	let mut extractions : TreeMap< u8, (String, f32)> = TreeMap::new();
	let rating_cap : f32 = 0.8;
	for &common_byte in common_bytes.iter() {
		for &common_char in common_chars.iter() {
			let common_char_byte = common_char.to_ascii().to_byte();
			let cipher_byte = common_char_byte ^ common_byte;
			if extractions.contains_key( &cipher_byte) {
				continue;}
			//create attempt
			let attempt_bytes = byte_cipher( input_bytes.as_slice(), cipher_byte);
			let attempt_slice = attempt_bytes.as_slice();
			if ! attempt_slice.is_ascii() {
				continue;}
			let attempt_ascii = attempt_slice.to_ascii();
			let attempt = attempt_ascii.as_str_ascii();
			for &trimchar in ['\n',' ','\t'].iter() {
				attempt.trim_chars( trimchar);}
			//try to filter attempt
			let rating  = rate_attempt( attempt);
			if rating > rating_cap {
				extractions.insert(
					cipher_byte, ( String::from_str( attempt), rating));}}}
	return extractions;}

/// rate the likelihood a string is a good decoding attempt
fn rate_attempt( attempt : &str) -> f32 {
	let good_chars = "abcdefghijklmnopqrstuvwxyz ,.?!\'\"";
	let neut_chars = "()[]{}<>-=_+:;/@#$%^&*~`";
	let mut positive : f32 = 0.0;
	let mut negative : f32 = 0.0;
	let count = attempt.len();
	//count good and (probably) bad chars
	for attempt_char in attempt.chars() {
		let char_lower = attempt_char.to_lowercase();
		if good_chars.contains_char( char_lower) {
			positive += 1.0;}
		else if ! neut_chars.contains_char( char_lower) {
			negative += 1.0;}}
	let numerator = positive.powi( 2) - negative.powi( 2);
	let denominator = count.to_f32().unwrap().powi( 2);
	return numerator / denominator;}

fn read_lines( filename : &str) -> Vec<String> {
	// Create a path to the desired file
	let path = Path::new( filename);
	let file = File::open( &path);
	let mut reader = BufferedReader::new( file);

	let mut result : Vec<String> = Vec::new();
	for line_result in reader.lines() {
		if ! line_result.is_ok() {
			fail!( "reading a line failed");}
		let line = line_result.unwrap();
		let line_stripped = line.as_slice().trim_chars('\n');
		result.push( String::from_str( line_stripped));}
	return result;}
<commit_msg>working on challenge five. seem to have made a mistake<commit_after>//imports
use std::collections::TreeMap;
use std::io::BufferedReader;
use std::io::File;

///rust all this set's challenges
fn main(){
	println!("set one ::");
	//challenge_one();
	//challenge_two();
	//challenge_three();
	//challenge_four();
	challenge_five();
	//challenge_six();
	//challenge_seven();
	//challenge_eight();
	println!("done set one");}

//challenges
/// solution for challenge one
fn challenge_one(){
	println!("challenge one ::");
	//params
	let input = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d";
	let desired = "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t";
	//get result
	let result = hexstr_tob64str( input);
	//print info
	//println!("input: {}", input);
	println!("result: {}", result);
	println!("result == desired: {}", result.as_slice() == desired);
	println!("done challenge one");}

/// solution for challenge two
fn challenge_two(){
	println!("challenge two ::");
	//params
	let input_a = "1c0111001f010100061a024b53535009181c";
	let input_b = "686974207468652062756c6c277320657965";
	let desired = "746865206b696420646f6e277420706c6179";
	//convert to bytes
	let a_bytes = hexstr_tobytes( input_a);
	let b_bytes = hexstr_tobytes( input_b);
	//apply xor
	let result_bytes = xor_bytes(
		a_bytes.as_slice(), b_bytes.as_slice());
	//convert to string
	let result = bytes_tohexstr( result_bytes.as_slice());
	//print info
	println!("result: {}", result);
	println!("result == desired: {}", result.as_slice() == desired);
	println!("done challenge two");}

/// solution for challenge three
fn challenge_three(){
	println!("challenge three ::");
	//params
	let input =
		"1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736";
	let extractions = crack_xor_cipher( input);
	println!("extractions:");
	println!("cipher :: message :: rating");
	for ( &cipher, &( ref message, ref rating)) in extractions.iter() {
		println!("{:02x} :: {} :: {:.2f}", cipher, message, *rating);}
	println!("done challenge three");}

/// solution for challenge four
fn challenge_four(){
	println!("challenge four ::");
	let lines = read_lines( "data/4.txt");
	let mut i : int = 0;
	for ref line in lines.iter() {
		let extractions = crack_xor_cipher( line.as_slice());
		if ! extractions.is_empty() {
			println!("extractions for line {}:", i);
			for ( &cipher, &( ref message, ref rating)) in extractions.iter() {
				println!("{:02x} :: {} :: {:.2f}", cipher, message, *rating);}}
		i += 1;}
	println!("done challenge four");}

/// solution for challenge five
fn challenge_five(){
	println!("challenge five ::");
	//params
	let input0 = "Burning 'em, if you ain't quick and nimble";
	let input1 = "I go crazy when I hear a cymbal";
	let desired0 =
		"0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272";
	let desired1 =
		"a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f";
	let key = "ICE";
	//convert to bytes
	let input0_bytes = ascii_tobytes( input0);
	let input1_bytes = ascii_tobytes( input1);
	let key_bytes = ascii_tobytes( key);
	//apply repeating-key xor cipher
	let result0_bytes = rkxor_cipher(
		input0_bytes.as_slice(), key_bytes.as_slice());
	let result1_bytes = rkxor_cipher(
		input1_bytes.as_slice(), key_bytes.as_slice());
	//convert to string
	let result0 = bytes_tohexstr( result0_bytes.as_slice());
	let result1 = bytes_tohexstr( result1_bytes.as_slice());
	//print info
	println!("result0: {}", result0);
	println!("result0 == desired0: {}", result0.as_slice() == desired0);
	println!("result1: {}", result1);
	println!("result1 == desired1: {}", result1.as_slice() == desired1);
	println!("done challenge five");}

/// solution for challenge six
fn challenge_six(){
	println!("challenge six ::");
	println!("done challenge six");}

/// solution for challenge seven
fn challenge_seven(){
	println!("challenge seven ::");
	println!("done challenge seven");}

/// solution for challenge eight
fn challenge_eight(){
	println!("challenge eight ::");
	println!("done challenge eight");}

//conversion functions
/// convert a hex string into base64
fn hexstr_tob64str( input: &str) -> String {
	//vars
	let bytes = hexstr_tobytes( input);
	let b64_codes : Vec<u8> = bytes_tob64codes( bytes.as_slice());
	return b64codes_tob64str( b64_codes.as_slice());
	}

/// convert a hex string into a byte vector
fn hexstr_tobytes( input: &str) -> Vec<u8> {
	let mut i = 0;
	let mut bytes : Vec<u8> = Vec::new();
	//parse bytes
	while i < input.len() {
		//current byte we're parsing
		let mut byte = 0u8;
		//parse first half
		byte += hex_toi( input.char_at( i));
		byte <<= 4;
		i += 1;
		//break if byte is \nincomplete
		if i == input.len() {
			bytes.push( byte);
			break;}
		//parse second half
		byte += hex_toi( input.char_at( i));
		//add byte
		bytes.push( byte);
		i += 1;}
	return bytes;}

fn bytes_tohexstr( bytes : &[u8]) -> String {
	let mut result = String::new();
	for &byte in bytes.iter() {
		let half1 = ( byte >> 4) & 0b1111;
		let half2 = byte & 0b1111;
		result.push_char( hexcode_tochar( half1));
		result.push_char( hexcode_tochar( half2));}
	return result;}

/// convert a byte string into b64 codes
fn bytes_tob64codes( bytes : &[u8]) -> Vec<u8> {
	let mut codes : Vec<u8> = Vec::new();
	//write bytes into b64 codes
	let mut leftover: u8 = 0;
	for i in range( 0, bytes.len()) {
		let byte = bytes[ i];
		match i % 3 {
			0 => {
				codes.push( ( byte >> 2));
				leftover = byte & 0b11;}
			1 => {
				codes.push( ( (leftover << 4) + (byte >> 4)));
				leftover = byte & 0b1111;}
			_ => {
				codes.push( ( (leftover << 2) + (byte >> 6)));
				codes.push( ( byte & 0b111111));}}}
	return codes;}

fn b64codes_tob64str( codes : &[u8]) -> String {
	let mut result = String::new();
	//convert b64 codes into string
	for i in range( 0, codes.len()) {
		result.push_char( b64code_tochar( codes[ i]));}
	return result;}

/// convert a hex char its corresponding int
fn hex_toi( character : char) -> u8 {
	match character {
		'0'..'9' => (character as u8) - ('0' as u8) + 0,
		'a'..'f' => (character as u8) - ('a' as u8) + 10,
		_ => fail!("error: input contained non-hex chars")}}

/// convert a base64 code into its corresponding char
fn b64code_tochar( code : u8) -> char {
	match code {
		00..25 => ( code - 00 + ('A' as u8)) as char,
		26..51 => ( code - 26 + ('a' as u8)) as char,
		52..61 => ( code - 52 + ('0' as u8)) as char,
		62 => '+',
		63 => '/',
		_ => fail!("error: code out of range")}}

/// convert a hec
fn hexcode_tochar( code : u8) -> char {
	match code {
		00..09 => ( code - 00 + ('0' as u8)) as char,
		10..15 => ( code - 10 + ('a' as u8)) as char,
		_ => fail!("error: code out of range")}}

fn ascii_tobytes( string : &str) -> Vec<u8> {
	let mut result = Vec::new();
	for character in string.chars() {
		result.push( character.to_ascii().to_byte());}
	return result;}

//utilities
/// xor two byte arrays
fn xor_bytes( a : &[u8], b : &[u8]) -> Vec<u8> {
	let size = std::cmp::min( a.len(), b.len());
	let mut result = Vec::new();
	for i in range( 0, size) {
		result.push( a[i] ^ b[i]);}
	return result;}

/// return a map of the bytes to their occurance counts
fn score_bytes( bytes : &[u8]) -> TreeMap<u8, u8> {
	let mut table : TreeMap<u8, u8> = TreeMap::new();
	for &byte in bytes.iter() {
		let new_count =
			match table.find( &byte) {
				Some( count) => count + 1,
				None => 1};
		table.insert( byte, new_count);}
	return table;}

/// single byte xor cipher
fn xor_cipher( original : &[u8], cipher : u8) -> Vec<u8> {
	let mut result = Vec::new();
	for &byte in original.iter() {
		result.push( byte ^ cipher);}
	return result;}

/// asdf
fn rkxor_cipher( original : &[u8], cipher : &[u8]) -> Vec<u8> {
	let mut result = Vec::new();
	let ks = cipher.len();
	for i in range( 0, original.len()) {
		result.push( original[i] ^ cipher[ i % ks ]);}
	return result;}

/// try to break single byte xor cipher
fn crack_xor_cipher( input : &str) -> TreeMap< u8, (String, f32)> {
	//convert input to bytes
	let input_bytes = hexstr_tobytes( input);
	//create score table
	let input_scores = score_bytes( input_bytes.as_slice());
	//println!("score table: {}", input_scores);
	//find top scores
	let mut top_scores : Vec<u8> = Vec::new();
	let scores_cap = 3;
	for &value in input_scores.values() {
		top_scores.push( value);}
	top_scores.sort();
	top_scores.reverse();
	let top_scores = top_scores.slice_to( scores_cap);
	//println!("top {} scores: {}", scores_cap, top_scores);
	//find bytes that match top scores
	let mut common_bytes : Vec<u8> = Vec::new();
	for ( &byte, score) in input_scores.iter() {
		if top_scores.contains( score) {
			common_bytes.push( byte);}}
	//result of above:
	//  most common bytes in input_bytes: { 120: 6, 55: 5, 54: 3 }
	let common_bytes = common_bytes.as_slice();
	//println!("common bytes: {}", common_bytes);
	//let common_chars = [' ','e','t','a','o','i','n','s','h','r','d','l','u'];
	let common_chars = [' ', 'e', 't', 'a', 'o', 'i'];
	let mut extractions : TreeMap< u8, (String, f32)> = TreeMap::new();
	let rating_cap : f32 = 0.8;
	for &common_byte in common_bytes.iter() {
		for &common_char in common_chars.iter() {
			let common_char_byte = common_char.to_ascii().to_byte();
			let cipher_byte = common_char_byte ^ common_byte;
			if extractions.contains_key( &cipher_byte) {
				continue;}
			//create attempt
			let attempt_bytes = xor_cipher( input_bytes.as_slice(), cipher_byte);
			let attempt_slice = attempt_bytes.as_slice();
			if ! attempt_slice.is_ascii() {
				continue;}
			let attempt_ascii = attempt_slice.to_ascii();
			let attempt = attempt_ascii.as_str_ascii();
			for &trimchar in ['\n',' ','\t'].iter() {
				attempt.trim_chars( trimchar);}
			//try to filter attempt
			let rating  = rate_attempt( attempt);
			if rating > rating_cap {
				extractions.insert(
					cipher_byte, ( String::from_str( attempt), rating));}}}
	return extractions;}

/// rate the likelihood a string is a good decoding attempt
fn rate_attempt( attempt : &str) -> f32 {
	let good_chars = "abcdefghijklmnopqrstuvwxyz ,.?!\'\"";
	let neut_chars = "()[]{}<>-=_+:;/@#$%^&*~`";
	let mut positive : f32 = 0.0;
	let mut negative : f32 = 0.0;
	let count = attempt.len();
	//count good and (probably) bad chars
	for attempt_char in attempt.chars() {
		let char_lower = attempt_char.to_lowercase();
		if good_chars.contains_char( char_lower) {
			positive += 1.0;}
		else if ! neut_chars.contains_char( char_lower) {
			negative += 1.0;}}
	let numerator = positive.powi( 2) - negative.powi( 2);
	let denominator = count.to_f32().unwrap().powi( 2);
	return numerator / denominator;}

fn read_lines( filename : &str) -> Vec<String> {
	// Create a path to the desired file
	let path = Path::new( filename);
	let file = File::open( &path);
	let mut reader = BufferedReader::new( file);

	let mut result : Vec<String> = Vec::new();
	for line_result in reader.lines() {
		if ! line_result.is_ok() {
			fail!( "reading a line failed");}
		let line = line_result.unwrap();
		let line_stripped = line.as_slice().trim_chars('\n');
		result.push( String::from_str( line_stripped));}
	return result;}
<|endoftext|>