<commit_before>extern crate chrono;
extern crate libc;

use std::cmp::Ordering::*;

use chrono::datetime::DateTime;
use chrono::offset::utc::UTC;
use chrono::duration::Duration;

fn main() {
    // TODO: argument parsing
    let countdown = Countdown::default();
    println!("Countdown Initiated!");
    for mark in countdown {
        match mark {
            Mark::Minute(t) => {
                println!("T minus {} minutes and counting...", t);
            },
            Mark::Second(t) => {
                println!("{}...", t);
            },
            Mark::Liftoff(s) => {
                println!("{}", s);
            }
        }
    }
}

struct Countdown {
    /// The power word used to end the countdown
    liftoff: String,
    /// When the countdown ends
    deadline: DateTime<UTC>,
    /// Final countdown
    countdown: u8
}

enum Mark {
    Minute(u32),
    Second(u32),
    Liftoff(String)
}

use Mark::*;

/// Default is: 3...2...1...Go!
impl Default for Countdown {
    fn default() -> Countdown {
        let t = UTC::now() + Duration::minutes(2) + Duration::milliseconds(10);
        Countdown { liftoff: "Go!".to_string(), deadline: t, countdown: 3 }
    }
}

impl Iterator for Countdown {
    type Item = Mark;

    fn next(&mut self) -> Option<Mark> {
        type SecondsAndNanos = libc::types::os::common::posix01::timespec;

        let req = SecondsAndNanos{tv_sec: 1, tv_nsec: 0};
        let mut rem = SecondsAndNanos{tv_sec: 0, tv_nsec: 0};

        loop {
            let d = self.deadline - UTC::now();
            unsafe { libc::funcs::posix88::unistd::nanosleep(&req, &mut rem); }

            match (d.num_minutes().cmp(&1),
                   d.num_seconds().cmp(&(self.countdown as i64)),
                   d.num_seconds() % 60,
                   d.num_seconds().cmp(&1),
                   d.cmp(&Duration::seconds(0))) {
                (Greater, _, 0, _, _) | (Equal, _, 0, _, _) =>
                    return Some(Minute(d.num_minutes() as u32)),
                (_, Equal, _, _, _) | (_, Less, _, Greater, _) |
                (_, Less, _, Equal, _) =>
                    return Some(Second(d.num_seconds() as u32)),
                (_, _, _, _, Equal) | (_, _, _, Less, Greater) =>
                    return Some(Liftoff(self.liftoff.clone())),
                (_, _, _, _, Less) => return None,
                (_, _, _, _, _)    => {}
            }
        }
    }
}
<commit_msg>Use goals -- more accurate and uses fewer syscalls<commit_after>extern crate chrono;
extern crate libc;

use std::cmp::Ordering::*;

use chrono::datetime::DateTime;
use chrono::offset::utc::UTC;
use chrono::duration::Duration;

fn main() {
    // TODO: argument parsing
    let countdown = Countdown::default();
    println!("Countdown Initiated!");
    for mark in countdown {
        match mark {
            Minute(t) => {
                println!("T minus {} minutes and counting...", t);
            },
            Second(t) => {
                println!("{}...", t);
            },
            Liftoff(s) => {
                println!("{}", s);
            }
        }
    }
}

struct Countdown {
    /// The power word used to end the countdown
    liftoff: String,
    /// When the countdown ends
    deadline: DateTime<UTC>,
    /// Final countdown
    countdown: u8
}

#[derive(Debug)]
enum Mark {
    Minute(u32),
    Second(u32),
    Liftoff(String)
}

use Mark::*;

/// Default is: 3...2...1...Go!
impl Default for Countdown {
    fn default() -> Countdown {
        let t = UTC::now() + Duration::minutes(2) + Duration::milliseconds(10);
        Countdown { liftoff: "Go!".to_string(), deadline: t, countdown: 3 }
    }
}

impl Iterator for Countdown {
    type Item = Mark;

    fn next(&mut self) -> Option<Mark> {
        let (goal, diff) = self.step();
        nanosleep(&diff);
        return if diff < Duration::zero() { None } else { Some(goal) };
    }
}

impl Countdown {
    fn step(&mut self) -> (Mark, Duration) {
        let diff = self.deadline - UTC::now();
        let countdown = self.countdown as i64;
        let (cmp1m, cmpct, cmp1s) = (diff.num_minutes().cmp(&1),
                                     diff.num_seconds().cmp(&countdown),
                                     diff.num_seconds().cmp(&1));
        let (goal, dur) = match (cmp1m, cmpct, cmp1s) {
            (Greater, Greater, _) | (Equal, Greater, _) =>
                (Minute(diff.num_minutes() as u32),
                 diff - Duration::minutes(diff.num_minutes())),
            (_, Greater, _) =>
                (Second(self.countdown as u32),
                 diff - Duration::seconds(countdown)),
            (_, _, Greater) | (_, _, Equal) =>
                (Second(diff.num_seconds() as u32),
                 diff - Duration::seconds(diff.num_seconds())),
            (_, _, _) => (Liftoff(self.liftoff.clone()), diff)
        };
        return (goal, dur);
    }
}

/// Call nanosleep to sleep the given duration, handling interruptions.
fn nanosleep(dur: &Duration) {
    use libc::types::os::common::posix01::timespec as SecondsAndNanos;

    let seconds = dur.num_seconds();
    let nanos = (*dur - Duration::seconds(seconds)).num_nanoseconds()
                                                   .expect("Catastrophe!");

    let mut req = SecondsAndNanos{tv_sec: seconds, tv_nsec: nanos};
    let mut rem = SecondsAndNanos{tv_sec: 0, tv_nsec: 0};

    unsafe { libc::funcs::posix88::unistd::nanosleep(&req, &mut rem); }
    while rem.tv_sec > 0 || rem.tv_nsec > 0 {
        req.tv_sec = rem.tv_sec;
        req.tv_nsec = rem.tv_nsec;
        unsafe { libc::funcs::posix88::unistd::nanosleep(&req, &mut rem); }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate rand;
extern crate rustty;
use rustty::{Event, Terminal};
use std::time::Duration;

mod addr;
mod byte;
mod dungeon;
mod fov;
mod geometry;
mod grid;
mod item;
mod log;
mod monster;
mod player;
mod spell;
mod sprite;
mod tile;
mod timer;
mod util;
mod view;
mod world;

use world::World;
use geometry::Point;

fn main() {
    let mut world = World::new();
    let mut terminal = Terminal::new().unwrap();

    loop {
        view::draw(&mut terminal, &world);
        terminal.swap_buffers().unwrap();
        if let Some(Event::Key(key)) = terminal.get_event(Duration::from_secs(99999)).unwrap() {
            match key {
                'q' => break,
                '<' => world.player.try_stairs_up(&mut world.dungeon),
                '>' => world.player.try_stairs_down(&mut world.dungeon),
                '\x1b' => {
                    // eat escape sequences
                    while terminal.get_event(Duration::from_millis(1)).unwrap().is_some() {
                    }
                }
                _ => {
                    // try movement commands
                    if let Some(step_direction) = key_to_direction(key) {
                        let took_turn = world.player.step(&mut world.log, &mut world.dungeon, step_direction);
                        if took_turn {
                            world.log.end_turn()
                        }
                    }
                }
            }
        }
    }
}

fn key_to_direction(key: char) -> Option<Point> {
    match key {
        'y' | '7' => Some(Point(-1, -1)),
        'k' | '8' => Some(Point(0, -1)),
        'u' | '9' => Some(Point(1, -1)),
        'h' | '4' => Some(Point(-1, 0)),
        '.' | '5' | 's' => Some(Point(0, 0)),
        'l' | '6' => Some(Point(1, 0)),
        'b' | '1' => Some(Point(-1, 1)),
        'j' | '2' => Some(Point(0, 1)),
        'n' | '3' => Some(Point(1, 1)),
        _ => None
    }
}
<commit_msg>clear terminal back-buffer between draws<commit_after>#![allow(dead_code)]
extern crate rand;
extern crate rustty;
use rustty::{Event, Terminal};
use std::time::Duration;

mod addr;
mod byte;
mod dungeon;
mod fov;
mod geometry;
mod grid;
mod item;
mod log;
mod monster;
mod player;
mod spell;
mod sprite;
mod tile;
mod timer;
mod util;
mod view;
mod world;

use world::World;
use geometry::Point;

fn main() {
    let mut world = World::new();
    let mut terminal = Terminal::new().unwrap();

    loop {
        terminal.clear().unwrap(); // clear back-buffer and notice terminal resize
        view::draw(&mut terminal, &world);
        terminal.swap_buffers().unwrap();
        if let Some(Event::Key(key)) = terminal.get_event(Duration::from_secs(99999)).unwrap() {
            match key {
                'q' => break,
                '<' => world.player.try_stairs_up(&mut world.dungeon),
                '>' => world.player.try_stairs_down(&mut world.dungeon),
                '\x1b' => {
                    // eat escape sequences
                    while terminal.get_event(Duration::from_millis(1)).unwrap().is_some() {
                    }
                }
                _ => {
                    // try movement commands
                    if let Some(step_direction) = key_to_direction(key) {
                        let took_turn = world.player.step(&mut world.log, &mut world.dungeon, step_direction);
                        if took_turn {
                            world.log.end_turn()
                        }
                    }
                }
            }
        }
    }
}

fn key_to_direction(key: char) -> Option<Point> {
    match key {
        'y' | '7' => Some(Point(-1, -1)),
        'k' | '8' => Some(Point(0, -1)),
        'u' | '9' => Some(Point(1, -1)),
        'h' | '4' => Some(Point(-1, 0)),
        '.' | '5' | 's' => Some(Point(0, 0)),
        'l' | '6' => Some(Point(1, 0)),
        'b' | '1' => Some(Point(-1, 1)),
        'j' | '2' => Some(Point(0, 1)),
        'n' | '3' => Some(Point(1, 1)),
        _ => None
    }
}
<|endoftext|>


<commit_before>#![feature(slicing_syntax)]

extern crate http;

use std::os;
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use http::method::{Get, Post};
use http::server::{Config, Server, Request, ResponseWriter};
use http::server::request::{AbsolutePath};

#[deriving(Clone)]
struct KarmaServer;

impl Server for KarmaServer {
    fn get_config(&self) -> Config {
        match os::getenv("PORT") {
            None => panic!("Must specify PORT"),
            Some(port) => {
                let port = from_str::<u16>(port.as_slice()).expect("PORT must be an int");
                Config { bind_address: SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: port } }
            }
        }
    }

    fn handle_request(&self, r: Request, w: &mut ResponseWriter) {
        let path = match r.request_uri { AbsolutePath(ref path) => path[], _ => return };

        println!("{}: {}", r.method, path);

        match (&r.method, path) {
            (&Get, "/") => {
                w.write(b"Hello world!");
            },
            (&Post, "/command") => {
                w.write(b"Hit Command");
            },
            (_, _) => {
                w.write(b"Not found :(");
            }
        }
    }
}

fn main() {
    KarmaServer.serve_forever();
}
<commit_msg>Rewrote slack bot to handle actual pushes from slack<commit_after>#![feature(slicing_syntax, macro_rules)]
#![feature(overloaded_calls)]

extern crate http;

use std::os;
use std::str;
use std::sync::{Arc, Mutex};
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::collections::HashMap;

use http::method::{Get, Post};
use http::server::{Config, Server, Request, ResponseWriter};
use http::server::request::{AbsolutePath};

type Scores = HashMap<String, i32>;

#[deriving(Send,Clone)]
struct KarmaServer {
    scores: Arc<Mutex<Scores>>,
}

impl KarmaServer {
    fn new(scores: Scores) -> KarmaServer {
        KarmaServer {
            scores: Arc::new(Mutex::new(scores)),
        }
    }
}

#[deriving(Show)]
struct SlackPayload<'a> {
    token: &'a str,
    team_id: &'a str,
    channel_id: &'a str,
    channel_name: &'a str,
    user_id: &'a str,
    user_name: &'a str,
    command: &'a str,
    text: &'a str,
}

