<commit_before>//! Demoscene framework.
//!
//! # Foreword
//!
//! This framework is intented to be used to build up [demos](https://en.wikipedia.org/wiki/Demoscene)
//! as a primary purpose. Everything was designed to quickly write demoscene effects and edit them
//! into an audiovisual executable. However, because a lot was added – especially for debugging
//! purposes, it *should* be possible to use this framework for other purposes as well – among
//! *simulations*, *animations* and *video games*.
//!
//! # Design
//!
//! This framework was designed to be *simple* and *flexible*. Following that path, it’s not
//! impossible that some of its features get moved out of the framework to become a set of
//! dependencies – so that people who don’t want those features can just preclude them from the
//! compilation chain.
//!
//! Up to now, the framework provides you with several modules:
//!
//! - **audio**: this module gives you the ability to play a soundtrack (no streaming implemented
//!   yet though; the whole soundtrack is loaded into memory) and interact with basic yet useful
//!   information about playback (play, pause, toggle, track length, track cursor, etc.)
//! - **bootstrapping**: this module abstracts over the underlying technologies and provides several
//!   simple types that can be used to interact with the demo, such as initialization, default
//!   event handling, and so on
//! - **camera**: provides some camera features for both release and debugging purposes
//! - **color**: color types
//! - **edit**: everything you need to edit your demo – it provides types and functions to reason
//!   about timelines, tracks, cuts and clips, hence easing the overall making of a demo
//! - **gui**: this module provides some GUI code that you can use to build nice debugging
//!   interfaces – up to now, it’s not designed for release code, but it might be at some time
//! - **linear**: linear algebra
//! - **model**: this module provides all the code required to abstract other meshes and add them
//!   the concept of *materials*
//! - **object**: linked to **models**, this module adds the concept of *space properties* to
//!   *models* – so that you can actually have them in your scenes
//! - **overlay**: this module provides 2D primitives and rendering functions
//! - **projection**: projection trait and functions
//! - **shader**: provides
//! - **extra**: some extra (but not mandatory) other modules

#![feature(associated_consts)]
#![feature(conservative_impl_trait)]
#![feature(const_fn)]

extern crate alto;
extern crate any_cache;
extern crate chrono;
extern crate gl;
extern crate glfw;
extern crate image;
pub extern crate luminance;
extern crate nalgebra;
extern crate notify;
extern crate num;
extern crate rusttype;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate vorbis;
extern crate wavefront_obj;

#[macro_use]
pub mod report;

pub mod audio;
pub mod bootstrap;
pub mod camera;
pub mod compositing;
pub mod color;
pub mod edit;
pub mod extra;
pub mod gui;
pub mod linear;
pub mod model;
pub mod object;
pub mod overlay;
pub mod projection;
pub mod resource;
pub mod scale;
pub mod shader;
pub mod spline;
pub mod text;
pub mod texture;
pub mod transform;

pub use audio::Audio;
pub use bootstrap::{Device, WindowDim};
pub use camera::{Camera, Freefly};
pub use color::{Color, ColorAlpha};
pub use linear::{Matrix4};
pub use model::{Model, ModelError, Part};
pub use object::Object;
pub use projection::{Projectable, perspective};
pub use resource::{Load, LoadError, Reload};
pub use shader::{Program, ShaderError, new_program};
pub use spline::{Interpolate, Interpolation, Key, Spline, SplineIterator, Time};
pub use texture::{Texture, TextureImage, load_rgba_texture, save_rgba_texture};
pub use transform::{Axis, Orientation, Position, Translation, Transformable, X_AXIS, Y_AXIS, Z_AXIS,
                    translation_matrix};
<commit_msg>Removed re-exports from root. I hate that actually. It makes things confused.<commit_after>//! Demoscene framework.
//!
//! # Foreword
//!
//! This framework is intented to be used to build up [demos](https://en.wikipedia.org/wiki/Demoscene)
//! as a primary purpose. Everything was designed to quickly write demoscene effects and edit them
//! into an audiovisual executable. However, because a lot was added – especially for debugging
//! purposes, it *should* be possible to use this framework for other purposes as well – among
//! *simulations*, *animations* and *video games*.
//!
//! # Design
//!
//! This framework was designed to be *simple* and *flexible*. Following that path, it’s not
//! impossible that some of its features get moved out of the framework to become a set of
//! dependencies – so that people who don’t want those features can just preclude them from the
//! compilation chain.
//!
//! Up to now, the framework provides you with several modules:
//!
//! - **audio**: this module gives you the ability to play a soundtrack (no streaming implemented
//!   yet though; the whole soundtrack is loaded into memory) and interact with basic yet useful
//!   information about playback (play, pause, toggle, track length, track cursor, etc.)
//! - **bootstrapping**: this module abstracts over the underlying technologies and provides several
//!   simple types that can be used to interact with the demo, such as initialization, default
//!   event handling, and so on
//! - **camera**: provides some camera features for both release and debugging purposes
//! - **color**: color types
//! - **edit**: everything you need to edit your demo – it provides types and functions to reason
//!   about timelines, tracks, cuts and clips, hence easing the overall making of a demo
//! - **gui**: this module provides some GUI code that you can use to build nice debugging
//!   interfaces – up to now, it’s not designed for release code, but it might be at some time
//! - **linear**: linear algebra
//! - **model**: this module provides all the code required to abstract other meshes and add them
//!   the concept of *materials*
//! - **object**: linked to **models**, this module adds the concept of *space properties* to
//!   *models* – so that you can actually have them in your scenes
//! - **overlay**: this module provides 2D primitives and rendering functions
//! - **projection**: projection trait and functions
//! - **shader**: provides
//! - **extra**: some extra (but not mandatory) other modules

#![feature(associated_consts)]
#![feature(conservative_impl_trait)]
#![feature(const_fn)]

extern crate alto;
extern crate any_cache;
extern crate chrono;
extern crate gl;
extern crate glfw;
extern crate image;
pub extern crate luminance;
extern crate nalgebra;
extern crate notify;
extern crate num;
extern crate rusttype;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate vorbis;
extern crate wavefront_obj;

#[macro_use]
pub mod report;

pub mod audio;
pub mod bootstrap;
pub mod camera;
pub mod compositing;
pub mod color;
pub mod edit;
pub mod extra;
pub mod gui;
pub mod linear;
pub mod model;
pub mod object;
pub mod overlay;
pub mod projection;
pub mod resource;
pub mod scale;
pub mod shader;
pub mod spline;
pub mod text;
pub mod texture;
pub mod transform;
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate getopts;
extern crate unix_daemonize;
extern crate byteorder;
extern crate udt;
extern crate time;
extern crate sodiumoxide;
extern crate rustc_serialize;
extern crate colored;

pub mod connection;

use unix_daemonize::{daemonize_redirect, ChdirMode};
use std::process::Command;
use std::net::{SocketAddr, IpAddr};
use std::str;
use std::env;
use std::thread;
use std::str::FromStr;
use std::fs::{OpenOptions, File};
use std::path::{Path, PathBuf};
use std::time::{Instant, Duration};
use std::io::{Cursor, Error, Seek, SeekFrom, stderr, Read, Write};
use std::sync::mpsc;
use log::{LogRecord, LogLevel, LogMetadata};
use colored::*;
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};
use sodiumoxide::crypto::secretbox;
use sodiumoxide::crypto::secretbox::xsalsa20poly1305::Key;
use rustc_serialize::hex::{FromHex, ToHex};

// TODO config
const INITIAL_ACCEPT_TIMEOUT_SECONDS: u64 = 60;

macro_rules! overprint {
    ($fmt: expr) => {
        print!(concat!("\x1b[2K\r", $fmt));
        std::io::stdout().flush().unwrap();
    };
    ($fmt:expr, $($arg:tt)*) => {
        print!(concat!("\x1b[2K\r", $fmt) , $($arg)*);
        std::io::stdout().flush().unwrap();
    };
}

#[macro_export]
macro_rules! die {
    ($fmt: expr) => {
        error!($fmt);
        panic!($fmt)
    };
    ($fmt:expr, $($arg:tt)*) => {
        error!($fmt, $($arg)*);
        panic!($fmt, $($arg)*)
    };
}

pub struct Server<'a> {
    pub ip: String,
    filename: &'a str,
    conn: connection::Server,
}

#[allow(dead_code)]
enum ShoopErrKind {
    Severed,
    Fatal,
}

struct ShoopErr {
    kind: ShoopErrKind,
    msg: Option<String>,
    finished: u64,
}

pub struct ShoopLogger;

impl log::Log for ShoopLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= LogLevel::Info
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let prefix_symbol = match record.level() {
                LogLevel::Error => "E".red().bold(),
                LogLevel::Warn => "W".yellow().bold(),
                LogLevel::Info => "I".normal(),
                LogLevel::Debug => "D".dimmed(),
                LogLevel::Trace => "T".dimmed(),
            };

            println!("[{}] {}", prefix_symbol, record.args());
        }
    }
}

impl ShoopLogger {
    pub fn init() -> Result<(), log::SetLoggerError> {
        log::set_logger(|max_log_level| {
            max_log_level.set(log::LogLevelFilter::Info);
            Box::new(ShoopLogger)
        })
    }
}

impl ShoopErr {
    pub fn new(kind: ShoopErrKind, msg: &str, finished: u64) -> ShoopErr {
        ShoopErr {
            kind: kind,
            msg: Some(String::from(msg)),
            finished: finished,
        }
    }

    #[allow(dead_code)]
    pub fn from(err: Error, finished: u64) -> ShoopErr {
        ShoopErr {
            kind: ShoopErrKind::Severed,
            msg: Some(format!("{:?}", err)),
            finished: finished,
        }
    }
}

impl<'a> Server<'a> {
    pub fn new(port_range: connection::PortRange, filename: &str) -> Server {
        let sshconnstr = match env::var("SSH_CONNECTION") {
            Ok(s) => s.trim().to_owned(),
            Err(_) => {
                die!("SSH_CONNECTION env variable unset and required. Quitting.");
            }
        };
        let sshconn: Vec<&str> = sshconnstr.split(' ').collect();
        let ip = sshconn[2].to_owned();
        let key = secretbox::gen_key();
        let Key(keybytes) = key;
        let port = connection::Server::get_open_port(&port_range).unwrap();
        println!("shoop 0 {} {} {}", ip, port, keybytes.to_hex());

        let stdout = Some(Path::new(&env::var("HOME").unwrap()).join(".shoop.log"));
        let stderr = Some(Path::new(&env::var("HOME").unwrap()).join(".shoop.log"));
        daemonize_redirect(stdout, stderr, ChdirMode::ChdirRoot).unwrap();

        let conn = connection::Server::new(IpAddr::from_str(&ip).unwrap(), port, key);
        Server {
            ip: ip,
            conn: conn,
            filename: filename,
        }
    }

    pub fn start(&self) {
        self.conn.listen().unwrap();

        let mut connection_count: usize = 0;
        info!("listening...");
        loop {
            info!("waiting for connection...");
            let (tx, rx) = mpsc::channel();
            if connection_count == 0 {
                thread::spawn(move || {
                    thread::sleep(Duration::from_secs(INITIAL_ACCEPT_TIMEOUT_SECONDS));
                    if let Err(_) = rx.try_recv() {
                        error!("timed out waiting for initial connection. exiting.");
                        std::process::exit(1);
                    }
                });
            }
            let client = match self.conn.accept() {
                Ok(client) => client,
                Err(e) => {
                    die!("error on sock accept() {:?}", e);
                }
            };
            connection_count += 1;
            tx.send(()).unwrap();
            info!("accepted connection!");
            if let Ok(starthdr) = client.recv() {
                let mut rdr = Cursor::new(starthdr);
                let offset = rdr.read_u64::<LittleEndian>().unwrap();
                match self.send_file(&client, offset) {
                    Ok(_) => {
                        info!("done sending file");
                        let _ = client.close();
                        break;
                    }
                    Err(ShoopErr { kind: ShoopErrKind::Severed, msg, finished }) => {
                        info!("connection severed, msg: {:?}, finished: {}", msg, finished);
                        let _ = client.close();
                        continue;
                    }
                    Err(ShoopErr { kind: ShoopErrKind::Fatal, msg, finished }) => {
                        die!("connection fatal, msg: {:?}, finished: {}", msg, finished);
                    }
                }
            } else {
                die!("failed to receive version byte from client");
            }
        }
        info!("exiting listen loop.");
    }

