<commit_before>#![feature(slicing_syntax)]

extern crate rusqlite;
extern crate "rust-crypto" as crypto;
extern crate time;

use rusqlite::SqliteConnection;
use std::io::IoResult;
use std::io::fs::{readdir, walk_dir, File, PathExtensions};
use std::path::posix::Path;

use crypto::{aes, buffer, symmetriccipher};
use crypto::digest::Digest;
use crypto::buffer::{WriteBuffer, ReadBuffer};
use crypto::blockmodes::PkcsPadding;

static DATABASE_FILE: &'static str = "index.db3";
static BLOCK_SIZE: uint = 1024 * 1024;
static TEST_KEY: &'static str = "testkey123";
static TEMP_INPUT_DIRECTORY: &'static str = ".";
static TEMP_OUTPUT_DIRECTORY: &'static str = "/tmp/";

/* TODO: there should be a type Result<T, String> because we use this all the time. using String instead of &'static str allows to return dynamic error messages */

struct Blocks<'a> {
    file: File,
    buffer: Box<[u8]>
}

impl<'a> Blocks<'a> {
    pub fn from_path(path: &Path, block_size: uint) -> Option<Blocks> {
        let file = match File::open(path) {
            Ok(f)   => f,
            Err(..) => return None
        };

        Some(Blocks {
            file: file,
            buffer: Vec::from_elem(block_size, 0).into_boxed_slice()
        })
    }

    pub fn next(&'a mut self) -> Option<&'a [u8]> {
        match self.file.read(&mut *self.buffer) {
            Err(..)   => None,
            Ok(bytes) => {
                let slice: &'a [u8] = self.buffer[0..bytes];

                Some(slice)
            }
        }
    }
}

enum BlockExportResult {
    Known,
    New(uint)
}

// CONSIDER: if we make this an Option<i64>, we won't have to cast when inserting/selecting to database
enum Directory {
    Root,
    Child(uint)
}

pub fn init() -> Result<(), &'static str> {
    println!("Setting up database..");

    let connection = match setup_database() {
        Ok(conn) => conn,
        Err(e)   => return Err(e)
    };

    //let connection = match SqliteConnection::open(DATABASE_FILE) {
    //    Ok(conn) => conn,
    //    Err(_)   => return Err("Couldn't create database")
    //};

    println!("Populating database..");

    populate_database(&connection)
}

fn populate_database(connection: &SqliteConnection) -> Result<(), &'static str> {
    let working_dir = Path::new(TEMP_INPUT_DIRECTORY);

    export_directory(connection, &working_dir, Directory::Root)
}

fn export_directory(connection: &SqliteConnection, path: &Path, directory: Directory) -> Result<(), &'static str> {
    let content_list = match readdir(path) {
        Ok(content) => content,
        Err(..)     => return Err("Could not read directory!")
    };

    let (directory_list, file_list) = content_list.partition(|path| path.is_dir());

    for file_path in file_list.iter() {
        try!(export_file(connection, directory, file_path));
    }

    for directory_path in directory_list.iter() {
        let relative_path = match directory_path.path_relative_from(path) {
            None    => return Err("... no words"),
            Some(p) => p
        };

        let name = match relative_path.as_str() {
            None    => return Err("Cannot express directory name in UTF8"),
            Some(s) => s
        };

        let child_directory = try!(get_directory_id(connection, directory, name));

        try!(export_directory(connection, directory_path, child_directory));
    }

    Ok(())
}

fn hash_file(path: &Path) -> Result<String, &'static str> {
    let mut hasher = crypto::sha2::Sha256::new();

    let mut blocks = match Blocks::from_path(path, 1024) {
        Some(blocks) => blocks,
        None         => return Err("Couldn't read file")
    };

    loop {
        match blocks.next() {
            Some(slice) => hasher.input(slice),
            None        => break
        }
    }

    Ok(hasher.result_str())
}

fn file_known(connection: &SqliteConnection, path: &Path) -> Result<(bool, String), &'static str> {
    let hash: String = match hash_file(path) {
        Err(e)     => return Err(e),
        Ok(string) => string
    };

    let known = connection.query_row(
        "SELECT COUNT(id) FROM file
        WHERE hash = $1;",
        &[&hash.as_slice()],
        |row| row.get::<i64>(0) > 0
    );

    Ok((known, hash))
}

fn export_file(connection: &SqliteConnection, directory: Directory, path: &Path) -> Result<(), &'static str> {
    let hash = match file_known(connection, path) {
        Ok((true, _))     => return Ok(()),
        Err(e)            => return Err(e),
        Ok((false, hash)) => hash
    };

    let mut blocks = match Blocks::from_path(path, BLOCK_SIZE) {
        Some(blocks) => blocks,
        None         => return Err("Couldn't read file")
    };

    /* FIXME: this next block should be done functionally */
    let mut block_id_list = Vec::new();

    loop {
        match blocks.next() {
            Some(slice) => match export_block(connection, slice) {
                Err(e)                         => return Err(e),
                Ok(BlockExportResult::New(id)) => block_id_list.push(id),
                Ok(BlockExportResult::Known)   => ()
            },
            None        => break
        }
    }

    if !index_persist_file(connection, directory, path, hash.as_slice(), block_id_list.as_slice()) {
        println!("Failed persisting file to database");
    }

    Ok(())
}

// FIXME: should return Result<(), &'static str> so we can more info what potentially went wrong
fn index_persist_file(connection: &SqliteConnection, directory: Directory, path: &Path, hash: &str, block_id_list: &[uint]) -> bool {
    let filename_bytes = match path.filename() {
        None        => return false,
        Some(bytes) => bytes
    };

    let filename: String = String::from_utf8_lossy(filename_bytes).into_owned();

    let transaction = match connection.transaction() {
        Ok(tx) => tx,
        Err(_) => return false
    };

    match connection.execute("INSERT INTO file (hash) VALUES ($1);", &[&hash]) {
        Err(_) => return false,
        Ok(..) => ()
    }

    let file_id = connection.last_insert_rowid();

    for (ordinal, block_id) in block_id_list.iter().enumerate() {
        let result = connection.execute(
            "INSERT INTO fileblock (file_id, block_id, ordinal) VALUES ($1, $2, $3);"
            , &[&(file_id as i64), &(*block_id as i64), &(ordinal as i64)]
        );

        match result {
            Err(_) => return false,
            Ok(..) => ()
        }
    }

    let alias_query = "INSERT INTO alias (directory_id, file_id, name, timestamp) VALUES ($1, $2, $3, $4);";
    let timestamp = time::get_time().sec;
    let directory_id: Option<i64> = match directory {
        Directory::Root      => None,
        Directory::Child(id) => Some(id as i64)
    };

    match connection.execute(alias_query, &[&directory_id, &(file_id as i64), &filename, &(timestamp as i64)]) {
        Err(e) => return false,
        Ok(..) => ()
    }

    transaction.commit().is_ok()
}

fn get_directory_id(connection: &SqliteConnection, parent: Directory, name: &str) -> Result<Directory, &'static str> {
    let parent_id: Option<i64> = match parent {
        Directory::Root      => None,
        Directory::Child(id) => Some(id as i64)
    };

    // TODO: escape name!
    let select_query = "SELECT SUM(id) FROM directory WHERE name = $1 AND parent_id = $2;";
    let directory_id: Option<i64> = connection.query_row(select_query, &[&name, &parent_id], |row| row.get(0));

    match directory_id {
        Some(id) => return Ok(Directory::Child(id as uint)),
        None     => ()
    }

    let insert_query = "INSERT INTO directory (parent_id, name) VALUES ($1, $2);";

    match connection.execute(insert_query, &[&parent_id, &name]) {
        Ok(..) => Ok(Directory::Child(connection.last_insert_rowid() as uint)),
        Err(_) => Err("Failed persisting new directory to database")
    }
}

fn hash_block(block: &[u8]) -> String {
    let mut hasher = crypto::sha2::Sha256::new();

    hasher.input(block);

    hasher.result_str()
}

fn block_known(connection: &SqliteConnection, hash: &str) -> bool {
    connection.query_row(
        "SELECT COUNT(id) FROM block
        WHERE hash = $1;",
        &[&hash],
        |row| row.get::<i64>(0) > 0
    )
}

fn export_block(connection: &SqliteConnection, block: &[u8]) -> Result<BlockExportResult, &'static str> {
    let hash = hash_block(block);

    if block_known(connection, hash.as_slice()) {
        return Ok(BlockExportResult::Known);
    }

    let bytes = match encrypt_block(block) {
        Some(vector) => vector,
        None         => return Err("Failed encrypting block")
    };

    match write_block(hash.as_slice(), bytes.as_slice()) {
        Err(_) => return Err("Failed writing block to disk"),
        Ok(..) => ()
    }

    match index_persist_block(connection, hash.as_slice()) {
        None     => Err("Failed persisting block to database"),
        Some(id) => Ok(BlockExportResult::New(id))
    }
}

fn write_block(hash: &str, bytes: &[u8]) -> IoResult<()> {
    let mut path = Path::new(TEMP_OUTPUT_DIRECTORY);
    path.push(hash);

    let mut file = match File::create(&path) {
        Ok(f)  => f,
        Err(e) => return Err(e)
    };

    match file.write(bytes) {
        Ok(..) => file.fsync(),
        Err(e) => Err(e)
    }
}