macro_rules! get(
    ($hash: expr, $opt:expr, $msg:expr) => {
        match $hash.get(&$opt) {
            Some(n) => *n,
            None => return Err($msg.to_string()),
        }
    }
)

impl<'a> SlackPayload<'a> {
    fn from_body<'a>(req: &[u8]) -> Result<SlackPayload, String> {
        let pieces = req.split(|c| *c == '&' as u8);
        let pieces: Vec<&str> = pieces.map(|c| str::from_utf8(c).unwrap()).collect();
        let mut vars = HashMap::new();

        for c in pieces.iter() {
            let mut l1 = c.splitn(1, '=');
            match (l1.next(), l1.next()) {
                (Some(m1), Some(m2)) => { vars.insert(m1, m2); },
                _ => {},
            }
        }

        return Ok(SlackPayload {
            token:          get!(vars, "token", "No `token` in request"),
            team_id:        get!(vars, "team_id", "No `team_id` in request"),
            channel_id:     get!(vars, "channel_id", "No `channel_id` in request"),
            channel_name:   get!(vars, "channel_name", "No `channel_name` in request"),
            user_id:        get!(vars, "user_id", "No `user_id` in request"),
            user_name:      get!(vars, "user_name", "No `user_name` in request"),
            command:        get!(vars, "command", "No `command` in request"),
            text:           get!(vars, "text", "No `text` in request"),
        })
    }
}

fn handle_karma(req: Vec<u8>, points: &mut Scores) {
    let payload = match SlackPayload::from_body(req.as_slice()) {
        Ok(payload) => payload,
        Err(err) => {
            println!("Error! {}", err); return
        }
    };

    let op = match payload.command {
        "%2F++" => |c: i32| c + 1,
        "%2F--" => |c: i32| c - 1,
        _ => return,
    };

    let current = points.insert(payload.user_name.to_string(), 0).unwrap_or(0);
    points.insert(payload.user_name.to_string(), op(current));

    println!("{} now has {}", payload.user_name, op(current));
}

impl Server for KarmaServer {
    fn get_config(&self) -> Config {
        match os::getenv("PORT") {
            None => panic!("Must specify PORT"),
            Some(port) => {
                let port = from_str::<u16>(port.as_slice()).expect("PORT must be an int");
                Config { bind_address: SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: port } }
            }
        }
    }

    fn handle_request(&self, r: Request, w: &mut ResponseWriter) {
        let path = match r.request_uri { AbsolutePath(ref path) => path[], _ => return };

        println!("{}: {}", r.method, path);

        match (&r.method, path) {
            (&Get, "/") => {
                w.write(b"Hello world!");
            },
            (&Post, "/slack") => {
                let mut scores = (*self.scores).lock();
                handle_karma(r.body, &mut *scores);
            },
            (_, _) => {
                w.write(b"Not found :(");
            }
        }
    }
}

fn main() {
    let server = KarmaServer::new(HashMap::new());
    server.serve_forever();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate pretty_env_logger;
extern crate clap;
extern crate libmodbus_rs;
extern crate iron;
extern crate router;
extern crate staticfile;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate ctrlc;
extern crate retry;
extern crate hex_slice;
#[macro_use]
extern crate enum_primitive;
#[macro_use]
extern crate bitflags;

use std::fs;
use std::path::Path;
use std::os::unix::fs::FileTypeExt;
use std::sync::{Arc, Mutex};
use std::convert::From;
use std::sync::atomic::{AtomicBool, Ordering};

use clap::{App, Arg};

use iron::Iron;
use iron::prelude::*;
use iron::status;
use iron::middleware::Handler;
use router::Router;
use staticfile::Static;

mod sunsaver_connection;
use sunsaver_connection::{SunSaverConnection, FileSunSaverConnection, ModbusSunSaverConnection};
mod sunsaver;
use sunsaver::{SunSaverResponse, ChargeState, ArrayFault};

#[derive(Debug, Clone, Serialize)]
struct ApiResponse {
    generation: ApiResponseGeneration,
    storage: ApiResponseStorage,
    load: ApiResponseLoad,
    temperature: ApiResponseTemperature,
    faults: ApiResponseFaults,
}

#[derive(Debug, Clone, Serialize)]
struct ApiResponseGeneration {
    solar_input_voltage_filtered: f32,
    calculated_generation_power: f32,
}

#[derive(Debug, Clone, Serialize)]
struct ApiResponseStorage {
    battery_voltage_filtered: f32,
    battery_charge_current_filtered: f32,
    battery_charge_power_calculated: f32,
    charge_state: ChargeState,
}

#[derive(Debug, Clone, Serialize)]
struct ApiResponseLoad {
    load_voltage_filtered: f32,
    load_current_filtered: f32,
    load_power_calculated: f32,
}

#[derive(Debug, Clone, Serialize)]
struct ApiResponseTemperature {
    heatsink_temperature: i8,
    battery_temperature: i8,
    ambient_temperature: i8,
    remote_temperature: i8,
}

#[derive(Debug, Clone, Serialize)]
struct ApiResponseFaults {
    array_fault: ArrayFault,
}

impl From<SunSaverResponse> for ApiResponse {
    fn from(response: SunSaverResponse) -> Self {
        let battery_voltage_filtered = response.battery_voltage_filtered();
        let battery_charge_current_filtered = response.battery_charge_current_filtered();
        let load_voltage_filtered = response.load_voltage_filtered();
        let load_current_filtered = response.load_current_filtered();
        let solar_input_voltage_filtered = response.solar_input_voltage_filtered();

        let generation = ApiResponseGeneration {
            solar_input_voltage_filtered: solar_input_voltage_filtered,
            calculated_generation_power: (load_current_filtered + battery_charge_current_filtered) * solar_input_voltage_filtered,
        };
        let storage = ApiResponseStorage {
            battery_voltage_filtered: battery_voltage_filtered,
            battery_charge_current_filtered: battery_charge_current_filtered,
            battery_charge_power_calculated: battery_voltage_filtered * battery_charge_current_filtered,
            charge_state: response.charge_state(),
        };
        let load = ApiResponseLoad {
            load_voltage_filtered: load_voltage_filtered,
            load_current_filtered: load_current_filtered,
            load_power_calculated: load_voltage_filtered * load_current_filtered,
        };
        let temperature = ApiResponseTemperature {
            heatsink_temperature: response.heatsink_temperature(),
            battery_temperature: response.battery_temperature(),
            ambient_temperature: response.ambient_temperature(),
            remote_temperature: response.remote_temperature(),
        };
        let faults = ApiResponseFaults {
            array_fault: response.array_fault(),
        };
        ApiResponse {
            generation: generation,
            storage: storage,
            load: load,
            temperature: temperature,
            faults: faults,
        }
    }
}

#[derive(Clone)]
struct ApiHandler {
    connection: Arc<Mutex<Box<SunSaverConnection>>>,
}

impl ApiHandler {
    fn new(connection: Box<SunSaverConnection>) -> ApiHandler {
        ApiHandler {
            connection: Arc::new(Mutex::new(connection)),
        }
    }
}

unsafe impl Send for ApiHandler {}
unsafe impl Sync for ApiHandler {}

impl Handler for ApiHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        debug!("{:?}", req.url);

        let connection = self.connection.clone();
        let mut unlocked_connection = connection.lock().unwrap();
        let a = ApiResponse::from(unlocked_connection.read_response());
        let b = serde_json::to_string_pretty(&a).unwrap();
        Ok(Response::with((status::Ok, b)))
    }
}

fn is_socket(path: &str) -> bool {
    let metadata = fs::metadata(path).unwrap();
    let file_type = metadata.file_type();
    debug!("is_socket for {} had metadata {:?}", path, metadata);
    debug!("is_socket for {} is_block_device: {}, is_char_device: {}, is_fifo: {}, is_socket: {}", path, file_type.is_block_device(), file_type.is_char_device(), file_type.is_fifo(), file_type.is_socket());
    metadata.file_type().is_char_device()
}

fn main() {
    assert!(pretty_env_logger::init().is_ok());

    let matches = App::new("simple-client")
        .version(env!("CARGO_PKG_VERSION"))
        .about("HTTP RESTful server for SunSaver MPPT ModBus data")
        .author("Guy Taylor <thebiggerguy.co.uk@gmail.com>")
        .arg(Arg::with_name("device")
            .help("Serial device e.g. /dev/ttyUSB0")
            .long("device")
            .short("d")
            .takes_value(true)
            .required(true))
        .get_matches();

    let serial_interface = matches.value_of("device").unwrap();

    let mut connection: Box<SunSaverConnection> = if is_socket(serial_interface) {
        info!("Device is a socket. Using Modbus");
        Box::new(ModbusSunSaverConnection::open(serial_interface))
    } else {
        info!("Device is not a socket. Using File");
        Box::new(FileSunSaverConnection::open(serial_interface))
    };

    debug!("Response: {:?}", connection.read_response());

    let api_handler = ApiHandler::new(connection);

    let mut router = Router::new();
    router.get("/", Static::new(Path::new("web")), "index");
    router.get("/api/v1/", api_handler, "api_v1");

    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();
    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
        info!("Cought Ctrl-C");
    }).expect("Error setting Ctrl-C handler");

    info!("Starting server ...");
    let bind_address = format!("0.0.0.0:{}", option_env!("PORT").unwrap_or("8080"));
    let mut listening = Iron::new(router).http(&bind_address).unwrap();
    info!("Started server {}", bind_address);

    info!("Use Ctrl-C to stop");
    while running.load(Ordering::SeqCst) {}
    listening.close().unwrap();
}
<commit_msg>Update routing<commit_after>#[macro_use]
extern crate log;
extern crate pretty_env_logger;
extern crate clap;
extern crate libmodbus_rs;
extern crate iron;
extern crate router;
extern crate staticfile;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate ctrlc;
extern crate retry;
extern crate hex_slice;
#[macro_use]
extern crate enum_primitive;
#[macro_use]
extern crate bitflags;

use std::fs;
use std::path::Path;
use std::os::unix::fs::FileTypeExt;
use std::sync::{Arc, Mutex};
use std::convert::From;
use std::sync::atomic::{AtomicBool, Ordering};

use clap::{App, Arg};

use iron::Iron;
use iron::prelude::*;
use iron::status;
use iron::middleware::Handler;
use router::Router;
use staticfile::Static;

mod sunsaver_connection;
use sunsaver_connection::{SunSaverConnection, FileSunSaverConnection, ModbusSunSaverConnection};
mod sunsaver;
use sunsaver::{SunSaverResponse, ChargeState, ArrayFault};

#[derive(Debug, Clone, Serialize)]
struct ApiResponse {
    generation: ApiResponseGeneration,
    storage: ApiResponseStorage,
    load: ApiResponseLoad,
    temperature: ApiResponseTemperature,
    faults: ApiResponseFaults,
}

#[derive(Debug, Clone, Serialize)]
struct ApiResponseGeneration {
    solar_input_voltage_filtered: f32,
    calculated_generation_power: f32,
}

#[derive(Debug, Clone, Serialize)]
struct ApiResponseStorage {
    battery_voltage_filtered: f32,
    battery_charge_current_filtered: f32,
    battery_charge_power_calculated: f32,
    charge_state: ChargeState,
}

#[derive(Debug, Clone, Serialize)]
struct ApiResponseLoad {
    load_voltage_filtered: f32,
    load_current_filtered: f32,
    load_power_calculated: f32,
}

#[derive(Debug, Clone, Serialize)]
struct ApiResponseTemperature {
    heatsink_temperature: i8,
    battery_temperature: i8,
    ambient_temperature: i8,
    remote_temperature: i8,
}

#[derive(Debug, Clone, Serialize)]
struct ApiResponseFaults {
    array_fault: ArrayFault,
}