    fn send_file(&self,
                 client: &connection::ServerConnection,
                 offset: u64)
                 -> Result<(), ShoopErr> {
        let mut f = File::open(self.filename).unwrap();
        f.seek(SeekFrom::Start(offset)).unwrap();
        let metadata = f.metadata().unwrap();

        let remaining = metadata.len() - offset;
        info!("total {} bytes", remaining);

        let mut wtr = vec![];
        wtr.write_u64::<LittleEndian>(remaining).unwrap();
        match client.send(&wtr[..]) {
            Ok(()) => info!("wrote filesize header."),
            Err(e) => {
                return Err(ShoopErr::new(ShoopErrKind::Severed, &format!("{:?}", e), remaining))
            }
        }
        let mut payload = vec![0; 1300];
        f.seek(SeekFrom::Start(offset)).unwrap();
        info!("sending file...");
        loop {
            match f.read(&mut payload) {
                Ok(0) => {
                    break;
                }
                Ok(read) => {
                    if let Err(e) = client.send(&payload[0..read]) {
                        return Err(ShoopErr::new(ShoopErrKind::Severed,
                                                 &format!("{:?}", e),
                                                 remaining));
                    }
                }
                Err(e) => {
                    client.close().expect("Error closing stream");
                    die!("failed to read from file: {:?}", e);
                }
            }
        }

        client.close().expect("Error closing stream.");
        Ok(())
    }
}

pub fn download(remote_ssh_host: &str,
                port_range: connection::PortRange,
                remote_path: &str,
                local_path: PathBuf) {
    let cmd = format!("shoop -s '{}' -p {}", remote_path, port_range);
    // println!("addr: {}, path: {}, cmd: {}", addr, path, cmd);

    overprint!(" - establishing SSH session...");
    assert!(command_exists("ssh"), "`ssh` is required!");
    let output = Command::new("ssh")
        .arg(remote_ssh_host.to_owned())
        .arg(cmd)
        .output()
        .unwrap_or_else(|e| {
            die!("failed to execute process: {}", e);
        });
    let infostring = String::from_utf8_lossy(&output.stdout).to_owned().trim().to_owned();
    let info: Vec<&str> = infostring.split(' ').collect();
    if info.len() != 5 {
        die!("Unexpected response from server. Are you suuuuure shoop is setup on the server?");
    }

    let (magic, version, ip, port, keyhex) = (info[0], info[1], info[2], info[3], info[4]);
    overprint!(" - opening UDT connection...");
    if magic != "shoop" || version != "0" {
        die!("Unexpected response from server. Are you suuuuure shoop is setup on the server?");
    }

    let mut keybytes = [0u8; 32];
    keybytes.copy_from_slice(&keyhex.from_hex().unwrap()[..]);
    let key = Key(keybytes);
    let addr: SocketAddr = SocketAddr::from_str(&format!("{}:{}", ip, port)[..])
        .unwrap();
    let conn = connection::Client::new(addr, key);

    let mut offset = 0u64;
    let mut filesize = None;
    let start_ts = Instant::now();
    loop {
        match conn.connect() {
            Ok(()) => {
                overprint!(" - connection opened, shakin' hands, makin' frands");
            }
            Err(e) => {
                die!("errrrrrrr connecting to {}:{} - {:?}", ip, port, e);
            }
        }
        let mut wtr = vec![];
        wtr.write_u64::<LittleEndian>(offset).unwrap();
        if let Err(_) = conn.send(&wtr[..]) {
            conn.close().unwrap();
            continue;
        }

        if let Ok(msg) = conn.recv() {
            if msg.is_empty() {
                die!("failed to get filesize from server, probable timeout.");
            }
            let mut rdr = Cursor::new(msg);
            filesize = filesize.or_else(|| Some(rdr.read_u64::<LittleEndian>().unwrap()));
            overprint!("downloading {} ({:.1}MB)\n",
                       local_path.to_string_lossy(),
                       (filesize.unwrap() as f64) / (1024f64 * 1024f64));
            match recv_file(&conn, filesize.unwrap(), &local_path, offset) {
                Ok(_) => {
                    break;
                }
                Err(ShoopErr { kind: ShoopErrKind::Severed, finished, .. }) => {
                    println!("{}", " * [[SEVERED]]".yellow().bold());
                    offset = finished;
                }
                Err(ShoopErr { kind: ShoopErrKind::Fatal, msg, .. }) => {
                    die!("{:?}", msg);
                }
            }
        }
        let _ = conn.close();
    }

    let elapsed = start_ts.elapsed().as_secs();
    let fmt_time = if elapsed < 60 {
        format!("{}s", elapsed)
    } else if elapsed < 60 * 60 {
        format!("{}m{}s", elapsed / 60, elapsed % 60)
    } else {
        format!("{}h{}m{}s", elapsed / (60 * 60), elapsed / 60, elapsed % 60)
    };
    println!("shooped it all up in {}", fmt_time.green().bold());
}

fn command_exists(command: &str) -> bool {
    match Command::new("which").arg(command).output() {
        Ok(output) => output.status.success(),
        Err(_) => false,
    }
}

fn recv_file(conn: &connection::Client,
             filesize: u64,
             filename: &PathBuf,
             offset: u64)
             -> Result<(), ShoopErr> {
    let mut f = OpenOptions::new().write(true).create(true).truncate(false).open(filename).unwrap();
    f.seek(SeekFrom::Start(offset)).unwrap();
    let start = Instant::now();
    let mut ts = Instant::now();
    let mut total = offset;
    let mut speed_ts = Instant::now();
    let mut speed_total = total;
    let mut speed = 0u64;
    loop {
        let buf = try!(conn.recv()
            .map_err(|e| ShoopErr::new(ShoopErrKind::Severed, &format!("{:?}", e), total)));
        if buf.len() < 1 {
            return Err(ShoopErr::new(ShoopErrKind::Severed, "empty msg", total));
        }

        f.write_all(&buf[..]).unwrap();
        total += buf.len() as u64;
        let speed_elapsed = speed_ts.elapsed();
        if speed_elapsed > Duration::new(1, 0) {
            speed = ((total - speed_total) as f64 /
                     ((speed_elapsed.as_secs() as f64) +
                      (speed_elapsed.subsec_nanos() as f64) /
                      1_000_000_000f64)) as u64;
            speed_ts = Instant::now();
            speed_total = total;
        }
        let speedfmt = if speed < 1024 {
            format!("{} b/s", speed)
        } else if speed < 1024 * 1024 {
            format!("{} kb/s", speed / 1024)
        } else {
            format!("{:.1} MB/s", ((speed / 1024) as f64) / 1024f64)
        };

        if ts.elapsed() > Duration::new(0, 100_000_000) {
            overprint!("   {:.1}M / {:.1}M ({:.1}%) [ {} ]",
                       (total as f64) / (1024f64 * 1024f64),
                       (filesize as f64) / (1024f64 * 1024f64),
                       (total as f64) / (filesize as f64) * 100f64,
                       speedfmt);
            ts = Instant::now();
        }
        if total >= filesize {
            overprint!("   {0:.1}M / {0:.1}M (100%) [ avg {1:.1} MB/s ]\n",
                       (filesize as f64) / (1024f64 * 1024f64),
                       ((total - offset) / start.elapsed().as_secs() / 1024) as f64 / 1024f64);
            break;
        }
    }
    let _ = conn.close();
    Ok(())
}
<commit_msg>scope send_file and recv_file evenly<commit_after>#[macro_use]
extern crate log;
extern crate getopts;
extern crate unix_daemonize;
extern crate byteorder;
extern crate udt;
extern crate time;
extern crate sodiumoxide;
extern crate rustc_serialize;
extern crate colored;

pub mod connection;

use unix_daemonize::{daemonize_redirect, ChdirMode};
use std::process::Command;
use std::net::{SocketAddr, IpAddr};
use std::str;
use std::env;
use std::thread;
use std::str::FromStr;
use std::fs::{OpenOptions, File};
use std::path::{Path, PathBuf};
use std::time::{Instant, Duration};
use std::io::{Cursor, Error, Seek, SeekFrom, stderr, Read, Write};
use std::sync::mpsc;
use log::{LogRecord, LogLevel, LogMetadata};
use colored::*;
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};
use sodiumoxide::crypto::secretbox;
use sodiumoxide::crypto::secretbox::xsalsa20poly1305::Key;
use rustc_serialize::hex::{FromHex, ToHex};

// TODO config
const INITIAL_ACCEPT_TIMEOUT_SECONDS: u64 = 60;

macro_rules! overprint {
    ($fmt: expr) => {
        print!(concat!("\x1b[2K\r", $fmt));
        std::io::stdout().flush().unwrap();
    };
    ($fmt:expr, $($arg:tt)*) => {
        print!(concat!("\x1b[2K\r", $fmt) , $($arg)*);
        std::io::stdout().flush().unwrap();
    };
}

#[macro_export]
macro_rules! die {
    ($fmt: expr) => {
        error!($fmt);
        panic!($fmt)
    };
    ($fmt:expr, $($arg:tt)*) => {
        error!($fmt, $($arg)*);
        panic!($fmt, $($arg)*)
    };
}

pub struct Server<'a> {
    pub ip: String,
    filename: &'a str,
    conn: connection::Server,
}

#[allow(dead_code)]
enum ShoopErrKind {
    Severed,
    Fatal,
}

struct ShoopErr {
    kind: ShoopErrKind,
    msg: Option<String>,
    finished: u64,
}

pub struct ShoopLogger;

impl log::Log for ShoopLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= LogLevel::Info
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let prefix_symbol = match record.level() {
                LogLevel::Error => "E".red().bold(),
                LogLevel::Warn => "W".yellow().bold(),
                LogLevel::Info => "I".normal(),
                LogLevel::Debug => "D".dimmed(),
                LogLevel::Trace => "T".dimmed(),
            };

            println!("[{}] {}", prefix_symbol, record.args());
        }
    }
}

impl ShoopLogger {
    pub fn init() -> Result<(), log::SetLoggerError> {
        log::set_logger(|max_log_level| {
            max_log_level.set(log::LogLevelFilter::Info);
            Box::new(ShoopLogger)
        })
    }
}

impl ShoopErr {
    pub fn new(kind: ShoopErrKind, msg: &str, finished: u64) -> ShoopErr {
        ShoopErr {
            kind: kind,
            msg: Some(String::from(msg)),
            finished: finished,
        }
    }

    #[allow(dead_code)]
    pub fn from(err: Error, finished: u64) -> ShoopErr {
        ShoopErr {
            kind: ShoopErrKind::Severed,
            msg: Some(format!("{:?}", err)),
            finished: finished,
        }
    }
}

impl<'a> Server<'a> {
    pub fn new(port_range: connection::PortRange, filename: &str) -> Server {
        let sshconnstr = match env::var("SSH_CONNECTION") {
            Ok(s) => s.trim().to_owned(),
            Err(_) => {
                die!("SSH_CONNECTION env variable unset and required. Quitting.");
            }
        };
        let sshconn: Vec<&str> = sshconnstr.split(' ').collect();
        let ip = sshconn[2].to_owned();
        let key = secretbox::gen_key();
        let Key(keybytes) = key;
        let port = connection::Server::get_open_port(&port_range).unwrap();
        println!("shoop 0 {} {} {}", ip, port, keybytes.to_hex());

        let stdout = Some(Path::new(&env::var("HOME").unwrap()).join(".shoop.log"));
        let stderr = Some(Path::new(&env::var("HOME").unwrap()).join(".shoop.log"));
        daemonize_redirect(stdout, stderr, ChdirMode::ChdirRoot).unwrap();

        let conn = connection::Server::new(IpAddr::from_str(&ip).unwrap(), port, key);
        Server {
            ip: ip,
            conn: conn,
            filename: filename,
        }
    }

