<commit_before>
#[macro_use]
extern crate log;

extern crate crypto;
#[macro_use] extern crate hyper;
extern crate rustc_serialize;
extern crate time;
use rustc_serialize::hex::ToHex;
pub mod hook;
pub mod rep;

use crypto::mac::Mac;
use crypto::hmac::Hmac;
use crypto::sha1::Sha1;
use hook::Hook;

use hyper::server::{Handler, Server, Request, Response};
use rep::{Payload, Ping};
use rustc_serialize::json::{self, DecodeResult};
use std::collections::HashMap;
use std::thread;
use std::io::Read;
use std::sync::Mutex;
use std::sync::mpsc::{channel, Receiver, Sender};

/// signature for request
/// see [this document](https://developer.github.com/webhooks/securing/) for more information
header! {(XHubSignature, "X-Hub-Signature") => [String]}

/// name of Github event
/// see [this document](https://developer.github.com/webhooks/#events) for available types
header! {(XGithubEvent, "X-Github-Event") => [String]}

/// unique id for each delivery
header! {(XGithubDelivery, "X-Github-Deliver") => [String]}

/// Raw, unparsed representation of an inbound github event
#[derive(Clone, Debug, Default)]
pub struct Event {
  pub delivery: String,
  pub name: String,
  pub payload: String
}

/// A hub is a handler for github event requests
struct Hub {
  secret: Option<String>,
  deliveries: Mutex<Sender<Event>>,
  hooks: Vec<Hook>
}

impl Hub {
  pub fn authenticate(secret: &String, payload: &String, signature: &String) -> bool {
    let sbytes = secret.as_bytes();
    let pbytes = payload.as_bytes();
    let mut mac = Hmac::new(Sha1::new(), &sbytes);
    mac.input(&pbytes);
    mac.result().code().to_hex() == str::replace(signature, "sha1=", "")
  }
}

impl Handler for Hub {
  fn handle(&self, mut req: Request, res: Response) {
    let mut payload = String::new();
    let headers = req.headers.clone();
    let delivery = match headers.get::<XGithubDelivery>() {
      Some(&XGithubDelivery(ref delivery)) => delivery.clone(),
      _ => "".to_owned()
    };
    if let Some(&XGithubEvent(ref event)) = headers.get::<XGithubEvent>() {
      if let Ok(_) = req.read_to_string(&mut payload) {
        info!("recv '{}' event", event);
        let deliver = || {
          let _ = self.deliveries.lock().unwrap().send(Event {
            delivery: delivery.clone(),
            name: event.clone(),
            payload: payload.clone()
          });
        };
        if let Some(ref secret) = self.secret {
           match headers.get::<XHubSignature>() {
             Some(sig) => {
                 if Hub::authenticate(&secret, &payload, &sig) {
                   deliver()
                 } else {
                   warn!("recv invalid signature for payload");
                 }
              },
                     _  => warn!("recv unsigned request recieved")
           }
        } else {
          deliver()
        }
      }
    }
    let _ = res.send(b"ok");
    ()
  }
}

/// Filters filter inbound events, invoking interested hooks
struct Filter { hooks: Vec<Hook> }

impl Filter {

  /// filters hooks based on event name
  /// `*` will match any event
  pub fn filter(&self, ev: &Event, payload: &Payload) -> Vec<&Hook> {
    (*self.hooks).into_iter()
      .filter(|h| h.targets(&ev.name, payload))
      .collect::<Vec<&Hook>>()
  }

  /// recv's github events from rx and sends them
  /// to interested hooks.
  /// a thread will be spawned once for each hook
  /// before awaiting the reciept of events
  pub fn recv(&self, rx: Receiver<Event>) {
    let mut lookup     = HashMap::new();
    let mut deliveries = HashMap::new();
    for hook in (&self.hooks).iter() {
      lookup.insert((*hook).clone().name(), (*hook).clone());
    }
    for (name, hook) in lookup.into_iter() {
      let (tx, rx) = channel();
      deliveries.insert(name.clone(), tx);
      thread::spawn(move || {
        hook.recv(rx);
      });
    }
    while let Ok(ev) = rx.recv() {
      fn parse_payload(raw: &String) -> DecodeResult<Payload> {
        json::decode::<Payload>(&raw).or(
          json::decode::<Ping>(&raw).map(|p|p.hook)
        )
      }
      match parse_payload(&ev.payload) {
        Ok(payload) => {
          let hooks = self.filter(&ev, &payload);
          for h in hooks {
            let name = h.clone().name();
            if let Err(e) = deliveries.get(&name).unwrap().send(ev.clone()) {
              error!("{} delivery to {} failed: {}", ev.name, name, e.to_string())
            }
          }
        }, _ => warn!("rec unparsable payload {:?}", ev.payload)
      }
    }
  }
}

/// A Service serves inbound requests for github events
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Service {
  pub secret: Option<String>,
  pub port: Option<u16>,
  pub hooks: Vec<Hook>
}

impl Service {

  /// return the configured port or 4567
  pub fn port(&self) -> u16 {
    self.port.unwrap_or(4567)
  }

  /// sets the current list of hooks in memory
  pub fn hooks(&mut self, hooks: Vec<Hook>) {
    self.hooks = hooks;
  }

  /// starts listening on the configured port
  pub fn run(self) {
    let (tx, rx) = channel();
    let hooks = self.hooks.clone();
    thread::spawn(move || {
      let filter = Filter { hooks: hooks };
      filter.recv(rx)
    });
    let addr = format!("0.0.0.0:{}", self.port());
    let srvc = Server::http(&addr[..]).unwrap()
      .handle(Hub {
         secret: self.secret,
         deliveries: Mutex::new(tx),
         hooks: self.hooks
      });
    println!("listening on {}", addr);
    srvc.unwrap();
  }
}

#[cfg(test)]
mod tests {
  use rustc_serialize::json;
  use super::{Event, Filter, Service};
  use super::hook::Hook;
  use super::rep::Payload;

  #[test]
  fn test_filter() {
    let hooks = vec![
      Hook {
        events: vec![
          "a".to_owned(),
          "b".to_owned()
        ],
        ..Default::default()
      },
      Hook {
        events: vec![
          "a".to_owned(),
          "c".to_owned()
        ],
        ..Default::default()
      },
      Hook {
        events: vec!["*".to_owned()],
        ..Default::default()
      }
    ];
    let filter = Filter { hooks: hooks };

    assert_eq!(3, filter.filter(&Event {
      name: "a".to_owned(),
      ..Default::default()
    }, &Payload {
       ..Default::default()
    }).len());

    assert_eq!(2, filter.filter(&Event {
      name: "c".to_owned(),
      ..Default::default()
    }, &Payload {
      ..Default::default()
    }).len())
  }

  #[test]
  fn test_service_config() {
    match json::decode::<Service>(&r#"{
     "hooks": [{
       "cmd": "ls",
       "events": ["test"]
     }]
    }"#) {
      Ok(svc) => {
         assert_eq!(4567, svc.port());
         assert_eq!(1, svc.hooks.len());
      },
      Err(e) => panic!("failed to decode service {}", e)
    }
  }
}
<commit_msg>typo in delivery header name<commit_after>
#[macro_use]
extern crate log;

extern crate crypto;
#[macro_use] extern crate hyper;
extern crate rustc_serialize;
extern crate time;
use rustc_serialize::hex::ToHex;
pub mod hook;
pub mod rep;

use crypto::mac::Mac;
use crypto::hmac::Hmac;
use crypto::sha1::Sha1;
use hook::Hook;

use hyper::server::{Handler, Server, Request, Response};
use rep::{Payload, Ping};
use rustc_serialize::json::{self, DecodeResult};
use std::collections::HashMap;
use std::thread;
use std::io::Read;
use std::sync::Mutex;
use std::sync::mpsc::{channel, Receiver, Sender};

/// signature for request
/// see [this document](https://developer.github.com/webhooks/securing/) for more information
header! {(XHubSignature, "X-Hub-Signature") => [String]}

/// name of Github event
/// see [this document](https://developer.github.com/webhooks/#events) for available types
header! {(XGithubEvent, "X-Github-Event") => [String]}

/// unique id for each delivery
header! {(XGithubDelivery, "X-Github-Delivery") => [String]}

/// Raw, unparsed representation of an inbound github event
#[derive(Clone, Debug, Default)]
pub struct Event {
  pub delivery: String,
  pub name: String,
  pub payload: String
}

/// A hub is a handler for github event requests
struct Hub {
  secret: Option<String>,
  deliveries: Mutex<Sender<Event>>,
  pub hooks: Vec<Hook>
}

impl Hub {
  pub fn authenticate(secret: &String, payload: &String, signature: &String) -> bool {
    let sbytes = secret.as_bytes();
    let pbytes = payload.as_bytes();
    let mut mac = Hmac::new(Sha1::new(), &sbytes);
    mac.input(&pbytes);
    mac.result().code().to_hex() == str::replace(signature, "sha1=", "")
  }
}

impl Handler for Hub {
  fn handle(&self, mut req: Request, res: Response) {
    let mut payload = String::new();
    let headers = req.headers.clone();
    let delivery = match headers.get::<XGithubDelivery>() {
      Some(&XGithubDelivery(ref delivery)) => delivery.clone(),
      _ => "".to_owned()
    };
    if let Some(&XGithubEvent(ref event)) = headers.get::<XGithubEvent>() {
      if let Ok(_) = req.read_to_string(&mut payload) {
        info!("recv '{}' event", event);
        let deliver = || {
          let _ = self.deliveries.lock().unwrap().send(Event {
            delivery: delivery.clone(),
            name: event.clone(),
            payload: payload.clone()
          });
        };
        if let Some(ref secret) = self.secret {
           match headers.get::<XHubSignature>() {
             Some(sig) => {
                 if Hub::authenticate(&secret, &payload, &sig) {
                   deliver()
                 } else {
                   warn!("recv invalid signature for payload");
                 }
              },
                     _  => warn!("recv unsigned request recieved")
           }
        } else {
          deliver()
        }
      }
    }
    let _ = res.send(b"ok");
    ()
  }
}

/// Filters filter inbound events, invoking interested hooks
struct Filter { hooks: Vec<Hook> }

impl Filter {

  /// filters hooks based on event name
  /// `*` will match any event
  pub fn filter(&self, ev: &Event, payload: &Payload) -> Vec<&Hook> {
    (*self.hooks).into_iter()
      .filter(|h| h.targets(&ev.name, payload))
      .collect::<Vec<&Hook>>()
  }

  /// recv's github events from rx and sends them
  /// to interested hooks.
  /// a thread will be spawned once for each hook
  /// before awaiting the reciept of events
  pub fn recv(&self, rx: Receiver<Event>) {
    let mut lookup     = HashMap::new();
    let mut deliveries = HashMap::new();
    for hook in (&self.hooks).iter() {
      lookup.insert((*hook).clone().name(), (*hook).clone());
    }
    for (name, hook) in lookup.into_iter() {
      let (tx, rx) = channel();
      deliveries.insert(name.clone(), tx);
      thread::spawn(move || {
        hook.recv(rx);
      });
    }
    while let Ok(ev) = rx.recv() {
      fn parse_payload(raw: &String) -> DecodeResult<Payload> {
        json::decode::<Payload>(&raw).or(
          json::decode::<Ping>(&raw).map(|p|p.hook)
        )
      }
      match parse_payload(&ev.payload) {
        Ok(payload) => {
          let hooks = self.filter(&ev, &payload);
          for h in hooks {
            let name = h.clone().name();
            if let Err(e) = deliveries.get(&name).unwrap().send(ev.clone()) {
              error!("{} delivery to {} failed: {}", ev.name, name, e.to_string())
            }
          }
        }, _ => warn!("rec unparsable payload {:?}", ev.payload)
      }
    }
  }
}

/// A Service serves inbound requests for github events
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Service {
  pub secret: Option<String>,
  pub port: Option<u16>,
  pub hooks: Vec<Hook>
}

impl Service {

  /// return the configured port or 4567
  pub fn port(&self) -> u16 {
    self.port.unwrap_or(4567)
  }

  /// sets the current list of hooks in memory
  pub fn hooks(&mut self, hooks: Vec<Hook>) {
    self.hooks = hooks;
  }