impl From<SunSaverResponse> for ApiResponse {
    fn from(response: SunSaverResponse) -> Self {
        let battery_voltage_filtered = response.battery_voltage_filtered();
        let battery_charge_current_filtered = response.battery_charge_current_filtered();
        let load_voltage_filtered = response.load_voltage_filtered();
        let load_current_filtered = response.load_current_filtered();
        let solar_input_voltage_filtered = response.solar_input_voltage_filtered();

        let generation = ApiResponseGeneration {
            solar_input_voltage_filtered: solar_input_voltage_filtered,
            calculated_generation_power: (load_current_filtered + battery_charge_current_filtered) * solar_input_voltage_filtered,
        };
        let storage = ApiResponseStorage {
            battery_voltage_filtered: battery_voltage_filtered,
            battery_charge_current_filtered: battery_charge_current_filtered,
            battery_charge_power_calculated: battery_voltage_filtered * battery_charge_current_filtered,
            charge_state: response.charge_state(),
        };
        let load = ApiResponseLoad {
            load_voltage_filtered: load_voltage_filtered,
            load_current_filtered: load_current_filtered,
            load_power_calculated: load_voltage_filtered * load_current_filtered,
        };
        let temperature = ApiResponseTemperature {
            heatsink_temperature: response.heatsink_temperature(),
            battery_temperature: response.battery_temperature(),
            ambient_temperature: response.ambient_temperature(),
            remote_temperature: response.remote_temperature(),
        };
        let faults = ApiResponseFaults {
            array_fault: response.array_fault(),
        };
        ApiResponse {
            generation: generation,
            storage: storage,
            load: load,
            temperature: temperature,
            faults: faults,
        }
    }
}

#[derive(Clone)]
struct ApiHandler {
    connection: Arc<Mutex<Box<SunSaverConnection>>>,
}

impl ApiHandler {
    fn new(connection: Box<SunSaverConnection>) -> ApiHandler {
        ApiHandler {
            connection: Arc::new(Mutex::new(connection)),
        }
    }
}

unsafe impl Send for ApiHandler {}
unsafe impl Sync for ApiHandler {}

impl Handler for ApiHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        debug!("{:?}", req.url);

        let path = req.url.path();
        let last_path = path.clone().pop().unwrap();
        match last_path {
            "status" => {
                let connection = self.connection.clone();
                let mut unlocked_connection = connection.lock().unwrap();
                let a = ApiResponse::from(unlocked_connection.read_response());
                let b = serde_json::to_string_pretty(&a).unwrap();
                return Ok(Response::with((status::Ok, b)))
            },
            "logger" => {
                let connection = self.connection.clone();
                let mut unlocked_connection = connection.lock().unwrap();
                unlocked_connection.read_logged_data();
                return Ok(Response::with((status::Ok)))
            },
            _ => panic!("Unknown action: {:?}", path),
        }
    }
}

fn is_socket(path: &str) -> bool {
    let metadata = fs::metadata(path).unwrap();
    let file_type = metadata.file_type();
    debug!("is_socket for {} had metadata {:?}", path, metadata);
    debug!("is_socket for {} is_block_device: {}, is_char_device: {}, is_fifo: {}, is_socket: {}", path, file_type.is_block_device(), file_type.is_char_device(), file_type.is_fifo(), file_type.is_socket());
    metadata.file_type().is_char_device()
}

fn main() {
    assert!(pretty_env_logger::init().is_ok());

    let matches = App::new("simple-client")
        .version(env!("CARGO_PKG_VERSION"))
        .about("HTTP RESTful server for SunSaver MPPT ModBus data")
        .author("Guy Taylor <thebiggerguy.co.uk@gmail.com>")
        .arg(Arg::with_name("device")
            .help("Serial device e.g. /dev/ttyUSB0")
            .long("device")
            .short("d")
            .takes_value(true)
            .required(true))
        .get_matches();

    let serial_interface = matches.value_of("device").unwrap();

    let mut connection: Box<SunSaverConnection> = if is_socket(serial_interface) {
        info!("Device is a socket. Using Modbus");
        Box::new(ModbusSunSaverConnection::open(serial_interface))
    } else {
        info!("Device is not a socket. Using File");
        Box::new(FileSunSaverConnection::open(serial_interface))
    };

    debug!("Response: {:?}", connection.read_response());

    let api_handler = ApiHandler::new(connection);

    let mut router = Router::new();
    router.get("/", Static::new(Path::new("web")), "index");
    router.get("/api/v1/status", api_handler.clone(), "api_v1_status");
    router.get("/api/v1/logger", api_handler.clone(), "api_v2_logger");

    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();
    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
        info!("Cought Ctrl-C");
    }).expect("Error setting Ctrl-C handler");

    info!("Starting server ...");
    let bind_address = format!("0.0.0.0:{}", option_env!("PORT").unwrap_or("8080"));
    let mut listening = Iron::new(router).http(&bind_address).unwrap();
    info!("Started server {}", bind_address);

    info!("Use Ctrl-C to stop");
    while running.load(Ordering::SeqCst) {}
    listening.close().unwrap();
}
<|endoftext|>


<commit_before>// Cargo.toml : use crate `colored = "1.3"`
extern crate regex;

pub mod parser;
pub mod base;
pub mod extra;

use std::fs::File;
use std::io::Read;
use std::u16;
use std::env::args;
use std::process::exit;
use extra::*;
use regex::Regex;