    pub fn start(&self) {
        self.conn.listen().unwrap();

        let mut connection_count: usize = 0;
        info!("listening...");
        loop {
            info!("waiting for connection...");
            let (tx, rx) = mpsc::channel();
            if connection_count == 0 {
                thread::spawn(move || {
                    thread::sleep(Duration::from_secs(INITIAL_ACCEPT_TIMEOUT_SECONDS));
                    if let Err(_) = rx.try_recv() {
                        error!("timed out waiting for initial connection. exiting.");
                        std::process::exit(1);
                    }
                });
            }
            let client = match self.conn.accept() {
                Ok(client) => client,
                Err(e) => {
                    die!("error on sock accept() {:?}", e);
                }
            };
            connection_count += 1;
            tx.send(()).unwrap();
            info!("accepted connection!");
            match self.send_file(&client) {
                Ok(_) => {
                    info!("done sending file");
                    let _ = client.close();
                    break;
                }
                Err(ShoopErr { kind: ShoopErrKind::Severed, msg, finished }) => {
                    info!("connection severed, msg: {:?}, finished: {}", msg, finished);
                    let _ = client.close();
                    continue;
                }
                Err(ShoopErr { kind: ShoopErrKind::Fatal, msg, finished }) => {
                    die!("connection fatal, msg: {:?}, finished: {}", msg, finished);
                }
            }
        }
        info!("exiting listen loop.");
    }

    fn send_file(&self, client: &connection::ServerConnection) -> Result<(), ShoopErr> {
        let starthdr = match client.recv() {
            Ok(hdr) => hdr,
            Err(e) => return Err(ShoopErr::new(ShoopErrKind::Severed, &format!("{:?}", e), 0)),
        };
        let mut rdr = Cursor::new(starthdr);
        let offset = rdr.read_u64::<LittleEndian>().unwrap();
        let mut f = File::open(self.filename).unwrap();
        f.seek(SeekFrom::Start(offset)).unwrap();
        let metadata = f.metadata().unwrap();

        let remaining = metadata.len() - offset;
        info!("total {} bytes", remaining);

        let mut wtr = vec![];
        wtr.write_u64::<LittleEndian>(remaining).unwrap();
        match client.send(&wtr[..]) {
            Ok(()) => info!("wrote filesize header."),
            Err(e) => {
                return Err(ShoopErr::new(ShoopErrKind::Severed, &format!("{:?}", e), remaining))
            }
        }
        let mut payload = vec![0; 1300];
        f.seek(SeekFrom::Start(offset)).unwrap();
        info!("sending file...");
        loop {
            match f.read(&mut payload) {
                Ok(0) => {
                    break;
                }
                Ok(read) => {
                    if let Err(e) = client.send(&payload[0..read]) {
                        return Err(ShoopErr::new(ShoopErrKind::Severed,
                                                 &format!("{:?}", e),
                                                 remaining));
                    }
                }
                Err(e) => {
                    client.close().expect("Error closing stream");
                    die!("failed to read from file: {:?}", e);
                }
            }
        }

        client.close().expect("Error closing stream.");
        Ok(())
    }
}

pub fn download(remote_ssh_host: &str,
                port_range: connection::PortRange,
                remote_path: &str,
                local_path: PathBuf) {
    let cmd = format!("shoop -s '{}' -p {}", remote_path, port_range);
    // println!("addr: {}, path: {}, cmd: {}", addr, path, cmd);

    overprint!(" - establishing SSH session...");
    assert!(command_exists("ssh"), "`ssh` is required!");
    let output = Command::new("ssh")
        .arg(remote_ssh_host.to_owned())
        .arg(cmd)
        .output()
        .unwrap_or_else(|e| {
            die!("failed to execute process: {}", e);
        });
    let infostring = String::from_utf8_lossy(&output.stdout).to_owned().trim().to_owned();
    let info: Vec<&str> = infostring.split(' ').collect();
    if info.len() != 5 {
        die!("Unexpected response from server. Are you suuuuure shoop is setup on the server?");
    }

    let (magic, version, ip, port, keyhex) = (info[0], info[1], info[2], info[3], info[4]);
    overprint!(" - opening UDT connection...");
    if magic != "shoop" || version != "0" {
        die!("Unexpected response from server. Are you suuuuure shoop is setup on the server?");
    }

    let mut keybytes = [0u8; 32];
    keybytes.copy_from_slice(&keyhex.from_hex().unwrap()[..]);
    let key = Key(keybytes);
    let addr: SocketAddr = SocketAddr::from_str(&format!("{}:{}", ip, port)[..]).unwrap();
    let conn = connection::Client::new(addr, key);

    let mut offset = 0u64;
    let mut filesize = None;
    let start_ts = Instant::now();
    loop {
        match conn.connect() {
            Ok(()) => {
                overprint!(" - connection opened, shakin' hands, makin' frands");
            }
            Err(e) => {
                die!("errrrrrrr connecting to {}:{} - {:?}", ip, port, e);
            }
        }
        let mut wtr = vec![];
        wtr.write_u64::<LittleEndian>(offset).unwrap();
        if let Err(_) = conn.send(&wtr[..]) {
            conn.close().unwrap();
            continue;
        }

        if let Ok(msg) = conn.recv() {
            if msg.is_empty() {
                die!("failed to get filesize from server, probable timeout.");
            }
            let mut rdr = Cursor::new(msg);
            filesize = filesize.or_else(|| Some(rdr.read_u64::<LittleEndian>().unwrap()));
            overprint!("downloading {} ({:.1}MB)\n",
                       local_path.to_string_lossy(),
                       (filesize.unwrap() as f64) / (1024f64 * 1024f64));
            match recv_file(&conn, filesize.unwrap(), &local_path, offset) {
                Ok(_) => {
                    break;
                }
                Err(ShoopErr { kind: ShoopErrKind::Severed, finished, .. }) => {
                    println!("{}", " * [[SEVERED]]".yellow().bold());
                    offset = finished;
                }
                Err(ShoopErr { kind: ShoopErrKind::Fatal, msg, .. }) => {
                    die!("{:?}", msg);
                }
            }
        }
        let _ = conn.close();
    }

    let elapsed = start_ts.elapsed().as_secs();
    let fmt_time = if elapsed < 60 {
        format!("{}s", elapsed)
    } else if elapsed < 60 * 60 {
        format!("{}m{}s", elapsed / 60, elapsed % 60)
    } else {
        format!("{}h{}m{}s", elapsed / (60 * 60), elapsed / 60, elapsed % 60)
    };
    println!("shooped it all up in {}", fmt_time.green().bold());
}

fn command_exists(command: &str) -> bool {
    match Command::new("which").arg(command).output() {
        Ok(output) => output.status.success(),
        Err(_) => false,
    }
}

fn recv_file(conn: &connection::Client,
             filesize: u64,
             filename: &PathBuf,
             offset: u64)
             -> Result<(), ShoopErr> {
    let mut f = OpenOptions::new().write(true).create(true).truncate(false).open(filename).unwrap();
    f.seek(SeekFrom::Start(offset)).unwrap();
    let start = Instant::now();
    let mut ts = Instant::now();
    let mut total = offset;
    let mut speed_ts = Instant::now();
    let mut speed_total = total;
    let mut speed = 0u64;
    loop {
        let buf = try!(conn.recv()
            .map_err(|e| ShoopErr::new(ShoopErrKind::Severed, &format!("{:?}", e), total)));
        if buf.len() < 1 {
            return Err(ShoopErr::new(ShoopErrKind::Severed, "empty msg", total));
        }

        f.write_all(&buf[..]).unwrap();
        total += buf.len() as u64;
        let speed_elapsed = speed_ts.elapsed();
        if speed_elapsed > Duration::new(1, 0) {
            speed = ((total - speed_total) as f64 /
                     ((speed_elapsed.as_secs() as f64) +
                      (speed_elapsed.subsec_nanos() as f64) /
                      1_000_000_000f64)) as u64;
            speed_ts = Instant::now();
            speed_total = total;
        }
        let speedfmt = if speed < 1024 {
            format!("{} b/s", speed)
        } else if speed < 1024 * 1024 {
            format!("{} kb/s", speed / 1024)
        } else {
            format!("{:.1} MB/s", ((speed / 1024) as f64) / 1024f64)
        };

        if ts.elapsed() > Duration::new(0, 100_000_000) {
            overprint!("   {:.1}M / {:.1}M ({:.1}%) [ {} ]",
                       (total as f64) / (1024f64 * 1024f64),
                       (filesize as f64) / (1024f64 * 1024f64),
                       (total as f64) / (filesize as f64) * 100f64,
                       speedfmt);
            ts = Instant::now();
        }
        if total >= filesize {
            overprint!("   {0:.1}M / {0:.1}M (100%) [ avg {1:.1} MB/s ]\n",
                       (filesize as f64) / (1024f64 * 1024f64),
                       ((total - offset) / start.elapsed().as_secs() / 1024) as f64 / 1024f64);
            break;
        }
    }
    let _ = conn.close();
    Ok(())
}
<|endoftext|>


<commit_before>extern crate html5ever;
extern crate string_cache;

use std::path::Path;
use std::fs::{File, read_dir};
use std::io::{self, Read, Write};
use std::default::Default;
use std::borrow::{Cow, ToOwned};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt;
use std::mem::swap;

use html5ever::Attribute;
use html5ever::tokenizer::{Tokenizer, TokenSink, Tag, TagKind, Doctype};
use html5ever::tokenizer::Token as HtmlToken;

use string_cache::atom::Atom;

use codegen::{Token, Content, Codegen, ContentType, Scope};
use fragments::{Fragment, ReturnType};

use parser::ExtensibleMap;

#[macro_use]
pub mod codegen;
pub mod fragments;
pub mod javascript;
pub mod rust;
mod parser;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Format(fmt::Error),
    Parse(Vec<Cow<'static, str>>)
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::Io(e)
    }
}

impl From<fmt::Error> for Error {
    fn from(e: fmt::Error) -> Error {
        Error::Format(e)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Io(ref e) => e.fmt(f),
            &Error::Format(ref e) => e.fmt(f),
            &Error::Parse(ref e) => {
                try!(write!(f, "parse errors: "));
                for (i, error) in e.iter().enumerate() {
                    if i == 0 {
                        try!(error.fmt(f));
                    } else {
                        try!(write!(f, ", {}", error));
                    }
                }
                Ok(())
            }
        }
    }
}

///A collection of templates.
pub struct TemplateGroup<'a> {
    templates: Vec<ParsedTemplate>,
    fragments: HashMap<&'static str, Box<Fragment + 'a>>
}

