<commit_before>extern crate hyper;
extern crate url;
extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate serde_derive;

use std::io::Read;

#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub struct JournalEntry {
    #[serde(rename = "__CURSOR")]
    pub cursor: String,
    #[serde(rename = "__REALTIME_TIMESTAMP")]
    pub realtime_timestamp: String,
    #[serde(rename = "__MONOTONIC_TIMESTAMP")]
    pub monotonic_timestamp: String,
    #[serde(rename = "_BOOT_ID")]
    pub boot_id: String,
    #[serde(rename = "_MACHINE_ID")]
    pub machine_id: String,
    #[serde(rename = "_HOSTNAME")]
    pub hostname: String,
    pub priority: Option<String>,
    #[serde(rename = "_UID")]
    pub uid: Option<String>,
    #[serde(rename = "_GID")]
    pub gid: Option<String>,
    #[serde(rename = "_SYSTEMD_SLICE")]
    pub systemd_slice: Option<String>,
    #[serde(rename = "_CAP_EFFECTIVE")]
    pub cap_effective: Option<String>,
    #[serde(rename = "_TRANSPORT")]
    pub transport: String,
    #[serde(rename = "_COMM")]
    pub command: Option<String>,
    #[serde(rename = "_EXE")]
    pub executable: Option<String>,
    #[serde(rename = "_SYSTEMD_CGROUP")]
    pub systemd_cgroup: Option<String>,
    #[serde(rename = "_SYSTEMD_UNIT")]
    pub systemd_unit: Option<String>,
    #[serde(rename = "_SYSTEMD_INVOCATION_ID")]
    pub systemd_invocation_id: Option<String>,
    #[serde(rename = "_SYSTEMD_OWNER_UID")]
    pub systemd_owner_uid: Option<String>,
    #[serde(rename = "_SYSTEMD_USER_SLICE")]
    pub systemd_user_slice: Option<String>,
    #[serde(rename = "_SYSTEMD_USER_UNIT")]
    pub systemd_user_unit: Option<String>,
    #[serde(rename = "_SYSTEMD_SESSION")]
    pub systemd_session: Option<String>,
    pub syslog_facility: Option<String>,
    pub syslog_identifier: Option<String>,
    #[serde(rename = "_CMDLINE")]
    pub command_line: Option<String>,
    #[serde(rename = "_AUDIT_LOGINUID")]
    pub audit_login_uid: Option<String>,
    pub message: String,
    pub code_file: Option<String>,
    pub code_line: Option<String>,
    pub code_function: Option<String>,
    pub unit: Option<String>,
    pub user_unit: Option<String>,
    pub userspace_usec: Option<String>,
    pub kernel_usec: Option<String>,
    pub message_id: Option<String>,
    pub result: Option<String>,
    pub user_id: Option<String>,
    pub seat_id: Option<String>,
    pub leader: Option<String>,
    pub journal_name: Option<String>,
    pub journal_path: Option<String>,
    pub current_use: Option<String>,
    pub current_use_pretty: Option<String>,
    pub max_use: Option<String>,
    pub max_use_pretty: Option<String>,
    pub disk_keep_free: Option<String>,
    pub disk_keep_free_pretty: Option<String>,
    pub disk_available: Option<String>,
    pub disk_available_pretty: Option<String>,
    pub available: Option<String>,
    pub available_pretty: Option<String>,
    pub limit: Option<String>,
    pub limit_pretty: Option<String>,
    pub session_id: Option<String>,
    pub syslog_pid: Option<String>,
    #[serde(rename = "_PID")]
    pub pid: Option<String>,
    #[serde(rename = "_AUDIT_SESSION")]
    pub audit_session: Option<String>,
    #[serde(rename = "_AUDIT_TYPE")]
    pub audit_type: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_NAME")]
    pub audit_field_name: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_APPARMOR")]
    pub audit_field_apparmor: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_OPERATION")]
    pub audit_field_operation: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_PROFILE")]
    pub audit_field_profile: Option<String>,
    #[serde(rename = "_AUDIT_ID")]
    pub audit_id: Option<String>,
    #[serde(rename = "_KERNEL_SUBSYSTEM")]
    pub kernel_subsystem: Option<String>,
    #[serde(rename = "_KERNEL_DEVICE")]
    pub kernel_device: Option<String>,
    #[serde(rename = "_UDEV_SYSNAME")]
    pub udev_sysname: Option<String>,
    #[serde(rename = "_UDEV_DEVNODE")]
    pub udev_devnode: Option<String>,
    #[serde(rename = "_UDEV_DEVLINK")]
    pub udev_devlink: Option<String>,
    #[serde(rename = "_SOURCE_REALTIME_TIMESTAMP")]
    pub source_realtime_timestamp: Option<String>,
    #[serde(rename = "_SOURCE_MONOTONIC_TIMESTAMP")]
    pub source_monotonic_timestamp: Option<String>,
}

pub struct JournalGateway {
    pub baseurl: url::Url,
    client: hyper::Client,
}

impl JournalGateway {
    pub fn new(baseurl_str: &str) -> JournalGateway {
        let baseurl = url::Url::parse(baseurl_str).expect("Error during parsing baseurl");
        JournalGateway {
            baseurl: baseurl.to_owned(),
            client: hyper::Client::new(),
        }
    }

    pub fn get_all_entries(&self) -> Vec<JournalEntry> {
        self.get_entries(None)
    }

    pub fn get_entries(&self, filters: Option<Vec<(String, String)>>) -> Vec<JournalEntry> {
        let mut url = self.baseurl.join("entries").expect("url join failed");
        if let Some(filters_unwrapped) = filters {
            url.query_pairs_mut().extend_pairs(filters_unwrapped);
        }

        let request = self.client
            .request(hyper::method::Method::Get, url.as_str())
            .header(hyper::header::Accept::json());

        let mut response = request.send().expect("request failure");
        let mut body = String::new();
        response
            .read_to_string(&mut body)
            .expect("body read failed");

        let mut res: Vec<JournalEntry> = vec![];
        for line in body.split("\n") {
            if line.len() > 0 {
                let deser_res = serde_json::from_str(&line);
                match deser_res {
                    Ok(entry) => res.push(entry),
                    Err(e) => println!("Error {}, skipping line: {}", e, line),
                }
            }
        }

        res
    }
}

#[cfg(test)]
mod tests {
    use JournalGateway;

    #[test]
    fn get_entries() {

        // TODO make this into a self contained test

        let journal_gw = JournalGateway::new("http://192.168.33.19:19531");
        let res = journal_gw.get_all_entries();
        for entry in res {
            println!("{}", entry.message);
        }
    }

    // TODO create another test with a filter, e.g.
    // let res = journal_gw.get_entries(Some(vec![("_COMM".to_string(), "cat".to_string())]));
}
<commit_msg>ignore unknown fields for now<commit_after>extern crate hyper;
extern crate url;
extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate serde_derive;

use std::io::Read;

#[derive(Serialize, Deserialize, Debug)]
//#[serde(deny_unknown_fields)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub struct JournalEntry {
    #[serde(rename = "__CURSOR")]
    pub cursor: String,
    #[serde(rename = "__REALTIME_TIMESTAMP")]
    pub realtime_timestamp: String,
    #[serde(rename = "__MONOTONIC_TIMESTAMP")]
    pub monotonic_timestamp: String,
    #[serde(rename = "_BOOT_ID")]
    pub boot_id: String,
    #[serde(rename = "_MACHINE_ID")]
    pub machine_id: String,
    #[serde(rename = "_HOSTNAME")]
    pub hostname: String,
    pub priority: Option<String>,
    #[serde(rename = "_UID")]
    pub uid: Option<String>,
    #[serde(rename = "_GID")]
    pub gid: Option<String>,
    #[serde(rename = "_SYSTEMD_SLICE")]
    pub systemd_slice: Option<String>,
    #[serde(rename = "_CAP_EFFECTIVE")]
    pub cap_effective: Option<String>,
    #[serde(rename = "_TRANSPORT")]
    pub transport: String,
    #[serde(rename = "_COMM")]
    pub command: Option<String>,
    #[serde(rename = "_EXE")]
    pub executable: Option<String>,
    #[serde(rename = "_SYSTEMD_CGROUP")]
    pub systemd_cgroup: Option<String>,
    #[serde(rename = "_SYSTEMD_UNIT")]
    pub systemd_unit: Option<String>,
    #[serde(rename = "_SYSTEMD_INVOCATION_ID")]
    pub systemd_invocation_id: Option<String>,
    #[serde(rename = "_SYSTEMD_OWNER_UID")]
    pub systemd_owner_uid: Option<String>,
    #[serde(rename = "_SYSTEMD_USER_SLICE")]
    pub systemd_user_slice: Option<String>,
    #[serde(rename = "_SYSTEMD_USER_UNIT")]
    pub systemd_user_unit: Option<String>,
    #[serde(rename = "_SYSTEMD_SESSION")]
    pub systemd_session: Option<String>,
    pub syslog_facility: Option<String>,
    pub syslog_identifier: Option<String>,
    #[serde(rename = "_CMDLINE")]
    pub command_line: Option<String>,
    #[serde(rename = "_AUDIT_LOGINUID")]
    pub audit_login_uid: Option<String>,
    pub message: String,
    pub code_file: Option<String>,
    pub code_line: Option<String>,
    pub code_function: Option<String>,
    pub unit: Option<String>,
    pub user_unit: Option<String>,
    pub userspace_usec: Option<String>,
    pub kernel_usec: Option<String>,
    pub message_id: Option<String>,
    pub result: Option<String>,
    pub user_id: Option<String>,
    pub seat_id: Option<String>,
    pub leader: Option<String>,
    pub journal_name: Option<String>,
    pub journal_path: Option<String>,
    pub current_use: Option<String>,
    pub current_use_pretty: Option<String>,
    pub max_use: Option<String>,
    pub max_use_pretty: Option<String>,
    pub disk_keep_free: Option<String>,
    pub disk_keep_free_pretty: Option<String>,
    pub disk_available: Option<String>,
    pub disk_available_pretty: Option<String>,
    pub available: Option<String>,
    pub available_pretty: Option<String>,
    pub limit: Option<String>,
    pub limit_pretty: Option<String>,
    pub session_id: Option<String>,
    pub syslog_pid: Option<String>,
    #[serde(rename = "_PID")]
    pub pid: Option<String>,
    #[serde(rename = "_AUDIT_SESSION")]
    pub audit_session: Option<String>,
    #[serde(rename = "_AUDIT_TYPE")]
    pub audit_type: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_NAME")]
    pub audit_field_name: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_APPARMOR")]
    pub audit_field_apparmor: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_OPERATION")]
    pub audit_field_operation: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_PROFILE")]
    pub audit_field_profile: Option<String>,
    #[serde(rename = "_AUDIT_ID")]
    pub audit_id: Option<String>,
    #[serde(rename = "_KERNEL_SUBSYSTEM")]
    pub kernel_subsystem: Option<String>,
    #[serde(rename = "_KERNEL_DEVICE")]
    pub kernel_device: Option<String>,
    #[serde(rename = "_UDEV_SYSNAME")]
    pub udev_sysname: Option<String>,
    #[serde(rename = "_UDEV_DEVNODE")]
    pub udev_devnode: Option<String>,
    #[serde(rename = "_UDEV_DEVLINK")]
    pub udev_devlink: Option<String>,
    #[serde(rename = "_SOURCE_REALTIME_TIMESTAMP")]
    pub source_realtime_timestamp: Option<String>,
    #[serde(rename = "_SOURCE_MONOTONIC_TIMESTAMP")]
    pub source_monotonic_timestamp: Option<String>,
}