static USAGE_STRING: &'static str = "\
>> available commands:
 -{n}       -- номер серии -n { стандартное значение = 1 }
 +{n}       -- номер серии +n { стандартное значение = 1 }
 a          -- добавить элемент [ a/имя | a/\"имя\" ]
 d          -- удалить элементы { найденые элементы параметром f }
 i          -- вывести весь список
 f{??}      -- поиск по параметру
   f        -- поиск по названию [ f/\"имя или regex\" ]
   fs{??}   -- по статусу { ?? -- буква статуса }
     где ??: c -- complete, d -- drop, h -- hold, p -- plan, w -- watch
   fp{??}   -- по номеру серии { ?? -- номер серии }
   fr{??}   -- по оценке { ?? -- оценка }
 s{??}      -- установить параметр
  sn        -- изменить имя на новое [ sn/имя | sn/\"имя\" ]
  sm{число} -- изменить максимальный номер серии { ? в случае онгоинга }
  sp{число} -- изменить номер серии на { число }
  sr{число} -- изменить рейтинг на { число }
  ss{??}    -- изменить статуc на { ?? -- буква статуса }
    где ??: c -- complete, d -- drop, h -- hold, p -- plan, w -- watch
 w          -- записать изменения в базу
>> example: 'f/\"One Piece\"/sm?/+5/-/sr7/sp23/ssc/sn/d.gray-man/sm24/w'";

fn main() {
    let arg_line = match args().nth(1) {
        Some(value) => value,
        None => {
            let app_name = args().nth(0).unwrap();
            println!("usage: {} '<regex>'\n{}", app_name, USAGE_STRING);
            exit(0);
        }
    };
    let mut anime_base = AnimeBase::new();
    let mut file = File::open("anime-list").unwrap();
    let mut buffer = String::new();
    file.read_to_string(&mut buffer).unwrap();
    for string in buffer.lines() {
        anime_base.push(base::Item::new(string));
    }
    println!("command list:");
    let mut iterator = parser::Splitter::new(&arg_line, parser::SplitFormat::Commands);
    let mut anime_list: Vec<usize> = Vec::new();
    // let mut color_exchange = true;
    while let Some(cmd) = iterator.next() {
        match ExecCmd::get(cmd, &mut iterator) {
            ExecCmd::Increment(value) => {
                println!("[cmd] inc by `{}`", value);
                for index in &anime_list {
                    let progress = anime_base.list.get(*index).unwrap().progress;
                    let result = match progress.checked_add(value) {
                        Some(value) => value,
                        None => u16::MAX
                    };
                    anime_base.list.get_mut(*index).unwrap().progress = result;
                    println!("> u: {}", anime_base.format_by_index(*index));
                }
            }
            ExecCmd::Decrement(value) => {
                println!("[cmd] dec by `{}`", value);
                for index in &anime_list {
                    let progress = anime_base.list.get(*index).unwrap().progress;
                    let result = match progress.checked_sub(value) {
                        Some(value) => value,
                        None => 0,
                    };
                    anime_base.list.get_mut(*index).unwrap().progress = result;
                    println!("> u: {}", anime_base.format_by_index(*index));
                }
            },
            ExecCmd::Append(name) => println!("[cmd] new anime `{}`", name),
            ExecCmd::Delete => println!("[cmd] delete item"),
            ExecCmd::Info => {
                println!("[cmd] print list");
                println!("{}", anime_base);
            },
            ExecCmd::Find(regex) => {
                println!("[cmd] find `{}`", regex);
                let re = Regex::new(&regex).unwrap();
                for (index, item) in anime_base.list.iter().enumerate() {
                    if re.is_match(&item.name) {
                        anime_list.push(index);
                        println!("> f: {}", anime_base.format(item));
                    }
                }
            },
            ExecCmd::FindParam(param) => println!("[cmd] find by param `{:?}`", param),
            ExecCmd::Maximum(value) => println!("[cmd] series limit `{}`", value.get()),
            ExecCmd::Rename(new_name) => println!("[cmd] new name `{}`", new_name),
            ExecCmd::Progress(value) => println!("[cmd] progress `{}`", value),
            ExecCmd::Status(status) => println!("[cmd] status `{:?}`", status),
            ExecCmd::Rate(value) => println!("[cmd] rate `{}`", value),
            ExecCmd::Write => println!("[cmd] write changes"),
            ExecCmd::Error(kind) => println!("[cmd] unknown command `{}`: {:?}", cmd, kind)
        };
    }
}
<commit_msg>[upd] russian in info<commit_after>// Cargo.toml : use crate `colored = "1.3"`
extern crate regex;

pub mod parser;
pub mod base;
pub mod extra;

use std::fs::File;
use std::io::Read;
use std::u16;
use std::env::args;
use std::process::exit;
use extra::*;
use regex::Regex;

static USAGE_STRING: &'static str = "\
>> доступные команды:
 -{n}       -- номер серии -n { стандартное значение = 1 }
 +{n}       -- номер серии +n { стандартное значение = 1 }
 a          -- добавить элемент [ a/имя | a/\"имя\" ]
 d          -- удалить элементы { найденые элементы параметром f }
 i          -- вывести весь список
 f{??}      -- поиск по параметру
   f        -- поиск по названию [ f/\"имя или regex\" ]
   fs{??}   -- по статусу { ?? -- буква статуса }
     где ??: c -- complete, d -- drop, h -- hold, p -- plan, w -- watch
   fp{??}   -- по номеру серии { ?? -- номер серии }
   fr{??}   -- по оценке { ?? -- оценка }
 s{??}      -- установить параметр
  sn        -- изменить имя на новое [ sn/имя | sn/\"имя\" ]
  sm{число} -- изменить максимальный номер серии { ? в случае онгоинга }
  sp{число} -- изменить номер серии на { число }
  sr{число} -- изменить рейтинг на { число }
  ss{??}    -- изменить статуc на { ?? -- буква статуса }
    где ??: c -- complete, d -- drop, h -- hold, p -- plan, w -- watch
 w          -- записать изменения в базу
>> example: 'f/\"One Piece\"/sm?/+5/-/sr7/sp23/ssc/sn/d.gray-man/sm24/w'";

fn main() {
    let arg_line = match args().nth(1) {
        Some(value) => value,
        None => {
            let app_name = args().nth(0).unwrap();
            println!("usage: {} '<regex>'\n{}", app_name, USAGE_STRING);
            exit(0);
        }
    };
    let mut anime_base = AnimeBase::new();
    let mut file = File::open("anime-list").unwrap();
    let mut buffer = String::new();
    file.read_to_string(&mut buffer).unwrap();
    for string in buffer.lines() {
        anime_base.push(base::Item::new(string));
    }
    println!("command list:");
    let mut iterator = parser::Splitter::new(&arg_line, parser::SplitFormat::Commands);
    let mut anime_list: Vec<usize> = Vec::new();
    // let mut color_exchange = true;
    while let Some(cmd) = iterator.next() {
        match ExecCmd::get(cmd, &mut iterator) {
            ExecCmd::Increment(value) => {
                println!("[cmd] inc by `{}`", value);
                for index in &anime_list {
                    let progress = anime_base.list.get(*index).unwrap().progress;
                    let result = match progress.checked_add(value) {
                        Some(value) => value,
                        None => u16::MAX
                    };
                    anime_base.list.get_mut(*index).unwrap().progress = result;
                    println!("> u: {}", anime_base.format_by_index(*index));
                }
            }
            ExecCmd::Decrement(value) => {
                println!("[cmd] dec by `{}`", value);
                for index in &anime_list {
                    let progress = anime_base.list.get(*index).unwrap().progress;
                    let result = match progress.checked_sub(value) {
                        Some(value) => value,
                        None => 0,
                    };
                    anime_base.list.get_mut(*index).unwrap().progress = result;
                    println!("> u: {}", anime_base.format_by_index(*index));
                }
            },
            ExecCmd::Append(name) => println!("[cmd] new anime `{}`", name),
            ExecCmd::Delete => println!("[cmd] delete item"),
            ExecCmd::Info => {
                println!("[cmd] print list");
                println!("{}", anime_base);
            },
            ExecCmd::Find(regex) => {
                println!("[cmd] find `{}`", regex);
                let re = Regex::new(&regex).unwrap();
                for (index, item) in anime_base.list.iter().enumerate() {
                    if re.is_match(&item.name) {
                        anime_list.push(index);
                        println!("> f: {}", anime_base.format(item));
                    }
                }
            },
            ExecCmd::FindParam(param) => println!("[cmd] find by param `{:?}`", param),
            ExecCmd::Maximum(value) => println!("[cmd] series limit `{}`", value.get()),
            ExecCmd::Rename(new_name) => println!("[cmd] new name `{}`", new_name),
            ExecCmd::Progress(value) => println!("[cmd] progress `{}`", value),
            ExecCmd::Status(status) => println!("[cmd] status `{:?}`", status),
            ExecCmd::Rate(value) => println!("[cmd] rate `{}`", value),
            ExecCmd::Write => println!("[cmd] write changes"),
            ExecCmd::Error(kind) => println!("[cmd] unknown command `{}`: {:?}", cmd, kind)
        };
    }
}
<|endoftext|>


<commit_before>#![feature(box_patterns)]

use std::error::Error;

extern crate csv;
use csv::{Reader, StringRecords};

/// The data types supported by this database. Currently just u64 and string but others
/// will be added later, including complex types
#[derive(Debug,Clone)]
enum DataType {
    UnsignedLong,
    String
}

/// Definition of a column in a relation (data set).
#[derive(Debug,Clone)]
struct ColumnMeta {
    name: String,
    data_type: DataType,
    nullable: bool
}

/// Definition of a relation (data set) consisting of one or more columns.
#[derive(Debug,Clone)]
struct TupleType {
    columns: Vec<ColumnMeta>
}

/// Value holder for all supported data types
#[derive(Debug,Clone,PartialEq,PartialOrd)]
enum Value {
    UnsignedLong(u64),
    String(String),
    Boolean(bool)
}

/// A tuple represents one row within a relation and is implemented as a trait to allow for
/// specific implementations for different data sources
trait Tuple {
    fn get_value(&self, index: usize) -> Result<Value, Box<std::error::Error>>;
}

/// A simple tuple implementation for testing and initial prototyping
#[derive(Debug)]
struct SimpleTuple {
    values: Vec<Value>
}

impl Tuple for SimpleTuple {

    fn get_value(&self, index: usize) -> Result<Value, Box<std::error::Error>> {
        Ok(self.values[index].clone())
    }

}

/// dumb
trait DataSource {
    fn scan(&self) -> Result<Box<Iterator<Item=Tuple>>, Box<Error>>;
}

struct CsvDataSource {
}

impl DataSource for CsvDataSource {
    fn scan(&self) -> Result<Box<Iterator<Item=Tuple>>, Box<Error>> {
        Err(From::from("not implemented yet"))
    }
}

#[derive(Debug)]
enum Operator {
    Eq,
    NotEq,
    Lt,
    LtEq,
    Gt,
    GtEq,
}

#[derive(Debug)]
enum Expr {
    /// index into a value within the tuple
    TupleValue(usize),
    /// literal value
    Literal(Value),
    /// binary expression e.g. "age > 21"
    BinaryExpr { left: Box<Expr>, op: Operator, right: Box<Expr> },
}

/// Query plan
#[derive(Debug)]
enum PlanNode {
    TableScan,
    Filter(Expr),
    Project(Vec<Expr>),
}

fn evaluate(tuple: &Tuple, tt: &TupleType, expr: &Expr) -> Result<Value, Box<std::error::Error>> {

    match expr {
        &Expr::BinaryExpr { box ref left, ref op, box ref right } => {
            //TODO: remove use of unwrap() here
            let left_value = evaluate(tuple, tt, left).unwrap();
            let right_value = evaluate(tuple, tt, right).unwrap();
            match op {
                &Operator::Eq => Ok(Value::Boolean(left_value == right_value)),
                &Operator::NotEq => Ok(Value::Boolean(left_value != right_value)),
                &Operator::Lt => Ok(Value::Boolean(left_value < right_value)),
                &Operator::LtEq => Ok(Value::Boolean(left_value <= right_value)),
                &Operator::Gt => Ok(Value::Boolean(left_value > right_value)),
                &Operator::GtEq => Ok(Value::Boolean(left_value >= right_value)),
            }
        },
        &Expr::TupleValue(index) => tuple.get_value(index),
        &Expr::Literal(ref value) => Ok(value.clone()),
    }

}

fn main() {

    let tt = TupleType {
        columns: vec![
            ColumnMeta { name: String::from("id"), data_type: DataType::UnsignedLong, nullable: false },
            ColumnMeta { name: String::from("name"), data_type: DataType::String, nullable: false }
        ]
    };

    println!("Tuple type: {:?}", tt);

    // create simple filter expression for "id = 2"
    let filter_expr = Expr::BinaryExpr {
        left: Box::new(Expr::TupleValue(0)),
        op: Operator::Eq,
        right: Box::new(Expr::Literal(Value::UnsignedLong(2)))
    };

    println!("Expression: {:?}", filter_expr);

    // execute scan with filter expr against csv file
    let mut rdr = csv::Reader::from_file("people.csv").unwrap();
    let mut records = rdr.records();

    // <Option<Result<Vec<String>>>
    while let Some(row) = records.next() {
        let data : Vec<String> = row.unwrap();
        println!("Row: {:?}", data);

        // for now, do an expensive translation of strings to the specific tuple type
        let mut converted : Vec<Value> = vec![];

        for i in 0..data.len() {
            converted.push(match tt.columns[i].data_type {
                    DataType::UnsignedLong => Value::UnsignedLong(data[i].parse::<u64>().unwrap()),
                    DataType::String => Value::String(data[i].clone()),
            });
        }

        let tuple = SimpleTuple { values: converted };

        let is_match = evaluate(&tuple, &tt, &filter_expr).unwrap();
        println!("filter expr evaluates to {:?}", is_match);
    }

}
<commit_msg>code cleanup<commit_after>#![feature(box_patterns)]

use std::error::Error;

extern crate csv;
use csv::{Reader, StringRecords};

/// The data types supported by this database. Currently just u64 and string but others
/// will be added later, including complex types
#[derive(Debug,Clone)]
enum DataType {
    UnsignedLong,
    String
}

/// Definition of a column in a relation (data set).
#[derive(Debug,Clone)]
struct ColumnMeta {
    name: String,
    data_type: DataType,
    nullable: bool
}

/// Definition of a relation (data set) consisting of one or more columns.
#[derive(Debug,Clone)]
struct TupleType {
    columns: Vec<ColumnMeta>
}

/// Value holder for all supported data types
#[derive(Debug,Clone,PartialEq,PartialOrd)]
enum Value {
    UnsignedLong(u64),
    String(String),
    Boolean(bool)
}

/// A tuple represents one row within a relation and is implemented as a trait to allow for
/// specific implementations for different data sources
trait Tuple {
    fn get_value(&self, index: usize) -> Result<Value, Box<std::error::Error>>;
}

/// A simple tuple implementation for testing and initial prototyping
#[derive(Debug)]
struct SimpleTuple {
    values: Vec<Value>
}

impl Tuple for SimpleTuple {

    fn get_value(&self, index: usize) -> Result<Value, Box<std::error::Error>> {
        Ok(self.values[index].clone())
    }

}

/// dumb
//trait DataSource {
//    fn scan(&self) -> Result<Box<Iterator<Item=Tuple>>, Box<Error>>;
//}
//
//struct CsvDataSource {
//}
//
//impl DataSource for CsvDataSource {
//    fn scan(&self) -> Result<Box<Iterator<Item=Tuple>>, Box<Error>> {
//        Err(From::from("not implemented yet"))
//    }
//}

#[derive(Debug)]
enum Operator {
    Eq,
    NotEq,
    Lt,
    LtEq,
    Gt,
    GtEq,
}

#[derive(Debug)]
enum Expr {
    /// index into a value within the tuple
    TupleValue(usize),
    /// literal value
    Literal(Value),
    /// binary expression e.g. "age > 21"
    BinaryExpr { left: Box<Expr>, op: Operator, right: Box<Expr> },
}

/// Query plan
#[derive(Debug)]
enum PlanNode {
    TableScan,
    Filter(Expr),
    Project(Vec<Expr>),
}

fn evaluate(tuple: &Tuple, tt: &TupleType, expr: &Expr) -> Result<Value, Box<std::error::Error>> {

    match expr {
        &Expr::BinaryExpr { box ref left, ref op, box ref right } => {
            //TODO: remove use of unwrap() here
            let left_value = evaluate(tuple, tt, left).unwrap();
            let right_value = evaluate(tuple, tt, right).unwrap();
            match op {
                &Operator::Eq => Ok(Value::Boolean(left_value == right_value)),
                &Operator::NotEq => Ok(Value::Boolean(left_value != right_value)),
                &Operator::Lt => Ok(Value::Boolean(left_value < right_value)),
                &Operator::LtEq => Ok(Value::Boolean(left_value <= right_value)),
                &Operator::Gt => Ok(Value::Boolean(left_value > right_value)),
                &Operator::GtEq => Ok(Value::Boolean(left_value >= right_value)),
            }
        },
        &Expr::TupleValue(index) => tuple.get_value(index),
        &Expr::Literal(ref value) => Ok(value.clone()),
    }

}

fn main() {

    // define schema for data source (csv file)
    let tt = TupleType {
        columns: vec![
            ColumnMeta { name: String::from("id"), data_type: DataType::UnsignedLong, nullable: false },
            ColumnMeta { name: String::from("name"), data_type: DataType::String, nullable: false }
        ]
    };

    // create simple filter expression for "id = 2"
    let filter_expr = Expr::BinaryExpr {
        left: Box::new(Expr::TupleValue(0)),
        op: Operator::Eq,
        right: Box::new(Expr::Literal(Value::UnsignedLong(2)))
    };

    // execute scan with filter expr against csv file
    let mut rdr = csv::Reader::from_file("people.csv").unwrap();
    let mut records = rdr.records();

    // iterate over data
    while let Some(row) = records.next() {
        let data : Vec<String> = row.unwrap();
        println!("Row: {:?}", data);

        // for now, do an expensive translation of strings to the specific tuple type for
        // every single column
        let mut converted : Vec<Value> = vec![];
        for i in 0..data.len() {
            converted.push(match tt.columns[i].data_type {
                    DataType::UnsignedLong => Value::UnsignedLong(data[i].parse::<u64>().unwrap()),
                    DataType::String => Value::String(data[i].clone()),
            });
        }
        let tuple = SimpleTuple { values: converted };

        let is_match = evaluate(&tuple, &tt, &filter_expr).unwrap();
        println!("filter expr evaluates to {:?}", is_match);
    }

}
<|endoftext|>


<commit_before>
mod vm;

fn main(){
	let bytecode = "\x0E\x00\x02\x00\x02\x02\x0A";
	println!("Perin v{}",vm::perin_version());
	println!("Perin VM executes FlopFlip bytecode");

	let mut perin = vm::PerinVM::new();
	perin.interpreter(bytecode);
}
<commit_msg>Doing a more complex math operation - 2+3<commit_after>mod vm;

fn main(){
	let bytecode = "\x0E\x00\x03\x00\x02\x02\x0A";
	println!("Perin v{}",vm::perin_version());
	println!("Perin VM executes FlopFlip bytecode");

	let mut perin = vm::PerinVM::new();
	perin.interpreter(bytecode);
}
<|endoftext|>


<commit_before>extern crate regex;
extern crate colored;

mod charpeek;

use charpeek::Charpeek;

use regex::Regex;
use colored::Colorize;

use std::collections::BTreeMap;
use std::fs;
use std::io::prelude::*;
use std::io;
use std::iter::repeat;
use std::env;
use std::process;

fn color_keywords(keys: &Regex, mut line: &str) -> String {
    use std::fmt::Write;
    let mut buf = String::new();
    while let Some((start, end)) = keys.find(line) {
        write!(buf, "{}{}", &line[..start], line[start..end].bold()).unwrap();
        line = &line[end..];
    }
    write!(buf, "{}", line).unwrap();
    buf
}

fn main() {
    let args: Vec<_> = env::args_os().collect();
    if args.len() <= 1 {
        let i = io::stdin();
        do_it(&mut i.lock());
    } else {
        let mut cmd = process::Command::new(&args[1])
            .args(&args[2..])
            .stdout(process::Stdio::piped())
            .spawn()
            .expect("Can't spawn process");
        do_it(&mut io::BufReader::new(cmd.stdout.as_mut().unwrap()));
        let status = cmd.wait().expect("Can't wait for process");
        if !status.success() {
            println!("{}: {}", "Exit status".yellow(), status);
        }
    }
}

fn do_it(reader: &mut BufRead) {
    let location_r = Regex::new(r#"^File "(.*)", line (\d+), characters (\d+)-(\d+):$"#).unwrap();
    let command_r = Regex::new(r"ocaml.* -I .* -o .*|^ocamldep.*\.mli? >|^ocamlbuild -package").unwrap();
    let val_r = Regex::new(r"^((?:let |val )?)(.+?) : (.+?) =(.*)$").unwrap();
    let type_r = Regex::new(r"^type (.+?) =(.*)$").unwrap();
    let word_r = Regex::new(r"^\w+").unwrap();
    let keywords_r = Regex::new(r"\b(let|in|match|with|for|do|done|if|then|else|begin|end|rec|when|and|or|val)\b").unwrap();
    let escape_r = Regex::new(r"\033\[.+?m").unwrap();

    let make_fence = |len: usize| repeat('-').take(len).collect::<String>();

    let mut lines = Charpeek::new(reader);
    let mut files: BTreeMap<String, Vec<String>> = BTreeMap::new();
    let mut inside = false;

    while let Some(byte) = lines.peek_byte() {
        // Handle prompt (we want to flush it immediately)
        if byte == b'#' || (byte as char).is_whitespace() {
            if byte == b'#' {
                print!("\n{}", "λ".green().bold());
                lines.flush_peek(io::sink());
            } else {
                lines.flush_peek(&mut io::stdout());
            }
            continue;
        }

        let line = if let Some(line) = lines.next_line() { line } else { break };
        let unescaped_line = escape_r.replace_all(&line, "");

        if let Some(captures) = location_r.captures(&unescaped_line) {
            // Handle error/warning
            inside = true;

            let filename = &captures[1];
            let i_row: usize = captures[2].parse().unwrap();
            let col_start: usize = captures[3].parse().unwrap();
            let mut col_end: usize = captures[4].parse().unwrap();

            let file = files.entry(filename.to_owned())
                .or_insert_with(||
                    fs::File::open(&filename)
                        .map(|file|
                             io::BufReader::new(file)
                                .lines()
                                .map(|x| x.unwrap_or_else(|_| "".into()))
                                .collect()
                        )
                        .unwrap_or_else(|_| vec![])
                );

            let filerow = format!("{}:{}", filename, i_row);
            let fence = format!("-- {} {}", filerow, make_fence(80 - 4 - filerow.len()));
            println!("\n{}", fence.cyan());

            // The message
            let message = lines.next_line().unwrap_or("".into());
            let message = escape_r.replace_all(&message, "");
            let message_type = &message[..word_r.find(&message).unwrap_or((0,0)).1];
            let colorize = |s: &str| match message_type {
                "Warning" => s.yellow(),
                "Error" => s.red().bold(),
                _ => s.bold(),
            };
            println!("{}{}", colorize(message_type), &message[message_type.len()..]);
            while lines
                    .peek_byte()
                    .map_or(false, |b| (b as char).is_whitespace()) {
                println!("{}", lines.next_line().unwrap());
            }
            println!("");

            // The snippet
            for i in i_row.. {
                let rownum = format!("{}|", i);
                let row = &file[i - 1];

                println!("{}{}", rownum.cyan(), color_keywords(&keywords_r, row));

                let col_start =
                    if i == i_row { col_start }
                    else { row.chars().take_while(|c| c.is_whitespace()).count() };

                for _ in 0..rownum.len() { print!(" ") }
                // print!("{}", "|".cyan());
                for c in row[..col_start].chars() {
                    if c.is_whitespace() { print!("{}", c) }
                    else { print!(" ") }
                }

                let underline_len = std::cmp::min(col_end, row.len()) - col_start;
                println!("{}", colorize(&repeat('~').take(underline_len).collect::<String>()));

                if col_end <= row.len() { break }
                else { col_end -= row.len() + 1 }
            }

        } else if command_r.is_match(&line) {
            // Handle commands printed by ocamlbuild
            if inside {
                println!("");
                inside = false;
            }
            println!("{}", line.dimmed());

        } else if let Some(captures) = val_r.captures(&line) {
            // Handle val/let assignments
            if inside {
                println!("");
                inside = false;
            }
            println!("{}{} : {} ={}", captures[1].bold(), &captures[2], captures[3].cyan(), &captures[4]);

        } else if let Some(captures) = type_r.captures(&line) {
            // Handle type declarations
            if inside {
                println!("");
                inside = false;
            }
            println!("{} {} ={}", "type".bold(), &captures[1].cyan(), &captures[2]);

        } else if line.starts_with("Hint:") {
            println!("\n{}\n{}{}", make_fence(80).cyan(), "Hint".green(), &line[4..]);

        } else {
            println!("{}", line);
        }
    }
}
<commit_msg>Handle errors at EOF<commit_after>extern crate regex;
extern crate colored;

mod charpeek;

use charpeek::Charpeek;

use regex::Regex;
use colored::Colorize;

use std::collections::BTreeMap;
use std::fs;
use std::io::prelude::*;
use std::io;
use std::iter::{once,repeat};
use std::env;
use std::process;

fn color_keywords(keys: &Regex, mut line: &str) -> String {
    use std::fmt::Write;
    let mut buf = String::new();
    while let Some((start, end)) = keys.find(line) {
        write!(buf, "{}{}", &line[..start], line[start..end].bold()).unwrap();
        line = &line[end..];
    }
    write!(buf, "{}", line).unwrap();
    buf
}

fn main() {
    let args: Vec<_> = env::args_os().collect();
    if args.len() <= 1 {
        let i = io::stdin();
        do_it(&mut i.lock());
    } else {
        let mut cmd = process::Command::new(&args[1])
            .args(&args[2..])
            .stdout(process::Stdio::piped())
            .spawn()
            .expect("Can't spawn process");
        do_it(&mut io::BufReader::new(cmd.stdout.as_mut().unwrap()));
        let status = cmd.wait().expect("Can't wait for process");
        if !status.success() {
            println!("{}: {}", "Exit status".yellow(), status);
        }
    }
}

fn do_it(reader: &mut BufRead) {
    let location_r = Regex::new(r#"^File "(.*)", line (\d+), characters (\d+)-(\d+):$"#).unwrap();
    let command_r = Regex::new(r"ocaml.* -I .* -o .*|^ocamldep.*\.mli? >|^ocamlbuild -package").unwrap();
    let val_r = Regex::new(r"^((?:let |val )?)(.+?) : (.+?) =(.*)$").unwrap();
    let type_r = Regex::new(r"^type (.+?) =(.*)$").unwrap();
    let word_r = Regex::new(r"^\w+").unwrap();
    let keywords_r = Regex::new(r"\b(let|in|match|with|for|do|done|if|then|else|begin|end|rec|when|and|or|val)\b").unwrap();
    let escape_r = Regex::new(r"\033\[.+?m").unwrap();

    let make_fence = |len: usize| repeat('-').take(len).collect::<String>();

    let mut lines = Charpeek::new(reader);
    let mut files: BTreeMap<String, Vec<String>> = BTreeMap::new();
    let mut inside = false;

    while let Some(byte) = lines.peek_byte() {
        // Handle prompt (we want to flush it immediately)
        if byte == b'#' || (byte as char).is_whitespace() {
            if byte == b'#' {
                print!("\n{}", "λ".green().bold());
                lines.flush_peek(io::sink());
            } else {
                lines.flush_peek(&mut io::stdout());
            }
            continue;
        }

        let line = if let Some(line) = lines.next_line() { line } else { break };
        let unescaped_line = escape_r.replace_all(&line, "");

        if let Some(captures) = location_r.captures(&unescaped_line) {
            // Handle error/warning
            inside = true;

            let filename = &captures[1];
            let i_row: usize = captures[2].parse().unwrap();
            let col_start: usize = captures[3].parse().unwrap();
            let mut col_end: usize = captures[4].parse().unwrap();

            let file = files.entry(filename.to_owned())
                .or_insert_with(||
                    fs::File::open(&filename)
                        .map(|file|
                             io::BufReader::new(file)
                                .lines()
                                .map(|x| x.unwrap_or_else(|_| "".into()))
                                .chain(once("<END OF FILE>".into()))
                                .collect()
                        )
                        .unwrap_or_else(|_| vec![])
                );

            let filerow = format!("{}:{}", filename, i_row);
            let fence = format!("-- {} {}", filerow, make_fence(80 - 4 - filerow.len()));
            println!("\n{}", fence.cyan());

            // The message
            let message = lines.next_line().unwrap_or("".into());
            let message = escape_r.replace_all(&message, "");
            let message_type = &message[..word_r.find(&message).unwrap_or((0,0)).1];
            let colorize = |s: &str| match message_type {
                "Warning" => s.yellow(),
                "Error" => s.red().bold(),
                _ => s.bold(),
            };
            println!("{}{}", colorize(message_type), &message[message_type.len()..]);
            while lines
                    .peek_byte()
                    .map_or(false, |b| (b as char).is_whitespace()) {
                println!("{}", lines.next_line().unwrap());
            }
            println!("");

            // The snippet
            for i in i_row.. {
                let rownum = format!("{}|", i);
                let row = &file.get(i - 1).map_or("<NO SUCH LINE>", |s| s.as_str());

                println!("{}{}", rownum.cyan(), color_keywords(&keywords_r, row));

                let col_start =
                    if i == i_row { col_start }
                    else { row.chars().take_while(|c| c.is_whitespace()).count() };

                for _ in 0..rownum.len() { print!(" ") }
                // print!("{}", "|".cyan());
                for c in row[..col_start].chars() {
                    if c.is_whitespace() { print!("{}", c) }
                    else { print!(" ") }
                }

                let underline_len = std::cmp::min(col_end, row.len()) - col_start;
                println!("{}", colorize(&repeat('~').take(underline_len).collect::<String>()));

                if col_end <= row.len() { break }
                else { col_end -= row.len() + 1 }
            }

        } else if command_r.is_match(&line) {
            // Handle commands printed by ocamlbuild
            if inside {
                println!("");
                inside = false;
            }
            println!("{}", line.dimmed());

        } else if let Some(captures) = val_r.captures(&line) {
            // Handle val/let assignments
            if inside {
                println!("");
                inside = false;
            }
            println!("{}{} : {} ={}", captures[1].bold(), &captures[2], captures[3].cyan(), &captures[4]);

        } else if let Some(captures) = type_r.captures(&line) {
            // Handle type declarations
            if inside {
                println!("");
                inside = false;
            }
            println!("{} {} ={}", "type".bold(), &captures[1].cyan(), &captures[2]);

        } else if line.starts_with("Hint:") {
            println!("\n{}\n{}{}", make_fence(80).cyan(), "Hint".green(), &line[4..]);

        } else {
            println!("{}", line);
        }
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate crc;

use std::fs::File;
use std::io::{Read, Result, Error, Seek, SeekFrom};
use std::io::ErrorKind::Other;

use byteorder::{LittleEndian, ByteOrder};

use crc::{crc32, Hasher32};

const LABEL_SCAN_SECTORS: usize = 4;
const MYPATH: &'static str = "/dev/mapper/luks-291e9250-200e-4c36-8e5e-66aa257669ed";
const ID_LEN: usize = 32;
const MDA_MAGIC: &'static [u8] = b"\x20\x4c\x56\x4d\x32\x20\x78\x5b\x35\x41\x25\x72\x30\x4e\x2a\x3e";
const INITIAL_CRC: u32 = 0xf597a6cf;
const SECTOR_SIZE: usize = 512;

mod lexer;

use lexer::{Lexer, Token};

#[derive(Debug)]
struct Label {
    id: String,
    sector: u64,
    crc: u32,
    offset: u32,
    label: String,
}

#[derive(Debug)]
struct PvArea {
    offset: u64,
    size: u64,
}

#[derive(Debug)]
struct PvHeader {
    uuid: String,
    size: u64, // in bytes
    ext_version: u32,
    ext_flags: u32,
    data_areas: Vec<PvArea>,
    metadata_areas: Vec<PvArea>,
    bootloader_areas: Vec<PvArea>,
}

fn get_label(buf: &[u8]) -> Result<Label> {
    for x in 0..LABEL_SCAN_SECTORS {
        let sec_buf = &buf[x*SECTOR_SIZE..x*SECTOR_SIZE+SECTOR_SIZE];
        if &sec_buf[..8] == b"LABELONE" {
            let crc = LittleEndian::read_u32(&sec_buf[16..20]);
            crc32_ok(crc, &sec_buf[20..SECTOR_SIZE]);

            let sector = LittleEndian::read_u64(&sec_buf[8..16]);
            if sector != x as u64 {
                println!("sector field is {} in sector {}", sector, x);
            }

            return Ok(Label{
                id: String::from_utf8_lossy(&sec_buf[..8]).into_owned(),
                sector: sector,
                crc: crc,
                offset: LittleEndian::read_u32(&sec_buf[20..24]) + (x*SECTOR_SIZE as usize) as u32,
                label: String::from_utf8_lossy(&sec_buf[24..32]).into_owned(),
            })
        }
    }

    Err(Error::new(Other, "bad"))
}

#[derive(Debug)]
struct PvAreaIter<'a> {
    area: &'a[u8],
}

fn iter_pv_area<'a>(buf: &'a[u8]) -> PvAreaIter<'a> {
    PvAreaIter { area: buf }
}

impl<'a> Iterator for PvAreaIter<'a> {
    type Item = PvArea;

    fn next (&mut self) -> Option<PvArea> {
        let off = LittleEndian::read_u64(&self.area[..8]);
        let size = LittleEndian::read_u64(&self.area[8..16]);

        if off == 0 {
            None
        }
        else {
            self.area = &self.area[16..];
            Some(PvArea {
                offset: off,
                size: size,
            })
        }
    }
}

//
// PV HEADER LAYOUT:
// - static header (uuid and size)
// - 0+ data areas
// - blank entry
// - 0+ metadata areas
// - blank entry
// - 8 bytes of pvextension header
// - if version > 0
//   - list of bootloader areas
//
fn get_pv_header(buf: &[u8]) -> Result<PvHeader> {

    let mut da_buf = &buf[ID_LEN+8..];

    let da_vec: Vec<_> = iter_pv_area(da_buf).collect();

    // move slice past any actual entries plus blank
    // terminating entry
    da_buf = &da_buf[(da_vec.len()+1)*16..];

    let md_vec: Vec<_> = iter_pv_area(da_buf).collect();

    da_buf = &da_buf[(md_vec.len()+1)*16..];

    let ext_version = LittleEndian::read_u32(&da_buf[..4]);
    let mut ext_flags = 0;
    let mut ba_vec = Vec::new();

    if ext_version != 0 {
        ext_flags = LittleEndian::read_u32(&da_buf[4..8]);

        da_buf = &da_buf[8..];

        ba_vec = iter_pv_area(da_buf).collect();
    }

    Ok(PvHeader{
        uuid: String::from_utf8_lossy(&buf[..ID_LEN]).into_owned(),
        size: LittleEndian::read_u64(&buf[ID_LEN..ID_LEN+8]),
        ext_version: ext_version,
        ext_flags: ext_flags,
        data_areas: da_vec,
        metadata_areas: md_vec,
        bootloader_areas: ba_vec,
    })
}

fn crc32_ok(val: u32, buf: &[u8]) -> bool {
    let mut digest = crc32::Digest::new(INITIAL_CRC);
    digest.write(&buf);
    let crc32 = digest.sum32();

    // TODO: all our crcs are failing, how come?
    if val != crc32 {
        println!("CRC32: input {:x} != calculated {:x}", val, crc32);
    }
    val == crc32
}

#[derive(Debug)]
struct RawLocn {
    offset: u64,
    size: u64,
    checksum: u32,
    flags: u32,
}

#[derive(Debug)]
struct RawLocnIter<'a> {
    area: &'a[u8],
}

fn iter_raw_locn<'a>(buf: &'a[u8]) -> RawLocnIter<'a> {
    RawLocnIter { area: buf }
}

impl<'a> Iterator for RawLocnIter<'a> {
    type Item = RawLocn;

    fn next (&mut self) -> Option<RawLocn> {
        let off = LittleEndian::read_u64(&self.area[..8]);
        let size = LittleEndian::read_u64(&self.area[8..16]);
        let checksum = LittleEndian::read_u32(&self.area[16..20]);
        let flags = LittleEndian::read_u32(&self.area[20..24]);

        if off == 0 {
            None
        }
        else {
            self.area = &self.area[24..];
            Some(RawLocn {
                offset: off,
                size: size,
                checksum: checksum,
                flags: flags,
            })
        }
    }
}

fn parse_mda_header(buf: &[u8]) -> () {

    crc32_ok(LittleEndian::read_u32(&buf[..4]), &buf[4..512]);

    if &buf[4..20] != MDA_MAGIC {
        println!("'{}' doesn't match '{}'", String::from_utf8_lossy(&buf[4..20]),
                 String::from_utf8_lossy(MDA_MAGIC));
    }

    let ver = LittleEndian::read_u32(&buf[20..24]);
    if ver != 1 {
        println!("bad version {}", ver);
    }

    println!("mdah start {}", LittleEndian::read_u64(&buf[24..32]));
    println!("mdah size {}", LittleEndian::read_u64(&buf[32..40]));

    for x in iter_raw_locn(&buf[40..]) {
        println!("rawlocn {:?}", x);
        let start: usize = x.offset as usize;
        let end = start + x.size as usize;
        let s = String::from_utf8_lossy(&buf[start..end]).into_owned();
        let t: String  = s.chars().take_while(|c| *c != ' ' && *c != '{').collect();
        println!("vgname {}", t);
        do_some_stuff(&buf[start..end]);
    }
}

fn find_stuff(path: &str) -> Result<Label> {

    let mut f = try!(File::open(path));

    let mut buf = vec![0; LABEL_SCAN_SECTORS * 512];

    try!(f.read(&mut buf));

    let label = try!(get_label(&buf));

    let pvheader = try!(get_pv_header(&buf[label.offset as usize..]));

    for md in &pvheader.metadata_areas {

        println!("mda {:?}", md);

        try!(f.seek(SeekFrom::Start(md.offset)));

        let mut buf = vec![0; md.size as usize];

        try!(f.read(&mut buf));

        parse_mda_header(&buf);
    }

    return Ok(label);
}

fn main() {

    let label = find_stuff(MYPATH).unwrap();

    println!("{}", label.id);
}

fn do_some_stuff(s: &[u8]) -> () {
    for token in Lexer::new(&s) {
        match token {
            Token::String(x) => { println!("string {}", String::from_utf8_lossy(x)) },
            Token::Comment(x) => { println!("comment {}", String::from_utf8_lossy(x)) },
            Token::Number(x) => { println!("number {}", x) },
            Token::Ident(x) => { println!("ident {}", String::from_utf8_lossy(x)) },
            _ => { println!("{:?}", token); },
        };
    }
}
<commit_msg>main socket<commit_after>extern crate byteorder;
extern crate crc;

use std::fs::File;
use std::io::{Read, Result, Error, Seek, SeekFrom};
use std::io::ErrorKind::Other;

use byteorder::{LittleEndian, ByteOrder};

use crc::{crc32, Hasher32};

const LABEL_SCAN_SECTORS: usize = 4;
const MYPATH: &'static str = "/dev/mapper/luks-291e9250-200e-4c36-8e5e-66aa257669ed";
const ID_LEN: usize = 32;
const MDA_MAGIC: &'static [u8] = b"\x20\x4c\x56\x4d\x32\x20\x78\x5b\x35\x41\x25\x72\x30\x4e\x2a\x3e";
const INITIAL_CRC: u32 = 0xf597a6cf;
const SECTOR_SIZE: usize = 512;

mod lexer;

use lexer::{Lexer, Token};

mod socket;

#[derive(Debug)]
struct Label {
    id: String,
    sector: u64,
    crc: u32,
    offset: u32,
    label: String,
}

#[derive(Debug)]
struct PvArea {
    offset: u64,
    size: u64,
}

#[derive(Debug)]
struct PvHeader {
    uuid: String,
    size: u64, // in bytes
    ext_version: u32,
    ext_flags: u32,
    data_areas: Vec<PvArea>,
    metadata_areas: Vec<PvArea>,
    bootloader_areas: Vec<PvArea>,
}

fn get_label(buf: &[u8]) -> Result<Label> {
    for x in 0..LABEL_SCAN_SECTORS {
        let sec_buf = &buf[x*SECTOR_SIZE..x*SECTOR_SIZE+SECTOR_SIZE];
        if &sec_buf[..8] == b"LABELONE" {
            let crc = LittleEndian::read_u32(&sec_buf[16..20]);
            crc32_ok(crc, &sec_buf[20..SECTOR_SIZE]);

            let sector = LittleEndian::read_u64(&sec_buf[8..16]);
            if sector != x as u64 {
                println!("sector field is {} in sector {}", sector, x);
            }

            return Ok(Label{
                id: String::from_utf8_lossy(&sec_buf[..8]).into_owned(),
                sector: sector,
                crc: crc,
                offset: LittleEndian::read_u32(&sec_buf[20..24]) + (x*SECTOR_SIZE as usize) as u32,
                label: String::from_utf8_lossy(&sec_buf[24..32]).into_owned(),
            })
        }
    }

    Err(Error::new(Other, "bad"))
}

#[derive(Debug)]
struct PvAreaIter<'a> {
    area: &'a[u8],
}

fn iter_pv_area<'a>(buf: &'a[u8]) -> PvAreaIter<'a> {
    PvAreaIter { area: buf }
}

impl<'a> Iterator for PvAreaIter<'a> {
    type Item = PvArea;

    fn next (&mut self) -> Option<PvArea> {
        let off = LittleEndian::read_u64(&self.area[..8]);
        let size = LittleEndian::read_u64(&self.area[8..16]);

        if off == 0 {
            None
        }
        else {
            self.area = &self.area[16..];
            Some(PvArea {
                offset: off,
                size: size,
            })
        }
    }
}

//
// PV HEADER LAYOUT:
// - static header (uuid and size)
// - 0+ data areas
// - blank entry
// - 0+ metadata areas
// - blank entry
// - 8 bytes of pvextension header
// - if version > 0
//   - list of bootloader areas
//
fn get_pv_header(buf: &[u8]) -> Result<PvHeader> {

    let mut da_buf = &buf[ID_LEN+8..];

    let da_vec: Vec<_> = iter_pv_area(da_buf).collect();

    // move slice past any actual entries plus blank
    // terminating entry
    da_buf = &da_buf[(da_vec.len()+1)*16..];

    let md_vec: Vec<_> = iter_pv_area(da_buf).collect();

    da_buf = &da_buf[(md_vec.len()+1)*16..];

    let ext_version = LittleEndian::read_u32(&da_buf[..4]);
    let mut ext_flags = 0;
    let mut ba_vec = Vec::new();

    if ext_version != 0 {
        ext_flags = LittleEndian::read_u32(&da_buf[4..8]);

        da_buf = &da_buf[8..];

        ba_vec = iter_pv_area(da_buf).collect();
    }

    Ok(PvHeader{
        uuid: String::from_utf8_lossy(&buf[..ID_LEN]).into_owned(),
        size: LittleEndian::read_u64(&buf[ID_LEN..ID_LEN+8]),
        ext_version: ext_version,
        ext_flags: ext_flags,
        data_areas: da_vec,
        metadata_areas: md_vec,
        bootloader_areas: ba_vec,
    })
}

fn crc32_ok(val: u32, buf: &[u8]) -> bool {
    let mut digest = crc32::Digest::new(INITIAL_CRC);
    digest.write(&buf);
    let crc32 = digest.sum32();

    // TODO: all our crcs are failing, how come?
    if val != crc32 {
        println!("CRC32: input {:x} != calculated {:x}", val, crc32);
    }
    val == crc32
}

#[derive(Debug)]
struct RawLocn {
    offset: u64,
    size: u64,
    checksum: u32,
    flags: u32,
}

#[derive(Debug)]
struct RawLocnIter<'a> {
    area: &'a[u8],
}