  /// starts listening on the configured port
  pub fn run(self) {
    let (tx, rx) = channel();
    let hooks = self.hooks.clone();
    thread::spawn(move || {
      let filter = Filter { hooks: hooks };
      filter.recv(rx)
    });
    let addr = format!("0.0.0.0:{}", self.port());
    let srvc = Server::http(&addr[..]).unwrap()
      .handle(Hub {
         secret: self.secret,
         deliveries: Mutex::new(tx),
         hooks: self.hooks
      });
    println!("listening on {}", addr);
    srvc.unwrap();
  }
}

#[cfg(test)]
mod tests {
  use rustc_serialize::json;
  use super::{Event, Filter, Service};
  use super::hook::Hook;
  use super::rep::Payload;

  #[test]
  fn test_filter() {
    let hooks = vec![
      Hook {
        events: vec![
          "a".to_owned(),
          "b".to_owned()
        ],
        ..Default::default()
      },
      Hook {
        events: vec![
          "a".to_owned(),
          "c".to_owned()
        ],
        ..Default::default()
      },
      Hook {
        events: vec!["*".to_owned()],
        ..Default::default()
      }
    ];
    let filter = Filter { hooks: hooks };

    assert_eq!(3, filter.filter(&Event {
      name: "a".to_owned(),
      ..Default::default()
    }, &Payload {
       ..Default::default()
    }).len());

    assert_eq!(2, filter.filter(&Event {
      name: "c".to_owned(),
      ..Default::default()
    }, &Payload {
      ..Default::default()
    }).len())
  }

  #[test]
  fn test_service_config() {
    match json::decode::<Service>(&r#"{
     "hooks": [{
       "cmd": "ls",
       "events": ["test"]
     }]
    }"#) {
      Ok(svc) => {
         assert_eq!(4567, svc.port());
         assert_eq!(1, svc.hooks.len());
      },
      Err(e) => panic!("failed to decode service {}", e)
    }
  }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

#![feature(custom_derive, plugin, custom_attribute)]
#![feature(conservative_impl_trait)]

// #![deny(missing_docs,
//         missing_debug_implementations, missing_copy_implementations,
//         trivial_casts, trivial_numeric_casts,
//         unsafe_code,
//         unstable_features,
//         unused_import_braces, unused_qualifications)]

#![recursion_limit = "1024"]
#[macro_use]
extern crate error_chain;

extern crate openssl;
extern crate rustc_serialize;
extern crate chrono;
extern crate url;

#[macro_use]
extern crate hyper;
extern crate hyper_openssl;

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

pub use errors::*;
pub mod errors;
pub mod authentication;
mod http_headers;
mod utils;
pub mod config;
pub mod api_client;
pub mod requests;
<commit_msg>remove some unused features<commit_after>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

#![feature(conservative_impl_trait)]

// #![deny(missing_docs,
//         missing_debug_implementations, missing_copy_implementations,
//         trivial_casts, trivial_numeric_casts,
//         unsafe_code,
//         unstable_features,
//         unused_import_braces, unused_qualifications)]

#![recursion_limit = "1024"]
#[macro_use]
extern crate error_chain;

extern crate openssl;
extern crate rustc_serialize;
extern crate chrono;
extern crate url;

#[macro_use]
extern crate hyper;
extern crate hyper_openssl;

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

pub use errors::*;
pub mod errors;
pub mod authentication;
mod http_headers;
mod utils;
pub mod config;
pub mod api_client;
pub mod requests;
<|endoftext|>


<commit_before>#![crate_name="civet"]
#![crate_type="rlib"]
#![feature(unsafe_destructor)]

extern crate libc;
extern crate debug;
extern crate native;
extern crate collections;
extern crate semver;
extern crate conduit;

use std::io;
use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::{IoResult, util, BufferedWriter};
use std::collections::HashMap;

use conduit::{Request, HeaderEntries, Handler, Extensions, TypeMap};

use raw::{RequestInfo,Header};
use raw::{get_header,get_headers,get_request_info};
use status::{ToStatusCode};

pub use raw::Config;

mod raw;
pub mod status;

pub struct Connection<'a> {
    request: CivetRequest<'a>,
    written: bool,
}

pub struct CivetRequest<'a> {
    conn: &'a raw::Connection,
    request_info: RequestInfo<'a>,
    headers: Headers<'a>,
    extensions: Extensions
}

fn ver(major: uint, minor: uint) -> semver::Version {
    semver::Version {
        major: major,
        minor: minor,
        patch: 0,
        pre: vec!(),
        build: vec!()
    }
}

impl<'a> conduit::Request for CivetRequest<'a> {
    fn http_version(&self) -> semver::Version {
        let version = self.request_info.http_version().unwrap();
        match version {
            "1.0" => ver(1, 0),
            "1.1" => ver(1, 1),
            _ => ver(1, 1)
        }
    }

    fn conduit_version(&self) -> semver::Version {
        ver(0, 1)
    }

    fn method(&self) -> conduit::Method {
        match self.request_info.method().unwrap() {
            "HEAD" => conduit::Head,
            "GET" => conduit::Get,
            "POST" => conduit::Post,
            "PUT" => conduit::Put,
            "DELETE" => conduit::Delete,
            "PATCH" => conduit::Patch,
            "PURGE" => conduit::Purge,
            "CONNECT" => conduit::Connect,
            "OPTIONS" => conduit::Options,
            "TRACE" => conduit::Trace,
            other @ _ => fail!("Civet does not support {} requests", other)
        }
    }

    fn scheme(&self) -> conduit::Scheme {
        if self.request_info.is_ssl() {
            conduit::Https
        } else {
            conduit::Http
        }
    }

    fn host<'a>(&'a self) -> conduit::Host<'a> {
        conduit::HostName(get_header(self.conn, "Host").unwrap())
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        None
    }

    fn path<'a>(&'a self) -> &'a str {
        self.request_info.url().unwrap()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request_info.query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        let ip = self.request_info.remote_ip();
        Ipv4Addr((ip >> 24) as u8,
                 (ip >> 16) as u8,
                 (ip >>  8) as u8,
                 (ip >>  0) as u8)
    }

    fn content_length(&self) -> Option<uint> {
        get_header(self.conn, "Content-Length").and_then(from_str)
    }

    fn headers<'a>(&'a self) -> &'a conduit::Headers {
        &self.headers as &conduit::Headers
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self as &mut Reader
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        &self.extensions
    }

    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
        &mut self.extensions
    }
}

pub fn response<S: ToStatusCode, R: Reader + Send>(status: S,
    headers: HashMap<String, Vec<String>>, body: R) -> conduit::Response
{
    conduit::Response {
        status: status.to_status().unwrap().to_code(),
        headers: headers,
        body: box body as Box<Reader + Send>
    }
}

impl<'a> Connection<'a> {
    fn new<'a>(conn: &'a raw::Connection) -> Result<Connection<'a>, String> {
        match request_info(conn) {
            Ok(info) => {
                let request = CivetRequest {
                    conn: conn,
                    request_info: info,
                    headers: Headers { conn: conn },
                    extensions: TypeMap::new()
                };

                Ok(Connection {
                    request: request,
                    written: false,
                })
            },
            Err(err) => Err(err)
        }
    }

}

impl<'a> Writer for Connection<'a> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.written = true;
        write_bytes(self.request.conn, buf).map_err(|_| {
            io::standard_error(io::IoUnavailable)
        })
    }
}

impl<'a> Reader for CivetRequest<'a> {
    fn read(&mut self, buf: &mut[u8]) -> IoResult<uint> {
        let ret = raw::read(self.conn, buf);

        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(ret as uint)
        }
    }
}

#[unsafe_destructor]
impl<'a> Drop for Connection<'a> {
    fn drop(&mut self) {
        if !self.written {
            let _ = writeln!(self, "HTTP/1.1 500 Internal Server Error");
        }
    }
}

pub struct Headers<'a> {
    conn: &'a raw::Connection
}

impl<'a> conduit::Headers for Headers<'a> {
    fn find<'a>(&'a self, string: &str) -> Option<Vec<&'a str>> {
        get_header(self.conn, string).map(|s| vec!(s))
    }

    fn has(&self, string: &str) -> bool {
        get_header(self.conn, string).is_some()
    }

    fn iter<'a>(&'a self) -> conduit::HeaderEntries<'a> {
        box HeaderIterator::new(self.conn) as conduit::HeaderEntries<'a>
    }
}

pub struct HeaderIterator<'a> {
    headers: Vec<Header<'a>>,
    position: uint
}

impl<'a> HeaderIterator<'a> {
    fn new<'b>(conn: &'b raw::Connection) -> HeaderIterator<'b> {
        HeaderIterator { headers: get_headers(conn), position: 0 }
    }
}

impl<'a> Iterator<(&'a str, Vec<&'a str>)> for HeaderIterator<'a> {
    fn next(&mut self) -> Option<(&'a str, Vec<&'a str>)> {
        let pos = self.position;
        let headers = &self.headers;

        if self.headers.len() <= pos {
            None
        } else {
            let header = &headers[pos];
            self.position += 1;
            header.name().map(|name| (name, vec!(header.value().unwrap())))
        }
    }
}

pub struct Server(raw::Server<Box<Handler + 'static + Sync>>);

impl Server {
    pub fn start<H: Handler + 'static + Sync>(options: Config, handler: H)
        -> IoResult<Server>
    {
        fn internal_handler(conn: &mut raw::Connection,
                            handler: &Box<Handler + 'static + Sync>)
                            -> Result<(), ()> {
            let mut connection = Connection::new(conn).unwrap();
            let response = handler.call(&mut connection.request);
            let mut writer = BufferedWriter::new(connection);

            fn err<W: Writer>(writer: &mut W) {
                let _ = writeln!(writer, "HTTP/1.1 500 Internal Server Error");
            }

            let conduit::Response { status, headers, mut body } = match response {
                Ok(r) => r,
                Err(_) => return Err(err(&mut writer)),
            };
            let (code, string) = status;
            try!(write!(&mut writer, "HTTP/1.1 {:u} {:s}\r\n", code, string).map_err(|_| ()));

            for (key, value) in headers.iter() {
                for header in value.iter() {
                    try!(write!(&mut writer, "{:s}: {:s}\r\n", *key, *header).map_err(|_| ()));
                }
            }

            try!(write!(&mut writer, "\r\n").map_err(|_| ()));
            let mut body: &mut Reader = &mut *body;
            try!(util::copy(&mut body, &mut writer).map_err(|_| ()));

            Ok(())
        }

        let handler = box handler;
        let raw_callback = raw::ServerCallback::new(internal_handler, handler);
        Ok(Server(try!(raw::Server::start(options, raw_callback))))
    }
}

fn write_bytes(connection: &raw::Connection, bytes: &[u8]) -> Result<(), String> {
    let ret = raw::write(connection, bytes);

    if ret == -1 {
        return Err("Couldn't write bytes to the connection".to_string())
    }

    Ok(())
}

fn request_info<'a>(connection: &'a raw::Connection)
    -> Result<RequestInfo<'a>, String>
{
    match get_request_info(connection) {
        Some(info) => Ok(info),
        None => Err("Couldn't get request info for connection".to_string())
    }
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use std::io::net::ip::SocketAddr;
    use std::io::net::tcp::TcpStream;
    use std::io::test::next_test_ip4;
    use std::io::{IoResult, MemReader};
    use std::fmt::Show;
    use std::sync::Mutex;
    use super::{Server, Config, response};
    use conduit::{Request, Response, Handler};

    fn noop(_: &mut Request) -> IoResult<Response> { unreachable!() }

    fn request(addr: SocketAddr, req: &str) -> String {
        let mut s = TcpStream::connect(addr.ip.to_string().as_slice(),
                                       addr.port).unwrap();
        s.write_str(req.trim_left()).unwrap();
        s.read_to_string().unwrap()
    }

    #[test]
    fn smoke() {
        let addr = next_test_ip4();
        Server::start(Config { port: addr.port, threads: 1 }, noop).unwrap();
    }

    #[test]
    fn dupe_port() {
        let addr = next_test_ip4();
        let s1 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s1.is_ok());
        let s2 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s2.is_err());
    }

    #[test]
    fn drops_handler() {
        static mut DROPPED: bool = false;
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                fail!()
            }
        }
        impl Drop for Foo {
            fn drop(&mut self) { unsafe { DROPPED = true; } }
        }

        let addr = next_test_ip4();
        drop(Server::start(Config { port: addr.port, threads: 1 }, Foo));
        unsafe { assert!(DROPPED); }
    }

    #[test]
    fn invokes() {
        struct Foo(Mutex<Sender<()>>);
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                let Foo(ref tx) = *self;
                tx.lock().send(());
                Ok(response(200i, HashMap::new(), MemReader::new(vec![])))
            }
        }

        let addr = next_test_ip4();
        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let _s = Server::start(Config { port: addr.port, threads: 1 }, handler);
        request(addr, r"
GET / HTTP/1.1

");
        rx.recv();
    }

    #[test]
    fn header_sent() {
        struct Foo(Mutex<Sender<String>>);
        impl Handler for Foo {
            fn call(&self, req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                let Foo(ref tx) = *self;
                tx.lock().send(req.headers().find("Foo").unwrap().connect(""));
                Ok(response(200i, HashMap::new(), MemReader::new(vec![])))
            }
        }

        let addr = next_test_ip4();
        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let _s = Server::start(Config { port: addr.port, threads: 1 }, handler);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert_eq!(rx.recv().as_slice(), "bar");
    }

    #[test]
    fn failing_handler() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                fail!()
            }
        }

        let addr = next_test_ip4();
        let _s = Server::start(Config { port: addr.port, threads: 1 }, Foo);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
    }

    #[test]
    fn failing_handler_is_500() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                fail!()
            }
        }

        let addr = next_test_ip4();
        let _s = Server::start(Config { port: addr.port, threads: 1 }, Foo);
        let response = request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert!(response.as_slice().contains("500 Internal"),
                "not a failing response: {}", response);
    }
}
<commit_msg>Remove the `debug` crate<commit_after>#![crate_name="civet"]
#![crate_type="rlib"]
#![feature(unsafe_destructor)]