pub struct JournalGateway {
    pub baseurl: url::Url,
    client: hyper::Client,
}

impl JournalGateway {
    pub fn new(baseurl_str: &str) -> JournalGateway {
        let baseurl = url::Url::parse(baseurl_str).expect("Error during parsing baseurl");
        JournalGateway {
            baseurl: baseurl.to_owned(),
            client: hyper::Client::new(),
        }
    }

    pub fn get_all_entries(&self) -> Vec<JournalEntry> {
        self.get_entries(None)
    }

    pub fn get_entries(&self, filters: Option<Vec<(String, String)>>) -> Vec<JournalEntry> {
        let mut url = self.baseurl.join("entries").expect("url join failed");
        if let Some(filters_unwrapped) = filters {
            url.query_pairs_mut().extend_pairs(filters_unwrapped);
        }

        let request = self.client
            .request(hyper::method::Method::Get, url.as_str())
            .header(hyper::header::Accept::json());

        let mut response = request.send().expect("request failure");
        let mut body = String::new();
        response
            .read_to_string(&mut body)
            .expect("body read failed");

        let mut res: Vec<JournalEntry> = vec![];
        for line in body.split("\n") {
            if line.len() > 0 {
                let deser_res = serde_json::from_str(&line);
                match deser_res {
                    Ok(entry) => res.push(entry),
                    Err(e) => println!("Error {}, skipping line: {}", e, line),
                }
            }
        }

        res
    }
}

#[cfg(test)]
mod tests {
    use JournalGateway;

    #[test]
    fn get_entries() {

        // TODO make this into a self contained test

        let journal_gw = JournalGateway::new("http://192.168.33.19:19531");
        let res = journal_gw.get_all_entries();
        for entry in res {
            println!("{}", entry.message);
        }
    }

    // TODO create another test with a filter, e.g.
    // let res = journal_gw.get_entries(Some(vec![("_COMM".to_string(), "cat".to_string())]));
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::IResult;
use nom::IResult::*;
use nom::Err::*;

mod helper;
use helper::*;

macro_rules! errprint {
    ($($arg:tt)*) => (
        std::io::stderr().write_fmt(format_args!($($arg)*))
        );
}

macro_rules! errln {
    ($fmt:expr) => (errprint!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (errprint!(concat!($fmt, "\n"), $($arg)*));
}

#[allow(unused_imports)] use std::io::Write;

#[derive(Debug,Eq,PartialEq)]
struct Date {
    year: i32,
    month: u32,
    day: u32,
}

#[derive(Debug,Eq,PartialEq)]
struct Time {
    hour: u32,
    minute: u32,
    second: u32,
    tz_offset: i32,
}

/// Take n bytes and ensure that they are only in the provided range of bytes
macro_rules! take_n_between(
    ($input:expr, $count:expr, $min:expr, $max:expr) => (
        {
            let new_min = $min as u8;
            let new_max = $max as u8;
            let cnt = $count as usize;
            if $input.len() < cnt {
                nom::IResult::Incomplete(nom::Needed::Size(cnt))
            } else {
                for idx in 0..$count {
                    if $input[idx] < new_min || $input[idx] > new_max {
                        return nom::IResult::Error(nom::Err::Position(42 as u32,$input));
                    }
                }

                nom::IResult::Done(&$input[$count..], &$input[0..$count])
            }
        }
        );
    );

macro_rules! char_between(
    ($input:expr, $min:expr, $max:expr) => (
        take_n_between!($input, 1, $min, $max)
    );
);

macro_rules! empty_or(
    ($i:expr, $submac:ident!( $($args:tt)* )) => (
        if $i.len() == 0 {
            nom::IResult::Done($i, None)
        } else {
            match $submac!($i, $($args)*) {
                nom::IResult::Done(i,o)     => nom::IResult::Done(i, Some(o)),
                nom::IResult::Error(e)      => nom::IResult::Error(e),
                nom::IResult::Incomplete(i) => nom::IResult::Incomplete(i)

            }
        }
    );
);

named!(year_prefix, alt!(tag!("+") | tag!("-")));

named!(pub year <&[u8], i32>, chain!(
        pref: opt!(year_prefix) ~
        year: take_n_between!(4, '0', '9')
        ,
        || {
            match pref {
                Some(b"-") => -buf_to_i32(year),
                _ => buf_to_i32(year)
            }
        }));

named!(lower_month <&[u8], u32>, chain!(tag!("0") ~ s:char_between!('1', '9') , || buf_to_u32(s)));
named!(upper_month <&[u8], u32>, chain!(tag!("1") ~ s:char_between!('0', '2') ,       || 10+buf_to_u32(s)));

named!(month <&[u8], u32>, alt!(lower_month | upper_month));

named!(day_zero <&[u8], u32>,  chain!(tag!("0") ~ s:char_between!('1', '9') ,  || buf_to_u32(s)));
named!(day_one <&[u8], u32>,   chain!(tag!("1") ~ s:char_between!('0', '9') , || 10+buf_to_u32(s)));
named!(day_two <&[u8], u32>,   chain!(tag!("2") ~ s:char_between!('0', '9') , || 20+buf_to_u32(s)));
named!(day_three <&[u8], u32>, chain!(tag!("3") ~ s:char_between!('0', '1') ,         || 30+buf_to_u32(s)));

named!(day <&[u8], u32>, alt!(day_zero | day_one | day_two | day_three));

named!(date <&[u8], Date>, chain!(
        y: year ~
        tag!("-") ~
        m: month ~
        tag!("-") ~
        d: day
        ,
        || { Date{ year: y, month: m, day: d } }
        ));

named!(lower_hour <&[u8], u32>, chain!(f:char_between!('0','1') ~ s:char_between!('0','9') ,
                                       || { buf_to_u32(f)*10 + buf_to_u32(s) } ));
named!(upper_hour <&[u8], u32>, chain!(tag!("2") ~ s:char_between!('0','4') , || 20+buf_to_u32(s)));
named!(hour <&[u8], u32>, alt!(lower_hour | upper_hour));

named!(below_sixty <&[u8], u32>, chain!(f:char_between!('0','5') ~ s:char_between!('0','9') ,
                                       || { buf_to_u32(f)*10 + buf_to_u32(s) } ));

named!(minute <&[u8], u32>, call!(below_sixty));
named!(second <&[u8], u32>, call!(below_sixty));

named!(append_seconds <&[u8], u32>, chain!(tag!(":") ~ sec:second, || sec));

named!(time <&[u8], Time>, chain!(
        h: hour ~
        tag!(":") ~
        m: minute ~
        s: empty_or!(
            chain!(tag!(":") ~ s:second , || s)
            )
        ,
        || {
            Time {
                hour: h,
                minute: m,
                second: s.unwrap_or(0),
                tz_offset: 0
            }
        }
        ));

named!(timezone <&[u8], u32>, chain!(
        tag!("+") ~
        h: hour ~
        tag!(":")? ~
        m: minute
        ,
        || { h }));

named!(tz_z, tag!("Z"));
named!(timezone_utc <&[u8], u32>, map!(tz_z, |_| 0));

named!(time_with_timezone <&[u8], Time>, chain!(
        t: time ~
        s: empty_or!(alt!(timezone_utc | timezone))
        ,
        || {
            Time {
                hour: t.hour,
                minute: t.minute,
                second: t.second,
                tz_offset: s.unwrap_or(0) as i32
            }
        }
        ));

#[test]
fn parse_year() {
    assert_eq!(Done(&[][..], 2015), year(b"2015"));
    assert_eq!(Done(&[][..], -0333), year(b"-0333"));

    assert_eq!(Done(&b"-"[..], 2015), year(b"2015-"));

    assert!(year(b"abcd").is_err());
    assert!(year(b"2a03").is_err());
}

#[test]
fn parse_month() {
    assert_eq!(Done(&[][..], 1), month(b"01"));
    assert_eq!(Done(&[][..], 6), month(b"06"));
    assert_eq!(Done(&[][..], 12), month(b"12"));
    assert_eq!(Done(&b"-"[..], 12), month(b"12-"));

    assert!(month(b"13").is_err());
    assert!(month(b"00").is_err());
}

#[test]
fn parse_day() {
    assert_eq!(Done(&[][..], 1), day(b"01"));
    assert_eq!(Done(&[][..], 12), day(b"12"));
    assert_eq!(Done(&[][..], 20), day(b"20"));
    assert_eq!(Done(&[][..], 28), day(b"28"));
    assert_eq!(Done(&[][..], 30), day(b"30"));
    assert_eq!(Done(&[][..], 31), day(b"31"));
    assert_eq!(Done(&b"-"[..], 31), day(b"31-"));

    assert!(day(b"00").is_err());
    assert!(day(b"32").is_err());
}

#[test]
fn parse_date() {
    assert_eq!(Done(&[][..], Date{ year: 2015, month: 6, day: 26 }), date(b"2015-06-26"));
    assert_eq!(Done(&[][..], Date{ year: -333, month: 7, day: 11 }), date(b"-0333-07-11"));

    assert!(date(b"201").is_incomplete());
    assert!(date(b"2015p00p00").is_err());
    assert!(date(b"pppp").is_err());
}

#[test]
fn parse_hour() {
    assert_eq!(Done(&[][..], 0), hour(b"00"));
    assert_eq!(Done(&[][..], 1), hour(b"01"));
    assert_eq!(Done(&[][..], 6), hour(b"06"));
    assert_eq!(Done(&[][..], 12), hour(b"12"));
    assert_eq!(Done(&[][..], 13), hour(b"13"));
    assert_eq!(Done(&[][..], 20), hour(b"20"));
    assert_eq!(Done(&[][..], 24), hour(b"24"));

    assert!(hour(b"25").is_err());
    assert!(hour(b"30").is_err());
    assert!(hour(b"ab").is_err());
}

#[test]
fn parse_minute() {
    assert_eq!(Done(&[][..], 0), minute(b"00"));
    assert_eq!(Done(&[][..], 1), minute(b"01"));
    assert_eq!(Done(&[][..], 30), minute(b"30"));
    assert_eq!(Done(&[][..], 59), minute(b"59"));

    assert!(minute(b"60").is_err());
    assert!(minute(b"61").is_err());
    assert!(minute(b"ab").is_err());
}

#[test]
fn parse_second() {
    assert_eq!(Done(&[][..], 0), second(b"00"));
    assert_eq!(Done(&[][..], 1), second(b"01"));
    assert_eq!(Done(&[][..], 30), second(b"30"));
    assert_eq!(Done(&[][..], 59), second(b"59"));

    assert!(second(b"60").is_err());
    assert!(second(b"61").is_err());
    assert!(second(b"ab").is_err());
}

#[test]
fn parse_time() {
    assert_eq!(Done(&[][..], Time{ hour: 16, minute: 43, second: 16, tz_offset: 0}), time(b"16:43:16"));
    assert_eq!(Done(&[][..], Time{ hour: 16, minute: 43, second:  0, tz_offset: 0}), time(b"16:43"));

    assert!(time(b"20:").is_incomplete());
    assert!(time(b"20p42p16").is_err());
    assert!(time(b"pppp").is_err());
}

#[test]
fn parse_time_with_timezone() {
    assert_eq!(Done(&[][..], Time{ hour: 16, minute: 43, second: 16, tz_offset: 0}),
               time_with_timezone(b"16:43:16"));
    assert_eq!(Done(&[][..], Time{ hour: 16, minute: 43, second: 16, tz_offset: 0}),
               time_with_timezone(b"16:43:16Z"));
    assert_eq!(Done(&[][..], Time{ hour: 16, minute: 43, second: 16, tz_offset: 0}),
               time_with_timezone(b"16:43:16+00:00"));
    assert_eq!(Done(&[][..], Time{ hour: 16, minute: 43, second: 16, tz_offset: 5}),
               time_with_timezone(b"16:43:16+05:00"));

    assert!(time_with_timezone(b"20:").is_incomplete());
    assert!(time_with_timezone(b"20p42p16").is_err());
    assert!(time_with_timezone(b"pppp").is_err());

    assert!(time_with_timezone(b"16:43:16+").is_err());
    assert!(time_with_timezone(b"16:43:16+0").is_err());
    assert!(time_with_timezone(b"16:43:16+05:").is_err());
}
<commit_msg>Implement Debug<commit_after>#[macro_use]
extern crate nom;

use nom::IResult;
use nom::IResult::*;
use nom::Err::*;
use std::fmt;

mod helper;
use helper::*;

macro_rules! errprint {
    ($($arg:tt)*) => (
        std::io::stderr().write_fmt(format_args!($($arg)*))
        );
}

macro_rules! errln {
    ($fmt:expr) => (errprint!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (errprint!(concat!($fmt, "\n"), $($arg)*));
}

#[allow(unused_imports)] use std::io::Write;

#[derive(Eq,PartialEq)]
struct Date {
    year: i32,
    month: u32,
    day: u32,
}

#[derive(Eq,PartialEq)]
struct Time {
    hour: u32,
    minute: u32,
    second: u32,
    tz_offset: i32,
}

#[derive(Eq,PartialEq)]
struct DateTime {
    date: Date,
    time: Time,
}

impl fmt::Debug for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0>4?}-{:0>2?}-{:0>2?}",
               self.year, self.month, self.day)
    }
}
impl fmt::Debug for Time {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0>2?}:{:0>2?}:{:0>2?}Z{:0>4?}",
               self.hour, self.minute, self.second, self.tz_offset*100)
    }
}
impl fmt::Debug for DateTime {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}T{:?}", self.date, self.time)
    }
}