fn iter_raw_locn<'a>(buf: &'a[u8]) -> RawLocnIter<'a> {
    RawLocnIter { area: buf }
}

impl<'a> Iterator for RawLocnIter<'a> {
    type Item = RawLocn;

    fn next (&mut self) -> Option<RawLocn> {
        let off = LittleEndian::read_u64(&self.area[..8]);
        let size = LittleEndian::read_u64(&self.area[8..16]);
        let checksum = LittleEndian::read_u32(&self.area[16..20]);
        let flags = LittleEndian::read_u32(&self.area[20..24]);

        if off == 0 {
            None
        }
        else {
            self.area = &self.area[24..];
            Some(RawLocn {
                offset: off,
                size: size,
                checksum: checksum,
                flags: flags,
            })
        }
    }
}

fn parse_mda_header(buf: &[u8]) -> () {

    crc32_ok(LittleEndian::read_u32(&buf[..4]), &buf[4..512]);

    if &buf[4..20] != MDA_MAGIC {
        println!("'{}' doesn't match '{}'", String::from_utf8_lossy(&buf[4..20]),
                 String::from_utf8_lossy(MDA_MAGIC));
    }

    let ver = LittleEndian::read_u32(&buf[20..24]);
    if ver != 1 {
        println!("bad version {}", ver);
    }

    println!("mdah start {}", LittleEndian::read_u64(&buf[24..32]));
    println!("mdah size {}", LittleEndian::read_u64(&buf[32..40]));

    for x in iter_raw_locn(&buf[40..]) {
        println!("rawlocn {:?}", x);
        let start = x.offset as usize;
        let end = start + x.size as usize;
        do_some_stuff(&buf[start..end]);
    }
}