impl<'a> TemplateGroup<'a> {
    pub fn new() -> TemplateGroup<'a> {
        TemplateGroup {
            templates: vec![],
            fragments: init_fragments()
        }
    }

    ///Add a template from a string.
    pub fn parse_string(&mut self, name: String, source: String) -> Result<(), Error> {
        let mut template = Template::extending(&self.fragments);
        try!(template.parse_string(source));
        self.templates.push(ParsedTemplate {
            name: name,
            parameters: template.parameters,
            tokens: template.tokens
        });

        Ok(())
    }

    ///Add every `*.html` and `*.htm` file in a directory to the template group.
    pub fn parse_directory<P: AsRef<Path>>(&mut self, dir: P) -> Result<(), Error> {
        let directory = try!(read_dir(dir));

        for path in directory {
            let path = try!(path).path();
            let info = (
                path.file_stem().and_then(|n| n.to_str()),
                path.extension().and_then(|e| e.to_str())
            );
            if let (Some(name), Some(ext)) = info {
                if ext == "html" || ext == "htm" {
                    let mut source = String::new();
                    try!(File::open(&path).and_then(|mut f| f.read_to_string(&mut source)));
                    try!(self.parse_string(name.to_string(), source));
                }
            }
        }

        Ok(())
    }

    ///Add an already parsed template to the group.
    pub fn add_template(&mut self, name: String, template: Template) {
        self.templates.push(ParsedTemplate {
            name: name,
            parameters: template.parameters,
            tokens: template.tokens
        });
    }

    ///Register a custom fragment.
    pub fn register_fragment<F: Fragment + 'a>(&mut self, fragment: F) {
        let fragment = Box::new(fragment);
        self.fragments.insert(fragment.identifier(), fragment);
    }

    ///Write template code.
    pub fn emit_code<W: Write, C: Codegen>(&self, writer: &mut W, codegen: &C) -> Result<(), Error> {
        codegen.build_module(writer, |w, indent| {
            for template in &self.templates {
                try!(codegen.build_template(w, &template.name, indent, &template.parameters, &template.tokens));
            }
            Ok(())
        })
    }
}

struct ParsedTemplate {
    name: String,
    parameters: HashMap<String, ContentType>,
    tokens: Vec<codegen::Token>
}

///A single template.
pub struct Template<'a> {
    fragments: ExtensibleMap<'a, &'static str, Box<Fragment + 'a>>,
    parameters: HashMap<String, ContentType>,
    tokens: Vec<codegen::Token>,
    errors: Vec<Cow<'static, str>>
}

impl<'a> Template<'a> {
    ///Create an empty template.
    pub fn new() -> Template<'a> {
        Template {
            fragments: ExtensibleMap::Owned(init_fragments()),
            parameters: HashMap::new(),
            tokens: vec![],
            errors: vec![]
        }
    }

    fn extending(fragments: &'a HashMap<&'static str, Box<Fragment + 'a>>) -> Template<'a> {
        Template {
            fragments: ExtensibleMap::extend(fragments),
            parameters: HashMap::new(),
            tokens: vec![],
            errors: vec![]
        }
    }

    ///Add content from a string to the template.
    pub fn parse_string(&mut self, source: String) -> Result<(), Error> {
        {
            let mut tokenizer = Tokenizer::new(&mut*self, Default::default());
            tokenizer.feed(source);
        }

        if self.errors.len() > 0 {
            let mut e = vec![];
            swap(&mut e, &mut self.errors);
            Err(Error::Parse(e))
        } else {
            Ok(())
        }
    }

    ///Register a custom fragment.
    pub fn register_fragment<F: Fragment + 'a>(&mut self, fragment: F) {
        let fragment = Box::new(fragment);
        self.fragments.insert(fragment.identifier(), fragment);
    }

    ///Write template code.
    pub fn emit_code<W: Write, C: Codegen>(&self, template_name: &str, writer: &mut W, codegen: &C) -> Result<(), Error> {
        codegen.build_template(writer, template_name, 0, &self.parameters, &self.tokens)
    }

    fn set_doctype(&mut self, doctype: Doctype) {
        self.tokens.push(Token::SetDoctype(doctype));
    }

    fn open_tag(&mut self, name: Atom, attributes: Vec<Attribute>, self_closing: bool) -> Result<(), Cow<'static, str>> {
        let void = is_void(name.as_slice());
        self.tokens.push(Token::BeginTag(name));

        for attribute in attributes {
            let mut content = try!(parser::parse_content(&attribute.value, &self.fragments)).into_iter();
            match content.next() {
                Some(ReturnType::String(text)) => self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::String(text))),
                Some(ReturnType::Placeholder(name, ty)) => {
                    try!(self.reg_placeholder(name.clone(), ty));
                    self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::Placeholder(name)));
                },
                Some(ReturnType::Logic(_)) => return Err(Cow::Borrowed("logic can not be used as text")),
                Some(ReturnType::Scope(scope)) => {
                    try!(self.reg_scope_vars(&scope));
                    self.tokens.push(Token::Scope(scope));
                },
                Some(ReturnType::End) => self.tokens.push(Token::End),
                None => self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::String(String::new())))
            }

            for part in content {
                match part {
                    ReturnType::String(text) => self.tokens.push(Token::AppendToAttribute(Content::String(text))),
                    ReturnType::Placeholder(name, ty) => {
                        try!(self.reg_placeholder(name.clone(), ty));
                        self.tokens.push(Token::AppendToAttribute(Content::Placeholder(name)));
                    },
                    ReturnType::Logic(_) => return Err(Cow::Borrowed("logic can not be used as text")),
                    ReturnType::Scope(scope) => {
                        try!(self.reg_scope_vars(&scope));
                        self.tokens.push(Token::Scope(scope));
                    },
                    ReturnType::End => self.tokens.push(Token::End),
                }
            }

            self.tokens.push(Token::EndAttribute);
        }

        self.tokens.push(Token::EndTag(void || self_closing));

        Ok(())
    }

    fn add_text(&mut self, text: String) -> Result<(), Cow<'static, str>> {
        let mut content = try!(parser::parse_content(&text, &self.fragments)).into_iter();
        match content.next() {
            Some(ReturnType::String(text)) => self.tokens.push(Token::BeginText(Content::String(text))),
            Some(ReturnType::Placeholder(name, ty)) => {
                try!(self.reg_placeholder(name.clone(), ty));
                self.tokens.push(Token::BeginText(Content::Placeholder(name)));
            },
            Some(ReturnType::Logic(_)) => return Err(Cow::Borrowed("logic can not be used as text")),
            Some(ReturnType::Scope(scope)) => {
                try!(self.reg_scope_vars(&scope));
                self.tokens.push(Token::Scope(scope));
            },
            Some(ReturnType::End) => self.tokens.push(Token::End),
            None => return Ok(())
        }

        for part in content {
            match part {
                ReturnType::String(text) => self.tokens.push(Token::AppendToText(Content::String(text))),
                ReturnType::Placeholder(name, ty) => {
                    try!(self.reg_placeholder(name.clone(), ty));
                    self.tokens.push(Token::AppendToText(Content::Placeholder(name)));
                },
                ReturnType::Logic(_) => return Err(Cow::Borrowed("logic can not be used as text")),
                ReturnType::Scope(scope) => {
                    try!(self.reg_scope_vars(&scope));
                    self.tokens.push(Token::Scope(scope));
                },
                ReturnType::End => self.tokens.push(Token::End),
            }
        }
        self.tokens.push(Token::EndText);

        Ok(())
    }

    fn close_tag(&mut self, tag: Atom) {
        self.tokens.push(Token::CloseTag(tag));
    }

    fn reg_scope_vars(&mut self, scope: &Scope) -> Result<(), Cow<'static, str>> {
        match scope {
            &Scope::If(ref logic) => for p in logic.placeholders() {
                try!(self.reg_placeholder(p.to_owned(), ContentType::Bool))
            }
        }

        Ok(())
    }

    fn reg_placeholder(&mut self, param: String, pref_ty: ContentType) -> Result<(), Cow<'static, str>> {
        match self.parameters.entry(param) {
            Entry::Occupied(mut entry) => {
                let new_ty = try!(entry.get().combined_with(pref_ty));
                *entry.get_mut() = new_ty;
            },
            Entry::Vacant(entry) => { entry.insert(pref_ty); },
        }

        Ok(())
    }
}

impl<'a, 'b: 'a> TokenSink for &'a mut Template<'b> {
    fn process_token(&mut self, token: HtmlToken) {
        match token {
            HtmlToken::TagToken(Tag {
                kind: TagKind::StartTag,
                name,
                attrs,
                self_closing
            }) => if let Err(e) = self.open_tag(name, attrs, self_closing) {
                self.errors.push(e);
            },
            HtmlToken::TagToken(Tag {
                kind: TagKind::EndTag,
                name,
                ..
            }) => self.close_tag(name),
            HtmlToken::CharacterTokens(text) => if let Err(e) = self.add_text(text) {
                self.errors.push(e);
            },
            HtmlToken::DoctypeToken(doctype) => self.set_doctype(doctype),

            HtmlToken::CommentToken(_) => {},
            HtmlToken::NullCharacterToken => {},
            HtmlToken::EOFToken => {},

            HtmlToken::ParseError(e) => self.errors.push(e)
        }
    }
}

// http://www.w3.org/TR/html5/syntax.html#void-elements
fn is_void(tag: &str) -> bool {
    match tag {
        "area" |
        "base" |
        "br" |
        "col" |
        "embed" |
        "hr" |
        "img" |
        "input" |
        "keygen" |
        "link" |
        "meta" |
        "param" |
        "source" |
        "track" |
        "wbr" => true,
        _ => false
    }
}

fn init_fragments<'a>() -> HashMap<&'static str, Box<Fragment + 'a>> {
    let mut map = HashMap::new();

    let f: Box<Fragment + 'a> = Box::new(fragments::If);
    map.insert(f.identifier(), f);

    let f = fragments::And;
    map.insert(f.identifier(), Box::new(f));

    let f = fragments::Or;
    map.insert(f.identifier(), Box::new(f));

    let f = fragments::Not;
    map.insert(f.identifier(), Box::new(f));

    let f = fragments::Template;
    map.insert(f.identifier(), Box::new(f));

    map
}<commit_msg>Fix missing BeginText and BeginAttribute if starting with a non-content token<commit_after>extern crate html5ever;
extern crate string_cache;

use std::path::Path;
use std::fs::{File, read_dir};
use std::io::{self, Read, Write};
use std::default::Default;
use std::borrow::{Cow, ToOwned};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt;
use std::mem::swap;

use html5ever::Attribute;
use html5ever::tokenizer::{Tokenizer, TokenSink, Tag, TagKind, Doctype};
use html5ever::tokenizer::Token as HtmlToken;

use string_cache::atom::Atom;

use codegen::{Token, Content, Codegen, ContentType, Scope};
use fragments::{Fragment, ReturnType};

use parser::ExtensibleMap;

#[macro_use]
pub mod codegen;
pub mod fragments;
pub mod javascript;
pub mod rust;
mod parser;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Format(fmt::Error),
    Parse(Vec<Cow<'static, str>>)
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::Io(e)
    }
}

impl From<fmt::Error> for Error {
    fn from(e: fmt::Error) -> Error {
        Error::Format(e)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Io(ref e) => e.fmt(f),
            &Error::Format(ref e) => e.fmt(f),
            &Error::Parse(ref e) => {
                try!(write!(f, "parse errors: "));
                for (i, error) in e.iter().enumerate() {
                    if i == 0 {
                        try!(error.fmt(f));
                    } else {
                        try!(write!(f, ", {}", error));
                    }
                }
                Ok(())
            }
        }
    }
}

///A collection of templates.
pub struct TemplateGroup<'a> {
    templates: Vec<ParsedTemplate>,
    fragments: HashMap<&'static str, Box<Fragment + 'a>>
}