/// Take n bytes and ensure that they are only in the provided range of bytes
macro_rules! take_n_between(
    ($input:expr, $count:expr, $min:expr, $max:expr) => (
        {
            let new_min = $min as u8;
            let new_max = $max as u8;
            let cnt = $count as usize;
            if $input.len() < cnt {
                nom::IResult::Incomplete(nom::Needed::Size(cnt))
            } else {
                for idx in 0..$count {
                    if $input[idx] < new_min || $input[idx] > new_max {
                        return nom::IResult::Error(nom::Err::Position(42 as u32,$input));
                    }
                }

                nom::IResult::Done(&$input[$count..], &$input[0..$count])
            }
        }
        );
    );

macro_rules! char_between(
    ($input:expr, $min:expr, $max:expr) => (
        take_n_between!($input, 1, $min, $max)
    );
);

macro_rules! empty_or(
    ($i:expr, $submac:ident!( $($args:tt)* )) => (
        if $i.len() == 0 {
            nom::IResult::Done($i, None)
        } else {
            match $submac!($i, $($args)*) {
                nom::IResult::Done(i,o)     => nom::IResult::Done(i, Some(o)),
                nom::IResult::Error(e)      => nom::IResult::Error(e),
                nom::IResult::Incomplete(i) => nom::IResult::Incomplete(i)

            }
        }
    );
);

named!(year_prefix, alt!(tag!("+") | tag!("-")));

named!(pub year <&[u8], i32>, chain!(
        pref: opt!(year_prefix) ~
        year: take_n_between!(4, '0', '9')
        ,
        || {
            match pref {
                Some(b"-") => -buf_to_i32(year),
                _ => buf_to_i32(year)
            }
        }));

named!(lower_month <&[u8], u32>, chain!(tag!("0") ~ s:char_between!('1', '9') , || buf_to_u32(s)));
named!(upper_month <&[u8], u32>, chain!(tag!("1") ~ s:char_between!('0', '2') ,       || 10+buf_to_u32(s)));

named!(month <&[u8], u32>, alt!(lower_month | upper_month));

named!(day_zero <&[u8], u32>,  chain!(tag!("0") ~ s:char_between!('1', '9') ,  || buf_to_u32(s)));
named!(day_one <&[u8], u32>,   chain!(tag!("1") ~ s:char_between!('0', '9') , || 10+buf_to_u32(s)));
named!(day_two <&[u8], u32>,   chain!(tag!("2") ~ s:char_between!('0', '9') , || 20+buf_to_u32(s)));
named!(day_three <&[u8], u32>, chain!(tag!("3") ~ s:char_between!('0', '1') ,         || 30+buf_to_u32(s)));

named!(day <&[u8], u32>, alt!(day_zero | day_one | day_two | day_three));

named!(date <&[u8], Date>, chain!(
        y: year ~
        tag!("-") ~
        m: month ~
        tag!("-") ~
        d: day
        ,
        || { Date{ year: y, month: m, day: d } }
        ));

named!(lower_hour <&[u8], u32>, chain!(f:char_between!('0','1') ~ s:char_between!('0','9') ,
                                       || { buf_to_u32(f)*10 + buf_to_u32(s) } ));
named!(upper_hour <&[u8], u32>, chain!(tag!("2") ~ s:char_between!('0','4') , || 20+buf_to_u32(s)));
named!(hour <&[u8], u32>, alt!(lower_hour | upper_hour));

named!(below_sixty <&[u8], u32>, chain!(f:char_between!('0','5') ~ s:char_between!('0','9') ,
                                       || { buf_to_u32(f)*10 + buf_to_u32(s) } ));

named!(minute <&[u8], u32>, call!(below_sixty));
named!(second <&[u8], u32>, call!(below_sixty));

named!(append_seconds <&[u8], u32>, chain!(tag!(":") ~ sec:second, || sec));

named!(time <&[u8], Time>, chain!(
        h: hour ~
        tag!(":") ~
        m: minute ~
        s: empty_or!(
            chain!(tag!(":") ~ s:second , || s)
            )
        ,
        || {
            Time {
                hour: h,
                minute: m,
                second: s.unwrap_or(0),
                tz_offset: 0
            }
        }
        ));

named!(timezone <&[u8], u32>, chain!(
        tag!("+") ~
        h: hour ~
        tag!(":")? ~
        m: minute
        ,
        || { h }));

named!(tz_z, tag!("Z"));
named!(timezone_utc <&[u8], u32>, map!(tz_z, |_| 0));

named!(time_with_timezone <&[u8], Time>, chain!(
        t: time ~
        s: empty_or!(alt!(timezone_utc | timezone))
        ,
        || {
            Time {
                hour: t.hour,
                minute: t.minute,
                second: t.second,
                tz_offset: s.unwrap_or(0) as i32
            }
        }
        ));

#[test]
fn parse_year() {
    assert_eq!(Done(&[][..], 2015), year(b"2015"));
    assert_eq!(Done(&[][..], -0333), year(b"-0333"));

    assert_eq!(Done(&b"-"[..], 2015), year(b"2015-"));

    assert!(year(b"abcd").is_err());
    assert!(year(b"2a03").is_err());
}

#[test]
fn parse_month() {
    assert_eq!(Done(&[][..], 1), month(b"01"));
    assert_eq!(Done(&[][..], 6), month(b"06"));
    assert_eq!(Done(&[][..], 12), month(b"12"));
    assert_eq!(Done(&b"-"[..], 12), month(b"12-"));

    assert!(month(b"13").is_err());
    assert!(month(b"00").is_err());
}

#[test]
fn parse_day() {
    assert_eq!(Done(&[][..], 1), day(b"01"));
    assert_eq!(Done(&[][..], 12), day(b"12"));
    assert_eq!(Done(&[][..], 20), day(b"20"));
    assert_eq!(Done(&[][..], 28), day(b"28"));
    assert_eq!(Done(&[][..], 30), day(b"30"));
    assert_eq!(Done(&[][..], 31), day(b"31"));
    assert_eq!(Done(&b"-"[..], 31), day(b"31-"));

    assert!(day(b"00").is_err());
    assert!(day(b"32").is_err());
}

#[test]
fn parse_date() {
    assert_eq!(Done(&[][..], Date{ year: 2015, month: 6, day: 26 }), date(b"2015-06-26"));
    assert_eq!(Done(&[][..], Date{ year: -333, month: 7, day: 11 }), date(b"-0333-07-11"));

    assert!(date(b"201").is_incomplete());
    assert!(date(b"2015p00p00").is_err());
    assert!(date(b"pppp").is_err());
}

#[test]
fn parse_hour() {
    assert_eq!(Done(&[][..], 0), hour(b"00"));
    assert_eq!(Done(&[][..], 1), hour(b"01"));
    assert_eq!(Done(&[][..], 6), hour(b"06"));
    assert_eq!(Done(&[][..], 12), hour(b"12"));
    assert_eq!(Done(&[][..], 13), hour(b"13"));
    assert_eq!(Done(&[][..], 20), hour(b"20"));
    assert_eq!(Done(&[][..], 24), hour(b"24"));

    assert!(hour(b"25").is_err());
    assert!(hour(b"30").is_err());
    assert!(hour(b"ab").is_err());
}

#[test]
fn parse_minute() {
    assert_eq!(Done(&[][..], 0), minute(b"00"));
    assert_eq!(Done(&[][..], 1), minute(b"01"));
    assert_eq!(Done(&[][..], 30), minute(b"30"));
    assert_eq!(Done(&[][..], 59), minute(b"59"));

    assert!(minute(b"60").is_err());
    assert!(minute(b"61").is_err());
    assert!(minute(b"ab").is_err());
}

#[test]
fn parse_second() {
    assert_eq!(Done(&[][..], 0), second(b"00"));
    assert_eq!(Done(&[][..], 1), second(b"01"));
    assert_eq!(Done(&[][..], 30), second(b"30"));
    assert_eq!(Done(&[][..], 59), second(b"59"));

    assert!(second(b"60").is_err());
    assert!(second(b"61").is_err());
    assert!(second(b"ab").is_err());
}

#[test]
fn parse_time() {
    assert_eq!(Done(&[][..], Time{ hour: 16, minute: 43, second: 16, tz_offset: 0}), time(b"16:43:16"));
    assert_eq!(Done(&[][..], Time{ hour: 16, minute: 43, second:  0, tz_offset: 0}), time(b"16:43"));

    assert!(time(b"20:").is_incomplete());
    assert!(time(b"20p42p16").is_err());
    assert!(time(b"pppp").is_err());
}

#[test]
fn parse_time_with_timezone() {
    assert_eq!(Done(&[][..], Time{ hour: 16, minute: 43, second: 16, tz_offset: 0}),
               time_with_timezone(b"16:43:16"));
    assert_eq!(Done(&[][..], Time{ hour: 16, minute: 43, second: 16, tz_offset: 0}),
               time_with_timezone(b"16:43:16Z"));
    assert_eq!(Done(&[][..], Time{ hour: 16, minute: 43, second: 16, tz_offset: 0}),
               time_with_timezone(b"16:43:16+00:00"));
    assert_eq!(Done(&[][..], Time{ hour: 16, minute: 43, second: 16, tz_offset: 5}),
               time_with_timezone(b"16:43:16+05:00"));

    assert!(time_with_timezone(b"20:").is_incomplete());
    assert!(time_with_timezone(b"20p42p16").is_err());
    assert!(time_with_timezone(b"pppp").is_err());

    assert!(time_with_timezone(b"16:43:16+").is_err());
    assert!(time_with_timezone(b"16:43:16+0").is_err());
    assert!(time_with_timezone(b"16:43:16+05:").is_err());
}
<|endoftext|>