fn find_stuff(path: &str) -> Result<Label> {

    let mut f = try!(File::open(path));

    let mut buf = vec![0; LABEL_SCAN_SECTORS * 512];

    try!(f.read(&mut buf));

    let label = try!(get_label(&buf));

    let pvheader = try!(get_pv_header(&buf[label.offset as usize..]));

    for md in &pvheader.metadata_areas {

        println!("mda {:?}", md);

        try!(f.seek(SeekFrom::Start(md.offset)));

        let mut buf = vec![0; md.size as usize];

        try!(f.read(&mut buf));

        parse_mda_header(&buf);
    }

    return Ok(label);
}

fn main() {

    let label = find_stuff(MYPATH).unwrap();

    println!("{}", label.id);

    open_lvmetad();
}

fn do_some_stuff(s: &[u8]) -> () {
    for token in Lexer::new(&s) {
        match token {
            Token::String(x) => { println!("string {}", String::from_utf8_lossy(x)) },
            Token::Comment(x) => { println!("comment {}", String::from_utf8_lossy(x)) },
            Token::Number(x) => { println!("number {}", x) },
            Token::Ident(x) => { println!("ident {}", String::from_utf8_lossy(x)) },
            _ => { println!("{:?}", token); },
        };
    }
}

fn open_lvmetad() {

    let path = "/run/lvm/lvmetad.socket";

//    let sa = SocketAddr::new(

}
<|endoftext|>