impl<'a> TemplateGroup<'a> {
    pub fn new() -> TemplateGroup<'a> {
        TemplateGroup {
            templates: vec![],
            fragments: init_fragments()
        }
    }

    ///Add a template from a string.
    pub fn parse_string(&mut self, name: String, source: String) -> Result<(), Error> {
        let mut template = Template::extending(&self.fragments);
        try!(template.parse_string(source));
        self.templates.push(ParsedTemplate {
            name: name,
            parameters: template.parameters,
            tokens: template.tokens
        });

        Ok(())
    }

    ///Add every `*.html` and `*.htm` file in a directory to the template group.
    pub fn parse_directory<P: AsRef<Path>>(&mut self, dir: P) -> Result<(), Error> {
        let directory = try!(read_dir(dir));

        for path in directory {
            let path = try!(path).path();
            let info = (
                path.file_stem().and_then(|n| n.to_str()),
                path.extension().and_then(|e| e.to_str())
            );
            if let (Some(name), Some(ext)) = info {
                if ext == "html" || ext == "htm" {
                    let mut source = String::new();
                    try!(File::open(&path).and_then(|mut f| f.read_to_string(&mut source)));
                    try!(self.parse_string(name.to_string(), source));
                }
            }
        }

        Ok(())
    }

    ///Add an already parsed template to the group.
    pub fn add_template(&mut self, name: String, template: Template) {
        self.templates.push(ParsedTemplate {
            name: name,
            parameters: template.parameters,
            tokens: template.tokens
        });
    }

    ///Register a custom fragment.
    pub fn register_fragment<F: Fragment + 'a>(&mut self, fragment: F) {
        let fragment = Box::new(fragment);
        self.fragments.insert(fragment.identifier(), fragment);
    }

    ///Write template code.
    pub fn emit_code<W: Write, C: Codegen>(&self, writer: &mut W, codegen: &C) -> Result<(), Error> {
        codegen.build_module(writer, |w, indent| {
            for template in &self.templates {
                try!(codegen.build_template(w, &template.name, indent, &template.parameters, &template.tokens));
            }
            Ok(())
        })
    }
}

struct ParsedTemplate {
    name: String,
    parameters: HashMap<String, ContentType>,
    tokens: Vec<codegen::Token>
}

///A single template.
pub struct Template<'a> {
    fragments: ExtensibleMap<'a, &'static str, Box<Fragment + 'a>>,
    parameters: HashMap<String, ContentType>,
    tokens: Vec<codegen::Token>,
    errors: Vec<Cow<'static, str>>
}

impl<'a> Template<'a> {
    ///Create an empty template.
    pub fn new() -> Template<'a> {
        Template {
            fragments: ExtensibleMap::Owned(init_fragments()),
            parameters: HashMap::new(),
            tokens: vec![],
            errors: vec![]
        }
    }

    fn extending(fragments: &'a HashMap<&'static str, Box<Fragment + 'a>>) -> Template<'a> {
        Template {
            fragments: ExtensibleMap::extend(fragments),
            parameters: HashMap::new(),
            tokens: vec![],
            errors: vec![]
        }
    }

    ///Add content from a string to the template.
    pub fn parse_string(&mut self, source: String) -> Result<(), Error> {
        {
            let mut tokenizer = Tokenizer::new(&mut*self, Default::default());
            tokenizer.feed(source);
        }

        if self.errors.len() > 0 {
            let mut e = vec![];
            swap(&mut e, &mut self.errors);
            Err(Error::Parse(e))
        } else {
            Ok(())
        }
    }

    ///Register a custom fragment.
    pub fn register_fragment<F: Fragment + 'a>(&mut self, fragment: F) {
        let fragment = Box::new(fragment);
        self.fragments.insert(fragment.identifier(), fragment);
    }

    ///Write template code.
    pub fn emit_code<W: Write, C: Codegen>(&self, template_name: &str, writer: &mut W, codegen: &C) -> Result<(), Error> {
        codegen.build_template(writer, template_name, 0, &self.parameters, &self.tokens)
    }

    fn set_doctype(&mut self, doctype: Doctype) {
        self.tokens.push(Token::SetDoctype(doctype));
    }

    fn open_tag(&mut self, name: Atom, attributes: Vec<Attribute>, self_closing: bool) -> Result<(), Cow<'static, str>> {
        let void = is_void(name.as_slice());
        self.tokens.push(Token::BeginTag(name));

        for attribute in attributes {
            let mut content = try!(parser::parse_content(&attribute.value, &self.fragments)).into_iter();
            match content.next() {
                Some(ReturnType::String(text)) => self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::String(text))),
                Some(ReturnType::Placeholder(name, ty)) => {
                    try!(self.reg_placeholder(name.clone(), ty));
                    self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::Placeholder(name)));
                },
                Some(ReturnType::Logic(_)) => return Err(Cow::Borrowed("logic can not be used as text")),
                Some(ReturnType::Scope(scope)) => {
                    self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::String("".into())));
                    try!(self.reg_scope_vars(&scope));
                    self.tokens.push(Token::Scope(scope));
                },
                Some(ReturnType::End) => {
                    self.tokens.push(Token::End);
                    self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::String("".into())));
                },
                None => self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::String(String::new())))
            }

            for part in content {
                match part {
                    ReturnType::String(text) => self.tokens.push(Token::AppendToAttribute(Content::String(text))),
                    ReturnType::Placeholder(name, ty) => {
                        try!(self.reg_placeholder(name.clone(), ty));
                        self.tokens.push(Token::AppendToAttribute(Content::Placeholder(name)));
                    },
                    ReturnType::Logic(_) => return Err(Cow::Borrowed("logic can not be used as text")),
                    ReturnType::Scope(scope) => {
                        try!(self.reg_scope_vars(&scope));
                        self.tokens.push(Token::Scope(scope));
                    },
                    ReturnType::End => self.tokens.push(Token::End),
                }
            }

            self.tokens.push(Token::EndAttribute);
        }

        self.tokens.push(Token::EndTag(void || self_closing));

        Ok(())
    }

    fn add_text(&mut self, text: String) -> Result<(), Cow<'static, str>> {
        let mut content = try!(parser::parse_content(&text, &self.fragments)).into_iter();
        match content.next() {
            Some(ReturnType::String(text)) => self.tokens.push(Token::BeginText(Content::String(text))),
            Some(ReturnType::Placeholder(name, ty)) => {
                try!(self.reg_placeholder(name.clone(), ty));
                self.tokens.push(Token::BeginText(Content::Placeholder(name)));
            },
            Some(ReturnType::Logic(_)) => return Err(Cow::Borrowed("logic can not be used as text")),
            Some(ReturnType::Scope(scope)) => {
                self.tokens.push(Token::BeginText(Content::String("".into())));
                try!(self.reg_scope_vars(&scope));
                self.tokens.push(Token::Scope(scope));
            },
            Some(ReturnType::End) => {
                self.tokens.push(Token::End);
                self.tokens.push(Token::BeginText(Content::String("".into())))
            },
            None => return Ok(())
        }

        for part in content {
            match part {
                ReturnType::String(text) => self.tokens.push(Token::AppendToText(Content::String(text))),
                ReturnType::Placeholder(name, ty) => {
                    try!(self.reg_placeholder(name.clone(), ty));
                    self.tokens.push(Token::AppendToText(Content::Placeholder(name)));
                },
                ReturnType::Logic(_) => return Err(Cow::Borrowed("logic can not be used as text")),
                ReturnType::Scope(scope) => {
                    try!(self.reg_scope_vars(&scope));
                    self.tokens.push(Token::Scope(scope));
                },
                ReturnType::End => self.tokens.push(Token::End),
            }
        }
        self.tokens.push(Token::EndText);

        Ok(())
    }

    fn close_tag(&mut self, tag: Atom) {
        self.tokens.push(Token::CloseTag(tag));
    }

    fn reg_scope_vars(&mut self, scope: &Scope) -> Result<(), Cow<'static, str>> {
        match scope {
            &Scope::If(ref logic) => for p in logic.placeholders() {
                try!(self.reg_placeholder(p.to_owned(), ContentType::Bool))
            }
        }

        Ok(())
    }

    fn reg_placeholder(&mut self, param: String, pref_ty: ContentType) -> Result<(), Cow<'static, str>> {
        match self.parameters.entry(param) {
            Entry::Occupied(mut entry) => {
                let new_ty = try!(entry.get().combined_with(pref_ty));
                *entry.get_mut() = new_ty;
            },
            Entry::Vacant(entry) => { entry.insert(pref_ty); },
        }

        Ok(())
    }
}

impl<'a, 'b: 'a> TokenSink for &'a mut Template<'b> {
    fn process_token(&mut self, token: HtmlToken) {
        match token {
            HtmlToken::TagToken(Tag {
                kind: TagKind::StartTag,
                name,
                attrs,
                self_closing
            }) => if let Err(e) = self.open_tag(name, attrs, self_closing) {
                self.errors.push(e);
            },
            HtmlToken::TagToken(Tag {
                kind: TagKind::EndTag,
                name,
                ..
            }) => self.close_tag(name),
            HtmlToken::CharacterTokens(text) => if let Err(e) = self.add_text(text) {
                self.errors.push(e);
            },
            HtmlToken::DoctypeToken(doctype) => self.set_doctype(doctype),

            HtmlToken::CommentToken(_) => {},
            HtmlToken::NullCharacterToken => {},
            HtmlToken::EOFToken => {},

            HtmlToken::ParseError(e) => self.errors.push(e)
        }
    }
}

// http://www.w3.org/TR/html5/syntax.html#void-elements
fn is_void(tag: &str) -> bool {
    match tag {
        "area" |
        "base" |
        "br" |
        "col" |
        "embed" |
        "hr" |
        "img" |
        "input" |
        "keygen" |
        "link" |
        "meta" |
        "param" |
        "source" |
        "track" |
        "wbr" => true,
        _ => false
    }
}

fn init_fragments<'a>() -> HashMap<&'static str, Box<Fragment + 'a>> {
    let mut map = HashMap::new();

    let f: Box<Fragment + 'a> = Box::new(fragments::If);
    map.insert(f.identifier(), f);

    let f = fragments::And;
    map.insert(f.identifier(), Box::new(f));

    let f = fragments::Or;
    map.insert(f.identifier(), Box::new(f));

    let f = fragments::Not;
    map.insert(f.identifier(), Box::new(f));

    let f = fragments::Template;
    map.insert(f.identifier(), Box::new(f));

    map
}<|endoftext|>


<commit_before>//! Cuckoo filter probabilistic data structure for membership testing and cardinlaity counting.
//!
//! # Usage
//!
//! This crate is [on crates.io](https://crates.io/crates/cuckoofilter) and can be
//! used by adding `cuckoofilter` to the dependencies in your project's `Cargo.toml`.
//!
//! ```toml
//! [dependencies]
//! cuckoofilter = "0.1"
//! ```
//!
//! And this in your crate root:
//!
//! ```rust
//! extern crate cuckoofilter;
//! ```

mod bucket;
mod util;

extern crate rand;

use bucket::{Bucket, Fingerprint, BUCKET_SIZE};
use util::{get_next_pow_2, get_fai, get_alt_index};
use rand::Rng;

pub const MAX_REBUCKET: usize = 500;

// A cuckoo filter class exposes a Bloomier filter interface,
// providing methods of add, delete, contains.
pub struct CuckooFilter {
    buckets: Vec<Bucket>,
    count: u64,
}

impl CuckooFilter {
    /**
     * Returns a Cuckoo Filter with a given max Capacity
     */
    pub fn new(cap: u64) -> CuckooFilter {
        let mut capacity = get_next_pow_2(cap);
        capacity = capacity/BUCKET_SIZE as u64;
        if capacity == 0 {
            capacity = 1;
        }
        let mut buckets: Vec<Bucket> = vec![];
        for _ in 0..capacity {
            buckets.push(Bucket::new())
        }
        return CuckooFilter{buckets: buckets, count: 0,}
    }

    /**
     * Returns a Cuckoo Filter with a default max Capacity 1000000 items/
     */
    pub fn default() -> CuckooFilter {
        return CuckooFilter::new(1000000);
    }

    /**
     * Returns if data is in filter.
     */
    pub fn contains(&mut self, data: &[u8]) -> bool {
        let fai = get_fai(data);
        let fp = fai.fp;
        let i1 = fai.i1;
        let i2 = fai.i2;
        let len = self.buckets.len();
        let b1 = self.buckets[i1%len].get_fingerprint_index(fp);
        let b2 = self.buckets[i2%len].get_fingerprint_index(fp);
        return b1 < BUCKET_SIZE || b2 < BUCKET_SIZE;
    }