<commit_before>extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use viewport::Viewport;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

#[derive(Clone)]
pub struct InputMap<A: Action> {
    keymap: KeyMap<A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputMap<A> {
    pub fn new(size: Size) -> Self {
        InputMap {
            keymap: KeyMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.translate($but_var) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    pub fn rebind_button(&mut self, _but: Button, _act: A) {
        // TODO implement
    }

    pub fn add_binding(&mut self, but: Button, act: A) {
        self.keymap.add_mapping(but, act);
    }

    pub fn get_bindings_for_action(&self, _act: A) -> ButtonTuple {
        ButtonTuple(None, None, None) // TODO implement
    }

    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.viewport_size = size
    }

    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslator {
    pub x_axis_movement_inverted: bool,
    pub y_axis_movement_inverted: bool,
    pub x_axis_scroll_inverted: bool,
    pub y_axis_scroll_inverted: bool,
    pub viewport_size: Size
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            x_axis_movement_inverted: false,
            y_axis_movement_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (_sw, _sh) = {
                    let Size {width, height} = self.viewport_size;
                    (width as f64, height as f64)
                };

                Motion::MouseCursor(x, y) // TODO implement
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[derive(Clone, Debug)]
struct KeyMap<A: Action> {
    btn_map: HashMap<ButtonTuple, A>
}

impl<A: Action> KeyMap<A> {
    fn new() -> Self {
        KeyMap {
            btn_map: HashMap::new()
        }
    }

    fn add_mapping(&mut self, button: Button, action: A) {
        let mut bt = self.get_bindings_for_action(action).unwrap_or(ButtonTuple::new());
        let bt = if bt.insert_inplace(button) {bt} else {ButtonTuple::new()};
        self.btn_map.insert(bt, action);
    }

    fn _with_mapping(mut self, button: Button, action: A) -> Self {
        self.add_mapping(button, action);
        self
    }

    fn get_bindings_for_action(&self, action: A) -> Option<ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(&bt, _)| bt)
    }

    fn translate(&self, button: Button) -> Option<A> {
        self.btn_map.iter().find(|&(&bt, _)| bt.contains(button)).map(|(_, &a)| a)
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(Option<Button>, Option<Button>, Option<Button>);

impl ButtonTuple {
    fn new() -> Self {
        ButtonTuple(None, None, None)
    }

    fn contains(&self, btn: Button) -> bool {
        let sbtn = Some(btn);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    fn _remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    fn _replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    fn insert_inplace(&mut self, btn: Button) -> bool {
        let &mut ButtonTuple(a, b, c) = self;
        if a.is_none() {
            *self = ButtonTuple(Some(btn), b, c)
        } else if b.is_none() {
            *self = ButtonTuple(a, Some(btn), c)
        } else if c.is_none() {
            *self = ButtonTuple(a, b, Some(btn))
        } else {
            return false;
        }
        true
    }
}
<commit_msg>Add more doc comments<commit_after>extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use viewport::Viewport;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputMap<A: Action> {
    keymap: KeyMap<A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputMap<A> {

    /// Creates an empty InputMap.
    pub fn new(size: Size) -> Self {
        InputMap {
            keymap: KeyMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.translate($but_var) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    pub fn rebind_button(&mut self, _but: Button, _act: A) {
        // TODO implement
    }

    pub fn add_binding(&mut self, but: Button, act: A) {
        self.keymap.add_mapping(but, act);
    }

    /// Get all the bindings for an action
    pub fn get_bindings_for_action(&self, _act: A) -> ButtonTuple {
        ButtonTuple(None, None, None) // TODO implement
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslator {
    pub x_axis_movement_inverted: bool,
    pub y_axis_movement_inverted: bool,
    pub x_axis_scroll_inverted: bool,
    pub y_axis_scroll_inverted: bool,
    pub viewport_size: Size
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            x_axis_movement_inverted: false,
            y_axis_movement_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (_sw, _sh) = {
                    let Size {width, height} = self.viewport_size;
                    (width as f64, height as f64)
                };

                Motion::MouseCursor(x, y) // TODO implement
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[derive(Clone, Debug)]
struct KeyMap<A: Action> {
    btn_map: HashMap<ButtonTuple, A>
}

impl<A: Action> KeyMap<A> {
    fn new() -> Self {
        KeyMap {
            btn_map: HashMap::new()
        }
    }

    fn add_mapping(&mut self, button: Button, action: A) {
        let mut bt = self.get_bindings_for_action(action).unwrap_or(ButtonTuple::new());
        let bt = if bt.insert_inplace(button) {bt} else {ButtonTuple::new()};
        self.btn_map.insert(bt, action);
    }

    fn _with_mapping(mut self, button: Button, action: A) -> Self {
        self.add_mapping(button, action);
        self
    }

    fn get_bindings_for_action(&self, action: A) -> Option<ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(&bt, _)| bt)
    }

    fn translate(&self, button: Button) -> Option<A> {
        self.btn_map.iter().find(|&(&bt, _)| bt.contains(button)).map(|(_, &a)| a)
    }
}

/// A three-element tuple of Option<Button>. Used as the key of an InputMap
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(Option<Button>, Option<Button>, Option<Button>);

impl ButtonTuple {
    fn new() -> Self {
        ButtonTuple(None, None, None)
    }

    fn contains(&self, btn: Button) -> bool {
        let sbtn = Some(btn);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    fn _remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    fn _replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    fn insert_inplace(&mut self, btn: Button) -> bool {
        let &mut ButtonTuple(a, b, c) = self;
        if a.is_none() {
            *self = ButtonTuple(Some(btn), b, c)
        } else if b.is_none() {
            *self = ButtonTuple(a, Some(btn), c)
        } else if c.is_none() {
            *self = ButtonTuple(a, b, Some(btn))
        } else {
            return false;
        }
        true
    }
}
<|endoftext|>


<commit_before>//! ByteSize is an utility that easily makes bytes size representation
//! and helps its arithmetic operations.
//!
//! ## Example
//!
//! ```ignore
//! extern crate bytesize;
//!
//! use bytesize::ByteSize;
//!
//! fn byte_arithmetic_operator() {
//!   let x = ByteSize::mb(1);
//!   let y = ByteSize::kb(100);
//!
//!   let plus = x + y;
//!   print!("{} bytes", plus.as_usize());
//!
//!   let minus = ByteSize::tb(100) - ByteSize::gb(4);
//!   print!("{} bytes", minus.as_usize());
//! }
//! ```
//!
//! It also provides its human readable string as follows:
//!
//! ```ignore
//!  assert_eq!("482 GiB".to_string(), ByteSize::gb(518).to_string(true));
//!  assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false));
//! ```

extern crate num;

use std::fmt::{Display,Formatter,Result};
use std::ops::{Add,Sub,Mul,Div};

/// byte size for 1 byte
pub static B: usize = 1;
/// bytes size for 1 kilobyte
pub static KB: usize = 1000;
/// bytes size for 1 megabyte
pub static MB: usize = 1000000;
/// bytes size for 1 gigabyte
pub static GB: usize = 1000000000;
/// bytes size for 1 terabyte
pub static TB: usize = 1000000000000;
/// bytes size for 1 petabyte
pub static PB: usize = 1000000000000000;

/// bytes size for 1 kibibyte
pub static KIB: usize = 1024;
/// bytes size for 1 mebibyte
pub static MIB: usize = 1048576;
/// bytes size for 1 gibibyte
pub static GIB: usize = 1073741824;
/// bytes size for 1 tebibyte
pub static TIB: usize = 1099511627776;
/// bytes size for 1 pebibyte
pub static PIB: usize = 1125899906842624;

#[derive(Debug, Copy, Clone)]
/// Byte size representation
pub struct ByteSize {
  size: usize
}

impl ByteSize {
  #[inline(always)]
  pub fn b(size: usize) -> ByteSize {
    ByteSize {size: size}
  }

  #[inline(always)]
  pub fn kb(size: usize) -> ByteSize {
    ByteSize {size: size * KB}
  }

  #[inline(always)]
  pub fn kib(size: usize) -> ByteSize {
   ByteSize {size: size * KIB}
  }

  #[inline(always)]
  pub fn mb(size: usize) -> ByteSize {
    ByteSize {size: size * MB}
  }

  #[inline(always)]
  pub fn mib(size: usize) -> ByteSize {
    ByteSize {size: size * MIB}
  }

  #[inline(always)]
  pub fn gb(size: usize) -> ByteSize {
    ByteSize {size: size * GB}
  }

  #[inline(always)]
  pub fn gib(size: usize) -> ByteSize {
    ByteSize {size: size * GIB}
  }

  #[inline(always)]
  pub fn tb(size: usize) -> ByteSize {
    ByteSize {size: size * TB}
  }

  #[inline(always)]
  pub fn tib(size: usize) -> ByteSize {
    ByteSize {size: size * TIB}
  }

  #[inline(always)]
  pub fn pb(size: usize) -> ByteSize {
    ByteSize {size: size * PB}
  }

  #[inline(always)]
  pub fn pib(size: usize) -> ByteSize {
    ByteSize {size: size * PIB}
  }

  #[inline(always)]
  pub fn as_usize(&self) -> usize {
    self.size
  }

  pub fn to_string(&self, si: bool) -> String
  {

    let unit = if si { KIB } else { KB };

    if self.size < unit {
      {format!("{} B", self.size)}
    } else {
      let mut exp = ((self.size as f64).ln() / (if si {LN_KIB} else {LN_KB})) as usize;
      if exp == 0 {
        exp = 1;
      }

      if si {
        format!("{} {}iB",(self.size / num::pow(unit, exp)), UNITS_SI.as_bytes()[exp - 1] as char)
      } else {
        format!("{} {}B",(self.size / num::pow(unit, exp)), UNITS.as_bytes()[exp - 1] as char)
      }
    }
  }
}

static UNITS:    &'static str = "KMGTPE";
static UNITS_SI: &'static str = "kMGTPE";
static LN_KB: f64 = 6.931471806; // ln 1024
static LN_KIB: f64 = 6.907755279; // ln 1000

impl Display for ByteSize {
  fn fmt(&self, f: &mut Formatter) -> Result {
    write!(f, "{}", self.to_string(false))
  }
}

impl Add<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size + rhs)}
  }
}

impl Add<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size + rhs.size)}
  }
}

impl Sub<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size - rhs)}
  }
}

impl Sub<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size - rhs.size)}
  }
}

impl Mul<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn mul(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size * rhs)}
  }
}

impl Div<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn div(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size / rhs)}
  }
}

#[test]
fn test_arithmetic() {
  let x = ByteSize::mb(1);
  let y = ByteSize::kb(100);

  assert_eq!(
    (x + y).as_usize(),
    1100000
  );
  assert_eq!(
    (x + (100*1000)).as_usize(),
    1100000
  );

  assert_eq!(
    (x - y).as_usize(),
    900000
  );
  assert_eq!(
    (x - (100*1000)).as_usize(),
    900000
  );
}

#[allow(dead_code)]
fn assert_display(expected: &str, b: ByteSize) {
  assert_eq!(expected, format!("{}", b));
}