fn index_persist_block(connection: &SqliteConnection, hash: &str) -> Option<uint> {
    let result = connection.execute("INSERT INTO block (hash) VALUES ($1);", &[&hash]);

    match result {
        Err(_) => None,
        Ok(..) => Some(connection.last_insert_rowid() as uint)
    }
}

fn encrypt_block(block: &[u8]) -> Option<Vec<u8>> {
    let mut encryptor: Box<symmetriccipher::Encryptor> = aes::cbc_encryptor(
        aes::KeySize::KeySize256,
        TEST_KEY.as_bytes(),
        &[],
        PkcsPadding
    );

    let mut final_result = Vec::<u8>::new();
    let mut buffer = [0, ..4096];
    let mut read_buffer = buffer::RefReadBuffer::new(block);
    let mut write_buffer = buffer::RefWriteBuffer::new(&mut buffer);

    while !read_buffer.is_empty() {
        match encryptor.encrypt(&mut read_buffer, &mut write_buffer, true) {
            Err(_) => return None,
            Ok(..) => ()
        }

        final_result.push_all(write_buffer.take_read_buffer().take_remaining());
    }

    Some(final_result)
}

fn setup_database() -> Result<SqliteConnection, &'static str> {
    let connection = try!(create_database());

    if ! create_directory_table(&connection) {
        return Err("Couldn't create directory table")
    }

    if ! create_file_table(&connection) {
        return Err("Couldn't create file table")
    }

    if ! create_file_alias_table(&connection) {
        return Err("Couldn't create file alias table")
    }

    if ! create_block_table(&connection) {
        return Err("Couldn't create block table")
    }

    if ! create_file_block_table(&connection) {
        return Err("Couldn't create file<->block table")
    }

    Ok(connection)
}

fn create_directory_table(connection: &SqliteConnection) -> bool {
    connection
        .execute("CREATE TABLE directory (
            id        INTEGER PRIMARY KEY,
            parent_id INTEGER,
            name      TEXT NOT NULL,
            FOREIGN KEY(parent_id) REFERENCES directory(id)
        );", &[])
        .is_ok()
}

fn create_file_table(connection: &SqliteConnection) -> bool {
    connection
        .execute("CREATE TABLE file (
            id           INTEGER PRIMARY KEY,
            hash         TEXT NOT NULL
        );", &[])
        .is_ok()
}

fn create_file_alias_table(connection: &SqliteConnection) -> bool {
    connection
        .execute("CREATE TABLE alias (
            id           INTEGER PRIMARY KEY,
            directory_id INTEGER,
            file_id      INTEGER,
            name         TEXT NOT NULL,
            timestamp    INTEGER,
            FOREIGN KEY(directory_id) REFERENCES directory(id),
            FOREIGN KEY(file_id) REFERENCES file(id)
        );", &[])
        .is_ok()
}

fn create_block_table(connection: &SqliteConnection) -> bool {
    connection
        .execute("CREATE TABLE block (
            id           INTEGER PRIMARY KEY,
            hash         TEXT NOT NULL
        );", &[])
        .is_ok()
}

fn create_file_block_table(connection: &SqliteConnection) -> bool {
    connection
        .execute("CREATE TABLE fileblock (
            id           INTEGER PRIMARY KEY,
            file_id      INTEGER NOT NULL,
            ordinal      INTEGER NOT NULL,
            block_id     INTEGER NOT NULL,
            FOREIGN KEY(file_id) REFERENCES file(id),
            FOREIGN KEY(block_id) REFERENCES block(id)
        );", &[])
        .is_ok()
}

fn create_database() -> Result<SqliteConnection, &'static str> {
    let working_dir = Path::new(".");
    let database_path = Path::new(DATABASE_FILE);

    let file_list = match readdir(&working_dir) {
        Ok(list) => list,
        Err(_)   => return Err("Failed reading directory")
    };

    if file_list.into_iter().find(|path| *path == database_path).is_some() {
        return Err("Database already exists");
    }

    match SqliteConnection::open(DATABASE_FILE) {
        Ok(conn) => Ok(conn),
        Err(_)   => Err("Couldn't create database")
    }
}
<commit_msg>split database and crypto functions to their own modules<commit_after>#![feature(slicing_syntax)]

extern crate rusqlite;

use std::io::IoResult;
use std::io::fs::{readdir, walk_dir, File, PathExtensions};
use std::path::posix::Path;
use rusqlite::{SqliteConnection, SqliteError};

mod database;
mod crypto;

static DATABASE_FILE: &'static str = "index.db3";
static TEMP_INPUT_DIRECTORY: &'static str = ".";
static TEMP_OUTPUT_DIRECTORY: &'static str = "/tmp/";
static BLOCK_SIZE: uint = 1024 * 1024;

/* TODO: there should be a different type Result<T, SomeEnum> because we use this all the time. using String instead of &'static str allows to return dynamic error messages */

enum BonzoError {
    DatabaseError(SqliteError),
    IoError
}

type BonzoResult<T> = Result<T, BonzoError>;

struct Blocks<'a> {
    file: File,
    buffer: Box<[u8]>
}

impl<'a> Blocks<'a> {
    pub fn from_path(path: &Path, block_size: uint) -> Option<Blocks> {
        let file = match File::open(path) {
            Ok(f)   => f,
            Err(..) => return None
        };

        Some(Blocks {
            file: file,
            buffer: Vec::from_elem(block_size, 0).into_boxed_slice()
        })
    }

    pub fn next(&'a mut self) -> Option<&'a [u8]> {
        match self.file.read(&mut *self.buffer) {
            Err(..)   => None,
            Ok(bytes) => {
                let slice: &'a [u8] = self.buffer[0..bytes];

                Some(slice)
            }
        }
    }
}

enum BlockExportResult {
    Known,
    New(uint)
}

// CONSIDER: if we make this an Option<i64>, we won't have to cast when inserting/selecting to database
enum Directory {
    Root,
    Child(uint)
}

pub fn init() -> Result<(), &'static str> {
    println!("Setting up database..");

    let database_path = Path::new(DATABASE_FILE);

    let connection = match database::setup(&Path::new(DATABASE_FILE)) {
        Ok(conn) => conn,
        Err(e)   => return Err(e)
    };

    //let connection = match SqliteConnection::open(DATABASE_FILE) {
    //    Ok(conn) => conn,
    //    Err(_)   => return Err("Couldn't create database")
    //};

    println!("Populating database..");

    populate_database(&connection)
}

fn populate_database(connection: &SqliteConnection) -> Result<(), &'static str> {
    let working_dir = Path::new(TEMP_INPUT_DIRECTORY);

    export_directory(connection, &working_dir, Directory::Root)
}

fn export_directory(connection: &SqliteConnection, path: &Path, directory: Directory) -> Result<(), &'static str> {
    let content_list = match readdir(path) {
        Ok(content) => content,
        Err(..)     => return Err("Could not read directory!")
    };

    let (directory_list, file_list) = content_list.partition(|path| path.is_dir());

    for file_path in file_list.iter() {
        try!(export_file(connection, directory, file_path));
    }

    for directory_path in directory_list.iter() {
        let relative_path = match directory_path.path_relative_from(path) {
            None    => return Err("... no words"),
            Some(p) => p
        };

        let name = match relative_path.as_str() {
            None    => return Err("Cannot express directory name in UTF8"),
            Some(s) => s
        };

        let child_directory = try!(database::get_directory_id(connection, directory, name));

        try!(export_directory(connection, directory_path, child_directory));
    }

    Ok(())
}

fn export_file(connection: &SqliteConnection, directory: Directory, path: &Path) -> Result<(), &'static str> {
    let hash = match database::file_known(connection, path) {
        Ok((true, _))     => return Ok(()),
        Err(e)            => return Err(e),
        Ok((false, hash)) => hash
    };

    let mut blocks = match Blocks::from_path(path, BLOCK_SIZE) {
        Some(blocks) => blocks,
        None         => return Err("Couldn't read file")
    };

    /* FIXME: this next block should be done functionally */
    let mut block_id_list = Vec::new();

    loop {
        match blocks.next() {
            Some(slice) => match export_block(connection, slice) {
                Err(e)                         => return Err(e),
                Ok(BlockExportResult::New(id)) => block_id_list.push(id),
                Ok(BlockExportResult::Known)   => ()
            },
            None        => break
        }
    }

    if !database::persist_file(connection, directory, path, hash.as_slice(), block_id_list.as_slice()) {
        println!("Failed persisting file to database");
    }

    Ok(())
}

fn export_block(connection: &SqliteConnection, block: &[u8]) -> Result<BlockExportResult, &'static str> {
    let hash = crypto::hash_block(block);

    if database::block_known(connection, hash.as_slice()) {
        return Ok(BlockExportResult::Known);
    }

    let bytes = match crypto::encrypt_block(block) {
        Some(vector) => vector,
        None         => return Err("Failed encrypting block")
    };

    match write_block(hash.as_slice(), bytes.as_slice()) {
        Err(_) => return Err("Failed writing block to disk"),
        Ok(..) => ()
    }

    match database::persist_block(connection, hash.as_slice()) {
        None     => Err("Failed persisting block to database"),
        Some(id) => Ok(BlockExportResult::New(id))
    }
}