extern crate libc;
extern crate native;
extern crate collections;
extern crate semver;
extern crate conduit;

use std::io;
use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::{IoResult, util, BufferedWriter};
use std::collections::HashMap;

use conduit::{Request, HeaderEntries, Handler, Extensions, TypeMap};

use raw::{RequestInfo,Header};
use raw::{get_header,get_headers,get_request_info};
use status::{ToStatusCode};

pub use raw::Config;

mod raw;
pub mod status;

pub struct Connection<'a> {
    request: CivetRequest<'a>,
    written: bool,
}

pub struct CivetRequest<'a> {
    conn: &'a raw::Connection,
    request_info: RequestInfo<'a>,
    headers: Headers<'a>,
    extensions: Extensions
}

fn ver(major: uint, minor: uint) -> semver::Version {
    semver::Version {
        major: major,
        minor: minor,
        patch: 0,
        pre: vec!(),
        build: vec!()
    }
}

impl<'a> conduit::Request for CivetRequest<'a> {
    fn http_version(&self) -> semver::Version {
        let version = self.request_info.http_version().unwrap();
        match version {
            "1.0" => ver(1, 0),
            "1.1" => ver(1, 1),
            _ => ver(1, 1)
        }
    }

    fn conduit_version(&self) -> semver::Version {
        ver(0, 1)
    }

    fn method(&self) -> conduit::Method {
        match self.request_info.method().unwrap() {
            "HEAD" => conduit::Head,
            "GET" => conduit::Get,
            "POST" => conduit::Post,
            "PUT" => conduit::Put,
            "DELETE" => conduit::Delete,
            "PATCH" => conduit::Patch,
            "PURGE" => conduit::Purge,
            "CONNECT" => conduit::Connect,
            "OPTIONS" => conduit::Options,
            "TRACE" => conduit::Trace,
            other @ _ => fail!("Civet does not support {} requests", other)
        }
    }

    fn scheme(&self) -> conduit::Scheme {
        if self.request_info.is_ssl() {
            conduit::Https
        } else {
            conduit::Http
        }
    }

    fn host<'a>(&'a self) -> conduit::Host<'a> {
        conduit::HostName(get_header(self.conn, "Host").unwrap())
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        None
    }

    fn path<'a>(&'a self) -> &'a str {
        self.request_info.url().unwrap()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request_info.query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        let ip = self.request_info.remote_ip();
        Ipv4Addr((ip >> 24) as u8,
                 (ip >> 16) as u8,
                 (ip >>  8) as u8,
                 (ip >>  0) as u8)
    }

    fn content_length(&self) -> Option<uint> {
        get_header(self.conn, "Content-Length").and_then(from_str)
    }

    fn headers<'a>(&'a self) -> &'a conduit::Headers {
        &self.headers as &conduit::Headers
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self as &mut Reader
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        &self.extensions
    }

    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
        &mut self.extensions
    }
}

pub fn response<S: ToStatusCode, R: Reader + Send>(status: S,
    headers: HashMap<String, Vec<String>>, body: R) -> conduit::Response
{
    conduit::Response {
        status: status.to_status().unwrap().to_code(),
        headers: headers,
        body: box body as Box<Reader + Send>
    }
}

impl<'a> Connection<'a> {
    fn new<'a>(conn: &'a raw::Connection) -> Result<Connection<'a>, String> {
        match request_info(conn) {
            Ok(info) => {
                let request = CivetRequest {
                    conn: conn,
                    request_info: info,
                    headers: Headers { conn: conn },
                    extensions: TypeMap::new()
                };

                Ok(Connection {
                    request: request,
                    written: false,
                })
            },
            Err(err) => Err(err)
        }
    }

}

impl<'a> Writer for Connection<'a> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.written = true;
        write_bytes(self.request.conn, buf).map_err(|_| {
            io::standard_error(io::IoUnavailable)
        })
    }
}

impl<'a> Reader for CivetRequest<'a> {
    fn read(&mut self, buf: &mut[u8]) -> IoResult<uint> {
        let ret = raw::read(self.conn, buf);

        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(ret as uint)
        }
    }
}

#[unsafe_destructor]
impl<'a> Drop for Connection<'a> {
    fn drop(&mut self) {
        if !self.written {
            let _ = writeln!(self, "HTTP/1.1 500 Internal Server Error");
        }
    }
}

pub struct Headers<'a> {
    conn: &'a raw::Connection
}

impl<'a> conduit::Headers for Headers<'a> {
    fn find<'a>(&'a self, string: &str) -> Option<Vec<&'a str>> {
        get_header(self.conn, string).map(|s| vec!(s))
    }

    fn has(&self, string: &str) -> bool {
        get_header(self.conn, string).is_some()
    }

    fn iter<'a>(&'a self) -> conduit::HeaderEntries<'a> {
        box HeaderIterator::new(self.conn) as conduit::HeaderEntries<'a>
    }
}

pub struct HeaderIterator<'a> {
    headers: Vec<Header<'a>>,
    position: uint
}

impl<'a> HeaderIterator<'a> {
    fn new<'b>(conn: &'b raw::Connection) -> HeaderIterator<'b> {
        HeaderIterator { headers: get_headers(conn), position: 0 }
    }
}

impl<'a> Iterator<(&'a str, Vec<&'a str>)> for HeaderIterator<'a> {
    fn next(&mut self) -> Option<(&'a str, Vec<&'a str>)> {
        let pos = self.position;
        let headers = &self.headers;

        if self.headers.len() <= pos {
            None
        } else {
            let header = &headers[pos];
            self.position += 1;
            header.name().map(|name| (name, vec!(header.value().unwrap())))
        }
    }
}

pub struct Server(raw::Server<Box<Handler + 'static + Sync>>);

impl Server {
    pub fn start<H: Handler + 'static + Sync>(options: Config, handler: H)
        -> IoResult<Server>
    {
        fn internal_handler(conn: &mut raw::Connection,
                            handler: &Box<Handler + 'static + Sync>)
                            -> Result<(), ()> {
            let mut connection = Connection::new(conn).unwrap();
            let response = handler.call(&mut connection.request);
            let mut writer = BufferedWriter::new(connection);

            fn err<W: Writer>(writer: &mut W) {
                let _ = writeln!(writer, "HTTP/1.1 500 Internal Server Error");
            }

            let conduit::Response { status, headers, mut body } = match response {
                Ok(r) => r,
                Err(_) => return Err(err(&mut writer)),
            };
            let (code, string) = status;
            try!(write!(&mut writer, "HTTP/1.1 {:u} {:s}\r\n", code, string).map_err(|_| ()));

            for (key, value) in headers.iter() {
                for header in value.iter() {
                    try!(write!(&mut writer, "{:s}: {:s}\r\n", *key, *header).map_err(|_| ()));
                }
            }

            try!(write!(&mut writer, "\r\n").map_err(|_| ()));
            let mut body: &mut Reader = &mut *body;
            try!(util::copy(&mut body, &mut writer).map_err(|_| ()));

            Ok(())
        }

        let handler = box handler;
        let raw_callback = raw::ServerCallback::new(internal_handler, handler);
        Ok(Server(try!(raw::Server::start(options, raw_callback))))
    }
}

fn write_bytes(connection: &raw::Connection, bytes: &[u8]) -> Result<(), String> {
    let ret = raw::write(connection, bytes);

    if ret == -1 {
        return Err("Couldn't write bytes to the connection".to_string())
    }

    Ok(())
}

fn request_info<'a>(connection: &'a raw::Connection)
    -> Result<RequestInfo<'a>, String>
{
    match get_request_info(connection) {
        Some(info) => Ok(info),
        None => Err("Couldn't get request info for connection".to_string())
    }
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use std::io::net::ip::SocketAddr;
    use std::io::net::tcp::TcpStream;
    use std::io::test::next_test_ip4;
    use std::io::{IoResult, MemReader};
    use std::fmt::Show;
    use std::sync::Mutex;
    use super::{Server, Config, response};
    use conduit::{Request, Response, Handler};

    fn noop(_: &mut Request) -> IoResult<Response> { unreachable!() }

    fn request(addr: SocketAddr, req: &str) -> String {
        let mut s = TcpStream::connect(addr.ip.to_string().as_slice(),
                                       addr.port).unwrap();
        s.write_str(req.trim_left()).unwrap();
        s.read_to_string().unwrap()
    }

    #[test]
    fn smoke() {
        let addr = next_test_ip4();
        Server::start(Config { port: addr.port, threads: 1 }, noop).unwrap();
    }

    #[test]
    fn dupe_port() {
        let addr = next_test_ip4();
        let s1 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s1.is_ok());
        let s2 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s2.is_err());
    }

    #[test]
    fn drops_handler() {
        static mut DROPPED: bool = false;
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                fail!()
            }
        }
        impl Drop for Foo {
            fn drop(&mut self) { unsafe { DROPPED = true; } }
        }

        let addr = next_test_ip4();
        drop(Server::start(Config { port: addr.port, threads: 1 }, Foo));
        unsafe { assert!(DROPPED); }
    }

    #[test]
    fn invokes() {
        struct Foo(Mutex<Sender<()>>);
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                let Foo(ref tx) = *self;
                tx.lock().send(());
                Ok(response(200i, HashMap::new(), MemReader::new(vec![])))
            }
        }

        let addr = next_test_ip4();
        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let _s = Server::start(Config { port: addr.port, threads: 1 }, handler);
        request(addr, r"
GET / HTTP/1.1

");
        rx.recv();
    }

    #[test]
    fn header_sent() {
        struct Foo(Mutex<Sender<String>>);
        impl Handler for Foo {
            fn call(&self, req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                let Foo(ref tx) = *self;
                tx.lock().send(req.headers().find("Foo").unwrap().connect(""));
                Ok(response(200i, HashMap::new(), MemReader::new(vec![])))
            }
        }

        let addr = next_test_ip4();
        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let _s = Server::start(Config { port: addr.port, threads: 1 }, handler);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert_eq!(rx.recv().as_slice(), "bar");
    }

    #[test]
    fn failing_handler() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                fail!()
            }
        }

        let addr = next_test_ip4();
        let _s = Server::start(Config { port: addr.port, threads: 1 }, Foo);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
    }

    #[test]
    fn failing_handler_is_500() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                fail!()
            }
        }

        let addr = next_test_ip4();
        let _s = Server::start(Config { port: addr.port, threads: 1 }, Foo);
        let response = request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert!(response.as_slice().contains("500 Internal"),
                "not a failing response: {}", response);
    }
}
<|endoftext|>