#[test]
fn test_display() {
  assert_display("215 B", ByteSize::b(215));
  assert_display("1 KB", ByteSize::kb(1));
  assert_display("301 KB", ByteSize::kb(301));
  assert_display("419 MB", ByteSize::mb(419));
  assert_display("518 GB", ByteSize::gb(518));
  assert_display("815 TB", ByteSize::tb(815));
  assert_display("609 PB", ByteSize::pb(609));
}

#[allow(dead_code)]
fn assert_to_string(expected: &str, b: ByteSize, si: bool) {
  assert_eq!(expected.to_string(), b.to_string(si));
}

#[test]
fn test_to_string() {
  assert_to_string("215 B", ByteSize::b(215), true);
  assert_to_string("215 B", ByteSize::b(215), false);

  assert_to_string("1 kiB", ByteSize::kib(1), true);
  assert_to_string("1 KB", ByteSize::kib(1), false);

  assert_to_string("293 kiB", ByteSize::kb(301), true);
  assert_to_string("301 KB", ByteSize::kb(301), false);

  assert_to_string("1 MiB", ByteSize::mib(1), true);
  assert_to_string("1048 KB", ByteSize::mib(1), false);

  assert_to_string("399 MiB", ByteSize::mb(419), true);
  assert_to_string("419 MB", ByteSize::mb(419), false);

  assert_to_string("482 GiB", ByteSize::gb(518), true);
  assert_to_string("518 GB", ByteSize::gb(518), false);

  assert_to_string("741 TiB", ByteSize::tb(815), true);
  assert_to_string("815 TB", ByteSize::tb(815), false);

  assert_to_string("540 PiB", ByteSize::pb(609), true);
  assert_to_string("609 PB", ByteSize::pb(609), false);
}
<commit_msg>move tests into a module<commit_after>//! ByteSize is an utility that easily makes bytes size representation
//! and helps its arithmetic operations.
//!
//! ## Example
//!
//! ```ignore
//! extern crate bytesize;
//!
//! use bytesize::ByteSize;
//!
//! fn byte_arithmetic_operator() {
//!   let x = ByteSize::mb(1);
//!   let y = ByteSize::kb(100);
//!
//!   let plus = x + y;
//!   print!("{} bytes", plus.as_usize());
//!
//!   let minus = ByteSize::tb(100) - ByteSize::gb(4);
//!   print!("{} bytes", minus.as_usize());
//! }
//! ```
//!
//! It also provides its human readable string as follows:
//!
//! ```ignore
//!  assert_eq!("482 GiB".to_string(), ByteSize::gb(518).to_string(true));
//!  assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false));
//! ```

extern crate num;

use std::fmt::{Display,Formatter,Result};
use std::ops::{Add,Sub,Mul,Div};

/// byte size for 1 byte
pub static B: usize = 1;
/// bytes size for 1 kilobyte
pub static KB: usize = 1000;
/// bytes size for 1 megabyte
pub static MB: usize = 1000000;
/// bytes size for 1 gigabyte
pub static GB: usize = 1000000000;
/// bytes size for 1 terabyte
pub static TB: usize = 1000000000000;
/// bytes size for 1 petabyte
pub static PB: usize = 1000000000000000;

/// bytes size for 1 kibibyte
pub static KIB: usize = 1024;
/// bytes size for 1 mebibyte
pub static MIB: usize = 1048576;
/// bytes size for 1 gibibyte
pub static GIB: usize = 1073741824;
/// bytes size for 1 tebibyte
pub static TIB: usize = 1099511627776;
/// bytes size for 1 pebibyte
pub static PIB: usize = 1125899906842624;

#[derive(Debug, Copy, Clone)]
/// Byte size representation
pub struct ByteSize {
  size: usize
}

impl ByteSize {
  #[inline(always)]
  pub fn b(size: usize) -> ByteSize {
    ByteSize {size: size}
  }

  #[inline(always)]
  pub fn kb(size: usize) -> ByteSize {
    ByteSize {size: size * KB}
  }

  #[inline(always)]
  pub fn kib(size: usize) -> ByteSize {
   ByteSize {size: size * KIB}
  }

  #[inline(always)]
  pub fn mb(size: usize) -> ByteSize {
    ByteSize {size: size * MB}
  }

  #[inline(always)]
  pub fn mib(size: usize) -> ByteSize {
    ByteSize {size: size * MIB}
  }

  #[inline(always)]
  pub fn gb(size: usize) -> ByteSize {
    ByteSize {size: size * GB}
  }

  #[inline(always)]
  pub fn gib(size: usize) -> ByteSize {
    ByteSize {size: size * GIB}
  }

  #[inline(always)]
  pub fn tb(size: usize) -> ByteSize {
    ByteSize {size: size * TB}
  }

  #[inline(always)]
  pub fn tib(size: usize) -> ByteSize {
    ByteSize {size: size * TIB}
  }

  #[inline(always)]
  pub fn pb(size: usize) -> ByteSize {
    ByteSize {size: size * PB}
  }

  #[inline(always)]
  pub fn pib(size: usize) -> ByteSize {
    ByteSize {size: size * PIB}
  }

  #[inline(always)]
  pub fn as_usize(&self) -> usize {
    self.size
  }

  pub fn to_string(&self, si: bool) -> String
  {

    let unit = if si { KIB } else { KB };

    if self.size < unit {
      {format!("{} B", self.size)}
    } else {
      let mut exp = ((self.size as f64).ln() / (if si {LN_KIB} else {LN_KB})) as usize;
      if exp == 0 {
        exp = 1;
      }

      if si {
        format!("{} {}iB",(self.size / num::pow(unit, exp)), UNITS_SI.as_bytes()[exp - 1] as char)
      } else {
        format!("{} {}B",(self.size / num::pow(unit, exp)), UNITS.as_bytes()[exp - 1] as char)
      }
    }
  }
}

static UNITS:    &'static str = "KMGTPE";
static UNITS_SI: &'static str = "kMGTPE";
static LN_KB: f64 = 6.931471806; // ln 1024
static LN_KIB: f64 = 6.907755279; // ln 1000

impl Display for ByteSize {
  fn fmt(&self, f: &mut Formatter) -> Result {
    write!(f, "{}", self.to_string(false))
  }
}

impl Add<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size + rhs)}
  }
}

impl Add<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size + rhs.size)}
  }
}

impl Sub<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size - rhs)}
  }
}

impl Sub<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size - rhs.size)}
  }
}

impl Mul<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn mul(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size * rhs)}
  }
}

impl Div<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn div(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size / rhs)}
  }
}

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

  #[test]
  fn test_arithmetic() {
    let x = ByteSize::mb(1);
    let y = ByteSize::kb(100);

    assert_eq!(
      (x + y).as_usize(),
      1100000
    );
    assert_eq!(
      (x + (100*1000)).as_usize(),
      1100000
    );

    assert_eq!(
      (x - y).as_usize(),
      900000
    );
    assert_eq!(
      (x - (100*1000)).as_usize(),
      900000
    );
  }

  fn assert_display(expected: &str, b: ByteSize) {
    assert_eq!(expected, format!("{}", b));
  }

  #[test]
  fn test_display() {
    assert_display("215 B", ByteSize::b(215));
    assert_display("1 KB", ByteSize::kb(1));
    assert_display("301 KB", ByteSize::kb(301));
    assert_display("419 MB", ByteSize::mb(419));
    assert_display("518 GB", ByteSize::gb(518));
    assert_display("815 TB", ByteSize::tb(815));
    assert_display("609 PB", ByteSize::pb(609));
  }

  fn assert_to_string(expected: &str, b: ByteSize, si: bool) {
    assert_eq!(expected.to_string(), b.to_string(si));
  }

  #[test]
  fn test_to_string() {
    assert_to_string("215 B", ByteSize::b(215), true);
    assert_to_string("215 B", ByteSize::b(215), false);

    assert_to_string("1 kiB", ByteSize::kib(1), true);
    assert_to_string("1 KB", ByteSize::kib(1), false);

    assert_to_string("293 kiB", ByteSize::kb(301), true);
    assert_to_string("301 KB", ByteSize::kb(301), false);

    assert_to_string("1 MiB", ByteSize::mib(1), true);
    assert_to_string("1048 KB", ByteSize::mib(1), false);

    assert_to_string("399 MiB", ByteSize::mb(419), true);
    assert_to_string("419 MB", ByteSize::mb(419), false);

    assert_to_string("482 GiB", ByteSize::gb(518), true);
    assert_to_string("518 GB", ByteSize::gb(518), false);

    assert_to_string("741 TiB", ByteSize::tb(815), true);
    assert_to_string("815 TB", ByteSize::tb(815), false);

    assert_to_string("540 PiB", ByteSize::pb(609), true);
    assert_to_string("609 PB", ByteSize::pb(609), false);
  }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Capture the screen with xlib

#![allow(dead_code, non_upper_case_globals, non_camel_case_types)]

extern crate x11;
extern crate libc;

use libc::c_ulong;

pub mod ffi;

#[derive(Debug, Eq, PartialEq)]
struct RGB8 {
	r: u8,
	g: u8,
	b: u8,
}

/// From a bitmask for a color in a pixel, calculate the color size in bits and the bitshift
fn mask_size_and_shift(mut mask: c_ulong) -> (c_ulong, u16) {
	let (mut bits, mut shift) = (0, 0);
	let mut prev = 0;
	for _ in 0..(c_ulong::max_value() as f64).log2() as u16 {
		if mask & 1 == 1 {
			bits += 1;
			prev = 1;
		} else if prev == 1 {
			break;
		} else {
			shift += 1;
		}
		mask >>= 1;
	}
	(bits, shift)
}

// #[test]
// fn test_create_window() {
// 	use x11::xlib;
// 	use std::ptr;

// 	unsafe {

// 	// use the information from the environment variable DISPLAY to create the X connection:
// 	let display = match xlib::XOpenDisplay(ptr::null_mut()) {
// 		null if null.is_null() => panic!("Unable to connect X server"),
// 		display => display,
// 	};

// 	let screen_num = xlib::XDefaultScreen(display);
// 	let (black_pixel, white_pixel) = (xlib::XBlackPixel(display, screen_num),
// 		xlib::XWhitePixel(display, screen_num));

// 	// Once the display is initialized, create the window
// 	let (x, y) = (0, 0);
// 	let (width, height, border_width) = (400, 500, 5);
// 	let (border_color, background_color) = (black_pixel, white_pixel);
// 	let window = xlib::XCreateSimpleWindow(display,
// 		xlib::XRootWindow(display, screen_num),
// 		x, y,
// 		width, height, border_width,
// 		border_color, background_color);

// 	// this routine determines which types of input are allowed in the input.
// 	xlib::XSelectInput(display, window,
// 		xlib::ExposureMask | xlib::ButtonPressMask | xlib::KeyPressMask);

// 	// create the Graphics Context
// 	let graphics_context = xlib::XCreateGC(display, window, 0, ptr::null_mut());

// 	xlib::XMapWindow(display, window);
// 	xlib::XFlush(display);

// 	std::thread::sleep_ms(1000);

// 	// it is good programming practice to return system resources to the system...
// 	xlib::XFreeGC(display, graphics_context);
// 	xlib::XDestroyWindow(display, window);
// 	xlib::XCloseDisplay(display);

// 	}
// }