    /**
     * Add data to the filter.
     * Returns true if successful.
     */
    pub fn add(&mut self, data: &[u8]) -> bool {
        let fai = get_fai(data);
        let fp = fai.fp;
        let i1 = fai.i1;
        let i2 = fai.i2;
        if self.put(fp, i1) || self.put(fp, i2) {
            return true;
        }
        return self.reinsert(fp, i2)
    }
    /**
     * If data is in filter and add an item to the filter if not exists.
     * This is like using lookup and adding if it returns true.
     * Returns true if data did not exist in filter an is added successfuly
     */
    pub fn test_and_add(&mut self, data: &[u8]) -> bool {
        if self.contains(data) {
            return false;
        }
        return self.add(data);
    }

    /**
     * Returns number of current inserted items;
     */
    pub fn get_count(&mut self) -> u64 {
        return self.count;
    }

    /**
     * Delete an data from the filter.
     * Returns true if successful (data exists in filter and was deleted).
     */
    pub fn delete(&mut self, data: &[u8]) -> bool{
        let fai = get_fai(data);
        let fp = fai.fp;
        let i1 = fai.i1;
        let i2 = fai.i2;

        return self.remove(fp, i1) || self.remove(fp, i2)
    }

    fn remove (&mut self, fp: Fingerprint, i: usize) -> bool {
        let len = self.buckets.len();
        if self.buckets[i%len].delete(fp) {
            self.count -= 1;
            return true;
        }
        return false;
    }

    fn put(&mut self, fp: Fingerprint, i: usize) -> bool {
        let len = self.buckets.len();
        let mut b = &mut self.buckets[i%len];
        if b.insert(fp) {
            self.count+=1;
            return true;
        }
        return false;
    }

    fn reinsert(&mut self, mut fp: Fingerprint, mut i: usize) -> bool {
        for _ in 0..MAX_REBUCKET {
            let j = rand::thread_rng().gen_range(0.0, BUCKET_SIZE as f64) as usize;
            let newfp = fp;
            let len = self.buckets.len();
            fp = self.buckets[i%len].0[j];
            self.buckets[i%len].0[j] = newfp;
            i = get_alt_index(&mut fp, i);
            if self.put(fp, i) {
                return true;
            }
        }
        return false;
    }
}<commit_msg>Rustify code a bit<commit_after>//! Cuckoo filter probabilistic data structure for membership testing and cardinlaity counting.
//!
//! # Usage
//!
//! This crate is [on crates.io](https://crates.io/crates/cuckoofilter) and can be
//! used by adding `cuckoofilter` to the dependencies in your project's `Cargo.toml`.
//!
//! ```toml
//! [dependencies]
//! cuckoofilter = "0.1"
//! ```
//!
//! And this in your crate root:
//!
//! ```rust
//! extern crate cuckoofilter;
//! ```

mod bucket;
mod util;

extern crate rand;

use bucket::{Bucket, Fingerprint, BUCKET_SIZE};
use util::{get_next_pow_2, get_fai, get_alt_index, FaI};
use rand::Rng;

pub const MAX_REBUCKET: usize = 500;

// A cuckoo filter class exposes a Bloomier filter interface,
// providing methods of add, delete, contains.
pub struct CuckooFilter {
    buckets: Vec<Bucket>,
    count: u64,
}

impl CuckooFilter {
    /**
     * Returns a Cuckoo Filter with a given max Capacity
     */
    pub fn new(cap: u64) -> CuckooFilter {
        let mut capacity = get_next_pow_2(cap);
        capacity = capacity/BUCKET_SIZE as u64;
        if capacity == 0 {
            capacity = 1;
        }
        let mut buckets: Vec<Bucket> = vec![];
        for _ in 0..capacity {
            buckets.push(Bucket::new())
        }
        return CuckooFilter{buckets: buckets, count: 0,}
    }

    /**
     * Returns a Cuckoo Filter with a default max Capacity 1000000 items/
     */
    pub fn default() -> CuckooFilter {
        return CuckooFilter::new(1000000);
    }

    /**
     * Returns if data is in filter.
     */
    pub fn contains(&mut self, data: &[u8]) -> bool {
        let FaI{fp, i1, i2} = get_fai(data);
        let len = self.buckets.len();
        let b1 = self.buckets[i1%len].get_fingerprint_index(fp);
        let b2 = self.buckets[i2%len].get_fingerprint_index(fp);
        return b1 < BUCKET_SIZE || b2 < BUCKET_SIZE;
    }

    /**
     * Add data to the filter.
     * Returns true if successful.
     */
    pub fn add(&mut self, data: &[u8]) -> bool {
        let FaI{fp, i1, i2} = get_fai(data);
        if self.put(fp, i1) || self.put(fp, i2) {
            return true;
        }
        return self.reinsert(fp, i2)
    }
    /**
     * If data is in filter and add an item to the filter if not exists.
     * This is like using lookup and adding if it returns true.
     * Returns true if data did not exist in filter an is added successfuly
     */
    pub fn test_and_add(&mut self, data: &[u8]) -> bool {
        if self.contains(data) {
            return false;
        }
        return self.add(data);
    }

    /**
     * Returns number of current inserted items;
     */
    pub fn get_count(&mut self) -> u64 {
        return self.count;
    }

    /**
     * Delete an data from the filter.
     * Returns true if successful (data exists in filter and was deleted).
     */
    pub fn delete(&mut self, data: &[u8]) -> bool{
        let FaI{fp, i1, i2} = get_fai(data);
        return self.remove(fp, i1) || self.remove(fp, i2)
    }

    fn remove (&mut self, fp: Fingerprint, i: usize) -> bool {
        let len = self.buckets.len();
        if self.buckets[i%len].delete(fp) {
            self.count -= 1;
            return true;
        }
        return false;
    }

    fn put(&mut self, fp: Fingerprint, i: usize) -> bool {
        let len = self.buckets.len();
        let mut b = &mut self.buckets[i%len];
        if b.insert(fp) {
            self.count+=1;
            return true;
        }
        return false;
    }

    fn reinsert(&mut self, mut fp: Fingerprint, mut i: usize) -> bool {
        for _ in 0..MAX_REBUCKET {
            let j = rand::thread_rng().gen_range(0.0, BUCKET_SIZE as f64) as usize;
            let newfp = fp;
            let len = self.buckets.len();
            fp = self.buckets[i%len].0[j];
            self.buckets[i%len].0[j] = newfp;
            i = get_alt_index(&mut fp, i);
            if self.put(fp, i) {
                return true;
            }
        }
        return false;
    }
}<|endoftext|>


<commit_before>#![feature(main)]
#![feature(plugin)]

#![plugin(clippy)]
#![allow(non_snake_case)]

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate thread_scoped;
extern crate time;
#[macro_use]
extern crate clap;
extern crate portaudio;
extern crate rgsl;

mod mvar;
mod note;
mod main;

mod thread {
  pub use std::thread::*;
  pub use thread_scoped::*;
}
<commit_msg>deny warnings<commit_after>#![feature(main)]
#![feature(plugin)]

#![plugin(clippy)]
#![allow(non_snake_case)]
#![deny(warnings)]

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate thread_scoped;
extern crate time;
#[macro_use]
extern crate clap;
extern crate portaudio;
extern crate rgsl;

mod mvar;
mod note;
mod main;

mod thread {
  pub use std::thread::*;
  pub use thread_scoped::*;
}
<|endoftext|>


<commit_before>//! Opcode and instruction abstractions

/// First register in an opcode
pub type Vx = u8;
/// Second register in an opcode
pub type Vy = u8;
/// Absolute memory address
pub type Addr = u16;
/// A byte
pub type Byte = u8;
/// A nibble (hex digit)
pub type Nibble = u8;

/// Assembly opcode
#[derive(Copy)]
pub struct Op {
    raw: u16
}

impl Op {
    pub fn new(raw: u16) -> Op {
        Op{ raw: raw }
    }

    #[allow(dead_code)]
    pub fn raw(&self) -> u16 {
        self.raw
    }

    pub fn addr(&self) -> Addr {
        self.raw & 0x0FFF
    }

    pub fn x(&self) -> Vx {
        ((self.raw & 0x0F00) >> 8) as u8
    }

    pub fn y(&self) -> Vy {
        ((self.raw & 0x00F0) >> 4) as u8
    }

    pub fn n_high(&self) -> Nibble {
        ((self.raw & 0xF000) >> 12) as u8
    }

    pub fn n_low(&self) -> Nibble {
        (self.raw & 0x000F) as u8
    }

    pub fn k(&self) -> Byte {
        (self.raw & 0x00FF) as u8
    }
}

/// Machine instruction
///
/// An instruction is a higher level view of an opcode.
#[derive(Copy,Debug)]
pub enum Instruction {
    Sys(Addr),              // 0nnn - SYS addr
    Clear,                  // 00E0 - CLS
    Return,                 // 00EE - RET
    Jump(Addr),             // 1nnn - JP addr
    Call(Addr),             // 2nnn - CALL addr
    SkipEqualK(Vx, Byte),   // 3xkk - SE Vx, byte
    SkipNotEqualK(Vx, Byte),// 4xkk - SNE Vx, byte
    SkipEqual(Vx, Vy),      // 5xy0 - SE Vx, Vy
    SetK(Vx, Byte),         // 6xkk - LD Vx, byte
    AddK(Vx, Byte),         // 7xkk - ADD Vx, byte
    Set(Vx, Vy),            // 8xy0 - LD Vx, Vy
    Or(Vx, Vy),             // 8xy1 - OR Vx, Vy
    And(Vx, Vy),            // 8xy2 - AND Vx, Vy
    XOr(Vx, Vy),            // 8xy3 - XOR Vx, Vy
    Add(Vx, Vy),            // 8xy4 - ADD Vx, Vy
    Sub(Vx, Vy),            // 8xy5 - SUB Vx, Vy
    ShiftRight(Vx, Vy),     // 8xy6 - SHR Vx {, Vy}
    SubInv(Vx, Vy),         // 8xy7 - SUBN Vx, Vy
    ShiftLeft(Vx, Vy),      // 8xyE - SHL Vx {, Vy}
    SkipNotEqual(Vx, Vy),   // 9xy0 - SNE Vx, Vy
    LoadI(Addr),            // Annn - LD I, addr
    LongJump(Addr),         // Bnnn - JP V0, addr
    Rand(Vx, Byte),         // Cxkk - RND Vx, byte
    Draw(Vx, Vy, Nibble),   // Dxyn - DRW Vx, Vy, nibble
    SkipPressed(Vx),        // Ex9E - SKP Vx
    SkipNotPressed(Vx),     // ExA1 - SKNP Vx
    GetTimer(Vx),           // Fx07 - LD Vx, DT
    WaitKey(Vx),            // Fx0A - LD Vx, K
    SetTimer(Vx),           // Fx15 - LD DT, Vx
    SetSoundTimer(Vx),      // Fx18 - LD ST, Vx
    AddToI(Vx),             // Fx1E - ADD I, Vx
    LoadHexGlyph(Vx),       // Fx29 - LD F, Vx
    StoreBCD(Vx),           // Fx33 - LD B, Vx
    StoreRegisters(Vx),     // Fx55 - LD [I], Vx
    LoadRegisters(Vx),      // Fx65 - LD Vx, [I]
    Unknown,
}