<commit_before>extern crate nom_lua53;

use nom_lua53::{parse_all, ParseResult, Statement, Exp};
use nom_lua53::op::BinOp;

#[derive(Debug)]
pub enum LuaValue {
    Nil,
    Integer(isize),
    Float(f64),
    Boolean(bool),
    Str(String),
}

// What do we say? We say "Merci Basile!"
fn lit_to_string(string: &nom_lua53::string::StringLit) -> String {
    return String::from_utf8_lossy(&(string.0)).to_string();
}

fn eval_addition(left_op: &Box<Exp>, right_op: &Box<Exp>, inverse: bool) -> LuaValue {
    let left_op = eval_expr(&left_op);
    let right_op = eval_expr(&right_op);

    // We're more likely to be in the float realm
    let multiplier = if inverse { -1. } else { 1. };

    match left_op {
        LuaValue::Integer(i) => match right_op {
            LuaValue::Integer(j) => LuaValue::Integer(i+j*(multiplier as isize)),
            LuaValue::Float(j) => LuaValue::Float((i as f64)+j*multiplier),
            _ => panic!("Trying to add non-numeric stuff.")
        },
        LuaValue::Float(i) => match right_op {
            LuaValue::Integer(j) => LuaValue::Float(i+(j as f64)*multiplier),
            LuaValue::Float(j) => LuaValue::Float(i+j*multiplier),
            _ => panic!("Trying to add non-numeric stuff.")
        },
        _ => panic!("Trying to add non-numeric stuff.")
    }
}

fn eval_binary_expr(left_op: &Box<Exp>, right_op: &Box<Exp>, operator: &BinOp) -> LuaValue
{
    // We cannot yet evaluate the operands as some binary operators are used to shortcut
    // evaluation.
    match *operator {
        BinOp::Plus => eval_addition(left_op, right_op, false),
        BinOp::Minus => eval_addition(left_op, right_op, true),
        _ => LuaValue::Nil
    }
}

fn eval_expr(expr: &Exp) -> LuaValue {
    match *expr {
        Exp::Nil => LuaValue::Nil,
        Exp::Bool(val) => LuaValue::Boolean(val),
        Exp::Num(val) => match val {
            nom_lua53::num::Numeral::Float(fl) => LuaValue::Float(fl),
            nom_lua53::num::Numeral::Int(i) => LuaValue::Integer(i),
        },
        Exp::BinExp(ref left, ref op, ref right) => eval_binary_expr(left, right, &op),
        Exp::Str(ref s) => LuaValue::Str(lit_to_string(s)),
        _ => LuaValue::Nil,
    }
}

pub fn eval_file(input: &[u8]) {
    match parse_all(input) {
        ParseResult::Done(blk) => {
            for stmt in blk.stmts {
                println!("{:?}", stmt);
                match stmt {
                    Statement::LVarAssign(ass) => {
                        let values = ass.vals.expect("There should be some values. Why isn't there any value?!");
                        for (var, val) in ass.vars.iter().zip(values.iter()) {
                            let computed_value = eval_expr(val);
                            println!("Assigning {:?} to {:?}", computed_value, var);
                        }
                    }
                    Statement::Assignment(ass) => {
                        println!("Assigning {:?} to {:?}", ass.vals, ass.vars);
                    }
                    _ => {}
                }
            }
        }

        ParseResult::Error(rest, ss) => {
            println!("Error. statements == {:#?}", ss);
            println!("rest == '{}'", String::from_utf8_lossy(rest));
        }
    }
}
<commit_msg>Rewrite the addition function to do arbitrary math<commit_after>extern crate nom_lua53;

use nom_lua53::{parse_all, ParseResult, Statement, Exp};
use nom_lua53::op::BinOp;

#[derive(Debug)]
pub enum LuaValue {
    Nil,
    Integer(isize),
    Float(f64),
    Boolean(bool),
    Str(String),
}

#[derive(Debug)]
pub enum LuaError {
    TypeError(String),
    ArithmeticError(String),
}

use LuaError::*;

type Result<T> = std::result::Result<T, LuaError>;

// What do we say? We say "Merci Basile!"
fn lit_to_string(string: &nom_lua53::string::StringLit) -> String {
    return String::from_utf8_lossy(&(string.0)).to_string();
}

fn eval_arithmetic(left_op: &Box<Exp>, right_op: &Box<Exp>,
                   integer: fn(isize, isize) -> Result<LuaValue>,
                   float: fn(f64, f64) -> Result<LuaValue>) -> Result<LuaValue> {

    let left_op = eval_expr(&left_op)?;
    let right_op = eval_expr(&right_op)?;

    match left_op {
        LuaValue::Integer(i) => match right_op {
            LuaValue::Integer(j) => integer(i, j),
            LuaValue::Float(j) => float(i as f64, j),
            _ => Err(TypeError("Trying to do arithmetic on non-numerical values.".to_owned()))
        },
        LuaValue::Float(i) => match right_op {
            LuaValue::Integer(j) => float(i, j as f64),
            LuaValue::Float(j) => float(i, j),
            _ => Err(TypeError("Trying to do arithmetic on non-numerical values.".to_owned()))
        },
        _ => Err(TypeError("Trying to do arithmetic on non-numerical values.".to_owned()))
    }
}

fn eval_binary_expr(left_op: &Box<Exp>, right_op: &Box<Exp>, operator: &BinOp) -> Result<LuaValue> {
    // We cannot yet evaluate the operands as some binary operators are used to shortcut
    // evaluation.
    match *operator {
        BinOp::Plus => eval_arithmetic(left_op, right_op,
                                       |i, j| Ok(LuaValue::Integer(i+j)),
                                       |i, j| Ok(LuaValue::Float(i+j))),
        BinOp::Minus => eval_arithmetic(left_op, right_op,
                                        |i, j| Ok(LuaValue::Integer(i-j)),
                                        |i, j| Ok(LuaValue::Float(i-j))),
        _ => Ok(LuaValue::Nil)
    }
}

fn eval_expr(expr: &Exp) -> Result<LuaValue> {
    match *expr {
        Exp::Nil => Ok(LuaValue::Nil),
        Exp::Bool(val) => Ok(LuaValue::Boolean(val)),
        Exp::Num(val) => Ok(match val {
            nom_lua53::num::Numeral::Float(fl) => LuaValue::Float(fl),
            nom_lua53::num::Numeral::Int(i) => LuaValue::Integer(i),
        }),
        Exp::BinExp(ref left, ref op, ref right) => eval_binary_expr(left, right, &op),
        Exp::Str(ref s) => Ok(LuaValue::Str(lit_to_string(s))),
        _ => Ok(LuaValue::Nil),
    }
}

pub fn eval_file(input: &[u8]) {
    match parse_all(input) {
        ParseResult::Done(blk) => {
            for stmt in blk.stmts {
                println!("{:?}", stmt);
                match stmt {
                    Statement::LVarAssign(ass) => {
                        let values = ass.vals.expect("There should be some values. Why isn't there any value?!");
                        for (var, val) in ass.vars.iter().zip(values.iter()) {
                            let computed_value = eval_expr(val);
                            println!("Assigning {:?} to {:?}", computed_value, var);
                        }
                    }
                    Statement::Assignment(ass) => {
                        println!("Assigning {:?} to {:?}", ass.vals, ass.vars);
                    }
                    _ => {}
                }
            }
        }

        ParseResult::Error(rest, ss) => {
            println!("Error. statements == {:#?}", ss);
            println!("rest == '{}'", String::from_utf8_lossy(rest));
        }
    }
}
<|endoftext|>


<commit_before>//! Library for reading and writing Elasto Mania files.

#![doc(html_root_url = "https://hexjelly.github.io/elma-rust/")]
#![feature(slice_patterns)]
#![feature(plugin)]
#![plugin(clippy)]

extern crate byteorder;

pub mod lev;
pub mod rec;

/// Shared position struct.
#[derive(Debug, Default, PartialEq)]
pub struct Position<T> {
    /// X-position.
    pub x: T,
    /// Y-position.
    pub y: T
}

/// Trims trailing bytes after and including null byte.
pub fn trim_string (data: &[u8]) -> Result<String, std::string::FromUtf8Error> {
    let bytes: Vec<u8> = data.into_iter()
                             .take_while(|&&d| d != 0)
                             .cloned()
                             .collect();

    String::from_utf8(bytes)
}

/// Converts times to various formats
pub fn time_format (time: i32) -> String {
    // TODO: figure out what to return etc.
    time.to_string()
}
<commit_msg>Add bad time format function for now<commit_after>//! Library for reading and writing Elasto Mania files.

#![doc(html_root_url = "https://hexjelly.github.io/elma-rust/")]
#![feature(slice_patterns)]
#![feature(plugin)]
#![plugin(clippy)]

extern crate byteorder;

pub mod lev;
pub mod rec;

/// Shared position struct.
#[derive(Debug, Default, PartialEq)]
pub struct Position<T> {
    /// X-position.
    pub x: T,
    /// Y-position.
    pub y: T
}

/// Trims trailing bytes after and including null byte.
pub fn trim_string (data: &[u8]) -> Result<String, std::string::FromUtf8Error> {
    let bytes: Vec<u8> = data.into_iter()
                             .take_while(|&&d| d != 0)
                             .cloned()
                             .collect();

    String::from_utf8(bytes)
}

/// Converts times to various formats.
pub fn time_format (time: i32) -> String {
    let time = time.to_string().into_bytes();
    let mut formatted = String::from("00:00,00").into_bytes();

    let mut n = 7;
    for byte in time.iter().rev() {
        formatted[n] = *byte;
        if n == 6 || n == 3 {
            n -= 2;
        } else if n > 0 {
            n -= 1;
        }
    }

    String::from_utf8(formatted).unwrap()
}
<|endoftext|>


<commit_before>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! Attempt of creating a cheap drawing context.

use std::num::Float;

pub type Matrix2d = [f64, ..6];
pub type Color = [f64, ..4];

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

/// Multiplies two matrices.
#[inline(always)]
pub fn multiply(m: &[f64, ..6], b: &[f64, ..6]) -> [f64, ..6] {
    [m[0]*b[0]+m[1]*b[3]+m[2]*0.0,  m[0]*b[1]+m[1]*b[4]+m[2]*0.0,  m[0]*b[2]+m[1]*b[5]+m[2]*1.0,
     m[3]*b[0]+m[4]*b[3]+m[5]*0.0,  m[3]*b[1]+m[4]*b[4]+m[5]*0.0,  m[3]*b[2]+m[4]*b[5]+m[5]*1.0]
}