#[test]
fn test_shm() {
	use x11::xlib;
	use std::{ ptr, mem };
	use ffi::*;
	use x11::xlib::Bool;
	use libc::{ c_uint, size_t, c_char, c_void, c_int };

	unsafe {

	// use the information from the environment variable DISPLAY to create the X connection:
	let display = xlib::XOpenDisplay(ptr::null_mut());
	if display.is_null() {
		panic!("Unable to connect X server");
	}

	println!("MIT-SHM available: {}", XShmQueryExtension(display) != 0);
	let (mut major_ver, mut minor_ver) = (0, 0);
	let mut shared_pixmaps: Bool = 0;
	XShmQueryVersion(display, &mut major_ver, &mut minor_ver, &mut shared_pixmaps);
	println!("SHM: major: {}, minor: {}, shared pixmaps: {}", major_ver, minor_ver, shared_pixmaps);

	let screen_num = xlib::XDefaultScreen(display);
	println!("Screen: {}", screen_num);

	let mut root_window = 0;
	let (mut root_x, mut root_y) = (0, 0);
	let (mut root_width, mut root_height, mut root_border_width) = (0, 0, 0);
	let mut root_pixel_depth = 0;
	if xlib::XGetGeometry(display, xlib::XRootWindow(display, screen_num),
		&mut root_window,
		&mut root_x, &mut root_y,
		&mut root_width, &mut root_height, &mut root_border_width,
		&mut root_pixel_depth) == 0
	{
		panic!("XGetGeometry failed");
	}
	println!("root window: {}; x, y: {:?}; w, h, bw: {:?}; d: {:?}",
		root_window, (root_x, root_y), (root_width, root_height, root_border_width),
		root_pixel_depth);

	let mut shm_segment_info = mem::zeroed();
	let image_ptr = XShmCreateImage(display, xlib::XDefaultVisual(display, screen_num),
		xlib::XDefaultDepth(display, screen_num) as c_uint,
		ZPixmap, ptr::null_mut(),
		&mut shm_segment_info,
		root_width, root_height);
	if image_ptr.is_null() {
		panic!("XShmCreateImage returned null pointer");
	}
	let image = &mut *image_ptr;

	shm_segment_info.shmid = shmget(IPC_PRIVATE,
		(image.bytes_per_line * image.height) as size_t,
		IPC_CREAT | 0777);
	if shm_segment_info.shmid == -1 {
		panic!("shmget failed");
	}

	shm_segment_info.shmaddr = shmat(shm_segment_info.shmid, ptr::null_mut(), 0) as *mut c_char;
	if shm_segment_info.shmaddr.is_null() {
		panic!("XShmCreateImage returned null pointer");
	}
	image.data = shm_segment_info.shmaddr;

	shm_segment_info.read_only = 0;

	if XShmAttach(display, &mut shm_segment_info) == 0 {
		panic!("XShmAttach failed");
	}

	if XShmGetImage(display, root_window, image, root_x, root_y, AllPlanes) == 0 {
		panic!("XShmGetImage failed");
	}

	println!("width {}, height {}, xoffset {}, format {}, byte_order {}, bitmap_unity {}, \
		bitmap_bit_order {}, bitmap_pad {}, depth {}, bytes_per_line {}, bits_per_pixel {}, \
		red_mask {:b}, green_mask {:b}, blue_mask {:b}",
		image.width, image.height, image.xoffset, image.format, image.byte_order,
		image.bitmap_unity, image.bitmap_bit_order, image.bitmap_pad, image.depth,
		image.bytes_per_line, image.bits_per_pixel,
		image.red_mask, image.green_mask, image.blue_mask);

	// Factor to multiply color value with for it to fit in a u8
	let (red_size, red_shift) = mask_size_and_shift(image.red_mask);
	let (green_size, green_shift) = mask_size_and_shift(image.red_mask);
	let (blue_size, blue_shift) = mask_size_and_shift(image.red_mask);
	if !(red_size == 8 && green_size == 8 && blue_size == 8 && image.bits_per_pixel == 32) {
		panic!("Bits per pixel is not 32 bits or Color channels are not 8 bits");
	}

	let raw_pixels = std::slice::from_raw_parts(image.data as *const u32,
		image.height as usize * image.width as usize);

	let mut pixel_buf = Vec::with_capacity(image.width as usize * image.height as usize);
	for row in 0..image.height as usize {
		for col in 0..image.width as usize {
			// println!("{:?}", (row, col));
			let pixel = raw_pixels[row * image.width as usize + col];
			pixel_buf.push(RGB8{
				r: ((pixel & image.red_mask as u32) >> red_shift) as u8,
				g: ((pixel & image.green_mask as u32) >> green_shift) as u8,
				b: ((pixel & image.blue_mask as u32) >> blue_shift) as u8,
			});
		}
	}

	println!("Tot color: {:?}", pixel_buf.iter()
		.fold((0, 0, 0), |(r, g, b), p| (r + p.r as u64, g + p.g as u64, b + p.b as u64))
	);

	XShmDetach(display, &mut shm_segment_info);
	xlib::XDestroyImage(image);
	shmdt(shm_segment_info.shmaddr as *mut c_void);
	shmctl(shm_segment_info.shmid, IPC_RMID, ptr::null_mut());

	xlib::XCloseDisplay(display);

	}
}<commit_msg>Problem with XGetPixel was caused by swapped x & y<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Capture the screen with xlib

#![allow(dead_code, non_upper_case_globals, non_camel_case_types)]

extern crate x11;
extern crate libc;

use libc::c_ulong;

pub mod ffi;

#[derive(Debug, Eq, PartialEq)]
struct RGB8 {
	r: u8,
	g: u8,
	b: u8,
}

/// From a bitmask for a color in a pixel, calculate the color size in bits and the bitshift
fn mask_size_and_shift(mut mask: c_ulong) -> (c_ulong, u16) {
	let (mut bits, mut shift) = (0, 0);
	let mut prev = 0;
	for _ in 0..(c_ulong::max_value() as f64).log2() as u16 {
		if mask & 1 == 1 {
			bits += 1;
			prev = 1;
		} else if prev == 1 {
			break;
		} else {
			shift += 1;
		}
		mask >>= 1;
	}
	(bits, shift)
}

// #[test]
// fn test_create_window() {
// 	use x11::xlib;
// 	use std::ptr;

// 	unsafe {

// 	// use the information from the environment variable DISPLAY to create the X connection:
// 	let display = match xlib::XOpenDisplay(ptr::null_mut()) {
// 		null if null.is_null() => panic!("Unable to connect X server"),
// 		display => display,
// 	};

// 	let screen_num = xlib::XDefaultScreen(display);
// 	let (black_pixel, white_pixel) = (xlib::XBlackPixel(display, screen_num),
// 		xlib::XWhitePixel(display, screen_num));

// 	// Once the display is initialized, create the window
// 	let (x, y) = (0, 0);
// 	let (width, height, border_width) = (400, 500, 5);
// 	let (border_color, background_color) = (black_pixel, white_pixel);
// 	let window = xlib::XCreateSimpleWindow(display,
// 		xlib::XRootWindow(display, screen_num),
// 		x, y,
// 		width, height, border_width,
// 		border_color, background_color);

// 	// this routine determines which types of input are allowed in the input.
// 	xlib::XSelectInput(display, window,
// 		xlib::ExposureMask | xlib::ButtonPressMask | xlib::KeyPressMask);

// 	// create the Graphics Context
// 	let graphics_context = xlib::XCreateGC(display, window, 0, ptr::null_mut());

// 	xlib::XMapWindow(display, window);
// 	xlib::XFlush(display);

// 	std::thread::sleep_ms(1000);

// 	// it is good programming practice to return system resources to the system...
// 	xlib::XFreeGC(display, graphics_context);
// 	xlib::XDestroyWindow(display, window);
// 	xlib::XCloseDisplay(display);

// 	}
// }

#[test]
fn test_shm() {
	use x11::xlib;
	use std::{ ptr, mem };
	use ffi::*;
	use x11::xlib::Bool;
	use libc::{ c_uint, size_t, c_char, c_void, c_int };

	unsafe {

	// use the information from the environment variable DISPLAY to create the X connection:
	let display = xlib::XOpenDisplay(ptr::null_mut());
	if display.is_null() {
		panic!("Unable to connect X server");
	}

	println!("MIT-SHM available: {}", XShmQueryExtension(display) != 0);
	let (mut major_ver, mut minor_ver) = (0, 0);
	let mut shared_pixmaps: Bool = 0;
	XShmQueryVersion(display, &mut major_ver, &mut minor_ver, &mut shared_pixmaps);
	println!("SHM: major: {}, minor: {}, shared pixmaps: {}", major_ver, minor_ver, shared_pixmaps);

	let screen_num = xlib::XDefaultScreen(display);
	println!("Screen: {}", screen_num);

	let mut root_window = 0;
	let (mut root_x, mut root_y) = (0, 0);
	let (mut root_width, mut root_height, mut root_border_width) = (0, 0, 0);
	let mut root_pixel_depth = 0;
	if xlib::XGetGeometry(display, xlib::XRootWindow(display, screen_num),
		&mut root_window,
		&mut root_x, &mut root_y,
		&mut root_width, &mut root_height, &mut root_border_width,
		&mut root_pixel_depth) == 0
	{
		panic!("XGetGeometry failed");
	}
	println!("root window: {}; x, y: {:?}; w, h, bw: {:?}; d: {:?}",
		root_window, (root_x, root_y), (root_width, root_height, root_border_width),
		root_pixel_depth);

	let mut shm_segment_info = mem::zeroed();
	let image_ptr = XShmCreateImage(display, xlib::XDefaultVisual(display, screen_num),
		xlib::XDefaultDepth(display, screen_num) as c_uint,
		ZPixmap, ptr::null_mut(),
		&mut shm_segment_info,
		root_width, root_height);
	if image_ptr.is_null() {
		panic!("XShmCreateImage returned null pointer");
	}
	let image = &mut *image_ptr;

	shm_segment_info.shmid = shmget(IPC_PRIVATE,
		(image.bytes_per_line * image.height) as size_t,
		IPC_CREAT | 0777);
	if shm_segment_info.shmid == -1 {
		panic!("shmget failed");
	}

	shm_segment_info.shmaddr = shmat(shm_segment_info.shmid, ptr::null_mut(), 0) as *mut c_char;
	if shm_segment_info.shmaddr.is_null() {
		panic!("XShmCreateImage returned null pointer");
	}
	image.data = shm_segment_info.shmaddr;

	shm_segment_info.read_only = 0;

	if XShmAttach(display, &mut shm_segment_info) == 0 {
		panic!("XShmAttach failed");
	}

	for _ in 0..10 {
		if XShmGetImage(display, root_window, image, root_x, root_y, AllPlanes) == 0 {
			panic!("XShmGetImage failed");
		}

		println!("width {}, height {}, xoffset {}, format {}, byte_order {}, bitmap_unity {}, \
			bitmap_bit_order {}, bitmap_pad {}, depth {}, bytes_per_line {}, bits_per_pixel {}, \
			red_mask {:b}, green_mask {:b}, blue_mask {:b}",
			image.width, image.height, image.xoffset, image.format, image.byte_order,
			image.bitmap_unity, image.bitmap_bit_order, image.bitmap_pad, image.depth,
			image.bytes_per_line, image.bits_per_pixel,
			image.red_mask, image.green_mask, image.blue_mask);

		// Factor to multiply color value with for it to fit in a u8
		let (red_size, red_shift) = mask_size_and_shift(image.red_mask);
		let (green_size, green_shift) = mask_size_and_shift(image.red_mask);
		let (blue_size, blue_shift) = mask_size_and_shift(image.red_mask);
		let (red_mask, green_mask, blue_mask) = (image.red_mask, image.green_mask, image.blue_mask);
		let masked_pixel_to_rgb: Box<Fn(c_ulong) -> RGB8> =
			if red_size == 8 && green_size == 8 && blue_size == 8
		{

			Box::new(move |pixel| RGB8{
				r: ((pixel & red_mask) >> red_shift) as u8,
				g: ((pixel & green_mask) >> green_shift) as u8,
				b: ((pixel & blue_mask) >> blue_shift) as u8,
			})
		} else {
			let red_size_factor = 8.0 / red_size as f32;
			let green_size_factor = 8.0 / green_size as f32;
			let blue_size_factor = 8.0 / blue_size as f32;
			Box::new(move |pixel| RGB8{
				r: (((pixel & red_mask) >> red_shift) as f32 * red_size_factor) as u8,
				g: (((pixel & green_mask) >> green_shift) as f32 * green_size_factor) as u8,
				b: (((pixel & blue_mask) >> blue_shift) as f32 * blue_size_factor) as u8,
			})
		};

		let mut pixel_buf = Vec::with_capacity(image.width as usize * image.height as usize);
		for row in 0..image.height {
			for col in 0..image.width {
				pixel_buf.push(masked_pixel_to_rgb(xlib::XGetPixel(image, col, row)));
			}
		}

		println!("Tot color: {:?}", pixel_buf.iter()
			.fold((0, 0, 0), |(r, g, b), p| (r + p.r as u64, g + p.g as u64, b + p.b as u64))
		);
	}

	XShmDetach(display, &mut shm_segment_info);
	xlib::XDestroyImage(image);
	shmdt(shm_segment_info.shmaddr as *mut c_void);
	shmctl(shm_segment_info.shmid, IPC_RMID, ptr::null_mut());

	xlib::XCloseDisplay(display);

	}
}<|endoftext|>