impl Instruction {
    pub fn from_op(op: &Op) -> Instruction {
        use ops::Instruction::*;
        match op.n_high() {
            0x0 => {
                match op.k() {
                    0xE0 => Clear,
                    0xEE => Return,
                    _ => Sys(op.addr())
                }
            },
            0x1 => Jump(op.addr()),
            0x2 => Call(op.addr()),
            0x3 => SkipEqualK(op.x(), op.k()),
            0x4 => SkipNotEqualK(op.x(), op.k()),
            0x5 => SkipEqual(op.x(), op.y()),
            0x6 => SetK(op.x(), op.k()),
            0x7 => AddK(op.x(), op.k()),
            0x8 => {
                match op.n_low() {
                    0x0 => Set(op.x(), op.y()),
                    0x1 => Or(op.x(), op.y()),
                    0x2 => And(op.x(), op.y()),
                    0x3 => XOr(op.x(), op.y()),
                    0x4 => Add(op.x(), op.y()),
                    0x5 => Sub(op.x(), op.y()),
                    0x6 => ShiftRight(op.x(), op.y()),
                    0x7 => SubInv(op.x(), op.y()),
                    0xE => ShiftLeft(op.x(), op.y()),
                    _ => Unknown
                }
            },
            0x9 => SkipNotEqual(op.x(), op.y()),
            0xA => LoadI(op.addr()),
            0xB => LongJump(op.addr()),
            0xC => Rand(op.x(), op.k()),
            0xD => Draw(op.x(), op.y(), op.n_low()),
            0xE => {
                match op.k() {
                    0x9E => SkipPressed(op.x()),
                    0xA1 => SkipNotPressed(op.x()),
                    _ => Unknown,
                }
            },
            0xF => {
                match op.k() {
                    0x07 => GetTimer(op.x()),
                    0x0A => WaitKey(op.x()),
                    0x15 => SetTimer(op.x()),
                    0x18 => SetSoundTimer(op.x()),
                    0x1E => AddToI(op.x()),
                    0x29 => LoadHexGlyph(op.x()),
                    0x33 => StoreBCD(op.x()),
                    0x55 => StoreRegisters(op.x()),
                    0x65 => LoadRegisters(op.x()),
                    _ => Unknown,
                }
            }
            _ => Unknown
        }
    }
}
<commit_msg>Add valid ranges for types to rustdoc<commit_after>//! Opcode and instruction abstractions

/// First register in an opcode
///
/// There are 16 registers, `V0`..`VF`
pub type Vx = u8;
/// Second register in an opcode
pub type Vy = u8;
/// Absolute memory address
///
/// Valid addresses are within `0x0` .. `0xFFF`.
pub type Addr = u16;
/// A byte
///
/// Valid values are within `0x0` .. `0xFF`.
pub type Byte = u8;
/// A nibble (hex digit)
///
/// Valid values are within `0x0` .. `0xF`.
pub type Nibble = u8;

/// Assembly opcode
#[derive(Copy)]
pub struct Op {
    raw: u16
}

impl Op {
    pub fn new(raw: u16) -> Op {
        Op{ raw: raw }
    }

    #[allow(dead_code)]
    pub fn raw(&self) -> u16 {
        self.raw
    }

    pub fn addr(&self) -> Addr {
        self.raw & 0x0FFF
    }

    pub fn x(&self) -> Vx {
        ((self.raw & 0x0F00) >> 8) as u8
    }

    pub fn y(&self) -> Vy {
        ((self.raw & 0x00F0) >> 4) as u8
    }

    pub fn n_high(&self) -> Nibble {
        ((self.raw & 0xF000) >> 12) as u8
    }

    pub fn n_low(&self) -> Nibble {
        (self.raw & 0x000F) as u8
    }

    pub fn k(&self) -> Byte {
        (self.raw & 0x00FF) as u8
    }
}

/// Machine instruction
#[derive(Copy,Debug)]
pub enum Instruction {
    Sys(Addr),              // 0nnn - SYS addr
    Clear,                  // 00E0 - CLS
    Return,                 // 00EE - RET
    Jump(Addr),             // 1nnn - JP addr
    Call(Addr),             // 2nnn - CALL addr
    SkipEqualK(Vx, Byte),   // 3xkk - SE Vx, byte
    SkipNotEqualK(Vx, Byte),// 4xkk - SNE Vx, byte
    SkipEqual(Vx, Vy),      // 5xy0 - SE Vx, Vy
    SetK(Vx, Byte),         // 6xkk - LD Vx, byte
    AddK(Vx, Byte),         // 7xkk - ADD Vx, byte
    Set(Vx, Vy),            // 8xy0 - LD Vx, Vy
    Or(Vx, Vy),             // 8xy1 - OR Vx, Vy
    And(Vx, Vy),            // 8xy2 - AND Vx, Vy
    XOr(Vx, Vy),            // 8xy3 - XOR Vx, Vy
    Add(Vx, Vy),            // 8xy4 - ADD Vx, Vy
    Sub(Vx, Vy),            // 8xy5 - SUB Vx, Vy
    ShiftRight(Vx, Vy),     // 8xy6 - SHR Vx {, Vy}
    SubInv(Vx, Vy),         // 8xy7 - SUBN Vx, Vy
    ShiftLeft(Vx, Vy),      // 8xyE - SHL Vx {, Vy}
    SkipNotEqual(Vx, Vy),   // 9xy0 - SNE Vx, Vy
    LoadI(Addr),            // Annn - LD I, addr
    LongJump(Addr),         // Bnnn - JP V0, addr
    Rand(Vx, Byte),         // Cxkk - RND Vx, byte
    Draw(Vx, Vy, Nibble),   // Dxyn - DRW Vx, Vy, nibble
    SkipPressed(Vx),        // Ex9E - SKP Vx
    SkipNotPressed(Vx),     // ExA1 - SKNP Vx
    GetTimer(Vx),           // Fx07 - LD Vx, DT
    WaitKey(Vx),            // Fx0A - LD Vx, K
    SetTimer(Vx),           // Fx15 - LD DT, Vx
    SetSoundTimer(Vx),      // Fx18 - LD ST, Vx
    AddToI(Vx),             // Fx1E - ADD I, Vx
    LoadHexGlyph(Vx),       // Fx29 - LD F, Vx
    StoreBCD(Vx),           // Fx33 - LD B, Vx
    StoreRegisters(Vx),     // Fx55 - LD [I], Vx
    LoadRegisters(Vx),      // Fx65 - LD Vx, [I]
    Unknown,
}

impl Instruction {
    pub fn from_op(op: &Op) -> Instruction {
        use ops::Instruction::*;
        match op.n_high() {
            0x0 => {
                match op.k() {
                    0xE0 => Clear,
                    0xEE => Return,
                    _ => Sys(op.addr())
                }
            },
            0x1 => Jump(op.addr()),
            0x2 => Call(op.addr()),
            0x3 => SkipEqualK(op.x(), op.k()),
            0x4 => SkipNotEqualK(op.x(), op.k()),
            0x5 => SkipEqual(op.x(), op.y()),
            0x6 => SetK(op.x(), op.k()),
            0x7 => AddK(op.x(), op.k()),
            0x8 => {
                match op.n_low() {
                    0x0 => Set(op.x(), op.y()),
                    0x1 => Or(op.x(), op.y()),
                    0x2 => And(op.x(), op.y()),
                    0x3 => XOr(op.x(), op.y()),
                    0x4 => Add(op.x(), op.y()),
                    0x5 => Sub(op.x(), op.y()),
                    0x6 => ShiftRight(op.x(), op.y()),
                    0x7 => SubInv(op.x(), op.y()),
                    0xE => ShiftLeft(op.x(), op.y()),
                    _ => Unknown
                }
            },
            0x9 => SkipNotEqual(op.x(), op.y()),
            0xA => LoadI(op.addr()),
            0xB => LongJump(op.addr()),
            0xC => Rand(op.x(), op.k()),
            0xD => Draw(op.x(), op.y(), op.n_low()),
            0xE => {
                match op.k() {
                    0x9E => SkipPressed(op.x()),
                    0xA1 => SkipNotPressed(op.x()),
                    _ => Unknown,
                }
            },
            0xF => {
                match op.k() {
                    0x07 => GetTimer(op.x()),
                    0x0A => WaitKey(op.x()),
                    0x15 => SetTimer(op.x()),
                    0x18 => SetSoundTimer(op.x()),
                    0x1E => AddToI(op.x()),
                    0x29 => LoadHexGlyph(op.x()),
                    0x33 => StoreBCD(op.x()),
                    0x55 => StoreRegisters(op.x()),
                    0x65 => LoadRegisters(op.x()),
                    _ => Unknown,
                }
            }
            _ => Unknown
        }
    }
}
<|endoftext|>


<commit_before>//! Rust representations of docker json structures