/// Drawing 2d context.
pub struct Context<'a> {
    base: Field<'a, Matrix2d>,
    transform: Field<'a, Matrix2d>,
    color: Field<'a, Color>,
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            transform: Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            color: Value([0.0, 0.0, 0.0, 1.0]),
        }
    }

    /// Returns a translated context.
    #[inline(always)]
    pub fn trans(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans: [f64, ..6] = [1.0, 0.0, x,
                                         0.0, 1.0, y];
                 multiply(&trans, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Rotates with degrees.
    #[inline(always)]
    pub fn rot_deg(&'a self, angle: f64) -> Context<'a> {
        let pi: f64 = Float::pi();
        self.rot(angle * pi / 180.0)
    }

    /// Returns a rotated context.
    #[inline(always)]
    pub fn rot(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let c = angle.cos();
                let s = angle.sin();
                let rot: [f64, ..6] = [c, s, 0.0,
                                      -s, c, 0.0];
                multiply(&rot, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }
}

#[test]
fn test_context() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        assert_eq!(d.transform.get()[2], 30.0);
        assert_eq!(d.transform.get()[5], 50.0);
    }
    assert_eq!(c.transform.get()[2], 0.0);
    assert_eq!(c.transform.get()[5], 0.0);

    let c = c.rot_deg(90.0);
    assert!((c.transform.get()[0] - 0.0).abs() < 0.00001);
    assert!((c.transform.get()[1] - 1.0).abs() < 0.00001);
}

<commit_msg>Added scale<commit_after>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! Attempt of creating a cheap drawing context.

use std::num::Float;

pub type Matrix2d = [f64, ..6];
pub type Color = [f64, ..4];

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

/// Multiplies two matrices.
#[inline(always)]
pub fn multiply(m: &[f64, ..6], b: &[f64, ..6]) -> [f64, ..6] {
    [m[0]*b[0]+m[1]*b[3]+m[2]*0.0,  m[0]*b[1]+m[1]*b[4]+m[2]*0.0,  m[0]*b[2]+m[1]*b[5]+m[2]*1.0,
     m[3]*b[0]+m[4]*b[3]+m[5]*0.0,  m[3]*b[1]+m[4]*b[4]+m[5]*0.0,  m[3]*b[2]+m[4]*b[5]+m[5]*1.0]
}

/// Drawing 2d context.
pub struct Context<'a> {
    base: Field<'a, Matrix2d>,
    transform: Field<'a, Matrix2d>,
    color: Field<'a, Color>,
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            transform: Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            color: Value([0.0, 0.0, 0.0, 1.0]),
        }
    }

    /// Returns a translated context.
    #[inline(always)]
    pub fn trans(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans: [f64, ..6] = [1.0, 0.0, x,
                                         0.0, 1.0, y];
                 multiply(&trans, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Rotates with degrees.
    #[inline(always)]
    pub fn rot_deg(&'a self, angle: f64) -> Context<'a> {
        let pi: f64 = Float::pi();
        self.rot(angle * pi / 180.0)
    }

    /// Returns a rotated context.
    #[inline(always)]
    pub fn rot(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let c = angle.cos();
                let s = angle.sin();
                let rot: [f64, ..6] = [c, s, 0.0,
                                      -s, c, 0.0];
                multiply(&rot, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a scaled context.
    #[inline(always)]
    pub fn scale(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale: [f64, ..6] = [sx, 0.0, 0.0,
                                         0.0, sy, 0.0];
                multiply(&scale, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }
}

#[test]
fn test_context() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        assert_eq!(d.transform.get()[2], 30.0);
        assert_eq!(d.transform.get()[5], 50.0);
    }
    assert_eq!(c.transform.get()[2], 0.0);
    assert_eq!(c.transform.get()[5], 0.0);

    let c = c.rot_deg(90.0);
    assert!((c.transform.get()[0] - 0.0).abs() < 0.00001);
    assert!((c.transform.get()[1] - 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    assert!((c.transform.get()[0] - 2.0).abs() < 0.00001);
    assert!((c.transform.get()[4] - 3.0).abs() < 0.00001);
}
<|endoftext|>


<commit_before>
pub fn to_hex(binary: &[u8]) -> String {
	/*
	let mut result = String::new();

	for b in binary.iter() {
		let hex1 = Char::from_digit((*b as uint & 0xf0) >> 4,16);
		let hex2 = Char::from_digit(*b as uint & 0x0f,16);

		result.push(hex1.unwrap());
		result.push(hex2.unwrap());
	}

	result
    */

	fn to_hex_char(byte: u8) -> char { Char::from_digit(byte as uint, 16).unwrap() }

	binary.iter().fold(String::new(), |mut s, &b| { s.push(to_hex_char(b >> 4)); s.push(to_hex_char(b & 0x0f)); s } )
}

pub fn fixed_xor(input1: &[u8], input2: &[u8]) -> Option<Vec<u8>> {

	let mut result = Vec::new();
	let mut second = input2.iter();

	for val1 in input1.iter() {
		match second.next() {
			None => return None,
			Some(val2) => result.push(*val1 ^ *val2)
		}
	}

	return match second.next() {
		None => return Some(result),
		_ => None
	}
}

#[test]
fn to_hex_basics() {
	assert_eq!(to_hex([]), "".to_string());
	assert_eq!(to_hex([0]), "00".to_string());
	assert_eq!(to_hex([1]), "01".to_string());
	assert_eq!(to_hex([16]), "10".to_string());
	assert_eq!(to_hex([255]), "ff".to_string());
	assert_eq!(to_hex([255,1]), "ff01".to_string());

}

#[test]
fn fixed_xor_basics() {
	assert_eq!(fixed_xor([],[]).unwrap(), vec![] );
	assert_eq!(fixed_xor([1],[1]).unwrap(), vec![0] );
	assert_eq!(fixed_xor([1],[0]).unwrap(), vec![1] );
	assert_eq!(fixed_xor([0],[1]).unwrap(), vec![1] );
	assert_eq!(fixed_xor([0,1],[1,0]).unwrap(), vec![1,1] );
	assert_eq!(fixed_xor([255,128],[64,127]).unwrap(), vec![191,255] );
}

#[test]
fn fixed_xor_fail() {
	assert_eq!(fixed_xor([],[1]), None );
	assert_eq!(fixed_xor([1],[]), None );
	assert_eq!(fixed_xor([1,1],[1]), None );
}

<commit_msg>Fix indentation<commit_after>
pub fn to_hex(binary: &[u8]) -> String {
    /*
    let mut result = String::new();

    for b in binary.iter() {
        let hex1 = Char::from_digit((*b as uint & 0xf0) >> 4,16);
        let hex2 = Char::from_digit(*b as uint & 0x0f,16);

        result.push(hex1.unwrap());
        result.push(hex2.unwrap());
    }

    result
    */

    fn to_hex_char(byte: u8) -> char { Char::from_digit(byte as uint, 16).unwrap() }

    binary.iter().fold(String::new(), |mut s, &b| { s.push(to_hex_char(b >> 4)); s.push(to_hex_char(b & 0x0f)); s } )
}

pub fn fixed_xor(input1: &[u8], input2: &[u8]) -> Option<Vec<u8>> {

    let mut result = Vec::new();
    let mut second = input2.iter();

    for val1 in input1.iter() {
        match second.next() {
            None => return None,
            Some(val2) => result.push(*val1 ^ *val2)
        }
    }

    return match second.next() {
        None => return Some(result),
        _ => None
    }
}

#[test]
fn to_hex_basics() {
    assert_eq!(to_hex([]), "".to_string());
    assert_eq!(to_hex([0]), "00".to_string());
    assert_eq!(to_hex([1]), "01".to_string());
    assert_eq!(to_hex([16]), "10".to_string());
    assert_eq!(to_hex([255]), "ff".to_string());
    assert_eq!(to_hex([255,1]), "ff01".to_string());

}

#[test]
fn fixed_xor_basics() {
    assert_eq!(fixed_xor([],[]).unwrap(), vec![] );
    assert_eq!(fixed_xor([1],[1]).unwrap(), vec![0] );
    assert_eq!(fixed_xor([1],[0]).unwrap(), vec![1] );
    assert_eq!(fixed_xor([0],[1]).unwrap(), vec![1] );
    assert_eq!(fixed_xor([0,1],[1,0]).unwrap(), vec![1,1] );
    assert_eq!(fixed_xor([255,128],[64,127]).unwrap(), vec![191,255] );
}

#[test]
fn fixed_xor_fail() {
    assert_eq!(fixed_xor([],[1]), None );
    assert_eq!(fixed_xor([1],[]), None );
    assert_eq!(fixed_xor([1,1],[1]), None );
}

<|endoftext|>


<commit_before>use std::fs::{read_dir, remove_file, File};
use std::io::{self, BufReader, Cursor};
use std::path::{Path, PathBuf};

use anyhow::{bail, Result};
use log::error;
use snap::write::FrameEncoder;

/// Return the paths to the `(stdout, stderr)` log files of a task.
pub fn get_log_paths(task_id: usize, path: &Path) -> (PathBuf, PathBuf) {
    let task_log_dir = path.join("task_logs");
    let out_path = task_log_dir.join(format!("{}_stdout.log", task_id));
    let err_path = task_log_dir.join(format!("{}_stderr.log", task_id));
    (out_path, err_path)
}

/// Create and return the file handle for the `(stdout, stderr)` log files of a task.
pub fn create_log_file_handles(task_id: usize, path: &Path) -> Result<(File, File)> {
    let (out_path, err_path) = get_log_paths(task_id, path);
    let stdout = File::create(out_path)?;
    let stderr = File::create(err_path)?;

    Ok((stdout, stderr))
}

/// Return the file handle for the `(stdout, stderr)` log files of a task.
pub fn get_log_file_handles(task_id: usize, path: &Path) -> Result<(File, File)> {
    let (out_path, err_path) = get_log_paths(task_id, path);
    let stdout = File::open(out_path)?;
    let stderr = File::open(err_path)?;

    Ok((stdout, stderr))
}

/// Remove the the log files of a task.
pub fn clean_log_handles(task_id: usize, path: &Path) {
    let (out_path, err_path) = get_log_paths(task_id, path);
    if let Err(err) = remove_file(out_path) {
        error!(
            "Failed to remove stdout file for task {} with error {:?}",
            task_id, err
        );
    };
    if let Err(err) = remove_file(err_path) {
        error!(
            "Failed to remove stderr file for task {} with error {:?}",
            task_id, err
        );
    };
}

/// Return the `(stdout, stderr)` output of a task. \
/// Task output is compressed using [snap] to save some memory and bandwidth.
pub fn read_and_compress_log_files(
    task_id: usize,
    path: &Path,
    lines: Option<usize>,
) -> Result<(Vec<u8>, Vec<u8>)> {
    let (mut stdout_file, mut stderr_file) = match get_log_file_handles(task_id, path) {
        Ok((stdout, stderr)) => (stdout, stderr),
        Err(err) => {
            bail!("Error while opening the output files: {}", err);
        }
    };

    let mut stdout = Vec::new();
    let mut stderr = Vec::new();

    if let Some(lines) = lines {
        // Get the last few lines of both files
        let stdout_bytes = read_last_lines(&mut stdout_file, lines).into_bytes();
        let stderr_bytes = read_last_lines(&mut stderr_file, lines).into_bytes();
        let mut stdout_cursor = Cursor::new(stdout_bytes);
        let mut stderr_cursor = Cursor::new(stderr_bytes);

        // Compress the partial log input and pipe it into the snappy compressor
        let mut stdout_compressor = FrameEncoder::new(&mut stdout);
        io::copy(&mut stdout_cursor, &mut stdout_compressor)?;
        let mut stderr_compressor = FrameEncoder::new(&mut stderr);
        io::copy(&mut stderr_cursor, &mut stderr_compressor)?;
    } else {
        // Compress the full log input and pipe it into the snappy compressor
        let mut stdout_compressor = FrameEncoder::new(&mut stdout);
        io::copy(&mut stdout_file, &mut stdout_compressor)?;
        let mut stderr_compressor = FrameEncoder::new(&mut stderr);
        io::copy(&mut stderr_file, &mut stderr_compressor)?;
    }

    Ok((stdout, stderr))
}

/// Return the last lines of `(stdout, stderr)` of a task. \
/// This output is uncompressed and may take a lot of memory, which is why we only read
/// the last few lines.
pub fn read_last_log_file_lines(
    task_id: usize,
    path: &Path,
    lines: usize,
) -> Result<(String, String)> {
    let (mut stdout_file, mut stderr_file) = match get_log_file_handles(task_id, path) {
        Ok((stdout, stderr)) => (stdout, stderr),
        Err(err) => {
            bail!(
                "Error while opening the log files for task {}: {}",
                task_id,
                err
            );
        }
    };

    // Get the last few lines of both files
    Ok((
        read_last_lines(&mut stdout_file, lines),
        read_last_lines(&mut stderr_file, lines),
    ))
}

/// Remove all files in the log directory.
pub fn reset_task_log_directory(path: &Path) {
    let task_log_dir = path.join("task_logs");

    let files = read_dir(task_log_dir).expect("Failed to open pueue's task_logs directory");

    for file in files.flatten() {
        if let Err(err) = remove_file(file.path()) {
            error!("Failed to delete log file: {}", err);
        }
    }
}

/// Read the last `amount` lines of a file to a string.
///
/// TODO: This is super imperformant, but works as long as we don't use the last
/// 1000 lines. It would be cleaner to seek to the beginning of the requested
/// position and simply stream the content.
pub fn read_last_lines(file: &mut File, amount: usize) -> String {
    let last_lines: Vec<String> = rev_lines::RevLines::new(BufReader::new(file))
        .expect("Failed to read last lines of file")
        .take(amount)
        .collect();

    last_lines
        .into_iter()
        .rev()
        .collect::<Vec<String>>()
        .join("\n")
}
<commit_msg>Return debug log string instead of panicking<commit_after>use std::fs::{read_dir, remove_file, File};
use std::io::{self, BufReader, Cursor};
use std::path::{Path, PathBuf};

use anyhow::{bail, Result};
use log::error;
use snap::write::FrameEncoder;

/// Return the paths to the `(stdout, stderr)` log files of a task.
pub fn get_log_paths(task_id: usize, path: &Path) -> (PathBuf, PathBuf) {
    let task_log_dir = path.join("task_logs");
    let out_path = task_log_dir.join(format!("{}_stdout.log", task_id));
    let err_path = task_log_dir.join(format!("{}_stderr.log", task_id));
    (out_path, err_path)
}

/// Create and return the file handle for the `(stdout, stderr)` log files of a task.
pub fn create_log_file_handles(task_id: usize, path: &Path) -> Result<(File, File)> {
    let (out_path, err_path) = get_log_paths(task_id, path);
    let stdout = File::create(out_path)?;
    let stderr = File::create(err_path)?;

    Ok((stdout, stderr))
}

/// Return the file handle for the `(stdout, stderr)` log files of a task.
pub fn get_log_file_handles(task_id: usize, path: &Path) -> Result<(File, File)> {
    let (out_path, err_path) = get_log_paths(task_id, path);
    let stdout = File::open(out_path)?;
    let stderr = File::open(err_path)?;

    Ok((stdout, stderr))
}

/// Remove the the log files of a task.
pub fn clean_log_handles(task_id: usize, path: &Path) {
    let (out_path, err_path) = get_log_paths(task_id, path);
    if let Err(err) = remove_file(out_path) {
        error!(
            "Failed to remove stdout file for task {} with error {:?}",
            task_id, err
        );
    };
    if let Err(err) = remove_file(err_path) {
        error!(
            "Failed to remove stderr file for task {} with error {:?}",
            task_id, err
        );
    };
}

/// Return the `(stdout, stderr)` output of a task. \
/// Task output is compressed using [snap] to save some memory and bandwidth.
pub fn read_and_compress_log_files(
    task_id: usize,
    path: &Path,
    lines: Option<usize>,
) -> Result<(Vec<u8>, Vec<u8>)> {
    let (mut stdout_file, mut stderr_file) = match get_log_file_handles(task_id, path) {
        Ok((stdout, stderr)) => (stdout, stderr),
        Err(err) => {
            bail!("Error while opening the output files: {}", err);
        }
    };

    let mut stdout = Vec::new();
    let mut stderr = Vec::new();

    if let Some(lines) = lines {
        // Get the last few lines of both files
        let stdout_bytes = read_last_lines(&mut stdout_file, lines).into_bytes();
        let stderr_bytes = read_last_lines(&mut stderr_file, lines).into_bytes();
        let mut stdout_cursor = Cursor::new(stdout_bytes);
        let mut stderr_cursor = Cursor::new(stderr_bytes);

        // Compress the partial log input and pipe it into the snappy compressor
        let mut stdout_compressor = FrameEncoder::new(&mut stdout);
        io::copy(&mut stdout_cursor, &mut stdout_compressor)?;
        let mut stderr_compressor = FrameEncoder::new(&mut stderr);
        io::copy(&mut stderr_cursor, &mut stderr_compressor)?;
    } else {
        // Compress the full log input and pipe it into the snappy compressor
        let mut stdout_compressor = FrameEncoder::new(&mut stdout);
        io::copy(&mut stdout_file, &mut stdout_compressor)?;
        let mut stderr_compressor = FrameEncoder::new(&mut stderr);
        io::copy(&mut stderr_file, &mut stderr_compressor)?;
    }

    Ok((stdout, stderr))
}

/// Return the last lines of `(stdout, stderr)` of a task. \
/// This output is uncompressed and may take a lot of memory, which is why we only read
/// the last few lines.
pub fn read_last_log_file_lines(
    task_id: usize,
    path: &Path,
    lines: usize,
) -> Result<(String, String)> {
    let (mut stdout_file, mut stderr_file) = match get_log_file_handles(task_id, path) {
        Ok((stdout, stderr)) => (stdout, stderr),
        Err(err) => {
            bail!(
                "Error while opening the log files for task {}: {}",
                task_id,
                err
            );
        }
    };

    // Get the last few lines of both files
    Ok((
        read_last_lines(&mut stdout_file, lines),
        read_last_lines(&mut stderr_file, lines),
    ))
}

/// Remove all files in the log directory.
pub fn reset_task_log_directory(path: &Path) {
    let task_log_dir = path.join("task_logs");

    let files = read_dir(task_log_dir).expect("Failed to open pueue's task_logs directory");

    for file in files.flatten() {
        if let Err(err) = remove_file(file.path()) {
            error!("Failed to delete log file: {}", err);
        }
    }
}

/// Read the last `amount` lines of a file to a string.
///
/// TODO: This is super imperformant, but works as long as we don't use the last
/// 1000 lines. It would be cleaner to seek to the beginning of the requested
/// position and simply stream the content.
pub fn read_last_lines(file: &mut File, amount: usize) -> String {
    // Read the lines from the file.
    // Return a debug string if it fails.
    let last_lines: Vec<String> = match rev_lines::RevLines::new(BufReader::new(file)) {
        Ok(lines) => lines.take(amount).collect(),
        Err(error) => return format!("(Pueue error) Failed to read last lines of file: {}", error),
    };

    last_lines
        .into_iter()
        .rev()
        .collect::<Vec<String>>()
        .join("\n")
}
<|endoftext|>


<commit_before>pub enum AddressMode {
    Absolute = 1, AbsoluteX, AbsoluteY, Accumulator, Immediate, Implied, Indirect, IndexedIndirect, IndirectIndexed, Relative,
    ZeroPage, ZeroPageX, ZeroPageY,
}

#[allow(non_camel_case_types)]
pub enum OpcodeClass {
    ADC = 1, AND, ASL, BCC, BCS, BEQ, BIT, BMI, BNE, BPL, BRK, BVC, BVS, CLC, CLD, CLI, CLV, CMP, CPX, CPY, DEC, DEX, DEY,
    EOR, INC, INX, INY, JMP, JSR, LDA, LDX, LDY, LSR, NOP, ORA, PHA, PHP, PLA, PLP, ROL, ROR, RTI, RTS, SBC, SEC, SED,
    SEI, STA, STX, STY, TAX, TAY, TSX, TXA, TXS, TYA,

    // illegal opcodes
    ILL_AHX, ILL_ALR, ILL_ANC, ILL_ARR, ILL_AXS, ILL_DCP, ILL_ISC, ILL_KIL, ILL_LAS, ILL_LAX1, ILL_LAX2, ILL_NOP,
    ILL_RLA, ILL_RRA, ILL_SAX, ILL_SBC, ILL_SHX, ILL_SHY, ILL_SLO, ILL_SRE, ILL_TAS, ILL_XAA,
}

#[derive(Default)]
pub struct OpcodeDebugInfo {
    pub opcode: u16,
    pub name: String,
    pub address_mode_name: String,
    pub notes: String,
}

#[derive(Default)]
pub struct OpcodeExecInfo {
    pub opcode: u16,
    pub len: u8,
    pub cycles: u8,
    pub page_cycles: u8,
}
<commit_msg>added FromStr trait implementations<commit_after>use std::str::FromStr;

#[derive(Debug)]
pub enum AddressMode {
    None = 0,
    Absolute,        AbsoluteX,
    AbsoluteY,       Accumulator,
    Immediate,       Implied,
    Indirect,        IndexedIndirect,
    IndirectIndexed, Relative,
    ZeroPage,        ZeroPageX,
    ZeroPageY,
}

impl FromStr for AddressMode {
    type Err = ();

    fn from_str(s:&str) -> Result<Self,Self::Err> {
        match s {
            "Absolute"        => Ok(AddressMode::Absolute       ), "AbsoluteX"       => Ok(AddressMode::AbsoluteX),
            "AbsoluteY"       => Ok(AddressMode::AbsoluteY      ), "Accumulator"     => Ok(AddressMode::Accumulator),
            "Immediate"       => Ok(AddressMode::Immediate      ), "Implied"         => Ok(AddressMode::Implied),
            "Indirect"        => Ok(AddressMode::Indirect       ), "IndexedIndirect" => Ok(AddressMode::IndexedIndirect),
            "IndirectIndexed" => Ok(AddressMode::IndirectIndexed), "Relative"        => Ok(AddressMode::Relative),
            "ZeroPage"        => Ok(AddressMode::ZeroPage       ), "ZeroPageX"       => Ok(AddressMode::ZeroPageX),
            "ZeroPageY"       => Ok(AddressMode::ZeroPageY      ),

            _ => Err(())
        }
    }
}

#[derive(Debug)]
#[allow(non_camel_case_types)]
pub enum OpcodeClass {
    None = 0,
    ADC, AND, ASL,BCC,
    BCS, BEQ, BIT, BMI,
    BNE, BPL, BRK, BVC,
    BVS, CLC, CLD, CLI,
    CLV, CMP, CPX, CPY,
    DEC, DEX, DEY, EOR,
    INC, INX, INY, JMP,
    JSR, LDA, LDX, LDY,
    LSR, NOP, ORA, PHA,
    PHP, PLA, PLP, ROL,
    ROR, RTI, RTS, SBC,
    SEC, SED, SEI, STA,
    STX, STY, TAX, TAY,
    TSX, TXA, TXS, TYA,

    // illegal opcodes
    ILL_AHX,  ILL_ALR,  ILL_ANC,
    ILL_ARR,  ILL_AXS,  ILL_DCP,
    ILL_ISC,  ILL_KIL,  ILL_LAS,
    ILL_LAX1, ILL_LAX2, ILL_NOP,
    ILL_RLA,  ILL_RRA,  ILL_SAX,
    ILL_SBC,  ILL_SHX,  ILL_SHY,
    ILL_SLO,  ILL_SRE,  ILL_TAS,
    ILL_XAA,
}

impl FromStr for OpcodeClass {
    type Err = ();

    fn from_str(s:&str) -> Result<Self,Self::Err> {
        match s {
            "ADC" => Ok(OpcodeClass::ADC), "AND" => Ok(OpcodeClass::AND), "ASL" => Ok(OpcodeClass::ASL), "BCC" => Ok(OpcodeClass::BCC),
            "BCS" => Ok(OpcodeClass::BCS), "BEQ" => Ok(OpcodeClass::BEQ), "BIT" => Ok(OpcodeClass::BIT), "BMI" => Ok(OpcodeClass::BMI),
            "BNE" => Ok(OpcodeClass::BNE), "BPL" => Ok(OpcodeClass::BPL), "BRK" => Ok(OpcodeClass::BRK), "BVC" => Ok(OpcodeClass::BVC),
            "BVS" => Ok(OpcodeClass::BVS), "CLC" => Ok(OpcodeClass::CLC), "CLD" => Ok(OpcodeClass::CLD), "CLI" => Ok(OpcodeClass::CLI),
            "CLV" => Ok(OpcodeClass::CLV), "CMP" => Ok(OpcodeClass::CMP), "CPX" => Ok(OpcodeClass::CPX), "CPY" => Ok(OpcodeClass::CPY),
            "DEC" => Ok(OpcodeClass::DEC), "DEX" => Ok(OpcodeClass::DEX), "DEY" => Ok(OpcodeClass::DEY), "EOR" => Ok(OpcodeClass::EOR),
            "INC" => Ok(OpcodeClass::INC), "INX" => Ok(OpcodeClass::INX), "INY" => Ok(OpcodeClass::INY), "JMP" => Ok(OpcodeClass::JMP),
            "JSR" => Ok(OpcodeClass::JSR), "LDA" => Ok(OpcodeClass::LDA), "LDX" => Ok(OpcodeClass::LDX), "LDY" => Ok(OpcodeClass::LDY),
            "LSR" => Ok(OpcodeClass::LSR), "NOP" => Ok(OpcodeClass::NOP), "ORA" => Ok(OpcodeClass::ORA), "PHA" => Ok(OpcodeClass::PHA),
            "PHP" => Ok(OpcodeClass::PHP), "PLA" => Ok(OpcodeClass::PLA), "PLP" => Ok(OpcodeClass::PLP), "ROL" => Ok(OpcodeClass::ROL),
            "ROR" => Ok(OpcodeClass::ROR), "RTI" => Ok(OpcodeClass::RTI), "RTS" => Ok(OpcodeClass::RTS), "SBC" => Ok(OpcodeClass::SBC),
            "SEC" => Ok(OpcodeClass::SEC), "SED" => Ok(OpcodeClass::SED), "SEI" => Ok(OpcodeClass::SEI), "STA" => Ok(OpcodeClass::STA),
            "STX" => Ok(OpcodeClass::STX), "STY" => Ok(OpcodeClass::STY), "TAX" => Ok(OpcodeClass::TAX), "TAY" => Ok(OpcodeClass::TAY),
            "TSX" => Ok(OpcodeClass::TSX), "TXA" => Ok(OpcodeClass::TXA), "TXS" => Ok(OpcodeClass::TXS), "TYA" => Ok(OpcodeClass::TYA),

            "ILL_AHX"  => Ok(OpcodeClass::ILL_AHX ), "ILL_ALR"  => Ok(OpcodeClass::ILL_ALR ), "ILL_ANC" => Ok(OpcodeClass::ILL_ANC),
            "ILL_ARR"  => Ok(OpcodeClass::ILL_ARR ), "ILL_AXS"  => Ok(OpcodeClass::ILL_AXS ), "ILL_DCP" => Ok(OpcodeClass::ILL_DCP),
            "ILL_ISC"  => Ok(OpcodeClass::ILL_ISC ), "ILL_KIL"  => Ok(OpcodeClass::ILL_KIL ), "ILL_LAS" => Ok(OpcodeClass::ILL_LAS),
            "ILL_LAX1" => Ok(OpcodeClass::ILL_LAX1), "ILL_LAX2" => Ok(OpcodeClass::ILL_LAX2), "ILL_NOP" => Ok(OpcodeClass::ILL_NOP),
            "ILL_RLA"  => Ok(OpcodeClass::ILL_RLA ), "ILL_RRA"  => Ok(OpcodeClass::ILL_RRA ), "ILL_SAX" => Ok(OpcodeClass::ILL_SAX),
            "ILL_SBC"  => Ok(OpcodeClass::ILL_SBC ), "ILL_SHX"  => Ok(OpcodeClass::ILL_SHX ), "ILL_SHY" => Ok(OpcodeClass::ILL_SHY),
            "ILL_SLO"  => Ok(OpcodeClass::ILL_SLO ), "ILL_SRE"  => Ok(OpcodeClass::ILL_SRE ), "ILL_TAS" => Ok(OpcodeClass::ILL_TAS),
            "ILL_XAA"  => Ok(OpcodeClass::ILL_XAA ),

            _ => Err(())
        }
    }
}

#[derive(Default)]
pub struct OpcodeDebugInfo {
    pub opcode: u16,
    pub name: String,
    pub address_mode_name: String,
    pub notes: String,
}

#[derive(Default)]
pub struct OpcodeExecInfo {
    pub opcode: u16,
    pub len: u8,
    pub cycles: u8,
    pub page_cycles: u8,
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2016 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for sending and receiving data link layer packets using the netmap library

#![allow(bad_style)]

extern crate netmap_sys;
extern crate libc;

use self::netmap_sys::netmap_user::{NETMAP_BUF, NETMAP_FD, NETMAP_TXRING, nm_close, nm_desc,
                                    nm_nextpkt, nm_open, nm_pkthdr, nm_ring_next};
use self::netmap_sys::netmap::{netmap_slot, nm_ring_empty};

use std::ffi::CString;
use std::path::Path;
use std::fs::File;
use std::io;
use std::io::Read;
use std::mem;
use std::ptr;
use std::slice;
use std::sync::Arc;

use datalink::{self, NetworkInterface};
use datalink::Channel::Ethernet;
use datalink::{EthernetDataLinkChannelIterator, EthernetDataLinkReceiver, EthernetDataLinkSender};
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
#[repr(C)]
struct pollfd {
    fd: libc::c_int,
    events: libc::c_short,
    revents: libc::c_short,
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
const POLLIN: libc::c_short = 0x0001;
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
const POLLOUT: libc::c_short = 0x0004;

#[cfg(target_os = "freebsd")]
type nfds_t = libc::c_uint;
#[cfg(target_os = "linux")]
type nfds_t = libc::c_ulong;

extern {
    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: libc::c_int) -> libc::c_int;
    fn ppoll(fds: *mut pollfd, nfds: nfds_t, timeout: *const libc::timespec, newsigmask: *const libc::sigset_t) -> libc::c_int;
}

struct NmDesc {
    desc: *mut nm_desc,
    buf_size: libc::c_uint,
}

unsafe impl Send for NmDesc {}
unsafe impl Sync for NmDesc {}

impl NmDesc {
    fn new(iface: &NetworkInterface) -> io::Result<NmDesc> {
        let ifname = CString::new(("netmap:".to_owned() + &iface.name[..]).as_bytes());
        let desc = unsafe { nm_open(ifname.unwrap().as_ptr(), ptr::null(), 0, ptr::null()) };

        if desc.is_null() {
            Err(io::Error::last_os_error())
        } else {
            let mut f = try!(File::open(&Path::new("/sys/module/netmap/parameters/buf_size")));
            let mut num_str = String::new();
            try!(f.read_to_string(&mut num_str));
            let buf_size = num_str.trim_right().parse().unwrap();

            Ok(NmDesc {
                desc: desc,
                buf_size: buf_size,
            })
        }
    }
}

impl Drop for NmDesc {
    fn drop(&mut self) {
        unsafe {
            nm_close(self.desc);
        }
    }
}

/// Netmap specific configuration
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Config {
    /// The read timeout. Defaults to None.
    pub read_timeout: Option<Duration>,

    /// The write timeout. Defaults to None.
    pub write_timeout: Option<Duration>,
}

impl<'a> From<&'a datalink::Config> for Config {
    fn from(_config: &datalink::Config) -> Config {
        Config {
            read_timeout: config.read_timeout,
            write_timeout: config.write_timeout,
        }
    }
}

impl Default for Config {
    fn default() -> Config {
        Config {
            read_timeout: None,
            write_timeout: None,
        }
    }
}

#[inline]
fn get_timeout(to: Option<Duration>) -> Option<libc::timespec> {
    to.map(|dur| {
        libc::timespec {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_nsec: dur.subsec_nanos() as libc::c_long
        }
    })
}

/// Create a datalink channel using the netmap library
#[inline]
pub fn channel(network_interface: &NetworkInterface, config: Config)
    -> io::Result<datalink::Channel> {
    // FIXME probably want one for each of send/recv
    let desc = NmDesc::new(network_interface);
    match desc {
        Ok(desc) => {
            let arc = Arc::new(desc);

            Ok(Ethernet(
                Box::new(DataLinkSenderImpl {
                    desc: arc.clone(),
                    timeout: get_timeout(config.write_timeout)
                }),
                Box::new(DataLinkReceiverImpl {
                    desc: arc,
                    timeout: get_timeout(config.read_timeout)
                })))
        }
        Err(e) => Err(e),
    }
}

struct DataLinkSenderImpl {
    desc: Arc<NmDesc>,
    timeout: Option<libc::timespec>,
}

impl EthernetDataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
        -> Option<io::Result<()>> {
        assert!(packet_size <= self.desc.buf_size as usize);
        let desc = self.desc.desc;
        let mut fds = pollfd {
            fd: unsafe { NETMAP_FD(desc) },
            events: POLLOUT,
            revents: 0,
        };
        let mut packet_idx = 0usize;
        while packet_idx < num_packets {
            unsafe {
                let timespec = self.timeout.as_ref().map(|ts| ts as *const _).unwrap_or(ptr::null());
                if ppoll(&mut fds, 1, timespec, ptr::null()) < 0 {
                    return Some(Err(io::Error::last_os_error()));
                }
                let ring = NETMAP_TXRING((*desc).nifp, 0);
                while !nm_ring_empty(ring) && packet_idx < num_packets {
                    let i = (*ring).cur;
                    let slot_ptr: *mut netmap_slot = mem::transmute(&mut (*ring).slot);
                    let buf = NETMAP_BUF(ring, (*slot_ptr.offset(i as isize)).buf_idx as isize);
                    let slice = slice::from_raw_parts_mut(buf as *mut u8, packet_size);
                    let meh = MutableEthernetPacket::new(slice).unwrap();
                    (*slot_ptr.offset(i as isize)).len = packet_size as u16;
                    func(meh);
                    let next = nm_ring_next(ring, i);
                    (*ring).head = next;
                    (*ring).cur = next;
                    packet_idx += 1;
                }
            }
        }

        Some(Ok(()))
    }

    #[inline]
    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        use packet::MutablePacket;
        self.build_and_send(1,
                            packet.packet().len(),
                            &mut |mut eh: MutableEthernetPacket| {
                                eh.clone_from(packet);
                            })
    }
}

struct DataLinkReceiverImpl {
    desc: Arc<NmDesc>,
    timeout: Option<libc::timespec>,
}

impl EthernetDataLinkReceiver for DataLinkReceiverImpl {
    // FIXME Layer 3
    fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
        Box::new(DataLinkChannelIteratorImpl { pc: self })
    }
}

struct DataLinkChannelIteratorImpl<'a> {
    pc: &'a mut DataLinkReceiverImpl,
}

impl<'a> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
    fn next(&mut self) -> io::Result<EthernetPacket> {
        let desc = self.pc.desc.desc;
        let mut h: nm_pkthdr = unsafe { mem::uninitialized() };
        let mut buf = unsafe { nm_nextpkt(desc, &mut h) };
        if buf.is_null() {
            let mut fds = pollfd {
                fd: unsafe { NETMAP_FD(desc) },
                events: POLLIN,
                revents: 0,
            };
            let timespec = self.timeout.as_ref().map(|ts| ts as *const _).unwrap_or(ptr::null());
            if unsafe { ppoll(&mut fds, 1, timespec, ptr::null()) } < 0 {
                return Err(io::Error::last_os_error());
            }
            buf = unsafe { nm_nextpkt(desc, &mut h) };
        }
        Ok(EthernetPacket::new(unsafe {
            slice::from_raw_parts(buf, h.len as usize)
        }).unwrap())
    }
}

/// Get a list of available network interfaces for the current machine.
pub fn interfaces() -> Vec<NetworkInterface> {
    #[path = "unix_interfaces.rs"]
    mod interfaces;
    interfaces::interfaces()
}
<commit_msg>Auto merge of #228 - brayniac:netmap-fix, r=mrmonday<commit_after>// Copyright (c) 2015-2016 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for sending and receiving data link layer packets using the netmap library

#![allow(bad_style)]

extern crate netmap_sys;
extern crate libc;

use self::netmap_sys::netmap_user::{NETMAP_BUF, NETMAP_FD, NETMAP_TXRING, nm_close, nm_desc,
                                    nm_nextpkt, nm_open, nm_pkthdr, nm_ring_next};
use self::netmap_sys::netmap::{netmap_slot, nm_ring_empty};

use std::ffi::CString;
use std::path::Path;
use std::fs::File;
use std::io;
use std::io::Read;
use std::mem;
use std::ptr;
use std::slice;
use std::sync::Arc;
use std::time::Duration;

use datalink::{self, NetworkInterface};
use datalink::Channel::Ethernet;
use datalink::{EthernetDataLinkChannelIterator, EthernetDataLinkReceiver, EthernetDataLinkSender};
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
#[repr(C)]
struct pollfd {
    fd: libc::c_int,
    events: libc::c_short,
    revents: libc::c_short,
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
const POLLIN: libc::c_short = 0x0001;
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
const POLLOUT: libc::c_short = 0x0004;

#[cfg(target_os = "freebsd")]
type nfds_t = libc::c_uint;
#[cfg(target_os = "linux")]
type nfds_t = libc::c_ulong;

extern {
    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: libc::c_int) -> libc::c_int;
    fn ppoll(fds: *mut pollfd, nfds: nfds_t, timeout: *const libc::timespec, newsigmask: *const libc::sigset_t) -> libc::c_int;
}

struct NmDesc {
    desc: *mut nm_desc,
    buf_size: libc::c_uint,
}

unsafe impl Send for NmDesc {}
unsafe impl Sync for NmDesc {}

impl NmDesc {
    fn new(iface: &NetworkInterface) -> io::Result<NmDesc> {
        let ifname = CString::new(("netmap:".to_owned() + &iface.name[..]).as_bytes());
        let desc = unsafe { nm_open(ifname.unwrap().as_ptr(), ptr::null(), 0, ptr::null()) };

        if desc.is_null() {
            Err(io::Error::last_os_error())
        } else {
            let mut f = try!(File::open(&Path::new("/sys/module/netmap/parameters/buf_size")));
            let mut num_str = String::new();
            try!(f.read_to_string(&mut num_str));
            let buf_size = num_str.trim_right().parse().unwrap();

            Ok(NmDesc {
                desc: desc,
                buf_size: buf_size,
            })
        }
    }
}

impl Drop for NmDesc {
    fn drop(&mut self) {
        unsafe {
            nm_close(self.desc);
        }
    }
}

/// Netmap specific configuration
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Config {
    /// The read timeout. Defaults to None.
    pub read_timeout: Option<Duration>,

    /// The write timeout. Defaults to None.
    pub write_timeout: Option<Duration>,
}

impl<'a> From<&'a datalink::Config> for Config {
    fn from(config: &datalink::Config) -> Config {
        Config {
            read_timeout: config.read_timeout,
            write_timeout: config.write_timeout,
        }
    }
}

impl Default for Config {
    fn default() -> Config {
        Config {
            read_timeout: None,
            write_timeout: None,
        }
    }
}

#[inline]
fn get_timeout(to: Option<Duration>) -> Option<libc::timespec> {
    to.map(|dur| {
        libc::timespec {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_nsec: dur.subsec_nanos() as libc::c_long
        }
    })
}

/// Create a datalink channel using the netmap library
#[inline]
pub fn channel(network_interface: &NetworkInterface, config: Config)
    -> io::Result<datalink::Channel> {
    // FIXME probably want one for each of send/recv
    let desc = NmDesc::new(network_interface);
    match desc {
        Ok(desc) => {
            let arc = Arc::new(desc);

            Ok(Ethernet(
                Box::new(DataLinkSenderImpl {
                    desc: arc.clone(),
                    timeout: get_timeout(config.write_timeout)
                }),
                Box::new(DataLinkReceiverImpl {
                    desc: arc,
                    timeout: get_timeout(config.read_timeout)
                })))
        }
        Err(e) => Err(e),
    }
}

struct DataLinkSenderImpl {
    desc: Arc<NmDesc>,
    timeout: Option<libc::timespec>,
}

impl EthernetDataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
        -> Option<io::Result<()>> {
        assert!(packet_size <= self.desc.buf_size as usize);
        let desc = self.desc.desc;
        let mut fds = pollfd {
            fd: unsafe { NETMAP_FD(desc) },
            events: POLLOUT,
            revents: 0,
        };
        let mut packet_idx = 0usize;
        while packet_idx < num_packets {
            unsafe {
                let timespec = self.timeout.as_ref().map(|ts| ts as *const _).unwrap_or(ptr::null());
                if ppoll(&mut fds, 1, timespec, ptr::null()) < 0 {
                    return Some(Err(io::Error::last_os_error()));
                }
                let ring = NETMAP_TXRING((*desc).nifp, 0);
                while !nm_ring_empty(ring) && packet_idx < num_packets {
                    let i = (*ring).cur;
                    let slot_ptr: *mut netmap_slot = mem::transmute(&mut (*ring).slot);
                    let buf = NETMAP_BUF(ring, (*slot_ptr.offset(i as isize)).buf_idx as isize);
                    let slice = slice::from_raw_parts_mut(buf as *mut u8, packet_size);
                    let meh = MutableEthernetPacket::new(slice).unwrap();
                    (*slot_ptr.offset(i as isize)).len = packet_size as u16;
                    func(meh);
                    let next = nm_ring_next(ring, i);
                    (*ring).head = next;
                    (*ring).cur = next;
                    packet_idx += 1;
                }
            }
        }

        Some(Ok(()))
    }

    #[inline]
    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        use packet::MutablePacket;
        self.build_and_send(1,
                            packet.packet().len(),
                            &mut |mut eh: MutableEthernetPacket| {
                                eh.clone_from(packet);
                            })
    }
}