<commit_before>#![feature(std_misc)]
mod models;

use std::fs::{File, read_dir};
use std::io::{BufReader, BufRead, Read, Write, stdout, copy};
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::collections::hash_map::Entry::*;
use std::ascii::OwnedAsciiExt;
use models::*;

fn count_tokens<T: Read, F: FnMut(String) -> ()>(reader: BufReader<T>, counter: &mut F) {
    for line in reader.lines() {
    	if let Ok(line) = line {
	    	for word in line.split(|c: char| !c.is_alphabetic()) {
	    		if word.len() > 0 {
	    			let word = word.to_string().into_ascii_lowercase();
		    		counter(word);
		    	}
	    	}
	    }
    }
}

fn find_most_common_words(corpus_loc: &str, outfile: &str) {
    let path = Path::new(corpus_loc);
    let mut word_counts = HashMap::new();
    iterate_dir(path, &mut |read| count_tokens(read, &mut |s|
        match (&mut word_counts).entry(s) {
            Vacant(e) => { e.insert(1); },
            Occupied(mut e) => { *e.get_mut() += 1; },
    }));

    let mut counts: Vec<_> = word_counts.into_iter().collect();
    counts.sort_by(|a, b| b.1.cmp(&a.1));

    let mut out = File::create(&Path::new(outfile)).unwrap();
    for &(ref word, count) in &counts[..] {
        out.write_all(format!("{}, {}\n", word, count).as_bytes()).unwrap();
    }

    println!("{:?}", &counts[0..20]);
    println!("{:?}", &counts[counts.len() - 20..counts.len()]);
}

fn load_most_common_words(filename: &str) -> Vec<String> {
    let file = File::open(&Path::new(filename)).unwrap();
    let reader = BufReader::new(file);
    reader.lines().map(|line|
        line.unwrap().split(',').next().unwrap().to_string()
    ).collect()
}

fn iterate_dir<F: FnMut(BufReader<File>) -> ()>(path: &Path, file_processor: &mut F) {
    let files = read_dir(path);
    for file in files.unwrap() {
        let path = file.unwrap().path();
        if path.to_str().unwrap().ends_with(".txt") {
            let file = File::open(&path).unwrap();
            let reader = BufReader::new(file);
            file_processor(reader);
        }
    }
}

fn main() {
    const corpus_dir: &'static str = "/home/jamougha/corpus";
    //find_most_common_words(corpus_dir, "/home/jamougha/corpus/word_counts.csv");
    let words = load_most_common_words("/home/jamougha/corpus/word_counts.csv");
    println!("{:?}", words);
    let mut builder = LanguageModelBuilder::new(words);

    let path = Path::new(corpus_dir);
    // let files = read_dir(path).unwrap()
    //                 .map(|p| p.unwrap().path());
                    //.filter(|p| p.extension().map(|s| s == "txt").unwrap_or(false));
    iterate_dir(&path, &mut |read| {
        let mut acc = builder.new_file();
        count_tokens(read, &mut |w| acc.add_word(w));
    });

    let model = builder.build();

    println!("{:?}", model.nearest_words(model.get("reflect").unwrap()));

    // let file = File::open(&Path::new(filename)).unwrap();
    // let reader = BufReader::new(file);
    // count_tokens(reader, |s| builder)
    // count_tokens

}
<commit_msg>cleanup/refactor<commit_after>#![feature(std_misc)]
mod models;

use std::fs::{File, read_dir};
use std::io::{BufReader, BufRead, Read, Write, stdout, copy};
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::collections::hash_map::Entry::*;
use std::ascii::OwnedAsciiExt;
use models::*;

fn visit_tokens<T: Read, F: FnMut(String) -> ()>(reader: BufReader<T>, mut counter: F) {
    for line in reader.lines() {
    	if let Ok(line) = line {
	    	for word in line.split(|c: char| !c.is_alphabetic()) {
	    		if word.len() > 0 {
	    			let word = word.to_string().into_ascii_lowercase();
		    		counter(word);
		    	}
	    	}
	    }
    }
}

fn find_most_common_words(corpus_loc: &str, outfile: &str) {
    let path = Path::new(corpus_loc);
    let mut word_counts = HashMap::new();
    visit_files(path, &mut |read| visit_tokens(read, &mut |s|
        match (&mut word_counts).entry(s) {
            Vacant(e) => { e.insert(1); },
            Occupied(mut e) => { *e.get_mut() += 1; },
    }));

    let mut counts: Vec<_> = word_counts.into_iter().collect();
    counts.sort_by(|a, b| b.1.cmp(&a.1));

    let mut out = File::create(&Path::new(outfile)).unwrap();
    for &(ref word, count) in &counts[..] {
        out.write_all(format!("{}, {}\n", word, count).as_bytes()).unwrap();
    }

    println!("{:?}", &counts[0..20]);
    println!("{:?}", &counts[counts.len() - 20..counts.len()]);
}

fn load_most_common_words(filename: &str) -> Vec<String> {
    let file = File::open(&Path::new(filename)).unwrap();
    let reader = BufReader::new(file);
    reader.lines().map(|line|
        line.unwrap().split(',').next().unwrap().to_string()
    ).collect()
}

fn visit_files<F: FnMut(BufReader<File>) -> ()>(path: &Path, mut file_processor: F) {
    let files = read_dir(path);
    for file in files.unwrap() {
        let path = file.unwrap().path();
        if path.to_str().unwrap().ends_with(".txt") {
            let file = File::open(&path).unwrap();
            let reader = BufReader::new(file);
            file_processor(reader);
        }
    }
}

fn main() {
    const corpus_dir: &'static str = "/home/jamougha/corpus";
    //find_most_common_words(corpus_dir, "/home/jamougha/corpus/word_counts.csv");
    let words = load_most_common_words("/home/jamougha/corpus/word_counts.csv");
    let mut builder = LanguageModelBuilder::new(words);

    let path = Path::new(corpus_dir);

    visit_files(&path, |read| {
        let mut acc = (&mut builder).new_file();
        visit_tokens(read, |w| (&mut acc).add_word(w));
    });

    let model = builder.build();

    println!("{:?}", model.nearest_words(model.get("ubuntu").unwrap()));

}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::num::Int;

type Collision = Vec<Vec<u8>>;
type Collisions = Vec<Collision>;