<commit_before>extern crate libc;
/*
 * seccomp actions
 */
#[allow(non_camel_case_types)]
pub type scmp_filter_ctx = libc::c_void;

/**
 * Error retern value
 */
pub const __NR_SCMP_ERROR: libc::c_int = -1;

/**
 * Kill the process
 */
pub const SCMP_ACT_KILL: u32  = 0x00000000;
/**
 * Throw a SIGSYS signal
 */
pub const SCMP_ACT_TRAP: u32 = 0x00030000;
/**
 * Return the specified error code
 */
#[allow(non_snake_case)]
pub fn SCMP_ACT_ERRNO(x: u32) -> u32 { 0x00050000 | ((x) & 0x0000ffff) }
/**
 * Notify a tracing process with the specified value
 */
#[allow(non_snake_case)]
pub fn SCMP_ACT_TRACE(x: u32) -> u32 { 0x7ff00000 | ((x) & 0x0000ffff) }
/**
 * Allow the syscall to be executed
 */
pub const SCMP_ACT_ALLOW: u32 = 0x7fff0000;

/**
 * Filter attributes
 */
#[derive(Debug)]
#[repr(C)]
pub enum scmp_filter_attr {
    _SCMP_FLTATR_MIN,
    SCMP_FLTATR_ACT_DEFAULT, /** default filter action */
    SCMP_FLTATR_ACT_BADARCH, /** bad architecture action */
    SCMP_FLTATR_CTL_NNP, /** set NO_NEW_PRIVS on filter load */
    _SCMP_FLTATR_MAX,
}

/**
 * Comparison operators
 */
#[derive(Debug)]
#[repr(C)]
pub enum scmp_compare {
        _SCMP_CMP_MIN = 0,
        SCMP_CMP_NE = 1,                /** not equal */
        SCMP_CMP_LT = 2,                /** less than */
        SCMP_CMP_LE = 3,                /** less than or equal */
        SCMP_CMP_EQ = 4,                /** equal */
        SCMP_CMP_GE = 5,                /** greater than or equal */
        SCMP_CMP_GT = 6,                /** greater than */
        SCMP_CMP_MASKED_EQ = 7,         /** masked equality */
        _SCMP_CMP_MAX,
}

/**
 * Argument datum
 */
#[allow(non_camel_case_types)]
pub type scmp_datum_t = libc::uint64_t;

/**
 * Argument / Value comparison definition
 */
#[derive(Debug)]
#[repr(C)]
pub struct scmp_arg_cmp {
        pub arg: libc::c_uint,        /** argument number, starting at 0 */
        pub op: scmp_compare,       /** the comparison op, e.g. SCMP_CMP_* */
        pub datum_a: scmp_datum_t,
        pub datum_b: scmp_datum_t,
}