struct DataLinkReceiverImpl {
    desc: Arc<NmDesc>,
    timeout: Option<libc::timespec>,
}

impl EthernetDataLinkReceiver for DataLinkReceiverImpl {
    // FIXME Layer 3
    fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
        Box::new(DataLinkChannelIteratorImpl { pc: self })
    }
}

struct DataLinkChannelIteratorImpl<'a> {
    pc: &'a mut DataLinkReceiverImpl,
}

impl<'a> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
    fn next(&mut self) -> io::Result<EthernetPacket> {
        let desc = self.pc.desc.desc;
        let mut h: nm_pkthdr = unsafe { mem::uninitialized() };
        let mut buf = unsafe { nm_nextpkt(desc, &mut h) };
        if buf.is_null() {
            let mut fds = pollfd {
                fd: unsafe { NETMAP_FD(desc) },
                events: POLLIN,
                revents: 0,
            };
            let timespec = self.pc.timeout.as_ref().map(|ts| ts as *const _).unwrap_or(ptr::null());
            if unsafe { ppoll(&mut fds, 1, timespec, ptr::null()) } < 0 {
                return Err(io::Error::last_os_error());
            }
            buf = unsafe { nm_nextpkt(desc, &mut h) };
        }
        Ok(EthernetPacket::new(unsafe {
            slice::from_raw_parts(buf, h.len as usize)
        }).unwrap())
    }
}