use std::collections::HashMap;

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SearchResult {
    pub description: String,
    pub is_official: bool,
    pub is_trusted: bool,
    pub name: String,
    pub star_count: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Image {
    pub Created: u64,
    pub Id: String,
    pub ParentId: String,
    // pub Labels: ???,
    pub RepoTags: Vec<String>,
    pub RepoDigests: Option<Vec<String>>,
    pub Size: u64,
    pub VirtualSize: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ImageDetails {
    pub Architecture: String,
    pub Author: String,
    pub Comment: String,
    pub Config: Config,
    pub Created: String,
    pub DockerVersion: String,
    pub Id: String,
    pub Os: String,
    pub Parent: String,
    pub Size: u64,
    pub VirtualSize: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Container {
    pub Created: u64,
    pub Command: String,
    pub Id: String,
    pub Image: String,
    pub Labels: HashMap<String, String>,
    pub Names: Vec<String>,
    pub Ports: Vec<Port>,
    pub Status: String,
    pub SizeRw: Option<u64>,
    pub SizeRootFs: Option<u64>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ContainerDetails {
    pub AppArmorProfile: String,
    pub Args: Vec<String>,
    pub Config: Config,
    pub Created: String,
    pub Driver: String,
    pub ExecDriver: String,
    // pub ExecIDs: ??
    pub HostConfig: HostConfig,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct HostConfig {
    pub CgroupParent: Option<String>,
    pub ContainerIDFile: String,
    pub CpuShares: Option<u64>,
    pub CpusetCpus: Option<String>,
    pub Memory: Option<u64>,
    pub MemorySwap: Option<u64>,
    pub NetworkMode: String,
    pub PidMode: Option<String>,
    // pub PortBindings: ???
    pub Privileged: bool,
    pub PublishAllPorts: bool,
    pub ReadonlyRootfs: Option<bool>, /* pub RestartPolicy: ???
                                       * pub SecurityOpt: Option<???>,
                                       * pub Ulimits: Option<???>
                                       * pub VolumesFrom: Option<??/> */
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Config {
    pub AttachStderr: bool,
    pub AttachStdin: bool,
    pub AttachStdout: bool,
    pub Cmd: Option<Vec<String>>,
    pub Domainname: String,
    pub Entrypoint: Option<Vec<String>>,
    pub Env: Option<Vec<String>>,
    // ExposedPorts
    pub Hostname: String,
    pub Image: String,
    // Labels:???
    // OnBuild: Option<String>,
    pub OpenStdin: bool,
    // PortSpecs: ???,
    pub StdinOnce: bool,
    pub Tty: bool,
    pub User: String,
    // Volumes: ??,
    pub WorkingDir: String,
}

impl Config {
    pub fn env(&self) -> HashMap<String, String> {
        let mut map = HashMap::new();
        match self.Env {
            Some(ref vars) => {
                for e in vars {
                    let pair: Vec<&str> = e.split("=").collect();
                    map.insert(pair[0].to_owned(), pair[1].to_owned());
                }
            }
            _ => (),
        };
        map
    }
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Port {
    pub IP: Option<String>,
    pub PrivatePort: u64,
    pub PublicPort: Option<u64>,
    pub Type: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Stats {
    pub read: String,
    pub networks: HashMap<String, Network>,
    pub memory_stats: MemoryStats,
    pub blkio_stats: BlkioStats,
    pub cpu_stats: CpuStats,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Network {
    pub rx_dropped: u64,
    pub rx_bytes: u64,
    pub rx_errors: u64,
    pub tx_packets: u64,
    pub tx_dropped: u64,
    pub rx_packets: u64,
    pub tx_errors: u64,
    pub tx_bytes: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStats {
    pub max_usage: u64,
    pub usage: u64,
    pub failcnt: u64,
    pub limit: u64,
    pub stats: MemoryStat,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStat {
    pub total_pgmajfault: u64,
    pub cache: u64,
    pub mapped_file: u64,
    pub total_inactive_file: u64,
    pub pgpgout: u64,
    pub rss: u64,
    pub total_mapped_file: u64,
    pub writeback: u64,
    pub unevictable: u64,
    pub pgpgin: u64,
    pub total_unevictable: u64,
    pub pgmajfault: u64,
    pub total_rss: u64,
    pub total_rss_huge: u64,
    pub total_writeback: u64,
    pub total_inactive_anon: u64,
    pub rss_huge: u64,
    pub hierarchical_memory_limit: u64,
    pub hierarchical_memsw_limit: u64,
    pub total_pgfault: u64,
    pub total_active_file: u64,
    pub active_anon: u64,
    pub total_active_anon: u64,
    pub total_pgpgout: u64,
    pub total_cache: u64,
    pub inactive_anon: u64,
    pub active_file: u64,
    pub pgfault: u64,
    pub inactive_file: u64,
    pub total_pgpgin: u64,
    pub swap: u64,
    pub total_swap: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct CpuStats {
    pub cpu_usage: CpuUsage,
    pub system_cpu_usage: u64,
    pub throttling_data: ThrottlingData,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct CpuUsage {
    pub percpu_usage: Vec<u64>,
    pub usage_in_usermode: u64,
    pub total_usage: u64,
    pub usage_in_kernelmode: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct ThrottlingData {
    pub periods: u64,
    pub throttled_periods: u64,
    pub throttled_time: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlkioStats {
    pub io_service_bytes_recursive: Vec<BlkioStat>,
    pub io_serviced_recursive: Vec<BlkioStat>,
    pub io_queue_recursive: Vec<BlkioStat>,
    pub io_service_time_recursive: Vec<BlkioStat>,
    pub io_wait_time_recursive: Vec<BlkioStat>,
    pub io_merged_recursive: Vec<BlkioStat>,
    pub io_time_recursive: Vec<BlkioStat>,
    pub sectors_recursive: Vec<BlkioStat>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlkioStat {
    pub major: u64,
    pub minor: u64,
    pub op: String,
    pub value: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Change {
    pub Kind: u64,
    pub Path: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Top {
    pub Titles: Vec<String>,
    pub Processes: Vec<Vec<String>>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Version {
    pub ApiVersion: String,
    pub Version: String,
    pub GitCommit: String,
    pub GoVersion: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Info {
    pub Containers: u64,
    pub Images: u64,
    pub Driver: String,
    pub DockerRootDir: String,
    pub DriverStatus: Vec<Vec<String>>,
    pub ExecutionDriver: String,
    pub ID: String,
    pub KernelVersion: String,
    // pub Labels: Option<???>,
    pub MemTotal: u64,
    pub MemoryLimit: bool,
    pub NCPU: u64,
    pub NEventsListener: u64,
    pub NGoroutines: u64,
    pub Name: String,
    pub OperatingSystem: String,
    // pub RegistryConfig:???
    pub SwapLimit: bool,
    pub SystemTime: Option<String>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ContainerCreateInfo {
    pub Id: String,
    pub Warnings: Option<Vec<String>>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct History {
    pub Id: String,
    pub Created: u64,
    pub CreatedBy: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Exit {
    pub StatusCode: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Event {
    pub status: String,
    pub id: String,
    pub from: Option<String>,
    pub time: u64,
    pub timeNano: u64,
}

#[derive(Debug)]
pub enum Status {
    Untagged(String),
    Deleted(String),
}
<commit_msg>flesh out more container details<commit_after>//! Rust representations of docker json structures

use std::collections::HashMap;

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SearchResult {
    pub description: String,
    pub is_official: bool,
    pub is_trusted: bool,
    pub name: String,
    pub star_count: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Image {
    pub Created: u64,
    pub Id: String,
    pub ParentId: String,
    // pub Labels: ???,
    pub RepoTags: Vec<String>,
    pub RepoDigests: Option<Vec<String>>,
    pub Size: u64,
    pub VirtualSize: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ImageDetails {
    pub Architecture: String,
    pub Author: String,
    pub Comment: String,
    pub Config: Config,
    pub Created: String,
    pub DockerVersion: String,
    pub Id: String,
    pub Os: String,
    pub Parent: String,
    pub Size: u64,
    pub VirtualSize: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Container {
    pub Created: u64,
    pub Command: String,
    pub Id: String,
    pub Image: String,
    pub Labels: HashMap<String, String>,
    pub Names: Vec<String>,
    pub Ports: Vec<Port>,
    pub Status: String,
    pub SizeRw: Option<u64>,
    pub SizeRootFs: Option<u64>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ContainerDetails {
    pub AppArmorProfile: String,
    pub Args: Vec<String>,
    pub Config: Config,
    pub Created: String,
    pub Driver: String,
    pub ExecDriver: String,
    // pub ExecIDs: ??
    pub HostConfig: HostConfig,
    pub HostnamePath: String,
    pub HostsPath: String,
    pub LogPath: String,
    pub Id: String,
    pub Image: String,
    pub MountLabel: String,
    pub NetworkSettings: NetworkSettings,
    pub Path: String,
    pub ProcessLabel: String,
    pub ResolvConfPath: String,
    pub RestartCount: u64,
    pub State: State,
    pub Mounts: Vec<Mount>
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Mount {
    pub Source: String,
    pub Destination: String,
    pub Mode: String,
    pub RW: bool
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct State {
    pub Error: String,
    pub ExitCode: u64,
    pub FinishedAt: String,
    pub OOMKilled: bool,
    pub Paused: bool,
    pub Pid: u64,
    pub Restarting: bool,
    pub Running: bool,
    pub StartedAt: String
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct NetworkSettings {
    pub Bridge: String,
    pub Gateway: String,
    pub IPAddress: String,
    pub IPPrefixLen: u64,
    pub MacAddress: String,
//    pub PortMapping: Option<???>,
 //   pub Ports: Option<???>
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct HostConfig {
    pub CgroupParent: Option<String>,
    pub ContainerIDFile: String,
    pub CpuShares: Option<u64>,
    pub CpusetCpus: Option<String>,
    pub Memory: Option<u64>,
    pub MemorySwap: Option<u64>,
    pub NetworkMode: String,
    pub PidMode: Option<String>,
    // pub PortBindings: ???
    pub Privileged: bool,
    pub PublishAllPorts: bool,
    pub ReadonlyRootfs: Option<bool>, /* pub RestartPolicy: ???
                                       * pub SecurityOpt: Option<???>,
                                       * pub Ulimits: Option<???>
                                       * pub VolumesFrom: Option<??/> */
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Config {
    pub AttachStderr: bool,
    pub AttachStdin: bool,
    pub AttachStdout: bool,
    pub Cmd: Option<Vec<String>>,
    pub Domainname: String,
    pub Entrypoint: Option<Vec<String>>,
    pub Env: Option<Vec<String>>,
    // ExposedPorts
    pub Hostname: String,
    pub Image: String,
    pub Labels: HashMap<String, String>,
//    pub MacAddress: String,
    pub OnBuild: Option<String>,
//    pub NetworkDisabled: bool,
    pub OpenStdin: bool,
    pub StdinOnce: bool,
    pub Tty: bool,
    pub User: String,
    pub WorkingDir: String,
}

impl Config {
    pub fn env(&self) -> HashMap<String, String> {
        let mut map = HashMap::new();
        match self.Env {
            Some(ref vars) => {
                for e in vars {
                    let pair: Vec<&str> = e.split("=").collect();
                    map.insert(pair[0].to_owned(), pair[1].to_owned());
                }
            }
            _ => (),
        };
        map
    }
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Port {
    pub IP: Option<String>,
    pub PrivatePort: u64,
    pub PublicPort: Option<u64>,
    pub Type: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Stats {
    pub read: String,
    pub networks: HashMap<String, Network>,
    pub memory_stats: MemoryStats,
    pub blkio_stats: BlkioStats,
    pub cpu_stats: CpuStats,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Network {
    pub rx_dropped: u64,
    pub rx_bytes: u64,
    pub rx_errors: u64,
    pub tx_packets: u64,
    pub tx_dropped: u64,
    pub rx_packets: u64,
    pub tx_errors: u64,
    pub tx_bytes: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStats {
    pub max_usage: u64,
    pub usage: u64,
    pub failcnt: u64,
    pub limit: u64,
    pub stats: MemoryStat,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStat {
    pub total_pgmajfault: u64,
    pub cache: u64,
    pub mapped_file: u64,
    pub total_inactive_file: u64,
    pub pgpgout: u64,
    pub rss: u64,
    pub total_mapped_file: u64,
    pub writeback: u64,
    pub unevictable: u64,
    pub pgpgin: u64,
    pub total_unevictable: u64,
    pub pgmajfault: u64,
    pub total_rss: u64,
    pub total_rss_huge: u64,
    pub total_writeback: u64,
    pub total_inactive_anon: u64,
    pub rss_huge: u64,
    pub hierarchical_memory_limit: u64,
    pub hierarchical_memsw_limit: u64,
    pub total_pgfault: u64,
    pub total_active_file: u64,
    pub active_anon: u64,
    pub total_active_anon: u64,
    pub total_pgpgout: u64,
    pub total_cache: u64,
    pub inactive_anon: u64,
    pub active_file: u64,
    pub pgfault: u64,
    pub inactive_file: u64,
    pub total_pgpgin: u64,
    pub swap: u64,
    pub total_swap: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct CpuStats {
    pub cpu_usage: CpuUsage,
    pub system_cpu_usage: u64,
    pub throttling_data: ThrottlingData,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct CpuUsage {
    pub percpu_usage: Vec<u64>,
    pub usage_in_usermode: u64,
    pub total_usage: u64,
    pub usage_in_kernelmode: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct ThrottlingData {
    pub periods: u64,
    pub throttled_periods: u64,
    pub throttled_time: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlkioStats {
    pub io_service_bytes_recursive: Vec<BlkioStat>,
    pub io_serviced_recursive: Vec<BlkioStat>,
    pub io_queue_recursive: Vec<BlkioStat>,
    pub io_service_time_recursive: Vec<BlkioStat>,
    pub io_wait_time_recursive: Vec<BlkioStat>,
    pub io_merged_recursive: Vec<BlkioStat>,
    pub io_time_recursive: Vec<BlkioStat>,
    pub sectors_recursive: Vec<BlkioStat>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlkioStat {
    pub major: u64,
    pub minor: u64,
    pub op: String,
    pub value: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Change {
    pub Kind: u64,
    pub Path: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Top {
    pub Titles: Vec<String>,
    pub Processes: Vec<Vec<String>>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Version {
    pub ApiVersion: String,
    pub Version: String,
    pub GitCommit: String,
    pub GoVersion: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Info {
    pub Containers: u64,
    pub Images: u64,
    pub Driver: String,
    pub DockerRootDir: String,
    pub DriverStatus: Vec<Vec<String>>,
    pub ExecutionDriver: String,
    pub ID: String,
    pub KernelVersion: String,
    // pub Labels: Option<???>,
    pub MemTotal: u64,
    pub MemoryLimit: bool,
    pub NCPU: u64,
    pub NEventsListener: u64,
    pub NGoroutines: u64,
    pub Name: String,
    pub OperatingSystem: String,
    // pub RegistryConfig:???
    pub SwapLimit: bool,
    pub SystemTime: Option<String>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ContainerCreateInfo {
    pub Id: String,
    pub Warnings: Option<Vec<String>>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct History {
    pub Id: String,
    pub Created: u64,
    pub CreatedBy: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Exit {
    pub StatusCode: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Event {
    pub status: String,
    pub id: String,
    pub from: Option<String>,
    pub time: u64,
    pub timeNano: u64,
}

#[derive(Debug)]
pub enum Status {
    Untagged(String),
    Deleted(String),
}
<|endoftext|>