#[link(name = "seccomp")]
extern {
    /**
     * Initialize the filter state
     *
     * @param def_action the default filter action
     *
     * This function initializes the internal seccomp filter state and should
     * be called before any other functions in this library to ensure the filter
     * state is initialized.  Returns a filter context on success, NULL on failure.
     *
     */
    pub fn seccomp_init(def_action: libc::uint32_t) -> *mut scmp_filter_ctx;
    /**
     * Reset the filter state
     *
     * @param ctx the filter context
     * @param def_action the default filter action
     *
     * This function resets the given seccomp filter state and ensures the
     * filter state is reinitialized.  This function does not reset any seccomp
     * filters already loaded into the kernel.  Returns zero on success, negative
     * values on failure.
     *
     */
    pub fn seccomp_reset(ctx: *mut scmp_filter_ctx, def_action: libc::uint32_t) -> libc::c_int;
    /**
     * Destroys the filter state and releases any resources
     *
     * @param ctx the filter context
     *
     * This functions destroys the given seccomp filter state and releases any
     * resources, including memory, associated with the filter state.  This
     * function does not reset any seccomp filters already loaded into the kernel.
     * The filter context can no longer be used after calling this function.
     *
     */
    pub fn seccomp_release(ctx: *mut scmp_filter_ctx);
    /**
     * Loads the filter into the kernel
     *
     * @param ctx the filter context
     *
     * This function loads the given seccomp filter context into the kernel.  If
     * the filter was loaded correctly, the kernel will be enforcing the filter
     * when this function returns.  Returns zero on success, negative values on
     * error.
     *
     */
    pub fn seccomp_load(ctx: *const scmp_filter_ctx) -> libc::c_int;

    /**
     * Get the value of a filter attribute
     *
     * @param ctx the filter context
     * @param attr the filter attribute name
     * @param value the filter attribute value
     *
     * This function fetches the value of the given attribute name and returns it
     * via @value.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_attr_get(ctx: *const scmp_filter_ctx,
                         attr: scmp_filter_attr, value: *mut libc::uint32_t) -> libc::c_int;

    /**
     * Set the value of a filter attribute
     *
     * @param ctx the filter context
     * @param attr the filter attribute name
     * @param value the filter attribute value
     *
     * This function sets the value of the given attribute.  Returns zero on
     * success, negative values on failure.
     *
     */
    pub fn seccomp_attr_set(ctx: *mut scmp_filter_ctx,
                         attr: scmp_filter_attr, value: libc::uint32_t) -> libc::c_int;

    /**
     * Resolve a syscall name to a number
     * @param name the syscall name
     *
     * Resolve the given syscall name to the syscall number.  Returns the syscall
     * number on success, including negative pseudo syscall numbers (e.g. __PNR_*);
     * returns __NR_SCMP_ERROR on failure.
     *
     */
    pub fn seccomp_syscall_resolve_name(name: *const libc::c_char) -> libc::c_int;

    /**
     * Set the priority of a given syscall
     *
     * @param ctx the filter context
     * @param syscall the syscall number
     * @param priority priority value, higher value == higher priority
     *
     * This function sets the priority of the given syscall; this value is used
     * when generating the seccomp filter code such that higher priority syscalls
     * will incur less filter code overhead than the lower priority syscalls in the
     * filter.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_syscall_priority(ctx: *mut scmp_filter_ctx,
                                 syscall: libc::c_int, priority: libc::uint8_t) -> libc::c_int;

    /**
     * Add a new rule to the filter
     *
     * @param ctx the filter context
     * @param action the filter action
     * @param syscall the syscall number
     * @param arg_cnt the number of argument filters in the argument filter chain
     * @param ... scmp_arg_cmp structs (use of SCMP_ARG_CMP() recommended)
     *
     * This function adds a series of new argument/value checks to the seccomp
     * filter for the given syscall; multiple argument/value checks can be
     * specified and they will be chained together (AND'd together) in the filter.
     * If the specified rule needs to be adjusted due to architecture specifics it
     * will be adjusted without notification.  Returns zero on success, negative
     * values on failure.
     *
     */
    pub fn seccomp_rule_add(ctx: *mut scmp_filter_ctx,
                         action: libc::uint32_t, syscall: libc::c_int, arg_cnt: libc::c_uint, ...) -> libc::c_int;

    /**
     * Add a new rule to the filter
     *
     * @param ctx the filter context
     * @param action the filter action
     * @param syscall the syscall number
     * @param arg_cnt the number of elements in the arg_array parameter
     * @param arg_array array of scmp_arg_cmp structs
     *
     * This function adds a series of new argument/value checks to the seccomp
     * filter for the given syscall; multiple argument/value checks can be
     * specified and they will be chained together (AND'd together) in the filter.
     * If the specified rule needs to be adjusted due to architecture specifics it
     * will be adjusted without notification.  Returns zero on success, negative
     * values on failure.
     *
     */
    pub fn seccomp_rule_add_array(ctx: *mut scmp_filter_ctx,
        action: libc::uint32_t, syscall: libc::c_int, arg_cnt: libc::c_uint,
        arg_array: *const scmp_arg_cmp) -> libc::c_int;

    /**
     * Add a new rule to the filter
     *
     * @param ctx the filter context
     * @param action the filter action
     * @param syscall the syscall number
     * @param arg_cnt the number of argument filters in the argument filter chain
     * @param ... scmp_arg_cmp structs (use of SCMP_ARG_CMP() recommended)
     *
     * This function adds a series of new argument/value checks to the seccomp
     * filter for the given syscall; multiple argument/value checks can be
     * specified and they will be chained together (AND'd together) in the filter.
     * If the specified rule can not be represented on the architecture the
     * function will fail.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_rule_add_exact(ctx: *mut scmp_filter_ctx, action: libc::uint32_t,
                               syscall: libc::c_int, arg_cnt: libc::c_uint, ...) -> libc::c_int;

    /**
     * Add a new rule to the filter
     *
     * @param ctx the filter context
     * @param action the filter action
     * @param syscall the syscall number
     * @param arg_cnt  the number of elements in the arg_array parameter
     * @param arg_array array of scmp_arg_cmp structs
     *
     * This function adds a series of new argument/value checks to the seccomp
     * filter for the given syscall; multiple argument/value checks can be
     * specified and they will be chained together (AND'd together) in the filter.
     * If the specified rule can not be represented on the architecture the
     * function will fail.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_rule_add_exact_array(ctx: *mut scmp_filter_ctx,
                                        action: libc::uint32_t, syscall: libc::c_int, arg_cnt: libc::c_uint,
                                        arg_array: *const scmp_arg_cmp) -> libc::c_int;

    /**
     * Generate seccomp Pseudo Filter Code (PFC) and export it to a file
     *
     * @param ctx the filter context
     * @param fd the destination fd
     *
     * This function generates seccomp Pseudo Filter Code (PFC) and writes it to
     * the given fd.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_export_pfc(ctx: *const scmp_filter_ctx, fd: libc::c_int) -> libc::c_int;

    /**
     * Generate seccomp Berkley Packet Filter (BPF) code and export it to a file
     *
     * @param ctx the filter context
     * @param fd the destination fd
     *
     * This function generates seccomp Berkley Packer Filter (BPF) code and writes
     * it to the given fd.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_export_bpf(ctx: *const scmp_filter_ctx, fd: libc::c_int) -> libc::c_int;
}

#[test]
fn does_it_even_work() {
    unsafe {
        let context = seccomp_init(SCMP_ACT_ALLOW);
        let comparator = scmp_arg_cmp {
            arg: 0,
            op: scmp_compare::SCMP_CMP_EQ,
            datum_a: 1000,
            datum_b: 0,
        };
        assert!(seccomp_rule_add(context, SCMP_ACT_KILL, 105, 1, comparator) == 0);
        assert!(seccomp_load(context) == 0);
        //assert!(libc::setuid(1000) == 0);
    }
}
<commit_msg>Derive Clone and Copy for enums for int conversion<commit_after>extern crate libc;
/*
 * seccomp actions
 */
#[allow(non_camel_case_types)]
pub type scmp_filter_ctx = libc::c_void;

/**
 * Error retern value
 */
pub const __NR_SCMP_ERROR: libc::c_int = -1;

/**
 * Kill the process
 */
pub const SCMP_ACT_KILL: u32  = 0x00000000;
/**
 * Throw a SIGSYS signal
 */
pub const SCMP_ACT_TRAP: u32 = 0x00030000;
/**
 * Return the specified error code
 */
#[allow(non_snake_case)]
pub fn SCMP_ACT_ERRNO(x: u32) -> u32 { 0x00050000 | ((x) & 0x0000ffff) }
/**
 * Notify a tracing process with the specified value
 */
#[allow(non_snake_case)]
pub fn SCMP_ACT_TRACE(x: u32) -> u32 { 0x7ff00000 | ((x) & 0x0000ffff) }
/**
 * Allow the syscall to be executed
 */
pub const SCMP_ACT_ALLOW: u32 = 0x7fff0000;

/**
 * Filter attributes
 */
#[derive(Debug,Clone,Copy)]
#[repr(C)]
pub enum scmp_filter_attr {
    _SCMP_FLTATR_MIN,
    SCMP_FLTATR_ACT_DEFAULT, /** default filter action */
    SCMP_FLTATR_ACT_BADARCH, /** bad architecture action */
    SCMP_FLTATR_CTL_NNP, /** set NO_NEW_PRIVS on filter load */
    _SCMP_FLTATR_MAX,
}

/**
 * Comparison operators
 */
#[derive(Debug,Clone,Copy)]
#[repr(C)]
pub enum scmp_compare {
        _SCMP_CMP_MIN = 0,
        SCMP_CMP_NE = 1,                /** not equal */
        SCMP_CMP_LT = 2,                /** less than */
        SCMP_CMP_LE = 3,                /** less than or equal */
        SCMP_CMP_EQ = 4,                /** equal */
        SCMP_CMP_GE = 5,                /** greater than or equal */
        SCMP_CMP_GT = 6,                /** greater than */
        SCMP_CMP_MASKED_EQ = 7,         /** masked equality */
        _SCMP_CMP_MAX,
}

/**
 * Argument datum
 */
#[allow(non_camel_case_types)]
pub type scmp_datum_t = libc::uint64_t;

/**
 * Argument / Value comparison definition
 */
#[derive(Debug)]
#[repr(C)]
pub struct scmp_arg_cmp {
        pub arg: libc::c_uint,        /** argument number, starting at 0 */
        pub op: scmp_compare,       /** the comparison op, e.g. SCMP_CMP_* */
        pub datum_a: scmp_datum_t,
        pub datum_b: scmp_datum_t,
}

#[link(name = "seccomp")]
extern {
    /**
     * Initialize the filter state
     *
     * @param def_action the default filter action
     *
     * This function initializes the internal seccomp filter state and should
     * be called before any other functions in this library to ensure the filter
     * state is initialized.  Returns a filter context on success, NULL on failure.
     *
     */
    pub fn seccomp_init(def_action: libc::uint32_t) -> *mut scmp_filter_ctx;
    /**
     * Reset the filter state
     *
     * @param ctx the filter context
     * @param def_action the default filter action
     *
     * This function resets the given seccomp filter state and ensures the
     * filter state is reinitialized.  This function does not reset any seccomp
     * filters already loaded into the kernel.  Returns zero on success, negative
     * values on failure.
     *
     */
    pub fn seccomp_reset(ctx: *mut scmp_filter_ctx, def_action: libc::uint32_t) -> libc::c_int;
    /**
     * Destroys the filter state and releases any resources
     *
     * @param ctx the filter context
     *
     * This functions destroys the given seccomp filter state and releases any
     * resources, including memory, associated with the filter state.  This
     * function does not reset any seccomp filters already loaded into the kernel.
     * The filter context can no longer be used after calling this function.
     *
     */
    pub fn seccomp_release(ctx: *mut scmp_filter_ctx);
    /**
     * Loads the filter into the kernel
     *
     * @param ctx the filter context
     *
     * This function loads the given seccomp filter context into the kernel.  If
     * the filter was loaded correctly, the kernel will be enforcing the filter
     * when this function returns.  Returns zero on success, negative values on
     * error.
     *
     */
    pub fn seccomp_load(ctx: *const scmp_filter_ctx) -> libc::c_int;

    /**
     * Get the value of a filter attribute
     *
     * @param ctx the filter context
     * @param attr the filter attribute name
     * @param value the filter attribute value
     *
     * This function fetches the value of the given attribute name and returns it
     * via @value.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_attr_get(ctx: *const scmp_filter_ctx,
                         attr: scmp_filter_attr, value: *mut libc::uint32_t) -> libc::c_int;

    /**
     * Set the value of a filter attribute
     *
     * @param ctx the filter context
     * @param attr the filter attribute name
     * @param value the filter attribute value
     *
     * This function sets the value of the given attribute.  Returns zero on
     * success, negative values on failure.
     *
     */
    pub fn seccomp_attr_set(ctx: *mut scmp_filter_ctx,
                         attr: scmp_filter_attr, value: libc::uint32_t) -> libc::c_int;

    /**
     * Resolve a syscall name to a number
     * @param name the syscall name
     *
     * Resolve the given syscall name to the syscall number.  Returns the syscall
     * number on success, including negative pseudo syscall numbers (e.g. __PNR_*);
     * returns __NR_SCMP_ERROR on failure.
     *
     */
    pub fn seccomp_syscall_resolve_name(name: *const libc::c_char) -> libc::c_int;

    /**
     * Set the priority of a given syscall
     *
     * @param ctx the filter context
     * @param syscall the syscall number
     * @param priority priority value, higher value == higher priority
     *
     * This function sets the priority of the given syscall; this value is used
     * when generating the seccomp filter code such that higher priority syscalls
     * will incur less filter code overhead than the lower priority syscalls in the
     * filter.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_syscall_priority(ctx: *mut scmp_filter_ctx,
                                 syscall: libc::c_int, priority: libc::uint8_t) -> libc::c_int;

    /**
     * Add a new rule to the filter
     *
     * @param ctx the filter context
     * @param action the filter action
     * @param syscall the syscall number
     * @param arg_cnt the number of argument filters in the argument filter chain
     * @param ... scmp_arg_cmp structs (use of SCMP_ARG_CMP() recommended)
     *
     * This function adds a series of new argument/value checks to the seccomp
     * filter for the given syscall; multiple argument/value checks can be
     * specified and they will be chained together (AND'd together) in the filter.
     * If the specified rule needs to be adjusted due to architecture specifics it
     * will be adjusted without notification.  Returns zero on success, negative
     * values on failure.
     *
     */
    pub fn seccomp_rule_add(ctx: *mut scmp_filter_ctx,
                         action: libc::uint32_t, syscall: libc::c_int, arg_cnt: libc::c_uint, ...) -> libc::c_int;

    /**
     * Add a new rule to the filter
     *
     * @param ctx the filter context
     * @param action the filter action
     * @param syscall the syscall number
     * @param arg_cnt the number of elements in the arg_array parameter
     * @param arg_array array of scmp_arg_cmp structs
     *
     * This function adds a series of new argument/value checks to the seccomp
     * filter for the given syscall; multiple argument/value checks can be
     * specified and they will be chained together (AND'd together) in the filter.
     * If the specified rule needs to be adjusted due to architecture specifics it
     * will be adjusted without notification.  Returns zero on success, negative
     * values on failure.
     *
     */
    pub fn seccomp_rule_add_array(ctx: *mut scmp_filter_ctx,
        action: libc::uint32_t, syscall: libc::c_int, arg_cnt: libc::c_uint,
        arg_array: *const scmp_arg_cmp) -> libc::c_int;

    /**
     * Add a new rule to the filter
     *
     * @param ctx the filter context
     * @param action the filter action
     * @param syscall the syscall number
     * @param arg_cnt the number of argument filters in the argument filter chain
     * @param ... scmp_arg_cmp structs (use of SCMP_ARG_CMP() recommended)
     *
     * This function adds a series of new argument/value checks to the seccomp
     * filter for the given syscall; multiple argument/value checks can be
     * specified and they will be chained together (AND'd together) in the filter.
     * If the specified rule can not be represented on the architecture the
     * function will fail.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_rule_add_exact(ctx: *mut scmp_filter_ctx, action: libc::uint32_t,
                               syscall: libc::c_int, arg_cnt: libc::c_uint, ...) -> libc::c_int;

    /**
     * Add a new rule to the filter
     *
     * @param ctx the filter context
     * @param action the filter action
     * @param syscall the syscall number
     * @param arg_cnt  the number of elements in the arg_array parameter
     * @param arg_array array of scmp_arg_cmp structs
     *
     * This function adds a series of new argument/value checks to the seccomp
     * filter for the given syscall; multiple argument/value checks can be
     * specified and they will be chained together (AND'd together) in the filter.
     * If the specified rule can not be represented on the architecture the
     * function will fail.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_rule_add_exact_array(ctx: *mut scmp_filter_ctx,
                                        action: libc::uint32_t, syscall: libc::c_int, arg_cnt: libc::c_uint,
                                        arg_array: *const scmp_arg_cmp) -> libc::c_int;

    /**
     * Generate seccomp Pseudo Filter Code (PFC) and export it to a file
     *
     * @param ctx the filter context
     * @param fd the destination fd
     *
     * This function generates seccomp Pseudo Filter Code (PFC) and writes it to
     * the given fd.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_export_pfc(ctx: *const scmp_filter_ctx, fd: libc::c_int) -> libc::c_int;

    /**
     * Generate seccomp Berkley Packet Filter (BPF) code and export it to a file
     *
     * @param ctx the filter context
     * @param fd the destination fd
     *
     * This function generates seccomp Berkley Packer Filter (BPF) code and writes
     * it to the given fd.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_export_bpf(ctx: *const scmp_filter_ctx, fd: libc::c_int) -> libc::c_int;
}

#[test]
fn does_it_even_work() {
    unsafe {
        let context = seccomp_init(SCMP_ACT_ALLOW);
        let comparator = scmp_arg_cmp {
            arg: 0,
            op: scmp_compare::SCMP_CMP_EQ,
            datum_a: 1000,
            datum_b: 0,
        };
        assert!(seccomp_rule_add(context, SCMP_ACT_KILL, 105, 1, comparator) == 0);
        assert!(seccomp_load(context) == 0);
        //assert!(libc::setuid(1000) == 0);
    }
}
<|endoftext|>