/// Get a list of available network interfaces for the current machine.
pub fn interfaces() -> Vec<NetworkInterface> {
    #[path = "unix_interfaces.rs"]
    mod interfaces;
    interfaces::interfaces()
}
<|endoftext|>


<commit_before>pub type Map = ~[Block];

pub type Block = ~[Cell];

pub struct Cell {
    graphic: u16,
    altitude: i8,
}

pub type Statics = ~[StaticLocation];

pub struct StaticLocation {
    object_id: u16,
    x: u8,
    y: u8,
    altitude: i8,
    remainder: u16
}

const BLOCK_SIZE: uint = 196;
const OFFSET: uint = 4;

pub struct MapReader {
    data_reader: io::Reader
}

impl MapReader {

    /**
     * Read a specific block from a map
     */
    fn read_block(&self, id: uint) -> Block {
        //Cycle to id * 196 + Offset
        self.data_reader.seek(((id * BLOCK_SIZE) + OFFSET) as int, io::SeekSet);
        let map_reader = self.data_reader as io::ReaderUtil;
        //Read the 64 cells
        let mut block: Block = ~[];
        //Read 64 cells
        for uint::range(0, 64) |_index| {
            block.push(Cell{
                graphic: map_reader.read_le_u16(),
                altitude: map_reader.read_i8()
            });
        }
        block
    }