fn write_block(hash: &str, bytes: &[u8]) -> IoResult<()> {
    let mut path = Path::new(TEMP_OUTPUT_DIRECTORY);
    path.push(hash);

    let mut file = match File::create(&path) {
        Ok(f)  => f,
        Err(e) => return Err(e)
    };

    match file.write(bytes) {
        Ok(..) => file.fsync(),
        Err(e) => Err(e)
    }
}
<|endoftext|>


<commit_before>#![crate_name = "r6"]

//! r6.rs is an attempt to implement R6RS Scheme in Rust language

#![feature(plugin)]
#![feature(slicing_syntax)]
#![feature(box_syntax)]

#![feature(core)]
#![feature(std_misc)]
#![feature(io)]
#![feature(collections)]
#![feature(unicode)]

// This line should be at the top of the extern link list,
// because some weird compiler bug lets log imported from rustc, not crates.io log
#[macro_use] extern crate log;

#[plugin]
extern crate phf_macros;
extern crate phf;
#[plugin]
#[no_link]
extern crate regex_macros;
extern crate regex;
extern crate unicode;
extern crate num;

macro_rules! list{
    ($($x:expr),*) => (
        vec![$($x),*].into_iter().collect()
    )
}

macro_rules! sym{
    ($e:expr) => (
        Datum::Sym(Cow::Borrowed($e))
    )
}

macro_rules! num{
    ($e:expr) => (
        Datum::Num(Number::new_int($e, 0))
    )
}

macro_rules! nil{
    () => (
        Datum::Nil
    )
}

/// Error values returned from parser, compiler or runtime
pub mod error;
/// Basic datum types
pub mod datum;
pub mod parser;
pub mod lexer;
/// Virtual machine running the bytecode
pub mod runtime;
/// Primitive functions
pub mod primitive;
/// Compiles datum into a bytecode
pub mod compiler;
/// R6RS `base` library
pub mod base;
/// Real part of the numerical tower
pub mod real;
/// Numerical tower
pub mod number;
<commit_msg>Rust changes: plugin syntax changes<commit_after>#![crate_name = "r6"]

//! r6.rs is an attempt to implement R6RS Scheme in Rust language

#![feature(plugin)]
#![feature(slicing_syntax)]
#![feature(box_syntax)]

#![feature(core)]
#![feature(std_misc)]
#![feature(io)]
#![feature(collections)]
#![feature(unicode)]

#![plugin(phf_macros)]
#![plugin(regex_macros)]

// This line should be at the top of the extern link list,
// because some weird compiler bug lets log imported from rustc, not crates.io log
#[macro_use] extern crate log;

extern crate phf;
extern crate regex;
extern crate unicode;
extern crate num;

macro_rules! list{
    ($($x:expr),*) => (
        vec![$($x),*].into_iter().collect()
    )
}

macro_rules! sym{
    ($e:expr) => (
        Datum::Sym(Cow::Borrowed($e))
    )
}

macro_rules! num{
    ($e:expr) => (
        Datum::Num(Number::new_int($e, 0))
    )
}

macro_rules! nil{
    () => (
        Datum::Nil
    )
}

/// Error values returned from parser, compiler or runtime
pub mod error;
/// Basic datum types
pub mod datum;
pub mod parser;
pub mod lexer;
/// Virtual machine running the bytecode
pub mod runtime;
/// Primitive functions
pub mod primitive;
/// Compiles datum into a bytecode
pub mod compiler;
/// R6RS `base` library
pub mod base;
/// Real part of the numerical tower
pub mod real;
/// Numerical tower
pub mod number;
<|endoftext|>


<commit_before>//! Iterator zippers
//!
//! This crate provides "zippers" as tuple structs: `Zip2`, `Zip3`, etc. These structs accept
//! iterators as fields, and provides iteration over the "zipped" elements.
//!
//! The functionality is similar to the `Iterator::zip` method. The difference is that the `zip`
//! method always produces an iterator that yields *two-element* tuples. If you want to zip 3
//! iterators, you'll write `xs.zip(ys).zip(zs)` which returns an iterator that yields elements of
//! type `((X, Y), Z)`. On the other hand, with this library you can write `Zip3(xs, ys, zs)` which
//! is an iterator that yields elements of type `(X, Y, Z)`.
//!
//! ```
//! use zip::Zip3;
//!
//! let chars = &['a', 'b', 'c'];
//! let mut v = vec![0u, 1, 2];
//! for (&c, i, &mut j) in Zip3(chars.iter(), range(0u, 5), v.iter_mut()) {
//!     assert!(i < 3);
//!     assert_eq!(i, j);
//! }
//! ```

#![deny(missing_docs, warnings)]
#![feature(macro_rules)]

macro_rules! min {
    ($x:expr) => { $x };
    ($x:expr, $($y:expr),+) => { ::std::cmp::min($x, min!($($y),+)) };
    ($($x:expr),+,) => { min!($($x),+) };
}

/// Two-iterator zipper
pub struct Zip2<A, B>(pub A, pub B);

impl<A, B, AI, BI> Iterator<(A, B)> for Zip2<AI, BI> where
    AI: Iterator<A>,
    BI: Iterator<B>,
{
    fn next(&mut self) -> Option<(A, B)> {
        if let Some(a) = self.0.next() {
            if let Some(b) = self.1.next() {
                return Some((a, b));
            }
        }

        None
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        (min!{
            self.0.size_hint().0,
            self.1.size_hint().0,
        }, None)
    }
}

/// Three-iterator zipper
pub struct Zip3<A, B, C>(pub A, pub B, pub C);

impl<A, B, C, AI, BI, CI> Iterator<(A, B, C)> for Zip3<AI, BI, CI> where
    AI: Iterator<A>,
    BI: Iterator<B>,
    CI: Iterator<C>,
{
    fn next(&mut self) -> Option<(A, B, C)> {
        if let Some(a) = self.0.next() {
            if let Some(b) = self.1.next() {
                if let Some(c) = self.2.next() {
                    return Some((a, b, c));
                }
            }
        }

        None
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        (min!{
            self.0.size_hint().0,
            self.1.size_hint().0,
            self.2.size_hint().0,
        }, None)
    }
}

/// Four-iterator zipper
pub struct Zip4<A, B, C, D>(pub A, pub B, pub C, pub D);

impl<A, B, C, D, AI, BI, CI, DI> Iterator<(A, B, C, D)> for Zip4<AI, BI, CI, DI> where
    AI: Iterator<A>,
    BI: Iterator<B>,
    CI: Iterator<C>,
    DI: Iterator<D>,
{
    fn next(&mut self) -> Option<(A, B, C, D)> {
        if let Some(a) = self.0.next() {
            if let Some(b) = self.1.next() {
                if let Some(c) = self.2.next() {
                    if let Some(d) = self.3.next() {
                        return Some((a, b, c, d))
                    }
                }
            }
        }

        None
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        (min!{
            self.0.size_hint().0,
            self.1.size_hint().0,
            self.2.size_hint().0,
            self.3.size_hint().0,
        }, None)
    }
}

/// Five-iterator zipper
pub struct Zip5<A, B, C, D, E>(pub A, pub B, pub C, pub D, pub E);

impl<A, B, C, D, E, AI, BI, CI, DI, EI> Iterator<(A, B, C, D, E)>
for Zip5<AI, BI, CI, DI, EI> where
    AI: Iterator<A>,
    BI: Iterator<B>,
    CI: Iterator<C>,
    DI: Iterator<D>,
    EI: Iterator<E>,
{
    fn next(&mut self) -> Option<(A, B, C, D, E)> {
        if let Some(a) = self.0.next() {
            if let Some(b) = self.1.next() {
                if let Some(c) = self.2.next() {
                    if let Some(d) = self.3.next() {
                        if let Some(e) = self.4.next() {
                            return Some((a, b, c, d, e))
                        }
                    }
                }
            }
        }

        None
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        (min!{
            self.0.size_hint().0,
            self.1.size_hint().0,
            self.2.size_hint().0,
            self.3.size_hint().0,
            self.4.size_hint().0,
        }, None)
    }
}

#[cfg(test)]
mod bench {
    extern crate test;

    use self::test::Bencher;

    const SIZE: uint = 1024;