fn find_collisions(rows: uint) -> Collisions {
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
      // Fill row of T1.
      for i in range(1, 17) {
          values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
      }

      // Last bytes are equal.
      values[row][32] = values[row][16];
      values[row][48] = values[row][16];

      // Next t value.
      values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
      for row in range(0, rows - col - 1) {
        let row2 = rows - row;
        values[row2][32 - col - 1] = S2[(values[row2][32 - col] ^ values[row2 - 1][32 - col]) as uint];
        values[row2][48 - col - 1] = S2[(values[row2][48 - col] ^ values[row2 - 1][48 - col]) as uint];
      }
    }

    let mut collisions: HashMap<Vec<u8>,Vec<u64>> = HashMap::new();

    // TODO random bytes
    for bytes in range(0u64, 256u64.pow(16 - rows)) {
        // TODO set bytes
        let mut shift = (16 - rows - 1) * 8;
        for col in range(17, 17 + 16 - rows) {
            values[rows][col] = (bytes >> shift) as u8;
            values[rows][col + 16] = (bytes >> shift) as u8;
            shift -= 8;
        }

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
            }

            // Next t value.
            values[row + 1][0] = values[row][48] + (row as u8) - 1;
        }

        let key = Vec::from_fn(17 - rows, |row| values[rows + 2 + row][0]);

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes)); },
            Occupied(mut entry) => { entry.get_mut().push(bytes); }
        };
    }

    // Compute original messages for each collision.
    collisions.values().filter(|x| x.len() > 1).map(|collision| {
        collision.iter().map(|bytes| {
            // TODO set bytes
            let mut shift = (16 - rows - 1) * 8;
            for col in range(17, 17 + 16 - rows) {
                values[rows][col] = (*bytes >> shift) as u8;
                values[rows][col + 16] = (*bytes >> shift) as u8;
                shift -= 8;
            }

            // Fill upper rectangles.
            for row in range(0, rows) {
                let row2 = rows - row;
                for col in range(17, 32 - row2 + 2) {
                    values[row2 - 1][col] = S[values[row2][col - 1] as uint] ^ values[row2][col];
                }
            }

            values[0].slice(17, 33).to_vec()
        }).collect()
    }).collect()
}

fn check_collisions(collisions: &Collisions) -> bool {
    let empty = [0u8, ..16];

    for collision in collisions.iter() {
        let mut first_hash: Option<[u8, ..16]> = None;

        for msg in collision.iter() {
            let md2 = md2_compress(&empty, msg.as_slice());

            match first_hash {
                Some(hash) => {
                    if hash != md2 {
                        return false;
                    }
                }
                None => first_hash = Some(md2)
            };
        }
    }

    true
}

fn main() {
    let collisions = find_collisions(14);
    if !check_collisions(&collisions) {
        panic!("invalid collision found :(");
    }

    println!("Found {} collisions.", collisions.iter().count());
}
<commit_msg>find collisions with arbitrary k values<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::slice::bytes::copy_memory;

type Collision = Vec<Vec<u8>>;
type Collisions = Vec<Collision>;

fn find_collisions(rows: uint) -> Collisions {
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
      // Fill row of T1.
      for i in range(1, 17) {
          values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
      }

      // Last bytes are equal.
      values[row][32] = values[row][16];
      values[row][48] = values[row][16];

      // Next t value.
      values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
      for row in range(0, rows - col - 1) {
        let row2 = rows - row;
        values[row2][32 - col - 1] = S2[(values[row2][32 - col] ^ values[row2 - 1][32 - col]) as uint];
        values[row2][48 - col - 1] = S2[(values[row2][48 - col] ^ values[row2 - 1][48 - col]) as uint];
      }
    }

    let mut bytes = Vec::from_elem(16 - rows, 0u8);
    let mut collisions: HashMap<Vec<u8>,Collision> = HashMap::new();

    loop {
        copy_memory(values[rows].slice_mut(17, 17 + 16 - rows), bytes.as_slice());
        copy_memory(values[rows].slice_mut(17 + 16, 17 + 16 - rows + 16), bytes.as_slice());

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
            }

            // Next t value.
            values[row + 1][0] = values[row][48] + (row as u8) - 1;
        }

        let key = Vec::from_fn(17 - rows, |row| values[rows + 2 + row][0]);

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes.clone())); },
            Occupied(mut entry) => { entry.get_mut().push(bytes.clone()); }
        };

        if !increase(bytes.as_mut_slice()) {
            break;
        }
    }

    // Compute original messages for each collision.
    collisions.values().filter(|x| x.len() > 1).map(|collision| {
        collision.iter().map(|bytes| {
            copy_memory(values[rows].slice_mut(17, 17 + 16 - rows), bytes.as_slice());
            copy_memory(values[rows].slice_mut(17 + 16, 17 + 16 - rows + 16), bytes.as_slice());

            // Fill upper rectangles.
            for row in range(0, rows) {
                let row2 = rows - row;
                for col in range(17, 32 - row2 + 2) {
                    values[row2 - 1][col] = S[values[row2][col - 1] as uint] ^ values[row2][col];
                }
            }

            values[0].slice(17, 33).to_vec()
        }).collect()
    }).collect()
}

fn increase(num: &mut [u8]) -> bool {
    let len = num.len();

    for i in range(0, len) {
        let i = len - 1 - i;

        if num[i] == 255 {
            continue;
        }

        num[i] += 1;

        for i in range(i + 1, len) {
            num[i] = 0;
        }

        return true;
    }

    false
}

fn check_collisions(collisions: &Collisions) -> bool {
    let empty = [0u8, ..16];

    for collision in collisions.iter() {
        let mut first_hash: Option<[u8, ..16]> = None;

        for msg in collision.iter() {
            let md2 = md2_compress(&empty, msg.as_slice());

            match first_hash {
                Some(hash) => {
                    if hash != md2 {
                        return false;
                    }
                }
                None => first_hash = Some(md2)
            };
        }
    }

    true
}

fn main() {
    let collisions = find_collisions(14);
    if !check_collisions(&collisions) {
        panic!("invalid collision found :(");
    }

    println!("Found {} collisions.", collisions.iter().count());
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;

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

    Eof,
}

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

struct Scanner {
    start: usize,
    current: usize,
    line: usize,
    source: String, // TODO: make a reference
}
impl Scanner {
    fn initialize(source: &String) -> Scanner {
        Scanner {
            start: 0,
            current: 0,
            line: 0,
            source: source.clone(),
        }
    }

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

    fn advance(&mut self) -> char {
        let result = self.source.chars().nth(self.current).unwrap();
        self.current += 1;
        result
    }

    fn add_simple_context(&self, token: Token) -> TokenWithContext {
        TokenWithContext {
            token: token,
            lexeme: None,
            line: self.line,
        }
    }

    fn scan_next(&mut self) -> TokenWithContext {
        match self.advance() {
            '(' => self.add_simple_context(Token::LeftParen),
            ')' => self.add_simple_context(Token::RightParen),
            '{' => self.add_simple_context(Token::LeftBrace),
            '}' => self.add_simple_context(Token::RightBrace),
            ',' => self.add_simple_context(Token::Comma),
            '.' => self.add_simple_context(Token::Dot),
            '-' => self.add_simple_context(Token::Minus),
            '+' => self.add_simple_context(Token::Plus),
            ';' => self.add_simple_context(Token::Semicolon),
            '*' => self.add_simple_context(Token::Star),
            _ => unimplemented!(),
        }
    }
}

fn tokenize(source: &String) -> Result<Vec<TokenWithContext>, String> {
    let mut scanner = Scanner::initialize(source);
    let mut tokens = Vec::new();
    while !scanner.is_at_end() {
        tokens.push(scanner.scan_next());
    }
    tokens.push(TokenWithContext {
        token: Token::Eof,
        lexeme: None,
        line: scanner.line,
    });
    Ok(tokens)
}

fn run(source: &String) -> Result<(), String> {
    let tokens = try!(tokenize(source));
    for token in tokens {
        println!("{:?}", token);
    }
    Ok(())
}

fn run_file(file_name: &String) -> Result<(), String> {
    match File::open(file_name) {
        Err(_) => {
            Err("Error opening file".into()) // TODO: add context
        }
        Ok(mut file) => {
            let mut source = String::new();
            match file.read_to_string(&mut source) {
                Err(_) => {
                    Err("Error reading file".into()) // TODO: add context
                }
                Ok(_) => run(&source),
            }
        }
    }
}

fn run_prompt() -> Result<(), String> {
    loop {
        print!("> ");
        io::stdout().flush();
        let mut source = String::new();
        io::stdin().read_line(&mut source);
        try!(run(&source));
        ()
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let result = match args.len() {
        // The first argument is the program name
        1 => run_prompt(),
        2 => run_file(&args[1]),
        _ => {
            println!("Usage: rulox [script]");
            Ok(())
        }
    };
    let exit_code = match result {
        Ok(_) => 0,
        Err(e) => {
            println!("{}", e);
            1
        }
    };
    std::process::exit(exit_code)
}
<commit_msg>Fixed bug in settebello points attribution<commit_after>use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;

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

    Eof,
}

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

struct Scanner {
    start: usize,
    current: usize,
    line: usize,
    source: String, // TODO: make a reference
}
impl Scanner {
    fn initialize(source: &String) -> Scanner {
        Scanner {
            start: 0,
            current: 0,
            line: 0,
            source: source.clone(),
        }
    }

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

    fn advance(&mut self) -> char {
        self.current += 1;
        self.source.chars().nth(self.current - 1).unwrap()
    }

    fn add_simple_context(&self, token: Token) -> TokenWithContext {
        TokenWithContext {
            token: token,
            lexeme: None,
            line: self.line,
        }
    }

    fn scan_next(&mut self) -> TokenWithContext {
        match self.advance() {
            '(' => self.add_simple_context(Token::LeftParen),
            ')' => self.add_simple_context(Token::RightParen),
            '{' => self.add_simple_context(Token::LeftBrace),
            '}' => self.add_simple_context(Token::RightBrace),
            ',' => self.add_simple_context(Token::Comma),
            '.' => self.add_simple_context(Token::Dot),
            '-' => self.add_simple_context(Token::Minus),
            '+' => self.add_simple_context(Token::Plus),
            ';' => self.add_simple_context(Token::Semicolon),
            '*' => self.add_simple_context(Token::Star),
            _ => unimplemented!(),
        }
    }
}

fn tokenize(source: &String) -> Result<Vec<TokenWithContext>, String> {
    let mut scanner = Scanner::initialize(source);
    let mut tokens = Vec::new();
    while !scanner.is_at_end() {
        tokens.push(scanner.scan_next());
    }
    tokens.push(TokenWithContext {
        token: Token::Eof,
        lexeme: None,
        line: scanner.line,
    });
    Ok(tokens)
}

fn run(source: &String) -> Result<(), String> {
    let tokens = try!(tokenize(source));
    for token in tokens {
        println!("{:?}", token);
    }
    Ok(())
}

fn run_file(file_name: &String) -> Result<(), String> {
    match File::open(file_name) {
        Err(_) => {
            Err("Error opening file".into()) // TODO: add context
        }
        Ok(mut file) => {
            let mut source = String::new();
            match file.read_to_string(&mut source) {
                Err(_) => {
                    Err("Error reading file".into()) // TODO: add context
                }
                Ok(_) => run(&source),
            }
        }
    }
}

fn run_prompt() -> Result<(), String> {
    loop {
        print!("> ");
        io::stdout().flush();
        let mut source = String::new();
        io::stdin().read_line(&mut source);
        try!(run(&source));
        ()
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let result = match args.len() {
        // The first argument is the program name
        1 => run_prompt(),
        2 => run_file(&args[1]),
        _ => {
            println!("Usage: rulox [script]");
            Ok(())
        }
    };
    let exit_code = match result {
        Ok(_) => 0,
        Err(e) => {
            println!("{}", e);
            1
        }
    };
    std::process::exit(exit_code)
}
<|endoftext|>