    /**
     * Read the whole map!
     */
    fn read_map(&self, max_blocks: uint) -> Map {
        let mut map: Map = ~[];
        let mut index = 0;
        while index < max_blocks {
            map.push(self.read_block(index));
            index += 1;
        }
        map
    }
}

/**
 * Create a handle to a mapreader, and read out given blocks as needed
 */
pub fn MapReader(path: ~str) -> result::Result<MapReader, ~str> {
    let mul_path: path::Path = path::Path(path);
    match io::file_reader(&mul_path) {
        result::Ok(data_reader) => {
            result::Ok(MapReader {
                data_reader: data_reader
            })
        },
        result::Err(error_message) => {
            result::Err(error_message)
        }
    }
}

pub struct StaticReader {
    mul_reader: mul_reader::MulReader
}

impl StaticReader {
    fn read_block(&self, id: uint) -> option::Option(Statics) {
        match self.mul_reader.read(id) {
            option::Some(record) => {
                assert record.len % 7 == 0;
                //TODO: Read the actual gumpf
            }
            option::None => {
                option::None
            }
        }
    }
}

pub fn StaticReader(index_path: &path::Path, mul_path: &path::Path) -> result::Result<StaticReader, ~str> {
    match mul_reader::MulReader(index_path, mul_path) {
        result::Err(message) => result::Err(message),
        result::Ok(mul_reader) => {
            result::Ok(StaticReader{
                mul_reader: mul_reader
            })
        }
    }
}
<commit_msg>Basic statics reading<commit_after>use mul_reader;
use byte_helpers;

pub type Map = ~[Block];

pub type Block = ~[Cell];

pub struct Cell {
    graphic: u16,
    altitude: i8,
}

pub type Statics = ~[StaticLocation];

pub struct StaticLocation {
    object_id: u16,
    x: u8,
    y: u8,
    altitude: i8,
    remainder: u16
}

const BLOCK_SIZE: uint = 196;
const OFFSET: uint = 4;

pub struct MapReader {
    data_reader: io::Reader
}

impl MapReader {

    /**
     * Read a specific block from a map
     */
    fn read_block(&self, id: uint) -> Block {
        //Cycle to id * 196 + Offset
        self.data_reader.seek(((id * BLOCK_SIZE) + OFFSET) as int, io::SeekSet);
        let map_reader = self.data_reader as io::ReaderUtil;
        //Read the 64 cells
        let mut block: Block = ~[];
        //Read 64 cells
        for uint::range(0, 64) |_index| {
            block.push(Cell{
                graphic: map_reader.read_le_u16(),
                altitude: map_reader.read_i8()
            });
        }
        block
    }

    /**
     * Read the whole map!
     */
    fn read_map(&self, max_blocks: uint) -> Map {
        let mut map: Map = ~[];
        let mut index = 0;
        while index < max_blocks {
            map.push(self.read_block(index));
            index += 1;
        }
        map
    }
}

/**
 * Create a handle to a mapreader, and read out given blocks as needed
 */
pub fn MapReader(path: ~str) -> result::Result<MapReader, ~str> {
    let mul_path: path::Path = path::Path(path);
    match io::file_reader(&mul_path) {
        result::Ok(data_reader) => {
            result::Ok(MapReader {
                data_reader: data_reader
            })
        },
        result::Err(error_message) => {
            result::Err(error_message)
        }
    }
}

pub struct StaticReader {
    mul_reader: mul_reader::MulReader
}

impl StaticReader {
    fn read_block(&self, id: uint) -> option::Option<Statics> {
        match self.mul_reader.read(id) {
            option::Some(record) => {
                assert record.data.len() % 7 == 0;
                let mut statics:Statics = ~[];
                //TODO: Read the actual gumpf
                for uint::range_step(0, record.data.len(), 7) |_i| {
                    let data_source = byte_helpers::Buffer(copy record.data);
                    let object_id: u16 = byte_helpers::bytes_to_le_uint(data_source.read(2)) as u16;
                    let x: u8 = byte_helpers::bytes_to_le_uint(data_source.read(1)) as u8;
                    let y: u8 = byte_helpers::bytes_to_le_uint(data_source.read(1)) as u8;
                    let altitude: i8 = byte_helpers::bytes_to_le_uint(data_source.read(1)) as i8;
                    let remainder: u16 = byte_helpers::bytes_to_le_uint(data_source.read(2)) as u16;
                    statics.push(StaticLocation{
                        object_id: object_id,
                        x: x,
                        y: y,
                        altitude: altitude,
                        remainder: remainder
                    });
                }
                option::Some(statics)
            }
            option::None => {
                option::None
            }
        }
    }
}

pub fn StaticReader(index_path: &path::Path, mul_path: &path::Path) -> result::Result<StaticReader, ~str> {
    match mul_reader::MulReader(index_path, mul_path) {
        result::Err(message) => result::Err(message),
        result::Ok(mul_reader) => {
            result::Ok(StaticReader{
                mul_reader: mul_reader
            })
        }
    }
}
<|endoftext|>