    #[bench]
    fn collect2(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let b = a.clone();

        z.iter(|| {
            ::Zip2(a.iter(), b.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn collect2_(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let b = a.clone();

        z.iter(|| {
            a.iter().zip(b.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn count2(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let b = a.clone();

        z.iter(|| {
            ::Zip2(a.iter(), b.iter()).count()
        })
    }

    #[bench]
    fn count2_(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let b = a.clone();

        z.iter(|| {
            a.iter().zip(b.iter()).count()
        })
    }

    #[bench]
    fn collect3(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let (b, c) = (a.clone(), a.clone());

        z.iter(|| {
            ::Zip3(a.iter(), b.iter(), c.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn collect3_(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let (b, c) = (a.clone(), a.clone());

        z.iter(|| {
            a.iter().zip(b.iter()).zip(c.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn count3(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let (b, c) = (a.clone(), a.clone());

        z.iter(|| {
            ::Zip3(a.iter(), b.iter(), c.iter()).count()
        })
    }

    #[bench]
    fn count3_(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let (b, c) = (a.clone(), a.clone());

        z.iter(|| {
            a.iter().zip(b.iter()).zip(c.iter()).count()
        })
    }

    #[bench]
    fn collect4(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let (b, c, d) = (a.clone(), a.clone(), a.clone());

        z.iter(|| {
            ::Zip4(a.iter(), b.iter(), c.iter(), d.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn collect4_(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let (b, c, d) = (a.clone(), a.clone(), a.clone());

        z.iter(|| {
            a.iter().zip(b.iter()).zip(c.iter()).zip(d.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn count4(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let (b, c, d) = (a.clone(), a.clone(), a.clone());

        z.iter(|| {
            ::Zip4(a.iter(), b.iter(), c.iter(), d.iter()).count()
        })
    }

    #[bench]
    fn count4_(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let (b, c, d) = (a.clone(), a.clone(), a.clone());

        z.iter(|| {
            a.iter().zip(b.iter()).zip(c.iter()).zip(d.iter()).count()
        })
    }

    #[bench]
    fn collect5(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let (b, c, d, e) = (a.clone(), a.clone(), a.clone(), a.clone());

        z.iter(|| {
            ::Zip5(a.iter(), b.iter(), c.iter(), d.iter(), e.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn collect5_(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let (b, c, d, e) = (a.clone(), a.clone(), a.clone(), a.clone());

        z.iter(|| {
            a.iter().zip(b.iter()).zip(c.iter()).zip(d.iter()).zip(e.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn count5(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let (b, c, d, e) = (a.clone(), a.clone(), a.clone(), a.clone());

        z.iter(|| {
            ::Zip5(a.iter(), b.iter(), c.iter(), d.iter(), e.iter()).count()
        })
    }

    #[bench]
    fn count5_(z: &mut Bencher) {
        let a = Vec::from_elem(SIZE, 0u8);
        let (b, c, d, e) = (a.clone(), a.clone(), a.clone(), a.clone());

        z.iter(|| {
            a.iter().zip(b.iter()).zip(c.iter()).zip(d.iter()).zip(e.iter()).count()
        })
    }
}
<commit_msg>fix(benches): `Vec::from_elem` is deprecated, use fixed size arrays<commit_after>//! Iterator zippers
//!
//! This crate provides "zippers" as tuple structs: `Zip2`, `Zip3`, etc. These structs accept
//! iterators as fields, and provides iteration over the "zipped" elements.
//!
//! The functionality is similar to the `Iterator::zip` method. The difference is that the `zip`
//! method always produces an iterator that yields *two-element* tuples. If you want to zip 3
//! iterators, you'll write `xs.zip(ys).zip(zs)` which returns an iterator that yields elements of
//! type `((X, Y), Z)`. On the other hand, with this library you can write `Zip3(xs, ys, zs)` which
//! is an iterator that yields elements of type `(X, Y, Z)`.
//!
//! ```
//! use zip::Zip3;
//!
//! let chars = &['a', 'b', 'c'];
//! let mut v = vec![0u, 1, 2];
//! for (&c, i, &mut j) in Zip3(chars.iter(), range(0u, 5), v.iter_mut()) {
//!     assert!(i < 3);
//!     assert_eq!(i, j);
//! }
//! ```

#![deny(missing_docs, warnings)]
#![feature(macro_rules)]

macro_rules! min {
    ($x:expr) => { $x };
    ($x:expr, $($y:expr),+) => { ::std::cmp::min($x, min!($($y),+)) };
    ($($x:expr),+,) => { min!($($x),+) };
}

/// Two-iterator zipper
pub struct Zip2<A, B>(pub A, pub B);

impl<A, B, AI, BI> Iterator<(A, B)> for Zip2<AI, BI> where
    AI: Iterator<A>,
    BI: Iterator<B>,
{
    fn next(&mut self) -> Option<(A, B)> {
        if let Some(a) = self.0.next() {
            if let Some(b) = self.1.next() {
                return Some((a, b));
            }
        }

        None
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        (min!{
            self.0.size_hint().0,
            self.1.size_hint().0,
        }, None)
    }
}

/// Three-iterator zipper
pub struct Zip3<A, B, C>(pub A, pub B, pub C);

impl<A, B, C, AI, BI, CI> Iterator<(A, B, C)> for Zip3<AI, BI, CI> where
    AI: Iterator<A>,
    BI: Iterator<B>,
    CI: Iterator<C>,
{
    fn next(&mut self) -> Option<(A, B, C)> {
        if let Some(a) = self.0.next() {
            if let Some(b) = self.1.next() {
                if let Some(c) = self.2.next() {
                    return Some((a, b, c));
                }
            }
        }

        None
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        (min!{
            self.0.size_hint().0,
            self.1.size_hint().0,
            self.2.size_hint().0,
        }, None)
    }
}

/// Four-iterator zipper
pub struct Zip4<A, B, C, D>(pub A, pub B, pub C, pub D);

impl<A, B, C, D, AI, BI, CI, DI> Iterator<(A, B, C, D)> for Zip4<AI, BI, CI, DI> where
    AI: Iterator<A>,
    BI: Iterator<B>,
    CI: Iterator<C>,
    DI: Iterator<D>,
{
    fn next(&mut self) -> Option<(A, B, C, D)> {
        if let Some(a) = self.0.next() {
            if let Some(b) = self.1.next() {
                if let Some(c) = self.2.next() {
                    if let Some(d) = self.3.next() {
                        return Some((a, b, c, d))
                    }
                }
            }
        }

        None
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        (min!{
            self.0.size_hint().0,
            self.1.size_hint().0,
            self.2.size_hint().0,
            self.3.size_hint().0,
        }, None)
    }
}

/// Five-iterator zipper
pub struct Zip5<A, B, C, D, E>(pub A, pub B, pub C, pub D, pub E);

impl<A, B, C, D, E, AI, BI, CI, DI, EI> Iterator<(A, B, C, D, E)>
for Zip5<AI, BI, CI, DI, EI> where
    AI: Iterator<A>,
    BI: Iterator<B>,
    CI: Iterator<C>,
    DI: Iterator<D>,
    EI: Iterator<E>,
{
    fn next(&mut self) -> Option<(A, B, C, D, E)> {
        if let Some(a) = self.0.next() {
            if let Some(b) = self.1.next() {
                if let Some(c) = self.2.next() {
                    if let Some(d) = self.3.next() {
                        if let Some(e) = self.4.next() {
                            return Some((a, b, c, d, e))
                        }
                    }
                }
            }
        }

        None
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        (min!{
            self.0.size_hint().0,
            self.1.size_hint().0,
            self.2.size_hint().0,
            self.3.size_hint().0,
            self.4.size_hint().0,
        }, None)
    }
}

#[cfg(test)]
mod bench {
    extern crate test;

    use self::test::Bencher;

    const SIZE: uint = 1024;

    #[bench]
    fn collect2(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let b = a;

        z.iter(|| {
            ::Zip2(a.iter(), b.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn collect2_(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let b = a;

        z.iter(|| {
            a.iter().zip(b.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn count2(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let b = a;

        z.iter(|| {
            ::Zip2(a.iter(), b.iter()).count()
        })
    }

    #[bench]
    fn count2_(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let b = a;

        z.iter(|| {
            a.iter().zip(b.iter()).count()
        })
    }

    #[bench]
    fn collect3(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let (b, c) = (a, a);

        z.iter(|| {
            ::Zip3(a.iter(), b.iter(), c.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn collect3_(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let (b, c) = (a, a);

        z.iter(|| {
            a.iter().zip(b.iter()).zip(c.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn count3(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let (b, c) = (a, a);

        z.iter(|| {
            ::Zip3(a.iter(), b.iter(), c.iter()).count()
        })
    }

    #[bench]
    fn count3_(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let (b, c) = (a, a);

        z.iter(|| {
            a.iter().zip(b.iter()).zip(c.iter()).count()
        })
    }

    #[bench]
    fn collect4(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let (b, c, d) = (a, a, a);

        z.iter(|| {
            ::Zip4(a.iter(), b.iter(), c.iter(), d.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn collect4_(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let (b, c, d) = (a, a, a);

        z.iter(|| {
            a.iter().zip(b.iter()).zip(c.iter()).zip(d.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn count4(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let (b, c, d) = (a, a, a);

        z.iter(|| {
            ::Zip4(a.iter(), b.iter(), c.iter(), d.iter()).count()
        })
    }

    #[bench]
    fn count4_(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let (b, c, d) = (a, a, a);

        z.iter(|| {
            a.iter().zip(b.iter()).zip(c.iter()).zip(d.iter()).count()
        })
    }

    #[bench]
    fn collect5(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let (b, c, d, e) = (a, a, a, a);

        z.iter(|| {
            ::Zip5(a.iter(), b.iter(), c.iter(), d.iter(), e.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn collect5_(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let (b, c, d, e) = (a, a, a, a);

        z.iter(|| {
            a.iter().zip(b.iter()).zip(c.iter()).zip(d.iter()).zip(e.iter()).collect::<Vec<_>>()
        })
    }

    #[bench]
    fn count5(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let (b, c, d, e) = (a, a, a, a);

        z.iter(|| {
            ::Zip5(a.iter(), b.iter(), c.iter(), d.iter(), e.iter()).count()
        })
    }

    #[bench]
    fn count5_(z: &mut Bencher) {
        let a = [0u8, ..SIZE];
        let (b, c, d, e) = (a, a, a, a);

        z.iter(|| {
            a.iter().zip(b.iter()).zip(c.iter()).zip(d.iter()).zip(e.iter()).count()
        })
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Daniel Grunwald
//
// 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.

#![feature(unsafe_no_drop_flag)] // crucial so that PyObject<'p> is binary compatible with *mut ffi::PyObject
#![feature(filling_drop)] // necessary to avoid segfault with unsafe_no_drop_flag
#![feature(optin_builtin_traits)] // for opting out of Sync/Send
#![feature(slice_patterns)] // for tuple_conversion macros
#![feature(plugin)]
#![plugin(interpolate_idents)]
#![allow(unused_imports)] // because some imports are only necessary with python 2.x or 3.x

//! Rust bindings to the Python interpreter.
//!
//! # Ownership and Lifetimes
//! In Python, all objects are implicitly reference counted.
//! In rust, we will use the `PyObject` type to represent a reference to a Python object.
//!
//! The method `clone_ref()` (from trait `PyClone`) can be used to create additional
//! references to the same Python object.
//!
//! Because all Python objects potentially have multiple owners, the
//! concept of Rust mutability does not apply to Python objects.
//! As a result, this API will allow mutating Python objects even if they are not stored
//! in a mutable Rust variable.
//!
//! The Python interpreter uses a global interpreter lock (GIL)
//! to ensure thread-safety.
//! This API uses a zero-sized `struct Python<'p>` as a token to indicate
//! that a function can assume that the GIL is held.
//!
//! You obtain a `Python` instance by acquiring the GIL,
//! and have to pass it into all operations that call into the Python runtime.
//!
//! # Error Handling
//! The vast majority of operations in this library will return `PyResult<...>`.
//! This is an alias for the type `Result<..., PyErr>`.
//!
//! A `PyErr` represents a Python exception. Errors within the rust-cpython library are
//! also exposed as Python exceptions.
//!
//! # Example
//! ```
//! extern crate cpython;
//!
//! use cpython::{PythonObject, Python};
//! use cpython::ObjectProtocol; //for call method
//!
//! fn main() {
//!     let gil = Python::acquire_gil();
//!     let py = gil.python(); // obtain `Python` token
//!
//!     let sys = py.import("sys").unwrap();
//!     let version: String = sys.get(py, "version").unwrap().extract(py).unwrap();
//!
//!     let os = py.import("os").unwrap();
//!     let getenv = os.get(py, "getenv").unwrap();
//!     let user: String = getenv.call(py, ("USER",), None).unwrap().extract(py).unwrap();
//!
//!     println!("Hello {}, I'm Python {}", user, version);
//! }
//! ```

extern crate libc;

#[macro_use]
extern crate abort_on_panic;

#[cfg(feature="python27-sys")]
extern crate python27_sys as ffi;

#[cfg(feature="python3-sys")]
extern crate python3_sys as ffi;

pub use ffi::Py_ssize_t;
pub use err::{PyErr, PyResult};
pub use objects::*;
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PyClone, PyDrop};
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
pub use conversion::{ExtractPyObject, ToPyObject};
pub use objectprotocol::{ObjectProtocol};
pub use rustobject::{PyRustType, PyRustObject};
pub use rustobject::typebuilder::PyRustTypeBuilder;

#[cfg(feature="python27-sys")]
#[allow(non_camel_case_types)]
pub type Py_hash_t = libc::c_long;

#[cfg(feature="python3-sys")]
#[allow(non_camel_case_types)]
pub type Py_hash_t = ffi::Py_hash_t;

use std::ptr;

/// Constructs a `&'static CStr` literal.
macro_rules! cstr(
    ($s: tt) => (
        // TODO: verify that $s is a string literal without nuls
        unsafe {
            ::std::ffi::CStr::from_ptr(concat!($s, "\0").as_ptr() as *const _)
        }
    );
);

mod python;
mod err;
mod conversion;
mod objects;
mod objectprotocol;
mod pythonrun;
pub mod argparse;
mod function;
mod rustobject;

/// Private re-exports for macros. Do not use.
#[doc(hidden)]
pub mod _detail {
    pub use ffi;
    pub use libc;
    pub use abort_on_panic::PanicGuard;
    pub use err::from_owned_ptr_or_panic;
    pub use function::py_fn_impl;
    pub use rustobject::method::{py_method_impl, py_class_method_impl};

    /// assume_gil_acquired(), but the returned Python<'p> is bounded by the scope
    /// of the referenced variable.
    /// This is useful in macros to ensure that type inference doesn't set `'p` == `'static`.
    #[inline]
    pub unsafe fn bounded_assume_gil_acquired<'p, T>(_bound: &'p T) -> super::Python<'p> {
        super::Python::assume_gil_acquired()
    }
}

/// Expands to an `extern "C"` function that allows Python to load
/// the rust code as a Python extension module.
///
/// Macro syntax: `py_module_initializer!($name, |$py, $m| $body)`
///
/// 1. `name`: The module name as a Rust identifier.
/// 2. A lambda of type `Fn(Python, &PyModule) -> PyResult<()>`.
///    This function will be called when the module is imported, and is responsible
///    for adding the module's members.
///
/// # Example
/// ```
/// #![crate_type = "dylib"]
/// #![feature(plugin)]
/// #![plugin(interpolate_idents)]
/// #[macro_use] extern crate cpython;
/// use cpython::{Python, PyResult, PyObject};
///
/// py_module_initializer!(example, |py, m| {
///     try!(m.add(py, "__doc__", "Module documentation string"));
///     try!(m.add(py, "run", py_fn!(run())));
///     Ok(())
/// });
///
/// fn run(py: Python) -> PyResult<PyObject> {
///     println!("Rust says: Hello Python!");
///     Ok(py.None())
/// }
/// # fn main() {}
/// ```
/// The code must be compiled into a file `example.so`.
///
/// ```bash
/// rustc example.rs -o example.so
/// ```
/// It can then be imported into Python:
///
/// ```python
/// >>> import example
/// >>> example.run()
/// Rust says: Hello Python!
/// ```
///
#[macro_export]
#[cfg(feature="python27-sys")]
macro_rules! py_module_initializer {
    ($name: ident, |$py_id: ident, $m_id: ident| $body: expr) => ( interpolate_idents! {
        #[[no_mangle]]
        #[allow(non_snake_case)]
        pub unsafe extern "C" fn [ init $name ]() {
            // Nest init function so that $body isn't in unsafe context
            fn init($py_id: $crate::Python, $m_id: &$crate::PyModule) -> $crate::PyResult<()> {
                $body
            }
            let name = concat!(stringify!($name), "\0").as_ptr() as *const _;
            $crate::py_module_initializer_impl(name, init)
        }
    })
}

#[doc(hidden)]
#[cfg(feature="python27-sys")]
pub unsafe fn py_module_initializer_impl(
    name: *const libc::c_char,
    init: fn(Python, &PyModule) -> PyResult<()>
) {
    abort_on_panic!({
        let py = Python::assume_gil_acquired();
        ffi::PyEval_InitThreads();
        let module = ffi::Py_InitModule(name, ptr::null_mut());
        if module.is_null() { return; }

        let module = match PyObject::from_borrowed_ptr(py, module).cast_into::<PyModule>(py) {
            Ok(m) => m,
            Err(e) => {
                PyErr::from(e).restore(py);
                return;
            }
        };
        match init(py, &module) {
            Ok(()) => (),
            Err(e) => e.restore(py)
        }
    })
}

#[macro_export]
#[cfg(feature="python3-sys")]
macro_rules! py_module_initializer {
    ($name: ident, |$py_id: ident, $m_id: ident| $body: expr) => ( interpolate_idents! {
        #[[no_mangle]]
        #[allow(non_snake_case)]
        pub unsafe extern "C" fn [ PyInit_ $name ]() -> *mut $crate::_detail::ffi::PyObject {
            // Nest init function so that $body isn't in unsafe context
            fn init($py_id: $crate::Python, $m_id: &$crate::PyModule) -> $crate::PyResult<()> {
                $body
            }
            static mut module_def: $crate::_detail::ffi::PyModuleDef = $crate::_detail::ffi::PyModuleDef {
                m_base: $crate::_detail::ffi::PyModuleDef_HEAD_INIT,
                m_name: 0 as *const _,
                m_doc: 0 as *const _,
                m_size: 0, // we don't use per-module state
                m_methods: 0 as *mut _,
                m_reload: None,
                m_traverse: None,
                m_clear: None,
                m_free: None
            };
            // We can't convert &'static str to *const c_char within a static initializer,
            // so we'll do it here in the module initialization:
            module_def.m_name = concat!(stringify!($name), "\0").as_ptr() as *const _;
            $crate::py_module_initializer_impl(&mut module_def, init)
        }
    })
}

#[doc(hidden)]
#[cfg(feature="python3-sys")]
pub unsafe fn py_module_initializer_impl(
    def: *mut ffi::PyModuleDef,
    init: fn(Python, &PyModule) -> PyResult<()>
) -> *mut ffi::PyObject {
    abort_on_panic!({
        let py = Python::assume_gil_acquired();
        ffi::PyEval_InitThreads();
        let module = ffi::PyModule_Create(def);
        if module.is_null() { return module; }

        let module = match PyObject::from_owned_ptr(py, module).cast_into::<PyModule>(py) {
            Ok(m) => m,
            Err(e) => {
                PyErr::from(e).restore(py);
                return ptr::null_mut();
            }
        };
        match init(py, &module) {
            Ok(()) => module.into_object().steal_ptr(),
            Err(e) => {
                e.restore(py);
                return ptr::null_mut();
            }
        }
    })
}
<commit_msg>Fix "reexport of private crate" warning.<commit_after>// Copyright (c) 2015 Daniel Grunwald
//
// 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.

#![feature(unsafe_no_drop_flag)] // crucial so that PyObject<'p> is binary compatible with *mut ffi::PyObject
#![feature(filling_drop)] // necessary to avoid segfault with unsafe_no_drop_flag
#![feature(optin_builtin_traits)] // for opting out of Sync/Send
#![feature(slice_patterns)] // for tuple_conversion macros
#![feature(plugin)]
#![plugin(interpolate_idents)]
#![allow(unused_imports)] // because some imports are only necessary with python 2.x or 3.x

//! Rust bindings to the Python interpreter.
//!
//! # Ownership and Lifetimes
//! In Python, all objects are implicitly reference counted.
//! In rust, we will use the `PyObject` type to represent a reference to a Python object.
//!
//! The method `clone_ref()` (from trait `PyClone`) can be used to create additional
//! references to the same Python object.
//!
//! Because all Python objects potentially have multiple owners, the
//! concept of Rust mutability does not apply to Python objects.
//! As a result, this API will allow mutating Python objects even if they are not stored
//! in a mutable Rust variable.
//!
//! The Python interpreter uses a global interpreter lock (GIL)
//! to ensure thread-safety.
//! This API uses a zero-sized `struct Python<'p>` as a token to indicate
//! that a function can assume that the GIL is held.
//!
//! You obtain a `Python` instance by acquiring the GIL,
//! and have to pass it into all operations that call into the Python runtime.
//!
//! # Error Handling
//! The vast majority of operations in this library will return `PyResult<...>`.
//! This is an alias for the type `Result<..., PyErr>`.
//!
//! A `PyErr` represents a Python exception. Errors within the rust-cpython library are
//! also exposed as Python exceptions.
//!
//! # Example
//! ```
//! extern crate cpython;
//!
//! use cpython::{PythonObject, Python};
//! use cpython::ObjectProtocol; //for call method
//!
//! fn main() {
//!     let gil = Python::acquire_gil();
//!     let py = gil.python(); // obtain `Python` token
//!
//!     let sys = py.import("sys").unwrap();
//!     let version: String = sys.get(py, "version").unwrap().extract(py).unwrap();
//!
//!     let os = py.import("os").unwrap();
//!     let getenv = os.get(py, "getenv").unwrap();
//!     let user: String = getenv.call(py, ("USER",), None).unwrap().extract(py).unwrap();
//!
//!     println!("Hello {}, I'm Python {}", user, version);
//! }
//! ```

extern crate libc;

#[macro_use]
extern crate abort_on_panic;

#[cfg(feature="python27-sys")]
extern crate python27_sys as ffi;

#[cfg(feature="python3-sys")]
extern crate python3_sys as ffi;

pub use ffi::Py_ssize_t;
pub use err::{PyErr, PyResult};
pub use objects::*;
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PyClone, PyDrop};
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
pub use conversion::{ExtractPyObject, ToPyObject};
pub use objectprotocol::{ObjectProtocol};
pub use rustobject::{PyRustType, PyRustObject};
pub use rustobject::typebuilder::PyRustTypeBuilder;

#[cfg(feature="python27-sys")]
#[allow(non_camel_case_types)]
pub type Py_hash_t = libc::c_long;

#[cfg(feature="python3-sys")]
#[allow(non_camel_case_types)]
pub type Py_hash_t = ffi::Py_hash_t;

use std::ptr;

/// Constructs a `&'static CStr` literal.
macro_rules! cstr(
    ($s: tt) => (
        // TODO: verify that $s is a string literal without nuls
        unsafe {
            ::std::ffi::CStr::from_ptr(concat!($s, "\0").as_ptr() as *const _)
        }
    );
);

mod python;
mod err;
mod conversion;
mod objects;
mod objectprotocol;
mod pythonrun;
pub mod argparse;
mod function;
mod rustobject;

/// Private re-exports for macros. Do not use.
#[doc(hidden)]
pub mod _detail {
    pub mod ffi {
        pub use ::ffi::*;
    }
    pub mod libc {
        pub use ::libc::c_char;
    }
    pub use abort_on_panic::PanicGuard;
    pub use err::from_owned_ptr_or_panic;
    pub use function::py_fn_impl;
    pub use rustobject::method::{py_method_impl, py_class_method_impl};

    /// assume_gil_acquired(), but the returned Python<'p> is bounded by the scope
    /// of the referenced variable.
    /// This is useful in macros to ensure that type inference doesn't set `'p` == `'static`.
    #[inline]
    pub unsafe fn bounded_assume_gil_acquired<'p, T>(_bound: &'p T) -> super::Python<'p> {
        super::Python::assume_gil_acquired()
    }
}

/// Expands to an `extern "C"` function that allows Python to load
/// the rust code as a Python extension module.
///
/// Macro syntax: `py_module_initializer!($name, |$py, $m| $body)`
///
/// 1. `name`: The module name as a Rust identifier.
/// 2. A lambda of type `Fn(Python, &PyModule) -> PyResult<()>`.
///    This function will be called when the module is imported, and is responsible
///    for adding the module's members.
///
/// # Example
/// ```
/// #![crate_type = "dylib"]
/// #![feature(plugin)]
/// #![plugin(interpolate_idents)]
/// #[macro_use] extern crate cpython;
/// use cpython::{Python, PyResult, PyObject};
///
/// py_module_initializer!(example, |py, m| {
///     try!(m.add(py, "__doc__", "Module documentation string"));
///     try!(m.add(py, "run", py_fn!(run())));
///     Ok(())
/// });
///
/// fn run(py: Python) -> PyResult<PyObject> {
///     println!("Rust says: Hello Python!");
///     Ok(py.None())
/// }
/// # fn main() {}
/// ```
/// The code must be compiled into a file `example.so`.
///
/// ```bash
/// rustc example.rs -o example.so
/// ```
/// It can then be imported into Python:
///
/// ```python
/// >>> import example
/// >>> example.run()
/// Rust says: Hello Python!
/// ```
///
#[macro_export]
#[cfg(feature="python27-sys")]
macro_rules! py_module_initializer {
    ($name: ident, |$py_id: ident, $m_id: ident| $body: expr) => ( interpolate_idents! {
        #[[no_mangle]]
        #[allow(non_snake_case)]
        pub unsafe extern "C" fn [ init $name ]() {
            // Nest init function so that $body isn't in unsafe context
            fn init($py_id: $crate::Python, $m_id: &$crate::PyModule) -> $crate::PyResult<()> {
                $body
            }
            let name = concat!(stringify!($name), "\0").as_ptr() as *const _;
            $crate::py_module_initializer_impl(name, init)
        }
    })
}

#[doc(hidden)]
#[cfg(feature="python27-sys")]
pub unsafe fn py_module_initializer_impl(
    name: *const libc::c_char,
    init: fn(Python, &PyModule) -> PyResult<()>
) {
    abort_on_panic!({
        let py = Python::assume_gil_acquired();
        ffi::PyEval_InitThreads();
        let module = ffi::Py_InitModule(name, ptr::null_mut());
        if module.is_null() { return; }

        let module = match PyObject::from_borrowed_ptr(py, module).cast_into::<PyModule>(py) {
            Ok(m) => m,
            Err(e) => {
                PyErr::from(e).restore(py);
                return;
            }
        };
        match init(py, &module) {
            Ok(()) => (),
            Err(e) => e.restore(py)
        }
    })
}

#[macro_export]
#[cfg(feature="python3-sys")]
macro_rules! py_module_initializer {
    ($name: ident, |$py_id: ident, $m_id: ident| $body: expr) => ( interpolate_idents! {
        #[[no_mangle]]
        #[allow(non_snake_case)]
        pub unsafe extern "C" fn [ PyInit_ $name ]() -> *mut $crate::_detail::ffi::PyObject {
            // Nest init function so that $body isn't in unsafe context
            fn init($py_id: $crate::Python, $m_id: &$crate::PyModule) -> $crate::PyResult<()> {
                $body
            }
            static mut module_def: $crate::_detail::ffi::PyModuleDef = $crate::_detail::ffi::PyModuleDef {
                m_base: $crate::_detail::ffi::PyModuleDef_HEAD_INIT,
                m_name: 0 as *const _,
                m_doc: 0 as *const _,
                m_size: 0, // we don't use per-module state
                m_methods: 0 as *mut _,
                m_reload: None,
                m_traverse: None,
                m_clear: None,
                m_free: None
            };
            // We can't convert &'static str to *const c_char within a static initializer,
            // so we'll do it here in the module initialization:
            module_def.m_name = concat!(stringify!($name), "\0").as_ptr() as *const _;
            $crate::py_module_initializer_impl(&mut module_def, init)
        }
    })
}

#[doc(hidden)]
#[cfg(feature="python3-sys")]
pub unsafe fn py_module_initializer_impl(
    def: *mut ffi::PyModuleDef,
    init: fn(Python, &PyModule) -> PyResult<()>
) -> *mut ffi::PyObject {
    abort_on_panic!({
        let py = Python::assume_gil_acquired();
        ffi::PyEval_InitThreads();
        let module = ffi::PyModule_Create(def);
        if module.is_null() { return module; }

        let module = match PyObject::from_owned_ptr(py, module).cast_into::<PyModule>(py) {
            Ok(m) => m,
            Err(e) => {
                PyErr::from(e).restore(py);
                return ptr::null_mut();
            }
        };
        match init(py, &module) {
            Ok(()) => module.into_object().steal_ptr(),
            Err(e) => {
                e.restore(py);
                return ptr::null_mut();
            }
        }
    })
}
<|endoftext|>


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

/**
 * 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
 */
#[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
 */
#[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
 */
#[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;

    /**
     * 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 Debug<commit_after>extern crate libc;
/*
 * seccomp actions
 */
#[allow(non_camel_case_types)]
pub type scmp_filter_ctx = libc::c_void;

/**
 * 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;

    /**
     * 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|>


<commit_before>//! TODO
#![deny(missing_docs)]

extern crate loirc;

use std::collections::HashMap;

pub use loirc::*;

/// Represents a channel.
#[derive(Debug)]
pub struct Channel {
    /// Name of the channel.
    pub name: String,
    /// List of users by nickname.
    pub users: Vec<String>,
}

/// Status of the connection.
#[derive(Debug)]
pub enum ConnectionStatus {
    /// Connection was closed.
    Closed(&'static str),
    /// Connection is alive.
    Connected,
    /// Connection was dropped.
    Disconnected,
    /// Attempting to reconnect.
    Reconnecting,
}

/// Represents the state of this connection.
#[derive(Debug)]
pub struct State {
    /// Status of the connection.
    pub status: ConnectionStatus,
    channels: HashMap<String, Channel>,
}

impl State {

    fn new() -> State {
        State {
            status: ConnectionStatus::Connected,
            channels: HashMap::new(),
        }
    }

    /// Get a channel by name.
    pub fn get_channel(&self, chan: &str) -> Option<&Channel> {
        self.channels.get(&chan.to_lowercase())
    }

}

/// Dispatches the raw events to functions.
pub struct Dispatcher {
    state: State,
    listener: Box<Listener + 'static>,
}

impl Dispatcher {

    /// Create a new dispatcher from the given listener.
    pub fn new<L: Listener + 'static>(listener: L) -> Dispatcher {
        Dispatcher {
            state: State::new(),
            listener: Box::new(listener),
        }
    }

    /// Borrow the state of check the data.
    pub fn borrow_state(&mut self) -> &State {
        &self.state
    }

    /// Feed an event to the dispatcher.
    pub fn feed(&mut self, event: &Event) {
        self.listener.any(&mut self.state, event);

        match *event {
            Event::Closed(reason) => {
                self.state.status = ConnectionStatus::Closed(reason);
            }
            Event::Disconnected => {
                self.state.status = ConnectionStatus::Disconnected;
                self.state.channels.clear();
            }
            Event::Reconnecting => {
                self.state.status = ConnectionStatus::Reconnecting;
            }
            Event::Message(ref msg) => {
                match msg.code {
                    Code::RplWelcome => {
                        self.listener.welcome(&mut self.state);
                    }
                    Code::RplNamreply => {
                        self.name_reply(msg);
                    }
                    Code::RplEndofnames => {
                        self.end_of_names(msg);
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }

    fn name_reply(&mut self, msg: &Message) {
        let channel_name = &msg.args[2];
        let channel_id = channel_name.to_lowercase();

        if !self.state.channels.contains_key(&channel_id) {
            self.state.channels.insert(channel_id.clone(), Channel {
                name: channel_name.to_owned(),
                users: Vec::new(),
            });
        }

        if let Some(ref suffix) = msg.suffix {
            let channel = self.state.channels.get_mut(&channel_id).unwrap();
            for nick in suffix.split(" ") {
                channel.users.push(nick.to_owned());
            }
        }
    }

    fn end_of_names(&mut self, msg: &Message) {
        self.listener.channel_join(&mut self.state, &msg.args[0]);
    }

}

/// Implement this trait to handle events.
pub trait Listener {

    /// Any event.
    #[allow(unused_variables)]
    fn any(&mut self, state: &mut State, event: &Event) {}

    /// When the server sends the welcome packet.
    #[allow(unused_variables)]
    fn welcome(&mut self, state: &mut State) {}

    /// When the client sucessfully joins a channel.
    #[allow(unused_variables)]
    fn channel_join(&mut self, state: &mut State, name: &str) {}

}
<commit_msg>Add join, part and quit support<commit_after>//! TODO
#![deny(missing_docs)]

extern crate loirc;

use std::collections::HashMap;

pub use loirc::*;

/// Represents a channel.
#[derive(Debug)]
pub struct Channel {
    /// Name of the channel.
    pub name: String,
    /// List of users by nickname.
    pub users: Vec<String>,
}

/// Status of the connection.
#[derive(Debug)]
pub enum ConnectionStatus {
    /// Connection was closed.
    Closed(&'static str),
    /// Connection is alive.
    Connected,
    /// Connection was dropped.
    Disconnected,
    /// Attempting to reconnect.
    Reconnecting,
}

/// Represents the state of this connection.
#[derive(Debug)]
pub struct State {
    /// Status of the connection.
    pub status: ConnectionStatus,
    channels: HashMap<String, Channel>,
}

impl State {

    fn new() -> State {
        State {
            status: ConnectionStatus::Connected,
            channels: HashMap::new(),
        }
    }

    /// Get a channel by name.
    pub fn get_channel(&self, chan: &str) -> Option<&Channel> {
        self.channels.get(&chan.to_lowercase())
    }

}

/// Dispatches the raw events to functions.
pub struct Dispatcher {
    state: State,
    listener: Box<Listener + 'static>,
}

impl Dispatcher {

    /// Create a new dispatcher from the given listener.
    pub fn new<L: Listener + 'static>(listener: L) -> Dispatcher {
        Dispatcher {
            state: State::new(),
            listener: Box::new(listener),
        }
    }

    /// Borrow the state of check the data.
    pub fn borrow_state(&mut self) -> &State {
        &self.state
    }

    /// Feed an event to the dispatcher.
    pub fn feed(&mut self, event: &Event) {
        self.listener.any(&mut self.state, event);

        match *event {
            Event::Closed(reason) => {
                self.state.status = ConnectionStatus::Closed(reason);
            }
            Event::Disconnected => {
                self.state.status = ConnectionStatus::Disconnected;
                self.state.channels.clear();
            }
            Event::Reconnecting => {
                self.state.status = ConnectionStatus::Reconnecting;
            }
            Event::Message(ref msg) => {
                match msg.code {
                    Code::RplWelcome => {
                        self.listener.welcome(&mut self.state);
                    }
                    Code::RplNamreply => {
                        self.name_reply(msg);
                    }
                    Code::RplEndofnames => {
                        self.listener.channel_join(&mut self.state, &msg.args[0]);
                    }
                    Code::Join => {
                        self.join(msg);
                    }
                    Code::Part => {
                        self.part(msg);
                    }
                    Code::Quit => {
                        self.quit(msg);
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }

    fn name_reply(&mut self, msg: &Message) {
        let channel_name = &msg.args[2];
        let channel_id = channel_name.to_lowercase();

        if !self.state.channels.contains_key(&channel_id) {
            self.state.channels.insert(channel_id.clone(), Channel {
                name: channel_name.to_owned(),
                users: Vec::new(),
            });
        }

        if let Some(ref suffix) = msg.suffix {
            let channel = self.state.channels.get_mut(&channel_id).unwrap();
            for nick in suffix.split(" ") {
                channel.users.push(nick.to_owned());
            }
        }
    }

    fn join(&mut self, msg: &Message) {
        if msg.args.len() >= 1 {
            if let Some(ref prefix) = msg.prefix {
                match *prefix {
                    Prefix::User(ref user) => {
                        let channel_name = &msg.args[0];
                        let channel_id = channel_name.to_lowercase();
                        if let Some(channel) = self.state.channels.get_mut(&channel_id) {
                            channel.users.push(user.nickname.to_owned());
                        }
                        if self.state.channels.contains_key(&channel_id) {
                            self.listener.user_join(&mut self.state, channel_name, &user.nickname);
                        }
                    }
                    _ => {}
                }
            }
        }
    }

    fn part(&mut self, msg: &Message) {
        if msg.args.len() >= 1 {
            if let Some(ref prefix) = msg.prefix {
                match *prefix {
                    Prefix::User(ref user) => {
                        let channel_name = &msg.args[0];
                        let channel_id = channel_name.to_lowercase();
                        if let Some(channel) = self.state.channels.get_mut(&channel_id) {
                            if let Some(pos) = channel.users.iter().position(|u| u == &user.nickname) {
                                channel.users.remove(pos);
                            }
                        }
                        self.listener.user_part(&mut self.state, channel_name, &user.nickname);
                    }
                    _ => {}
                }
            }
        }
    }

    fn quit(&mut self, msg: &Message) {
        if let Some(ref prefix) = msg.prefix {
            match *prefix {
                Prefix::User(ref user) => {
                    for (_, channel) in self.state.channels.iter_mut() {
                        if let Some(pos) = channel.users.iter().position(|u| u == &user.nickname) {
                            channel.users.remove(pos);
                        }
                    }
                    self.listener.user_quit(&mut self.state, &user.nickname);
                }
                _ => {}
            }
        }
    }

}

/// Implement this trait to handle events.
pub trait Listener {

    /// Any event.
    #[allow(unused_variables)]
    fn any(&mut self, state: &mut State, event: &Event) {}

    /// When the server sends the welcome packet.
    #[allow(unused_variables)]
    fn welcome(&mut self, state: &mut State) {}

    /// When the client sucessfully joins a channel.
    #[allow(unused_variables)]
    fn channel_join(&mut self, state: &mut State, channel: &str) {}

    /// When a user joins a channel we are listening on.
    #[allow(unused_variables)]
    fn user_join(&mut self, state: &mut State, channel: &str, nickname :&str) {}

    /// When a user parts a channel we are listening on.
    #[allow(unused_variables)]
    fn user_part(&mut self, state: &mut State, channel: &str, nickname :&str) {}

    /// When a user quits.
    #[allow(unused_variables)]
    fn user_quit(&mut self, state: &mut State, nickname: &str) {}

}
<|endoftext|>


<commit_before>#![feature(core, old_io, old_path)]

extern crate tcod;

pub mod engine;
pub mod gui;
pub mod util;
<commit_msg>Remove core feature gate<commit_after>#![feature(old_io, old_path)]

extern crate tcod;

pub mod engine;
pub mod gui;
pub mod util;
<|endoftext|>


<commit_before>#![feature(if_let)]

use std::os;
use std::io::Command;
use std::io::process::InheritFd;
use std::default::Default;

/// Extra configuration to pass to gcc.
pub struct Config {
    /// Directories where gcc will look for header files.
    pub include_directories: Vec<Path>,
    /// Additional definitions (`-DKEY` or `-DKEY=VALUE`).
    pub definitions: Vec<(String, Option<String>)>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            include_directories: Vec::new(),
            definitions: Vec::new(),
        }
    }
}

/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
/// into the output. This will read the standard environment variables to detect
/// cross compilations and such.
///
/// # Example
///
/// ```no_run
/// use std::default::Default;
/// gcc::compile_library("libfoo.a", &Default::default(), &[
///     "foo.c",
///     "bar.c",
/// ]);
/// ```
pub fn compile_library(output: &str, config: &Config, files: &[&str]) {
    assert!(output.starts_with("lib"));
    assert!(output.ends_with(".a"));

    let target = os::getenv("TARGET").unwrap();
    let opt_level = os::getenv("OPT_LEVEL").unwrap();

    let mut cmd = Command::new(gcc());
    cmd.arg(format!("-O{}", opt_level));
    cmd.arg("-c");
    cmd.arg("-ffunction-sections").arg("-fdata-sections");
    cmd.args(cflags().as_slice());

    if target.as_slice().contains("i686") {
        cmd.arg("-m32");
    } else if target.as_slice().contains("x86_64") {
        cmd.arg("-m64");
    }

    if !target.as_slice().contains("i686") {
        cmd.arg("-fPIC");
    }

    for directory in config.include_directories.iter() {
        cmd.arg("-I").arg(directory);
    }

    for &(ref key, ref value) in config.definitions.iter() {
        if let &Some(ref value) = value {
            cmd.arg(format!("-D{}={}", key, value));
        } else {
            cmd.arg(format!("-D{}", key));
        }
    }

    let src = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    let dst = Path::new(os::getenv("OUT_DIR").unwrap());
    let mut objects = Vec::new();
    for file in files.iter() {
        let obj = dst.join(*file).with_extension("o");
        std::io::fs::mkdir_recursive(&obj.dir_path(), std::io::USER_RWX).unwrap();
        run(cmd.clone().arg(src.join(*file)).arg("-o").arg(&obj));
        objects.push(obj);
    }

    run(Command::new(ar()).arg("crus")
                          .arg(dst.join(output))
                          .args(objects.as_slice()));
    println!("cargo:rustc-flags=-L {} -l {}:static",
             dst.display(), output.slice(3, output.len() - 2));
}

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    assert!(cmd.stdout(InheritFd(1))
               .stderr(InheritFd(2))
               .status()
               .unwrap()
               .success());

}

fn gcc() -> String {
    os::getenv("CC").unwrap_or(if cfg!(windows) {
        "gcc".to_string()
    } else {
        "cc".to_string()
    })
}

fn ar() -> String {
    os::getenv("AR").unwrap_or("ar".to_string())
}

fn cflags() -> Vec<String> {
    os::getenv("CFLAGS").unwrap_or(String::new())
       .as_slice().words().map(|s| s.to_string())
       .collect()
}
<commit_msg>Allow specification of additional objects to link in<commit_after>#![feature(if_let)]

use std::os;
use std::io::Command;
use std::io::process::InheritFd;
use std::default::Default;

/// Extra configuration to pass to gcc.
pub struct Config {
    /// Directories where gcc will look for header files.
    pub include_directories: Vec<Path>,
    /// Additional definitions (`-DKEY` or `-DKEY=VALUE`).
    pub definitions: Vec<(String, Option<String>)>,
    /// Additional object files to link into the final archive
    pub objects: Vec<Path>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            include_directories: Vec::new(),
            definitions: Vec::new(),
            objects: Vec::new(),
        }
    }
}

/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
/// into the output. This will read the standard environment variables to detect
/// cross compilations and such.
///
/// # Example
///
/// ```no_run
/// use std::default::Default;
/// gcc::compile_library("libfoo.a", &Default::default(), &[
///     "foo.c",
///     "bar.c",
/// ]);
/// ```
pub fn compile_library(output: &str, config: &Config, files: &[&str]) {
    assert!(output.starts_with("lib"));
    assert!(output.ends_with(".a"));

    let target = os::getenv("TARGET").unwrap();
    let opt_level = os::getenv("OPT_LEVEL").unwrap();

    let mut cmd = Command::new(gcc());
    cmd.arg(format!("-O{}", opt_level));
    cmd.arg("-c");
    cmd.arg("-ffunction-sections").arg("-fdata-sections");
    cmd.args(cflags().as_slice());

    if target.as_slice().contains("i686") {
        cmd.arg("-m32");
    } else if target.as_slice().contains("x86_64") {
        cmd.arg("-m64");
    }

    if !target.as_slice().contains("i686") {
        cmd.arg("-fPIC");
    }

    for directory in config.include_directories.iter() {
        cmd.arg("-I").arg(directory);
    }

    for &(ref key, ref value) in config.definitions.iter() {
        if let &Some(ref value) = value {
            cmd.arg(format!("-D{}={}", key, value));
        } else {
            cmd.arg(format!("-D{}", key));
        }
    }

    let src = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    let dst = Path::new(os::getenv("OUT_DIR").unwrap());
    let mut objects = Vec::new();
    for file in files.iter() {
        let obj = dst.join(*file).with_extension("o");
        std::io::fs::mkdir_recursive(&obj.dir_path(), std::io::USER_RWX).unwrap();
        run(cmd.clone().arg(src.join(*file)).arg("-o").arg(&obj));
        objects.push(obj);
    }

    run(Command::new(ar()).arg("crus")
                          .arg(dst.join(output))
                          .args(objects.as_slice())
                          .args(config.objects.as_slice()));
    println!("cargo:rustc-flags=-L {} -l {}:static",
             dst.display(), output.slice(3, output.len() - 2));
}

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    assert!(cmd.stdout(InheritFd(1))
               .stderr(InheritFd(2))
               .status()
               .unwrap()
               .success());

}

fn gcc() -> String {
    os::getenv("CC").unwrap_or(if cfg!(windows) {
        "gcc".to_string()
    } else {
        "cc".to_string()
    })
}

fn ar() -> String {
    os::getenv("AR").unwrap_or("ar".to_string())
}

fn cflags() -> Vec<String> {
    os::getenv("CFLAGS").unwrap_or(String::new())
       .as_slice().words().map(|s| s.to_string())
       .collect()
}
<|endoftext|>