<commit_before>#[macro_use]
extern crate exonum;
#[macro_use]
extern crate log;

use std::fmt;

use exonum::blockchain::{Service, Transaction, Schema, NodeState};
use exonum::crypto::{PublicKey, Hash};
use exonum::messages::{RawMessage, Message, FromRaw, RawTransaction, Error as MessageError};
use exonum::storage::{MerkleTable, MemoryDB, Map, List, View, MapTable, MerklePatriciaTable,
                      Result as StorageResult};

pub const CONFIG_SERVICE: u16 = 1;
pub const CONFIG_PROPOSE_MESSAGE_ID: u16 = 0;
pub const CONFIG_VOTE_MESSAGE_ID: u16 = 1;

message! {
    TxConfigPropose {
        const TYPE = CONFIG_SERVICE;
        const ID = CONFIG_PROPOSE_MESSAGE_ID;
        const SIZE = 56;

        from:           &PublicKey  [00 => 32]
        height:         u64         [32 => 40]
        config:        &[u8]        [40 => 48] // serialized config bytes
        actual_from_height: u64     [48 => 56] // с какой высоты становится актуальным
    }
}

message! {
    TxConfigVote {
        const TYPE = CONFIG_SERVICE;
        const ID = CONFIG_VOTE_MESSAGE_ID;
        const SIZE = 81;

        from:           &PublicKey  [00 => 32]
        height:         u64         [32 => 40]
        hash_propose:   &Hash       [40 => 72] // hash of transacion we're voting for
        seed:           u64         [72 => 80] // incremental (1, 2, 3, 4, 5, 6, 7) проверять +1
        revoke:         bool        [80 => 81] // голос_за=false / отозвать=true
    }
}

#[derive(Clone, PartialEq)]
pub enum ConfigTx {
    ConfigPropose(TxConfigPropose),
    ConfigVote(TxConfigVote),
}

#[derive(Default)]
pub struct ConfigurationService {}

pub struct ConfigurationSchema<'a> {
    view: &'a View,
}

impl ConfigTx {
    pub fn from(&self) -> &PublicKey {
        match *self {
            ConfigTx::ConfigPropose(ref msg) => msg.from(),
            ConfigTx::ConfigVote(ref msg) => msg.from(),
        }
    }

    pub fn height(&self) -> u64 {
        match *self {
            ConfigTx::ConfigPropose(ref msg) => msg.height(),
            ConfigTx::ConfigVote(ref msg) => msg.height(),
        }
    }
}

impl fmt::Debug for ConfigTx {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            ConfigTx::ConfigPropose(ref msg) => write!(fmt, "{:?}", msg),
            ConfigTx::ConfigVote(ref msg) => write!(fmt, "{:?}", msg),
        }
    }
}

impl FromRaw for ConfigTx {
    fn from_raw(raw: RawMessage) -> Result<ConfigTx, MessageError> {
        match raw.message_type() {
            CONFIG_PROPOSE_MESSAGE_ID => {
                Ok(ConfigTx::ConfigPropose(TxConfigPropose::from_raw(raw)?))
            }
            CONFIG_VOTE_MESSAGE_ID => Ok(ConfigTx::ConfigVote(TxConfigVote::from_raw(raw)?)),
            _ => Err(MessageError::IncorrectMessageType { message_type: raw.message_type() }),
        }
    }
}

impl Message for ConfigTx {
    fn raw(&self) -> &RawMessage {
        match *self {
            ConfigTx::ConfigPropose(ref msg) => msg.raw(),
            ConfigTx::ConfigVote(ref msg) => msg.raw(),
        }
    }

    fn verify_signature(&self, public_key: &PublicKey) -> bool {
        match *self {
            ConfigTx::ConfigPropose(ref msg) => msg.verify_signature(public_key),
            ConfigTx::ConfigVote(ref msg) => msg.verify_signature(public_key),
        }
    }

    fn hash(&self) -> Hash {
        match *self {
            ConfigTx::ConfigPropose(ref msg) => msg.hash(),
            ConfigTx::ConfigVote(ref msg) => msg.hash(),
        }
    }
}

impl<'a> ConfigurationSchema<'a> {
    pub fn new(view: &'a View) -> ConfigurationSchema {
        ConfigurationSchema { view: view }
    }

    fn config_proposes
        (&self)
         -> MerklePatriciaTable<MapTable<View, [u8], Vec<u8>>, Hash, TxConfigPropose> {
        // config_propose paricia merkletree <hash_tx> транзакция пропоз
        MerklePatriciaTable::new(MapTable::new(vec![04], self.view))
    }

    fn config_votes
        (&self)
         -> MerklePatriciaTable<MapTable<View, [u8], Vec<u8>>, PublicKey, TxConfigVote> {
        // config_votes patricia merkletree <pub_key> последний голос
        MerklePatriciaTable::new(MapTable::new(vec![05], self.view))
    }

    pub fn state_hash(&self) -> StorageResult<Hash> {
        let db = MemoryDB::new();
        let hashes: MerkleTable<MemoryDB, u64, Hash> = MerkleTable::new(db);

        hashes.append(self.config_proposes().root_hash()?)?;
        hashes.append(self.config_votes().root_hash()?)?;
        hashes.root_hash()
    }
    pub fn get_config_propose(&self,
                              hash: &Hash)
                              -> Result<Option<TxConfigPropose>, ::storage::Error> {
        self.config_proposes().get(hash)
    }

    pub fn get_vote(&self, pub_key: &PublicKey) -> Result<Option<TxConfigVote>, ::storage::Error> {
        self.config_votes().get(pub_key)
    }
}

impl TxConfigPropose {
    fn execute(&self, view: &View) -> StorageResult<()> {
        let blockchain_schema = Schema::new(view);
        let config_schema = ConfigurationSchema::new(view);

        let config = blockchain_schema.get_actual_configuration()?;
        if !config.validators.contains(self.from()) {
            error!("ConfigPropose from unknown validator: {:?}", self.from());
            return Ok(());
        }

        let hash = self.hash();
        if config_schema.config_proposes().get(&hash)?.is_some() {
            error!("Received config_propose has already been handled, msg={:?}",
                   self);
            return Ok(());
        }

        trace!("Handle ConfigPropose");
        config_schema.config_proposes().put(&hash, self.clone())?;
        Ok(())
    }
}

impl TxConfigVote {
    fn execute(&self, view: &View) -> StorageResult<()> {
        let blockchain_schema = Schema::new(view);
        let config_schema = ConfigurationSchema::new(view);

        let config = blockchain_schema.get_actual_configuration()?;

        if !config.validators.contains(self.from()) {
            error!("ConfigVote from unknown validator: {:?}", self.from());
            return Ok(());
        }

        if config_schema.config_proposes().get(self.hash_propose())?.is_none() {
            error!("Received config_vote for unknown transaciton, msg={:?}",
                   self);
            return Ok(());
        }

        if let Some(vote) = config_schema.config_votes().get(self.from())? {
            if vote.seed() != self.seed() - 1 {
                error!("Received config_vote with wrong seed, msg={:?}", self);
                return Ok(());
            }
        }

        let msg = self.clone();
        config_schema.config_votes().put(msg.from(), self.clone())?;

        let mut votes_count = 0;
        for pub_key in config.validators.clone() {
            if let Some(vote) = config_schema.config_votes().get(&pub_key)? {
                if !vote.revoke() {
                    votes_count += 1;
                }
            }
        }

        if votes_count > 2 / 3 * config.validators.len() {
            if let Some(config_propose) =
                config_schema.config_proposes()
                    .get(self.hash_propose())? {
                blockchain_schema.commit_actual_configuration(config_propose.actual_from_height(),
                                                 config_propose.config())?;
            }
        }
        Ok(())
    }
}

impl Transaction for ConfigTx {
    fn verify(&self) -> bool {
        self.verify_signature(self.from())
    }

    fn execute(&self, view: &View) -> StorageResult<()> {
        match *self {
            ConfigTx::ConfigPropose(ref tx) => tx.execute(view),
            ConfigTx::ConfigVote(ref tx) => tx.execute(view),
        }
    }
}

impl ConfigurationService {
    pub fn new() -> ConfigurationService {
        ConfigurationService {}
    }
}

impl Service for ConfigurationService {
    fn service_id(&self) -> u16 {
        CONFIG_SERVICE
    }

    fn state_hash(&self, view: &View) -> Option<StorageResult<Hash>> {
        let schema = ConfigurationSchema::new(view);
        Some(schema.state_hash())
    }

    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, MessageError> {
        ConfigTx::from_raw(raw).map(|tx| Box::new(tx) as Box<Transaction>)
    }

    fn handle_commit(&self, state: &mut NodeState) -> StorageResult<()> {
        let actual_config = {
            let schema = Schema::new(state.view());
            let height = state.height();
            schema.get_configuration_at_height(height)?
        };

        if let Some(config) = actual_config {
            info!("Updated node config={:#?}", config);
            state.update_config(config);
        }
        Ok(())
    }
}<commit_msg>After rebase fix #2<commit_after>#[macro_use]
extern crate exonum;
#[macro_use]
extern crate log;

use std::fmt;

use exonum::blockchain::{Service, Transaction, Schema, NodeState};
use exonum::crypto::{PublicKey, Hash};
use exonum::messages::{RawMessage, Message, FromRaw, RawTransaction, Error as MessageError};
use exonum::storage::{MerkleTable, MemoryDB, Map, List, View, MapTable, MerklePatriciaTable,
                      Result as StorageResult};

pub const CONFIG_SERVICE: u16 = 1;
pub const CONFIG_PROPOSE_MESSAGE_ID: u16 = 0;
pub const CONFIG_VOTE_MESSAGE_ID: u16 = 1;

message! {
    TxConfigPropose {
        const TYPE = CONFIG_SERVICE;
        const ID = CONFIG_PROPOSE_MESSAGE_ID;
        const SIZE = 56;

        from:           &PublicKey  [00 => 32]
        height:         u64         [32 => 40]
        config:        &[u8]        [40 => 48] // serialized config bytes
        actual_from_height: u64     [48 => 56] // с какой высоты становится актуальным
    }
}

message! {
    TxConfigVote {
        const TYPE = CONFIG_SERVICE;
        const ID = CONFIG_VOTE_MESSAGE_ID;
        const SIZE = 81;

        from:           &PublicKey  [00 => 32]
        height:         u64         [32 => 40]
        hash_propose:   &Hash       [40 => 72] // hash of transacion we're voting for
        seed:           u64         [72 => 80] // incremental (1, 2, 3, 4, 5, 6, 7) проверять +1
        revoke:         bool        [80 => 81] // голос_за=false / отозвать=true
    }
}

#[derive(Clone, PartialEq)]
pub enum ConfigTx {
    ConfigPropose(TxConfigPropose),
    ConfigVote(TxConfigVote),
}

#[derive(Default)]
pub struct ConfigurationService {}

pub struct ConfigurationSchema<'a> {
    view: &'a View,
}

impl ConfigTx {
    pub fn from(&self) -> &PublicKey {
        match *self {
            ConfigTx::ConfigPropose(ref msg) => msg.from(),
            ConfigTx::ConfigVote(ref msg) => msg.from(),
        }
    }

    pub fn height(&self) -> u64 {
        match *self {
            ConfigTx::ConfigPropose(ref msg) => msg.height(),
            ConfigTx::ConfigVote(ref msg) => msg.height(),
        }
    }
}

impl fmt::Debug for ConfigTx {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            ConfigTx::ConfigPropose(ref msg) => write!(fmt, "{:?}", msg),
            ConfigTx::ConfigVote(ref msg) => write!(fmt, "{:?}", msg),
        }
    }
}

impl FromRaw for ConfigTx {
    fn from_raw(raw: RawMessage) -> Result<ConfigTx, MessageError> {
        match raw.message_type() {
            CONFIG_PROPOSE_MESSAGE_ID => {
                Ok(ConfigTx::ConfigPropose(TxConfigPropose::from_raw(raw)?))
            }
            CONFIG_VOTE_MESSAGE_ID => Ok(ConfigTx::ConfigVote(TxConfigVote::from_raw(raw)?)),
            _ => Err(MessageError::IncorrectMessageType { message_type: raw.message_type() }),
        }
    }
}

impl Message for ConfigTx {
    fn raw(&self) -> &RawMessage {
        match *self {
            ConfigTx::ConfigPropose(ref msg) => msg.raw(),
            ConfigTx::ConfigVote(ref msg) => msg.raw(),
        }
    }

    fn verify_signature(&self, public_key: &PublicKey) -> bool {
        match *self {
            ConfigTx::ConfigPropose(ref msg) => msg.verify_signature(public_key),
            ConfigTx::ConfigVote(ref msg) => msg.verify_signature(public_key),
        }
    }

    fn hash(&self) -> Hash {
        match *self {
            ConfigTx::ConfigPropose(ref msg) => msg.hash(),
            ConfigTx::ConfigVote(ref msg) => msg.hash(),
        }
    }
}

impl<'a> ConfigurationSchema<'a> {
    pub fn new(view: &'a View) -> ConfigurationSchema {
        ConfigurationSchema { view: view }
    }

    fn config_proposes
        (&self)
         -> MerklePatriciaTable<MapTable<View, [u8], Vec<u8>>, Hash, TxConfigPropose> {
        // config_propose paricia merkletree <hash_tx> транзакция пропоз
        MerklePatriciaTable::new(MapTable::new(vec![04], self.view))
    }

    fn config_votes
        (&self)
         -> MerklePatriciaTable<MapTable<View, [u8], Vec<u8>>, PublicKey, TxConfigVote> {
        // config_votes patricia merkletree <pub_key> последний голос
        MerklePatriciaTable::new(MapTable::new(vec![05], self.view))
    }

    pub fn state_hash(&self) -> StorageResult<Hash> {
        let db = MemoryDB::new();
        let hashes: MerkleTable<MemoryDB, u64, Hash> = MerkleTable::new(db);

        hashes.append(self.config_proposes().root_hash()?)?;
        hashes.append(self.config_votes().root_hash()?)?;
        hashes.root_hash()
    }
    pub fn get_config_propose(&self,
                              hash: &Hash)
                              -> Result<Option<TxConfigPropose>, exonum::storage::Error> {
        self.config_proposes().get(hash)
    }

    pub fn get_vote(&self,
                    pub_key: &PublicKey)
                    -> Result<Option<TxConfigVote>, exonum::storage::Error> {
        self.config_votes().get(pub_key)
    }
}

impl TxConfigPropose {
    fn execute(&self, view: &View) -> StorageResult<()> {
        let blockchain_schema = Schema::new(view);
        let config_schema = ConfigurationSchema::new(view);

        let config = blockchain_schema.get_actual_configuration()?;
        if !config.validators.contains(self.from()) {
            error!("ConfigPropose from unknown validator: {:?}", self.from());
            return Ok(());
        }

        let hash = self.hash();
        if config_schema.config_proposes().get(&hash)?.is_some() {
            error!("Received config_propose has already been handled, msg={:?}",
                   self);
            return Ok(());
        }

        trace!("Handle ConfigPropose");
        config_schema.config_proposes().put(&hash, self.clone())?;
        Ok(())
    }
}

impl TxConfigVote {
    fn execute(&self, view: &View) -> StorageResult<()> {
        let blockchain_schema = Schema::new(view);
        let config_schema = ConfigurationSchema::new(view);

        let config = blockchain_schema.get_actual_configuration()?;

        if !config.validators.contains(self.from()) {
            error!("ConfigVote from unknown validator: {:?}", self.from());
            return Ok(());
        }

        if config_schema.config_proposes().get(self.hash_propose())?.is_none() {
            error!("Received config_vote for unknown transaciton, msg={:?}",
                   self);
            return Ok(());
        }

        if let Some(vote) = config_schema.config_votes().get(self.from())? {
            if vote.seed() != self.seed() - 1 {
                error!("Received config_vote with wrong seed, msg={:?}", self);
                return Ok(());
            }
        }

        let msg = self.clone();
        config_schema.config_votes().put(msg.from(), self.clone())?;

        let mut votes_count = 0;
        for pub_key in config.validators.clone() {
            if let Some(vote) = config_schema.config_votes().get(&pub_key)? {
                if !vote.revoke() {
                    votes_count += 1;
                }
            }
        }

        if votes_count > 2 / 3 * config.validators.len() {
            if let Some(config_propose) =
                config_schema.config_proposes()
                    .get(self.hash_propose())? {
                blockchain_schema.commit_actual_configuration(config_propose.actual_from_height(),
                                                 config_propose.config())?;
            }
        }
        Ok(())
    }
}

impl Transaction for ConfigTx {
    fn verify(&self) -> bool {
        self.verify_signature(self.from())
    }

    fn execute(&self, view: &View) -> StorageResult<()> {
        match *self {
            ConfigTx::ConfigPropose(ref tx) => tx.execute(view),
            ConfigTx::ConfigVote(ref tx) => tx.execute(view),
        }
    }
}

impl ConfigurationService {
    pub fn new() -> ConfigurationService {
        ConfigurationService {}
    }
}

impl Service for ConfigurationService {
    fn service_id(&self) -> u16 {
        CONFIG_SERVICE
    }

    fn state_hash(&self, view: &View) -> Option<StorageResult<Hash>> {
        let schema = ConfigurationSchema::new(view);
        Some(schema.state_hash())
    }

    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, MessageError> {
        ConfigTx::from_raw(raw).map(|tx| Box::new(tx) as Box<Transaction>)
    }

    fn handle_commit(&self, state: &mut NodeState) -> StorageResult<()> {
        let actual_config = {
            let schema = Schema::new(state.view());
            let height = state.height();
            schema.get_configuration_at_height(height)?
        };

        if let Some(config) = actual_config {
            info!("Updated node config={:#?}", config);
            state.update_config(config);
        }
        Ok(())
    }
}<|endoftext|>


<commit_before>extern crate tokio_core;
extern crate futures;
extern crate reqwest;
extern crate serde;

extern crate influxdb;

use std::error::Error;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

use futures::Future;

use influxdb::{AsyncDb, QueryResponse, InfluxServerError};

const HOSTNAME: &'static str = "http://localhost:8086/";

#[test]
fn query_asynchronously() {
    let db = fresh_db();

    db.add_data("cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000")
        .unwrap();

    let response = with_core(|core| {
        let async_db = AsyncDb::new(core.handle(), HOSTNAME, &db.name).unwrap();

        async_db.query(r#"SELECT "value","host" FROM "cpu_load_short" WHERE "region"='us-west'"#)
    });

    assert_eq!(response.results[0].series[0].name, "cpu_load_short");
    assert_eq!(response.results[0].series[0].values[0][1].as_f64(), Some(0.64));
    assert_eq!(response.results[0].series[0].values[0][2].as_str(), Some("server01"));
}

#[test]
fn add_data_asynchronously() {
    let db = fresh_db();

    with_core(|core| {
        let async_db = AsyncDb::new(core.handle(), HOSTNAME, &db.name).unwrap();

        async_db.add_data("cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000")
    });

    let response: QueryResponse = db.query(r#"SELECT "value","host" FROM "cpu_load_short" WHERE "region"='us-west'"#).unwrap();

    assert_eq!(response.results[0].series[0].name, "cpu_load_short");
    assert_eq!(response.results[0].series[0].values[0][1].as_f64(), Some(0.64));
    assert_eq!(response.results[0].series[0].values[0][2].as_str(), Some("server01"));
}

#[test]
#[ignore] // TODO: handle errors returned in the response instead of status code
fn query_nonexistent_db() {
    let response = with_core(|core| {
        let async_db = AsyncDb::new(core.handle(), HOSTNAME, "does_not_exist").unwrap();

        async_db.query(r#"SELECT "value","host" FROM "cpu_load_short" WHERE "region"='us-west'"#)
    });
}

#[test]
fn test_infrastructure() {
    let db = fresh_db();

    db.add_data("cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000")
        .unwrap();

    let response: QueryResponse =
        db.query(r#"SELECT "value","host" FROM "cpu_load_short" WHERE "region"='us-west'"#)
        .unwrap();

    assert_eq!(response.results[0].series[0].name, "cpu_load_short");
    assert_eq!(response.results[0].series[0].values[0][1].as_f64(), Some(0.64));
    assert_eq!(response.results[0].series[0].values[0][2].as_str(), Some("server01"));
}

fn fresh_db() -> TestingDb {
    static DB_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;

    let id = DB_COUNTER.fetch_add(1, Ordering::SeqCst);
    let name = format!("influxdb_rs_{}", id);
    let db = TestingDb::new(HOSTNAME, name)
        .expect("Unable to create test database");
    db.create_db()
        .expect("Unable to create test database");

    // The InfluxDB created isn't ready immediately; this prevents
    // intermittent failures.
    std::thread::sleep(std::time::Duration::from_millis(5));
    db
}

fn with_core<F, T>(f: F) -> T::Item
    where F: FnOnce(&mut tokio_core::reactor::Core) -> T,
          T: Future,
          T::Error: std::fmt::Debug,
{
    let mut core = tokio_core::reactor::Core::new()
        .expect("Unable to create reactor core for testing");

    let future = f(&mut core);

    core.run(future).expect("Unable to run future to completion")
}

struct TestingDb {
    name: String,
    client: reqwest::Client,
    query_endpoint: reqwest::Url,
    write_endpoint: reqwest::Url,
}

impl TestingDb {
    /// `base_url` should include the protocol, host, and port (`http://localhost:8086`)
    fn new<S>(base_url: &str, name: S) -> Result<Self, Box<Error>>
        where S: Into<String>,
    {
        let name = name.into();

        let base_url = reqwest::Url::parse(base_url)?;
        let query_endpoint = base_url.join("/query")?;
        let mut write_endpoint = base_url.join("/write")?;
        write_endpoint.query_pairs_mut()
            .append_pair("db", &name);

        let client = reqwest::Client::new()?;

        Ok(TestingDb {
            name: name,
            client: client,
            query_endpoint: query_endpoint,
            write_endpoint: write_endpoint,
        })
    }

    fn create_db(&self) -> Result<(), Box<Error>> {
        let mut u = self.query_endpoint.clone();
        u.query_pairs_mut()
            .append_pair("q", &format!("CREATE DATABASE {}", self.name));
        let mut res = self.client.post(u).send()?;

        check_result(&mut res)?;
        Ok(())
    }

    fn drop_db(&self) -> Result<(), Box<Error>> {
        let mut u = self.query_endpoint.clone();
        u.query_pairs_mut()
            .append_pair("q", &format!("DROP DATABASE {}", self.name));
        let mut res = self.client.post(u).send()?;

        check_result(&mut res)?;
        Ok(())
    }

    fn add_data(&self, data: &str) -> Result<(), Box<Error>> {
        let mut res = self.client.post(self.write_endpoint.clone())
            .body(data)
            .send()?;

        check_result(&mut res)?;
        Ok(())
    }

    fn query<T>(&self, query: &str) -> Result<T, Box<Error>>
        where T: serde::Deserialize,
    {
        let mut u = self.query_endpoint.clone();
        u.query_pairs_mut()
            .append_pair("db", &self.name)
            .append_pair("q", query);
        let mut res = self.client.get(u).send()?;

        check_result(&mut res)?;
        let val = res.json()?;
        Ok(val)
    }
}

impl Drop for TestingDb {
    fn drop(&mut self) {
        // TODO: What happens if we drop twice?
        self.drop_db().unwrap_or_else(|e| panic!("Unable to drop database {}: {}", self.name, e));
    }
}

fn check_result(res: &mut reqwest::Response) -> Result<(), Box<Error>> {
    let status = *res.status();

    if status.is_success() {
        Ok(())
    } else if status.is_client_error() {
        Err(parse_influx_server_error(res, "Client error").into())
    } else if status.is_server_error() {
        Err(parse_influx_server_error(res, "Server error").into())
    } else {
        Err(parse_influx_server_error(res, "Unknown error").into())
    }
}

fn parse_influx_server_error(res: &mut reqwest::Response, kind: &str) -> String {
    match res.json::<InfluxServerError>() {
        Ok(e) => format!("{}: {}", kind, e.error),
        Err(_) => format!("{}: (unable to parse error message)", kind),
    }
}
<commit_msg>Add a test for multiple queries in one request<commit_after>extern crate tokio_core;
extern crate futures;
extern crate reqwest;
extern crate serde;

extern crate influxdb;

use std::error::Error;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

use futures::Future;

use influxdb::{AsyncDb, QueryResponse, InfluxServerError};

const HOSTNAME: &'static str = "http://localhost:8086/";

#[test]
fn query_asynchronously() {
    let db = fresh_db();

    db.add_data("cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000")
        .unwrap();

    let response = with_core(|core| {
        let async_db = AsyncDb::new(core.handle(), HOSTNAME, &db.name).unwrap();

        async_db.query(r#"SELECT "value","host" FROM "cpu_load_short" WHERE "region"='us-west'"#)
    });

    assert_eq!(response.results[0].series[0].name, "cpu_load_short");
    assert_eq!(response.results[0].series[0].values[0][1].as_f64(), Some(0.64));
    assert_eq!(response.results[0].series[0].values[0][2].as_str(), Some("server01"));
}

#[test]
fn add_data_asynchronously() {
    let db = fresh_db();

    with_core(|core| {
        let async_db = AsyncDb::new(core.handle(), HOSTNAME, &db.name).unwrap();

        async_db.add_data("cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000")
    });

    let response: QueryResponse = db.query(r#"SELECT "value","host" FROM "cpu_load_short" WHERE "region"='us-west'"#).unwrap();

    assert_eq!(response.results[0].series[0].name, "cpu_load_short");
    assert_eq!(response.results[0].series[0].values[0][1].as_f64(), Some(0.64));
    assert_eq!(response.results[0].series[0].values[0][2].as_str(), Some("server01"));
}

#[test]
#[ignore] // TODO: handle errors returned in the response instead of status code
fn query_nonexistent_db() {
    let response = with_core(|core| {
        let async_db = AsyncDb::new(core.handle(), HOSTNAME, "does_not_exist").unwrap();

        async_db.query(r#"SELECT "value","host" FROM "cpu_load_short" WHERE "region"='us-west'"#)
    });
}

#[test]
fn multiple_queries() {
    let db = fresh_db();

    db.add_data("cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000")
        .unwrap();
    db.add_data("cpu_load_short,host=server02,region=us-west value=0.8")
        .unwrap();
    db.add_data("cpu_load_short,host=server01,region=us-west value=0.4")
        .unwrap();

    let mut response = with_core(|core| {
        let async_db = AsyncDb::new(core.handle(), HOSTNAME, &db.name).unwrap();

        async_db.query(r#"SELECT "value","host" FROM "cpu_load_short" WHERE "region"='us-west'; SELECT "value" FROM "cpu_load_short" WHERE "host"='server01'"#)
    });

    response.results.sort_by_key(|k| k.statement_id);

    assert_eq!(response.results[0].statement_id, 0);
    assert_eq!(response.results[0].series[0].name, "cpu_load_short");
    assert_eq!(response.results[0].series[0].values[0][1].as_f64(), Some(0.64));
    assert_eq!(response.results[0].series[0].values[0][2].as_str(), Some("server01"));

    assert_eq!(response.results[1].statement_id, 1);
    assert_eq!(response.results[1].series[0].name, "cpu_load_short");
    assert_eq!(response.results[1].series[0].values[0][1].as_f64(), Some(0.64));
    assert_eq!(response.results[1].series[0].values[1][1].as_f64(), Some(0.4));
}

#[test]
fn test_infrastructure() {
    let db = fresh_db();

    db.add_data("cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000")
        .unwrap();

    let response: QueryResponse =
        db.query(r#"SELECT "value","host" FROM "cpu_load_short" WHERE "region"='us-west'"#)
        .unwrap();

    assert_eq!(response.results[0].series[0].name, "cpu_load_short");
    assert_eq!(response.results[0].series[0].values[0][1].as_f64(), Some(0.64));
    assert_eq!(response.results[0].series[0].values[0][2].as_str(), Some("server01"));
}

fn fresh_db() -> TestingDb {
    static DB_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;

    let id = DB_COUNTER.fetch_add(1, Ordering::SeqCst);
    let name = format!("influxdb_rs_{}", id);
    let db = TestingDb::new(HOSTNAME, name)
        .expect("Unable to create test database");
    db.create_db()
        .expect("Unable to create test database");

    // The InfluxDB created isn't ready immediately; this prevents
    // intermittent failures.
    std::thread::sleep(std::time::Duration::from_millis(5));
    db
}

fn with_core<F, T>(f: F) -> T::Item
    where F: FnOnce(&mut tokio_core::reactor::Core) -> T,
          T: Future,
          T::Error: std::fmt::Debug,
{
    let mut core = tokio_core::reactor::Core::new()
        .expect("Unable to create reactor core for testing");

    let future = f(&mut core);

    core.run(future).expect("Unable to run future to completion")
}

struct TestingDb {
    name: String,
    client: reqwest::Client,
    query_endpoint: reqwest::Url,
    write_endpoint: reqwest::Url,
}

impl TestingDb {
    /// `base_url` should include the protocol, host, and port (`http://localhost:8086`)
    fn new<S>(base_url: &str, name: S) -> Result<Self, Box<Error>>
        where S: Into<String>,
    {
        let name = name.into();

        let base_url = reqwest::Url::parse(base_url)?;
        let query_endpoint = base_url.join("/query")?;
        let mut write_endpoint = base_url.join("/write")?;
        write_endpoint.query_pairs_mut()
            .append_pair("db", &name);

        let client = reqwest::Client::new()?;

        Ok(TestingDb {
            name: name,
            client: client,
            query_endpoint: query_endpoint,
            write_endpoint: write_endpoint,
        })
    }

    fn create_db(&self) -> Result<(), Box<Error>> {
        let mut u = self.query_endpoint.clone();
        u.query_pairs_mut()
            .append_pair("q", &format!("CREATE DATABASE {}", self.name));
        let mut res = self.client.post(u).send()?;

        check_result(&mut res)?;
        Ok(())
    }

    fn drop_db(&self) -> Result<(), Box<Error>> {
        let mut u = self.query_endpoint.clone();
        u.query_pairs_mut()
            .append_pair("q", &format!("DROP DATABASE {}", self.name));
        let mut res = self.client.post(u).send()?;

        check_result(&mut res)?;
        Ok(())
    }

    fn add_data(&self, data: &str) -> Result<(), Box<Error>> {
        let mut res = self.client.post(self.write_endpoint.clone())
            .body(data)
            .send()?;

        check_result(&mut res)?;
        Ok(())
    }

    fn query<T>(&self, query: &str) -> Result<T, Box<Error>>
        where T: serde::Deserialize,
    {
        let mut u = self.query_endpoint.clone();
        u.query_pairs_mut()
            .append_pair("db", &self.name)
            .append_pair("q", query);
        let mut res = self.client.get(u).send()?;

        check_result(&mut res)?;
        let val = res.json()?;
        Ok(val)
    }
}

impl Drop for TestingDb {
    fn drop(&mut self) {
        // TODO: What happens if we drop twice?
        self.drop_db().unwrap_or_else(|e| panic!("Unable to drop database {}: {}", self.name, e));
    }
}

fn check_result(res: &mut reqwest::Response) -> Result<(), Box<Error>> {
    let status = *res.status();

    if status.is_success() {
        Ok(())
    } else if status.is_client_error() {
        Err(parse_influx_server_error(res, "Client error").into())
    } else if status.is_server_error() {
        Err(parse_influx_server_error(res, "Server error").into())
    } else {
        Err(parse_influx_server_error(res, "Unknown error").into())
    }
}

fn parse_influx_server_error(res: &mut reqwest::Response, kind: &str) -> String {
    match res.json::<InfluxServerError>() {
        Ok(e) => format!("{}: {}", kind, e.error),
        Err(_) => format!("{}: (unable to parse error message)", kind),
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option.  This file may not be copied, modified, or distributed
// except according to those terms.
//
// Portions of this implementation are based on work by Nat Pryce:
// https://github.com/npryce/rusty-pi/blob/master/src/pi/gpio.rs

#![crate_type = "lib"]
#![crate_name = "sysfs_gpio"]

///! GPIO access under Linux using the GPIO sysfs interface
///!
///! The methods exposed by this library are centered around
///! the `Pin` struct and map pretty directly the API exposed
///! by the kernel in syfs (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt).
///!
///! # Examples
///!
///! Typical usage for systems where one wants to ensure that
///! the pins in use are unexported upon completion looks like
///! the follwoing:
///!
///! ```rust,ignore
///! extern crate sysfs_gpio;
///! use sysfs_gpio::Pin;
///!
///!
///! ```

extern crate nix;

use nix::sys::epoll::*;
use nix::fcntl::Fd;
use nix::unistd::close;

use std::io::prelude::*;
use std::os::unix::prelude::*;
use std::io;
use std::io::{Error, ErrorKind, SeekFrom};
use std::fs;
use std::fs::{File};

pub struct Pin {
    pin_num : u64,
}

#[derive(Clone,Debug)]
pub enum Direction {In, Out, High, Low}

#[derive(Clone,Debug)]
pub enum Edge {NoInterrupt, RisingEdge, FallingEdge, BothEdges}

#[macro_export]
macro_rules! try_unexport {
    ($gpio:ident, $e:expr) => (match $e {
        Ok(res) => res,
        Err(e) => { try!($gpio.unexport()); return Err(e) },
    });
}

fn from_nix_error(err: ::nix::Error) -> io::Error {
    io::Error::from_raw_os_error(err.errno() as i32)
}

/// Flush up to max bytes from the provided files input buffer
///
/// Typically, one would just use seek() for this sort of thing,
/// but for certain files (e.g. in sysfs), you need to actually
/// read it.
fn flush_input_from_file(dev_file: &mut File, max : usize) -> io::Result<usize> {
    let mut s = String::with_capacity(max);
    dev_file.read_to_string(&mut s)
}

/// Get the pin value from the provided file
fn get_value_from_file(dev_file: &mut File) -> io::Result<u8> {
    let mut s = String::with_capacity(10);
    try!(dev_file.seek(SeekFrom::Start(0)));
    try!(dev_file.read_to_string(&mut s));
    match s[..1].parse::<u8>() {
        Ok(n) => Ok(n),
        Err(_) => Err(Error::new(ErrorKind::Other, "Unexpected Error")),
    }
}

impl Pin {
    /// Write all of the provided contents to the specified devFile
    fn write_to_device_file(&self, dev_file_name: &str, value: &str) -> io::Result<()> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::create(&gpio_path));
        try!(dev_file.write_all(value.as_bytes()));
        Ok(())
    }

    /// Create a new Pin with the provided `pin_num`
    ///
    /// This function does not export the provided pin_num.
    pub fn new(pin_num : u64) -> Pin {
        Pin {
            pin_num: pin_num,
        }
    }

    /// Run a closure with the GPIO exported
    ///
    /// Prior to the provided closure being executed, the Gpio
    /// will be eported.  After the closure execution is complete,
    /// the Gpio will be unexported.
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// gpio = Pin::new(24);
    /// let res = gpio::with_exported(|| {
    ///     println!("At this point, the Pin is exported");
    ///     try!(gpio.set_direction(Direction::Low));
    ///     try!(gpio.set_value(1));
    ///     // ...
    /// };
    /// ```
    #[inline]
    pub fn with_exported<F: FnOnce() -> io::Result<()>>(&self, closure : F) -> io::Result<()> {
        try!(self.export());
        match closure() {
            Ok(()) => { try!(self.unexport()); Ok(()) },
            Err(err) => { try!(self.unexport()); Err(err) },
        }
    }

    /// Export the GPIO
    ///
    /// This is equivalent to `echo N > /sys/class/gpio/export` with
    /// the exception that the case where the GPIO is already exported
    /// is not an error.
    ///
    /// # Errors
    ///
    /// The main cases in which this function will fail and return an
    /// error are the following:
    /// 1. The system does not support the GPIO sysfs interface
    /// 2. The requested GPIO is out of range and cannot be exported
    /// 3. The requested GPIO is in use by the kernel and cannot
    ///    be exported by use in userspace
    ///
    /// # Example
    /// ```rust,ignore
    /// use sysfs_gpio::Pin;
    ///
    /// gpio = Pin::new(24);
    /// match gpio.export() {
    ///     Ok(()) => println!("Gpio {} exported!", gpio.pin),
    ///     Err(err) => println!("Gpio {} could not be exported: {}", gpio.pin, err),
    /// }
    /// ```
    pub fn export(&self) -> io::Result<()> {
        match fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            Ok(_) => {},
            Err(_) => {
                let mut export_file = try!(File::create("/sys/class/gpio/export"));
                try!(export_file.write_all(format!("{}", self.pin_num).as_bytes()));
            }
        };
        Ok(())
    }

    /// Unexport the GPIO
    ///
    /// This function will unexport the provided by from syfs if
    /// it is currently exported.  If the pin is not currently
    /// exported, it will return without error.  That is, whenever
    /// this function returns Ok, the GPIO is not exported.
    pub fn unexport(&self) -> io::Result<()> {
        match fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            Ok(_) => {
                let mut unexport_file = try!(File::create("/sys/class/gpio/unexport"));
                try!(unexport_file.write_all(format!("{}", self.pin_num).as_bytes()));
            },
            Err(_) => {} // not exported
        };
        Ok(())
    }

    /// Set this GPIO as either an input or an output
    ///
    /// The basic values allowed here are `Direction::In` and
    /// `Direction::Out` which set the Pin as either an input
    /// or output respectively.  In addition to those, two
    /// additional settings of `Direction::High` and
    /// `Direction::Low`.  These both set the Pin as an output
    /// but do so with an initial value of high or low respectively.
    /// This allows for glitch-free operation.
    ///
    /// Note that this entry may not exist if the kernel does
    /// not support changing the direction of a pin in userspace.  If
    /// this is the case, you will get an error.
    pub fn set_direction(&self, dir : Direction) -> io::Result<()> {
        self.write_to_device_file("direction", match dir {
            Direction::In => "in",
            Direction::Out => "out",
            Direction::High => "high",
            Direction::Low => "low",
        })
    }

    /// Get the value of the Pin (0 or 1)
    ///
    /// If successful, 1 will be returned if the pin is high
    /// and 0 will be returned if the pin is low (this may or may
    /// not match the signal level of the actual signal depending
    /// on the GPIO "active_low" entry).
    pub fn get_value(&self) -> io::Result<u8> {
        let mut dev_file = try!(File::open(&format!("/sys/class/gpio/gpio{}/value", self.pin_num)));
        get_value_from_file(&mut dev_file)
    }

    /// Set the value of the Pin
    ///
    /// This will set the value of the pin either high or low.
    /// A 0 value will set the pin low and any other value will
    /// set the pin high (1 is typical).
    pub fn set_value(&self, value : u8) -> io::Result<()> {
        let val = if value == 0 {
            "0"
        } else {
            "1"
        };
        self.write_to_device_file("value", val)
    }

    /// Set the edge on which this GPIO will trigger when polled
    ///
    /// The configured edge determines what changes to the Pin will
    /// result in `poll()` returning.  This call will return an Error
    /// if the pin does not allow interrupts.
    pub fn set_edge(&self, edge: Edge) -> io::Result<()> {
        self.write_to_device_file("edge", match edge {
            Edge::NoInterrupt => "none",
            Edge::RisingEdge => "rising",
            Edge::FallingEdge => "falling",
            Edge::BothEdges => "both",
        })
    }

    /// Get the currently configured edge for this pin
    ///
    /// This value will only be present if the Pin allows
    /// for interrupts.
    pub fn get_edge(&self) -> io::Result<Edge> {
        let mut dev_file = try!(File::open(&format!("/sys/class/gpio/gpio{}/edge", self.pin_num)));
        let mut s = String::with_capacity(10);
        try!(dev_file.read_to_string(&mut s));
        match s.trim() {
            "none" => Ok(Edge::NoInterrupt),
            "rising" => Ok(Edge::RisingEdge),
            "falling" => Ok(Edge::FallingEdge),
            "both" => Ok(Edge::BothEdges),
            other => Err(Error::new(ErrorKind::Other, format!("Unexpected edge file contents {}", other))),
        }
    }

    /// Get a PinPoller object for this pin
    ///
    /// This pin poller object will register an interrupt with the
    /// kernel and allow you to poll() on it and receive notifications
    /// that an interrupt has occured with minimal delay.
    pub fn get_poller(&self) -> io::Result<PinPoller> {
        PinPoller::new(self.pin_num)
    }
}

pub struct PinPoller {
    pin_num : u64,
    epoll_fd : Fd,
    devfile : File,
}

impl PinPoller {

    /// Get the pin associated with this PinPoller
    ///
    /// Note that this will be a new Pin object with the
    /// proper pin number.
    pub fn get_pin(&self) -> Pin {
        return Pin::new(self.pin_num);
    }

    /// Create a new PinPoller for the provided pin number
    pub fn new(pin_num : u64) -> io::Result<PinPoller> {
        let devfile : File = try!(File::open(&format!("/sys/class/gpio/gpio{}/value", pin_num)));
        let devfile_fd = devfile.as_raw_fd();
        let epoll_fd = try!(epoll_create().map_err(from_nix_error));
        let events = EPOLLPRI | EPOLLET;
        let info = EpollEvent {
            events: events,
            data: 0u64,
        };

        match epoll_ctl(epoll_fd, EpollOp::EpollCtlAdd, devfile_fd, &info) {
            Ok(_) => {
                let pp = PinPoller {
                    pin_num: pin_num,
                    devfile: devfile,
                    epoll_fd: epoll_fd,
                };
                Ok(pp)
            },
            Err(err) => {
                let _ = close(epoll_fd); // cleanup
                Err(from_nix_error(err))
            }
        }
    }

    /// Block until an interrupt occurs
    ///
    /// This call will block until an interrupt occurs.  The types
    /// of interrupts which may result in this call returning
    /// may be configured by calling `set_edge()` prior to
    /// makeing this call.  This call makes use of epoll under the
    /// covers.  If it is desirable to poll on multiple GPIOs or
    /// other event source, you will need to implement that logic
    /// yourself.
    ///
    /// This function will return Some(value) of the pin if a change is
    /// detected or None if a timeout occurs.  Note that the value provided
    /// is the value of the pin as soon as we get to hanlding the interrupt
    /// in userspace.  Each time this fuction returns with a value, a change
    /// has occurred, but you could end up reading the same value multiple
    /// times as the value has changed back between when the interrupt
    /// ocurred and the current time.
    pub fn poll(&mut self, timeout_ms: usize) -> io::Result<Option<u8>> {
        try!(flush_input_from_file(&mut self.devfile, 255));
        let dummy_event = EpollEvent { events: EPOLLPRI | EPOLLET, data: 0u64};
        let mut events: [EpollEvent; 1] = [ dummy_event ];
        let cnt = try!(epoll_wait(self.epoll_fd, &mut events, timeout_ms).map_err(from_nix_error));
        Ok(match cnt {
            0 => None, // timeout
            _ => Some(try!(get_value_from_file(&mut self.devfile))),
        })
    }
}

impl Drop for PinPoller {
    fn drop(&mut self) {
        // we implement drop to close the underlying epoll fd as
        // it does not implement drop itself.  This is similar to
        // how mio works
        close(self.epoll_fd).unwrap();  // panic! if close files
    }
}
<commit_msg>fix nix usage: no nix::fcntl::Fd, timeout_ms type in poll is isize<commit_after>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option.  This file may not be copied, modified, or distributed
// except according to those terms.
//
// Portions of this implementation are based on work by Nat Pryce:
// https://github.com/npryce/rusty-pi/blob/master/src/pi/gpio.rs

#![crate_type = "lib"]
#![crate_name = "sysfs_gpio"]

///! GPIO access under Linux using the GPIO sysfs interface
///!
///! The methods exposed by this library are centered around
///! the `Pin` struct and map pretty directly the API exposed
///! by the kernel in syfs (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt).
///!
///! # Examples
///!
///! Typical usage for systems where one wants to ensure that
///! the pins in use are unexported upon completion looks like
///! the follwoing:
///!
///! ```rust,ignore
///! extern crate sysfs_gpio;
///! use sysfs_gpio::Pin;
///!
///!
///! ```

extern crate nix;

use nix::sys::epoll::*;
use nix::unistd::close;

use std::io::prelude::*;
use std::os::unix::prelude::*;
use std::io;
use std::io::{Error, ErrorKind, SeekFrom};
use std::fs;
use std::fs::{File};

pub struct Pin {
    pin_num : u64,
}

#[derive(Clone,Debug)]
pub enum Direction {In, Out, High, Low}

#[derive(Clone,Debug)]
pub enum Edge {NoInterrupt, RisingEdge, FallingEdge, BothEdges}

#[macro_export]
macro_rules! try_unexport {
    ($gpio:ident, $e:expr) => (match $e {
        Ok(res) => res,
        Err(e) => { try!($gpio.unexport()); return Err(e) },
    });
}

fn from_nix_error(err: ::nix::Error) -> io::Error {
    io::Error::from_raw_os_error(err.errno() as i32)
}

/// Flush up to max bytes from the provided files input buffer
///
/// Typically, one would just use seek() for this sort of thing,
/// but for certain files (e.g. in sysfs), you need to actually
/// read it.
fn flush_input_from_file(dev_file: &mut File, max : usize) -> io::Result<usize> {
    let mut s = String::with_capacity(max);
    dev_file.read_to_string(&mut s)
}

/// Get the pin value from the provided file
fn get_value_from_file(dev_file: &mut File) -> io::Result<u8> {
    let mut s = String::with_capacity(10);
    try!(dev_file.seek(SeekFrom::Start(0)));
    try!(dev_file.read_to_string(&mut s));
    match s[..1].parse::<u8>() {
        Ok(n) => Ok(n),
        Err(_) => Err(Error::new(ErrorKind::Other, "Unexpected Error")),
    }
}

impl Pin {
    /// Write all of the provided contents to the specified devFile
    fn write_to_device_file(&self, dev_file_name: &str, value: &str) -> io::Result<()> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::create(&gpio_path));
        try!(dev_file.write_all(value.as_bytes()));
        Ok(())
    }

    /// Create a new Pin with the provided `pin_num`
    ///
    /// This function does not export the provided pin_num.
    pub fn new(pin_num : u64) -> Pin {
        Pin {
            pin_num: pin_num,
        }
    }

    /// Run a closure with the GPIO exported
    ///
    /// Prior to the provided closure being executed, the Gpio
    /// will be eported.  After the closure execution is complete,
    /// the Gpio will be unexported.
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// gpio = Pin::new(24);
    /// let res = gpio::with_exported(|| {
    ///     println!("At this point, the Pin is exported");
    ///     try!(gpio.set_direction(Direction::Low));
    ///     try!(gpio.set_value(1));
    ///     // ...
    /// };
    /// ```
    #[inline]
    pub fn with_exported<F: FnOnce() -> io::Result<()>>(&self, closure : F) -> io::Result<()> {
        try!(self.export());
        match closure() {
            Ok(()) => { try!(self.unexport()); Ok(()) },
            Err(err) => { try!(self.unexport()); Err(err) },
        }
    }

    /// Export the GPIO
    ///
    /// This is equivalent to `echo N > /sys/class/gpio/export` with
    /// the exception that the case where the GPIO is already exported
    /// is not an error.
    ///
    /// # Errors
    ///
    /// The main cases in which this function will fail and return an
    /// error are the following:
    /// 1. The system does not support the GPIO sysfs interface
    /// 2. The requested GPIO is out of range and cannot be exported
    /// 3. The requested GPIO is in use by the kernel and cannot
    ///    be exported by use in userspace
    ///
    /// # Example
    /// ```rust,ignore
    /// use sysfs_gpio::Pin;
    ///
    /// gpio = Pin::new(24);
    /// match gpio.export() {
    ///     Ok(()) => println!("Gpio {} exported!", gpio.pin),
    ///     Err(err) => println!("Gpio {} could not be exported: {}", gpio.pin, err),
    /// }
    /// ```
    pub fn export(&self) -> io::Result<()> {
        match fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            Ok(_) => {},
            Err(_) => {
                let mut export_file = try!(File::create("/sys/class/gpio/export"));
                try!(export_file.write_all(format!("{}", self.pin_num).as_bytes()));
            }
        };
        Ok(())
    }

    /// Unexport the GPIO
    ///
    /// This function will unexport the provided by from syfs if
    /// it is currently exported.  If the pin is not currently
    /// exported, it will return without error.  That is, whenever
    /// this function returns Ok, the GPIO is not exported.
    pub fn unexport(&self) -> io::Result<()> {
        match fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            Ok(_) => {
                let mut unexport_file = try!(File::create("/sys/class/gpio/unexport"));
                try!(unexport_file.write_all(format!("{}", self.pin_num).as_bytes()));
            },
            Err(_) => {} // not exported
        };
        Ok(())
    }

    /// Set this GPIO as either an input or an output
    ///
    /// The basic values allowed here are `Direction::In` and
    /// `Direction::Out` which set the Pin as either an input
    /// or output respectively.  In addition to those, two
    /// additional settings of `Direction::High` and
    /// `Direction::Low`.  These both set the Pin as an output
    /// but do so with an initial value of high or low respectively.
    /// This allows for glitch-free operation.
    ///
    /// Note that this entry may not exist if the kernel does
    /// not support changing the direction of a pin in userspace.  If
    /// this is the case, you will get an error.
    pub fn set_direction(&self, dir : Direction) -> io::Result<()> {
        self.write_to_device_file("direction", match dir {
            Direction::In => "in",
            Direction::Out => "out",
            Direction::High => "high",
            Direction::Low => "low",
        })
    }

    /// Get the value of the Pin (0 or 1)
    ///
    /// If successful, 1 will be returned if the pin is high
    /// and 0 will be returned if the pin is low (this may or may
    /// not match the signal level of the actual signal depending
    /// on the GPIO "active_low" entry).
    pub fn get_value(&self) -> io::Result<u8> {
        let mut dev_file = try!(File::open(&format!("/sys/class/gpio/gpio{}/value", self.pin_num)));
        get_value_from_file(&mut dev_file)
    }

    /// Set the value of the Pin
    ///
    /// This will set the value of the pin either high or low.
    /// A 0 value will set the pin low and any other value will
    /// set the pin high (1 is typical).
    pub fn set_value(&self, value : u8) -> io::Result<()> {
        let val = if value == 0 {
            "0"
        } else {
            "1"
        };
        self.write_to_device_file("value", val)
    }

    /// Set the edge on which this GPIO will trigger when polled
    ///
    /// The configured edge determines what changes to the Pin will
    /// result in `poll()` returning.  This call will return an Error
    /// if the pin does not allow interrupts.
    pub fn set_edge(&self, edge: Edge) -> io::Result<()> {
        self.write_to_device_file("edge", match edge {
            Edge::NoInterrupt => "none",
            Edge::RisingEdge => "rising",
            Edge::FallingEdge => "falling",
            Edge::BothEdges => "both",
        })
    }

    /// Get the currently configured edge for this pin
    ///
    /// This value will only be present if the Pin allows
    /// for interrupts.
    pub fn get_edge(&self) -> io::Result<Edge> {
        let mut dev_file = try!(File::open(&format!("/sys/class/gpio/gpio{}/edge", self.pin_num)));
        let mut s = String::with_capacity(10);
        try!(dev_file.read_to_string(&mut s));
        match s.trim() {
            "none" => Ok(Edge::NoInterrupt),
            "rising" => Ok(Edge::RisingEdge),
            "falling" => Ok(Edge::FallingEdge),
            "both" => Ok(Edge::BothEdges),
            other => Err(Error::new(ErrorKind::Other, format!("Unexpected edge file contents {}", other))),
        }
    }

    /// Get a PinPoller object for this pin
    ///
    /// This pin poller object will register an interrupt with the
    /// kernel and allow you to poll() on it and receive notifications
    /// that an interrupt has occured with minimal delay.
    pub fn get_poller(&self) -> io::Result<PinPoller> {
        PinPoller::new(self.pin_num)
    }
}

pub struct PinPoller {
    pin_num : u64,
    epoll_fd : RawFd,
    devfile : File,
}

impl PinPoller {

    /// Get the pin associated with this PinPoller
    ///
    /// Note that this will be a new Pin object with the
    /// proper pin number.
    pub fn get_pin(&self) -> Pin {
        return Pin::new(self.pin_num);
    }

    /// Create a new PinPoller for the provided pin number
    pub fn new(pin_num : u64) -> io::Result<PinPoller> {
        let devfile : File = try!(File::open(&format!("/sys/class/gpio/gpio{}/value", pin_num)));
        let devfile_fd = devfile.as_raw_fd();
        let epoll_fd = try!(epoll_create().map_err(from_nix_error));
        let events = EPOLLPRI | EPOLLET;
        let info = EpollEvent {
            events: events,
            data: 0u64,
        };

        match epoll_ctl(epoll_fd, EpollOp::EpollCtlAdd, devfile_fd, &info) {
            Ok(_) => {
                let pp = PinPoller {
                    pin_num: pin_num,
                    devfile: devfile,
                    epoll_fd: epoll_fd,
                };
                Ok(pp)
            },
            Err(err) => {
                let _ = close(epoll_fd); // cleanup
                Err(from_nix_error(err))
            }
        }
    }

    /// Block until an interrupt occurs
    ///
    /// This call will block until an interrupt occurs.  The types
    /// of interrupts which may result in this call returning
    /// may be configured by calling `set_edge()` prior to
    /// makeing this call.  This call makes use of epoll under the
    /// covers.  If it is desirable to poll on multiple GPIOs or
    /// other event source, you will need to implement that logic
    /// yourself.
    ///
    /// This function will return Some(value) of the pin if a change is
    /// detected or None if a timeout occurs.  Note that the value provided
    /// is the value of the pin as soon as we get to hanlding the interrupt
    /// in userspace.  Each time this fuction returns with a value, a change
    /// has occurred, but you could end up reading the same value multiple
    /// times as the value has changed back between when the interrupt
    /// ocurred and the current time.
    pub fn poll(&mut self, timeout_ms: isize) -> io::Result<Option<u8>> {
        try!(flush_input_from_file(&mut self.devfile, 255));
        let dummy_event = EpollEvent { events: EPOLLPRI | EPOLLET, data: 0u64};
        let mut events: [EpollEvent; 1] = [ dummy_event ];
        let cnt = try!(epoll_wait(self.epoll_fd, &mut events, timeout_ms).map_err(from_nix_error));
        Ok(match cnt {
            0 => None, // timeout
            _ => Some(try!(get_value_from_file(&mut self.devfile))),
        })
    }
}

impl Drop for PinPoller {
    fn drop(&mut self) {
        // we implement drop to close the underlying epoll fd as
        // it does not implement drop itself.  This is similar to
        // how mio works
        close(self.epoll_fd).unwrap();  // panic! if close files
    }
}
<|endoftext|>


<commit_before>//! indicatif is a library for Rust that helps you build command line
//! interfaces that report progress to users.  It comes with various
//! tools and utilities for formatting anything that indicates progress.
//!
//! Platform support:
//!
//! * Linux
//! * OS X
//! * Windows (colors require Windows 10)
//!
//! Best paired with other libraries in the family:
//!
//! * [console](https://crates.io/crates/console)
//!
//! # Crate Contents
//!
//! * **Progress bars**
//!   * [`ProgressBar`](struct.ProgressBar.html) for bars and spinners
//!   * [`MultiProgress`](struct.MultiProgress.html) for multiple bars
//! * **Data Formatting**
//!   * [`HumanBytes`](struct.HumanBytes.html) for formatting bytes
//!   * [`HumanDuration`](struct.HumanDuration.html) for formatting durations
//!
//! # Progress Bars and Spinners
//!
//! indicatif comes with a `ProgressBar` type that support both bounded
//! progress bar uses as well as unbounded "spinner" type progress reports.
//! Progress bars are `Sync` and `Send` objects which means that they are
//! internally locked and can be passed from thread to thread.
//!
//! Additionally a `MultiProgress` utility is provided that can manage
//! rendering multiple progress bars at once (eg: for instance from
//! multiple threads).
//!
//! To wet your appetite, this is what this can look like:
//!
//!
//!
//! Progress bars are manually advanced and by default draw to stdout.
//! When you are done the progress bar can be finished either visibly
//! (eg: the progress bar stays on the screen) or cleared (the progress
//! bar will be removed).
//!
//! ```rust
//! use indicatif::ProgressBar;
//!
//! let bar = ProgressBar::new(1000);
//! for _ in 0..1000 {
//!     bar.inc(1);
//!     // ...
//! }
//! bar.finish();
//! ```
//!
//! General progress bar behaviors:
//!
//! * if a non terminal is detected the progress bar will be completely
//!   hidden.  This makes piping programs to logfiles make sense out of
//!   the box.
//! * progress bars should be explicitly finished to reset the rendering
//!   for others.  Either by also clearing them or by replacing them with
//!   a new message / retaining the current message.
//! * the default template renders neither message nor prefix.
//!
//! # Templates
//!
//! Progress bars can be styled with simple format strings similar to the
//! ones in Rust itself.  The format for a placeholder is `{key:options}`
//! where the `options` part is optional.  If provided the format is this:
//!
//! ```text
//! [<^>]           for an optional alignment specification
//! WIDTH           an optional width as positive integer
//! !               an optional exclamation mark to enable truncation
//! .STYLE          an optional dot separated style string
//! /STYLE          an optional dot separated alternative style string
//! ```
//!
//! For the style component see `Styled::from_dotted_str` for more
//! information.
//!
//! Some examples for templates:
//!
//! ```text
//! [{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}
//! ```
//!
//! This sets a progress bar that is 40 characters wide and has cyan
//! as primary style color and blue as alternative style color.
//! Alternative styles are currently only used for progress bars.
//!
//! Example configuration:
//!
//! ```ignore
//! bar.set_style(ProgressStyle::default_bar()
//!     .template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
//!     .progress_chars("##-"));
//! ```
//!
//! The following keys exist:
//!
//! * `bar`: renders a progress bar. By default 20 characters wide.  The
//!   style string is used to color the elapsed part, the alternative
//!   style is used for the bar that is yet to render.
//! * `wide_bar`: like `bar` but always fills the remaining space.
//! * `spinner`: renders the spinner (current tick char)
//! * `prefix`: renders the prefix set on the progress bar.
//! * `msg`: renders the currently set message on the progress bar.
//! * `pos`: renders the current position of the bar as integer
//! * `len`: renders the total length of the bar as integer
//! * `bytes`: renders the current position of the bar as bytes.
//! * `total_bytes`: renders the total length of the bar as bytes.
//! * `elapsed_precise`: renders the elapsed time as `HH:MM:SS`.
//! * `elapased`: renders the elapsed time as `42s`, `1m` etc.
//! * `eta_precise`: the remaining time (like `elapsed_precise`).
//! * `eta`: the remaining time (like `elapsed`).
//!
//! The design of the progress bar can be altered with the integrated
//! template functionality.  The template can be set by changing a
//! `ProgressStyle` and attaching it to the progress bar.
//!
//! # Human Readable Formatting
//!
//! There are some formatting wrappers for showing elapsed time and
//! file sizes for human users:
//!
//! ```ignore
//! use std::time::Instant;
//! use indicatif::{HumanDuration, HumanBytes};
//!
//! let started = Instant::now();
//! println!("The file is {} large", HumanBytes(file.size));
//! println!("The script took {}", HumanDuration(started.elapsed()));
//! ```
extern crate parking_lot;
extern crate regex;
#[macro_use] extern crate lazy_static;
extern crate console;

mod progress;
mod utils;
mod format;

pub use progress::{ProgressBar, MultiProgress,
                   ProgressDrawTarget, ProgressStyle};
pub use format::{HumanDuration, FormattedDuration, HumanBytes};
<commit_msg>Added dialoguer link<commit_after>//! indicatif is a library for Rust that helps you build command line
//! interfaces that report progress to users.  It comes with various
//! tools and utilities for formatting anything that indicates progress.
//!
//! Platform support:
//!
//! * Linux
//! * OS X
//! * Windows (colors require Windows 10)
//!
//! Best paired with other libraries in the family:
//!
//! * [console](https://crates.io/crates/console)
//! * [dialoguer](https://crates.io/crates/dialoguer)
//!
//! # Crate Contents
//!
//! * **Progress bars**
//!   * [`ProgressBar`](struct.ProgressBar.html) for bars and spinners
//!   * [`MultiProgress`](struct.MultiProgress.html) for multiple bars
//! * **Data Formatting**
//!   * [`HumanBytes`](struct.HumanBytes.html) for formatting bytes
//!   * [`HumanDuration`](struct.HumanDuration.html) for formatting durations
//!
//! # Progress Bars and Spinners
//!
//! indicatif comes with a `ProgressBar` type that support both bounded
//! progress bar uses as well as unbounded "spinner" type progress reports.
//! Progress bars are `Sync` and `Send` objects which means that they are
//! internally locked and can be passed from thread to thread.
//!
//! Additionally a `MultiProgress` utility is provided that can manage
//! rendering multiple progress bars at once (eg: for instance from
//! multiple threads).
//!
//! To wet your appetite, this is what this can look like:
//!
//!
//!
//! Progress bars are manually advanced and by default draw to stdout.
//! When you are done the progress bar can be finished either visibly
//! (eg: the progress bar stays on the screen) or cleared (the progress
//! bar will be removed).
//!
//! ```rust
//! use indicatif::ProgressBar;
//!
//! let bar = ProgressBar::new(1000);
//! for _ in 0..1000 {
//!     bar.inc(1);
//!     // ...
//! }
//! bar.finish();
//! ```
//!
//! General progress bar behaviors:
//!
//! * if a non terminal is detected the progress bar will be completely
//!   hidden.  This makes piping programs to logfiles make sense out of
//!   the box.
//! * progress bars should be explicitly finished to reset the rendering
//!   for others.  Either by also clearing them or by replacing them with
//!   a new message / retaining the current message.
//! * the default template renders neither message nor prefix.
//!
//! # Templates
//!
//! Progress bars can be styled with simple format strings similar to the
//! ones in Rust itself.  The format for a placeholder is `{key:options}`
//! where the `options` part is optional.  If provided the format is this:
//!
//! ```text
//! [<^>]           for an optional alignment specification
//! WIDTH           an optional width as positive integer
//! !               an optional exclamation mark to enable truncation
//! .STYLE          an optional dot separated style string
//! /STYLE          an optional dot separated alternative style string
//! ```
//!
//! For the style component see `Styled::from_dotted_str` for more
//! information.
//!
//! Some examples for templates:
//!
//! ```text
//! [{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}
//! ```
//!
//! This sets a progress bar that is 40 characters wide and has cyan
//! as primary style color and blue as alternative style color.
//! Alternative styles are currently only used for progress bars.
//!
//! Example configuration:
//!
//! ```ignore
//! bar.set_style(ProgressStyle::default_bar()
//!     .template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
//!     .progress_chars("##-"));
//! ```
//!
//! The following keys exist:
//!
//! * `bar`: renders a progress bar. By default 20 characters wide.  The
//!   style string is used to color the elapsed part, the alternative
//!   style is used for the bar that is yet to render.
//! * `wide_bar`: like `bar` but always fills the remaining space.
//! * `spinner`: renders the spinner (current tick char)
//! * `prefix`: renders the prefix set on the progress bar.
//! * `msg`: renders the currently set message on the progress bar.
//! * `pos`: renders the current position of the bar as integer
//! * `len`: renders the total length of the bar as integer
//! * `bytes`: renders the current position of the bar as bytes.
//! * `total_bytes`: renders the total length of the bar as bytes.
//! * `elapsed_precise`: renders the elapsed time as `HH:MM:SS`.
//! * `elapased`: renders the elapsed time as `42s`, `1m` etc.
//! * `eta_precise`: the remaining time (like `elapsed_precise`).
//! * `eta`: the remaining time (like `elapsed`).
//!
//! The design of the progress bar can be altered with the integrated
//! template functionality.  The template can be set by changing a
//! `ProgressStyle` and attaching it to the progress bar.
//!
//! # Human Readable Formatting
//!
//! There are some formatting wrappers for showing elapsed time and
//! file sizes for human users:
//!
//! ```ignore
//! use std::time::Instant;
//! use indicatif::{HumanDuration, HumanBytes};
//!
//! let started = Instant::now();
//! println!("The file is {} large", HumanBytes(file.size));
//! println!("The script took {}", HumanDuration(started.elapsed()));
//! ```
extern crate parking_lot;
extern crate regex;
#[macro_use] extern crate lazy_static;
extern crate console;

mod progress;
mod utils;
mod format;

pub use progress::{ProgressBar, MultiProgress,
                   ProgressDrawTarget, ProgressStyle};
pub use format::{HumanDuration, FormattedDuration, HumanBytes};
<|endoftext|>


<commit_before>extern crate xml;

use std::fs::File;
use std::io::BufReader;
use std::str::FromStr;

use xml::reader::{EventReader, XmlEvent};
use xml::name::OwnedName;
use xml::attribute::OwnedAttribute;

#[allow(dead_code)]
pub struct Bounds {
    minlat: f64,
    minlon: f64,
    maxlat: f64,
    maxlon: f64,
}

#[allow(dead_code)]
pub struct OSM {
    bounds: Bounds
}

impl OSM {
    fn empty() -> OSM {
        OSM {
            bounds: Bounds { minlat: 0.0, minlon: 0.0, maxlat: 0.0, maxlon: 0.0 }
        }
    }

    pub fn parse(file: File) -> Option<OSM> {
        let mut osm = OSM::empty();

        let reader = BufReader::new(file);
        let parser = EventReader::new(reader);

        for element in parser {
            match element {
                Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                    handle_element(&mut osm, name, attributes);
                },
                _ => { }
            }
        }

        Some(osm)
    }
}

fn handle_element(osm: &mut OSM, name: OwnedName, attrs: Vec<OwnedAttribute>) {
    let downcased = name.local_name.to_lowercase();

    if downcased == "bounds" {
        let bounds = parse_bounds(&attrs);
        osm.bounds = bounds;
    }
}

fn parse_bounds(attrs: &Vec<OwnedAttribute>) -> Bounds {
    let minlat = find_attribute::<f64>("minlat", attrs).unwrap();
    let minlon = find_attribute::<f64>("minlon", attrs).unwrap();
    let maxlat = find_attribute::<f64>("maxlat", attrs).unwrap();
    let maxlon = find_attribute::<f64>("maxlon", attrs).unwrap();

    Bounds {
        minlat: minlat,
        minlon: minlon,
        maxlat: maxlat,
        maxlon: maxlon,
    }
}

fn find_attribute<T: FromStr>(name: &str, attrs: &Vec<OwnedAttribute>) -> Option<T> {
    let attr = attrs.iter().find(|attr| attr.name.local_name == name);
    match attr {
        Some(a) => {
            let val = a.value.parse::<T>();
            match val {
                Ok(v) => Some(v),
                _ => None
            }
        },
        None => None
    }
}

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

    #[test]
    fn bounds_parsing() {
        let f = File::open("./test_data/bounds.osm").unwrap();
        let osm = OSM::parse(f).unwrap();
        assert_eq!(osm.bounds.minlat, 54.0889580);
        assert_eq!(osm.bounds.minlon, 12.2487570);
        assert_eq!(osm.bounds.maxlat, 54.0913900);
        assert_eq!(osm.bounds.maxlon, 12.2524800);
    }
}
<commit_msg>Remove unwraps<commit_after>extern crate xml;

use std::fs::File;
use std::io::BufReader;
use std::str::FromStr;
use std::num;

use xml::reader::{EventReader, XmlEvent};
use xml::name::OwnedName;
use xml::attribute::OwnedAttribute;

enum ErrorKind {
    BoundsMissing(AttributeError),
}

enum AttributeError {
    ParseFloat(num::ParseFloatError),
    Missing
}

impl From<num::ParseFloatError> for AttributeError {
    fn from(err: num::ParseFloatError) -> AttributeError {
        AttributeError::ParseFloat(err)
    }
}

#[allow(dead_code)]
pub struct Bounds {
    minlat: f64,
    minlon: f64,
    maxlat: f64,
    maxlon: f64,
}

#[allow(dead_code)]
pub struct OSM {
    bounds: Option<Bounds>
}

impl OSM {
    fn empty() -> OSM {
        OSM {
            bounds: None
        }
    }

    pub fn parse(file: File) -> Option<OSM> {
        let mut osm = OSM::empty();

        let reader = BufReader::new(file);
        let parser = EventReader::new(reader);

        for element in parser {
            match element {
                Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                    handle_element(&mut osm, name, attributes);
                },
                _ => { }
            }
        }

        Some(osm)
    }
}

fn handle_element(osm: &mut OSM, name: OwnedName, attrs: Vec<OwnedAttribute>) {
    let downcased = name.local_name.to_lowercase();

    if downcased == "bounds" {
        match parse_bounds(&attrs) {
            Ok(bounds) => osm.bounds = Some(bounds),
            Err(_) => osm.bounds = None
        }
    }
}

fn parse_bounds(attrs: &Vec<OwnedAttribute>) -> Result<Bounds, ErrorKind> {
    let minlat = try!(find_attribute::<f64>("minlat", attrs).map_err(ErrorKind::BoundsMissing));
    let minlon = try!(find_attribute::<f64>("minlon", attrs).map_err(ErrorKind::BoundsMissing));
    let maxlat = try!(find_attribute::<f64>("maxlat", attrs).map_err(ErrorKind::BoundsMissing));
    let maxlon = try!(find_attribute::<f64>("maxlon", attrs).map_err(ErrorKind::BoundsMissing));

    Ok(Bounds {
        minlat: minlat,
        minlon: minlon,
        maxlat: maxlat,
        maxlon: maxlon,
    })
}

fn find_attribute<T: FromStr>( name: &str, attrs: &Vec<OwnedAttribute>) -> Result<T, AttributeError>
    where AttributeError: std::convert::From<<T as std::str::FromStr>::Err>
{
    let attr = attrs.iter().find(|attr| attr.name.local_name == name);
    match attr {
        Some(a) => {
            let val = try!(a.value.parse::<T>());
            Ok(val)
        },
        None => Err(AttributeError::Missing)
    }
}

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

    #[test]
    fn bounds_parsing() {
        let f = File::open("./test_data/bounds.osm").unwrap();
        let osm = OSM::parse(f).unwrap();
        let bounds = osm.bounds.unwrap();
        assert_eq!(bounds.minlat, 54.0889580);
        assert_eq!(bounds.minlon, 12.2487570);
        assert_eq!(bounds.maxlat, 54.0913900);
        assert_eq!(bounds.maxlon, 12.2524800);
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::net::{SocketAddrV4, SocketAddrV6};
use libc::*;

pub enum WirelessMode {
    Auto, /* Let the driver decide */
    AdHoc, /* Single cell network */
    Infra, /* Multi cell network, roaming, ... */
    Master, /* Synchronisation master or Access Point */
    Repeat, /* Wireless Repeater (forwarder) */
    Second, /* Secondary master/repeater (backup) */
    Monitor, /* Passive monitor (listen only) */
}

pub struct IwQuality {
    quality: u8,
    level: u8,
    noise: u8,
}

pub struct IwStats {
    status: uint16_t,
    quality: IwQuality,
}

pub struct WirelessKey<'a> {
    key: &'a [u8],
    size: u32,
    flags: i32,
}

pub struct WirelessNetwork<'a> {
    ap_addr4: Option<SocketAddrV4>,
    ap_addr6: Option<SocketAddrV6>,
    stats: Option<IwStats>,
    maxbitrate: Option<i32>,
    name: String,
    freq: Option<f64>,
    key: Option<WirelessKey<'a>>,
    essid: Option<String>,
    mode: Option<WirelessMode>,
}

struct priv_iw_quality {
    qual: uint8_t,
    level: uint8_t,
    noise: uint8_t,
    updated: uint8_t,
}

struct priv_iw_freq {
    m: int32_t,
    e: int16_t,
    i: uint8_t,
    flags: uint8_t,
}

#[repr(C)]
struct iw_range {
    /* Informative stuff (to choose between different interface) */
    throughput: uint32_t, /* To give an idea... */
    /* In theory this value should be the maximum benchmarked
     * TCP/IP throughput, because with most of these devices the
     * bit rate is meaningless (overhead an co) to estimate how
     * fast the connection will go and pick the fastest one.
     * I suggest people to play with Netperf or any benchmark...
     */

    /* NWID (or domain id) */
    min_nwid: uint32_t, /* Minimal NWID we are able to set */
    max_nwid: uint32_t, /* Maximal NWID we are able to set */

    /* Old Frequency (backward compat - moved lower ) */
    old_num_channels: uint16_t,
    old_num_frequency: uint8_t,

    /* Wireless event capability bitmasks */
    event_capa: [uint32_t; 6],

    /* signal level threshold range */
    sensitivity: int32_t,

    /* Quality of link & SNR stuff */
    /* Quality range (link, level, noise)
     * If the quality is absolute, it will be in the range [0 , max_qual],
     * if the quality is dBm, it will be in the range [max_qual , 0].
     * Don't forget that we use 8 bit arithmetics... */
    max_qual: priv_iw_quality, /* Quality of the link */
    /* This should contain the average/typical values of the quality
     * indicator. This should be the threshold between a "good" and
     * a "bad" link (example : monitor going from green to orange).
     * Currently, user space apps like quality monitors don't have any
     * way to calibrate the measurement. With this, they can split
     * the range between 0 and max_qual in different quality level
     * (using a geometric subdivision centered on the average).
     * I expect that people doing the user space apps will feedback
     * us on which value we need to put in each driver... */
    avg_qual: priv_iw_quality, /* Quality of the link */

    /* Rates */
    num_bitrates: uint8_t, /* Number of entries in the list */
    bitrate: [int32_t; IW_MAX_BITRATES], /* list, in bps */

    /* RTS threshold */
    min_rts: int32_t, /* Minimal RTS threshold */
    max_rts: int32_t, /* Maximal RTS threshold */

    /* Frag threshold */
    min_frag: int32_t, /* Minimal frag threshold */
    max_frag: int32_t, /* Maximal frag threshold */

    /* Power Management duration & timeout */
    min_pmp: int32_t, /* Minimal PM period */
    max_pmp: int32_t, /* Maximal PM period */
    min_pmt: int32_t, /* Minimal PM timeout */
    max_pmt: int32_t, /* Maximal PM timeout */
    pmp_flags: uint16_t, /* How to decode max/min PM period */
    pmt_flags: uint16_t, /* How to decode max/min PM timeout */
    pm_capa: uint16_t, /* What PM options are supported */

    /* Encoder stuff */
    encoding_size: [uint16_t; IW_MAX_ENCODING_SIZES], /* Different token sizes */
    num_encoding_sizes: uint8_t, /* Number of entry in the list */
    max_encoding_tokens: uint8_t, /* Max number of tokens */
    /* For drivers that need a "login/passwd" form */
    encoding_login_index: uint8_t, /* token index for login token */

    /* Transmit power */
    txpower_capa: uint16_t, /* What options are supported */
    num_txpower: uint8_t, /* Number of entries in the list */
    txpower: [int32_t; IW_MAX_TXPOWER], /* list, in bps */

    /* Wireless Extension version info */
    we_version_compiled: uint8_t, /* Must be WIRELESS_EXT */
    we_version_source: uint8_t, /* Last update of source */

    /* Retry limits and lifetime */
    retry_capa: uint16_t, /* What retry options are supported */
    retry_flags: uint16_t, /* How to decode max/min retry limit */
    r_time_flags: uint16_t, /* How to decode max/min retry life */
    min_retry: int32_t, /* Minimal number of retries */
    max_retry: int32_t, /* Maximal number of retries */
    min_r_time: int32_t, /* Minimal retry lifetime */
    max_r_time: int32_t, /* Maximal retry lifetime */

    /* Frequency */
    num_channels: uint16_t, /* Number of channels [0, num - 1] */
    num_frequency: uint8_t, /* Number of entry in the list */
    freq: [priv_iw_freq; IW_MAX_FREQUENCIES], /* list */
    /* Note : this frequency list doesn't need to fit channel numbers,
     * because each entry contain its channel index */
    enc_capa: uint32_t, /* IW_ENC_CAPA_* bit field */

    /* More power management stuff */
    min_pms: int32_t, /* Minimal PM saving */
    max_pms: int32_t, /* Maximal PM saving */
    pms_flags: int16_t, /* How to decode max/min PM saving */

    /* All available modulations for driver (hw may support less) */
    modul_capa: uint32_t, /* IW_MODUL_* bit field */

    /* More bitrate stuff */
    bitrate_capa: uint32_t, /* Types of bitrates supported */
}

pub struct WifiScan<'a> {
    networks: Vec<WirelessNetwork<'a>>,
}

impl<'a> WifiScan<'a> {
    pub fn new() -> WifiScan {
        WifiScan { networks: Vec::new() }
    }

    pub fn scan() {
        // Scan things here
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>Add lifetimes and consts<commit_after>extern crate libc;

use std::net::{SocketAddrV4, SocketAddrV6};
use libc::*;

const IW_AUTH_WPA_VERSION_DISABLED: u8 = 0x00000001;
const IW_AUTH_WPA_VERSION_WPA: u8 = 0x00000002;
const IW_AUTH_WPA_VERSION_WPA2: u8 = 0x00000004;
const IW_MAX_BITRATES: usize = 32;
const IW_MAX_ENCODING_SIZES: usize = 8;
const IW_MAX_FREQUENCIES: usize = 32;
const IW_MAX_TXPOWER: usize = 8;

pub enum WirelessMode {
    Auto, /* Let the driver decide */
    AdHoc, /* Single cell network */
    Infra, /* Multi cell network, roaming, ... */
    Master, /* Synchronisation master or Access Point */
    Repeat, /* Wireless Repeater (forwarder) */
    Second, /* Secondary master/repeater (backup) */
    Monitor, /* Passive monitor (listen only) */
}

pub struct IwQuality {
    quality: u8,
    level: u8,
    noise: u8,
}

pub struct IwStats {
    status: uint16_t,
    quality: IwQuality,
}

pub struct WirelessKey<'a> {
    key: &'a [u8],
    size: u32,
    flags: i32,
}

pub struct WirelessNetwork<'a> {
    ap_addr4: Option<SocketAddrV4>,
    ap_addr6: Option<SocketAddrV6>,
    stats: Option<IwStats>,
    maxbitrate: Option<i32>,
    name: String,
    freq: Option<f64>,
    key: Option<WirelessKey<'a>>,
    essid: Option<String>,
    mode: Option<WirelessMode>,
}

struct priv_iw_quality {
    qual: uint8_t,
    level: uint8_t,
    noise: uint8_t,
    updated: uint8_t,
}

struct priv_iw_freq {
    m: int32_t,
    e: int16_t,
    i: uint8_t,
    flags: uint8_t,
}

#[repr(C)]
struct iw_range {
    /* Informative stuff (to choose between different interface) */
    throughput: uint32_t, /* To give an idea... */
    /* In theory this value should be the maximum benchmarked
     * TCP/IP throughput, because with most of these devices the
     * bit rate is meaningless (overhead an co) to estimate how
     * fast the connection will go and pick the fastest one.
     * I suggest people to play with Netperf or any benchmark...
     */

    /* NWID (or domain id) */
    min_nwid: uint32_t, /* Minimal NWID we are able to set */
    max_nwid: uint32_t, /* Maximal NWID we are able to set */

    /* Old Frequency (backward compat - moved lower ) */
    old_num_channels: uint16_t,
    old_num_frequency: uint8_t,

    /* Wireless event capability bitmasks */
    event_capa: [uint32_t; 6],

    /* signal level threshold range */
    sensitivity: int32_t,

    /* Quality of link & SNR stuff */
    /* Quality range (link, level, noise)
     * If the quality is absolute, it will be in the range [0 , max_qual],
     * if the quality is dBm, it will be in the range [max_qual , 0].
     * Don't forget that we use 8 bit arithmetics... */
    max_qual: priv_iw_quality, /* Quality of the link */
    /* This should contain the average/typical values of the quality
     * indicator. This should be the threshold between a "good" and
     * a "bad" link (example : monitor going from green to orange).
     * Currently, user space apps like quality monitors don't have any
     * way to calibrate the measurement. With this, they can split
     * the range between 0 and max_qual in different quality level
     * (using a geometric subdivision centered on the average).
     * I expect that people doing the user space apps will feedback
     * us on which value we need to put in each driver... */
    avg_qual: priv_iw_quality, /* Quality of the link */

    /* Rates */
    num_bitrates: uint8_t, /* Number of entries in the list */
    bitrate: [int32_t; IW_MAX_BITRATES], /* list, in bps */

    /* RTS threshold */
    min_rts: int32_t, /* Minimal RTS threshold */
    max_rts: int32_t, /* Maximal RTS threshold */

    /* Frag threshold */
    min_frag: int32_t, /* Minimal frag threshold */
    max_frag: int32_t, /* Maximal frag threshold */

    /* Power Management duration & timeout */
    min_pmp: int32_t, /* Minimal PM period */
    max_pmp: int32_t, /* Maximal PM period */
    min_pmt: int32_t, /* Minimal PM timeout */
    max_pmt: int32_t, /* Maximal PM timeout */
    pmp_flags: uint16_t, /* How to decode max/min PM period */
    pmt_flags: uint16_t, /* How to decode max/min PM timeout */
    pm_capa: uint16_t, /* What PM options are supported */

    /* Encoder stuff */
    encoding_size: [uint16_t; IW_MAX_ENCODING_SIZES], /* Different token sizes */
    num_encoding_sizes: uint8_t, /* Number of entry in the list */
    max_encoding_tokens: uint8_t, /* Max number of tokens */
    /* For drivers that need a "login/passwd" form */
    encoding_login_index: uint8_t, /* token index for login token */

    /* Transmit power */
    txpower_capa: uint16_t, /* What options are supported */
    num_txpower: uint8_t, /* Number of entries in the list */
    txpower: [int32_t; IW_MAX_TXPOWER], /* list, in bps */

    /* Wireless Extension version info */
    we_version_compiled: uint8_t, /* Must be WIRELESS_EXT */
    we_version_source: uint8_t, /* Last update of source */

    /* Retry limits and lifetime */
    retry_capa: uint16_t, /* What retry options are supported */
    retry_flags: uint16_t, /* How to decode max/min retry limit */
    r_time_flags: uint16_t, /* How to decode max/min retry life */
    min_retry: int32_t, /* Minimal number of retries */
    max_retry: int32_t, /* Maximal number of retries */
    min_r_time: int32_t, /* Minimal retry lifetime */
    max_r_time: int32_t, /* Maximal retry lifetime */

    /* Frequency */
    num_channels: uint16_t, /* Number of channels [0, num - 1] */
    num_frequency: uint8_t, /* Number of entry in the list */
    freq: [priv_iw_freq; IW_MAX_FREQUENCIES], /* list */
    /* Note : this frequency list doesn't need to fit channel numbers,
     * because each entry contain its channel index */
    enc_capa: uint32_t, /* IW_ENC_CAPA_* bit field */

    /* More power management stuff */
    min_pms: int32_t, /* Minimal PM saving */
    max_pms: int32_t, /* Maximal PM saving */
    pms_flags: int16_t, /* How to decode max/min PM saving */

    /* All available modulations for driver (hw may support less) */
    modul_capa: uint32_t, /* IW_MODUL_* bit field */

    /* More bitrate stuff */
    bitrate_capa: uint32_t, /* Types of bitrates supported */
}

pub struct WifiScan<'a> {
    networks: Vec<WirelessNetwork<'a>>,
}

impl<'a> WifiScan<'a> {
    pub fn new() -> WifiScan<'a> {
        WifiScan { networks: Vec::new() }
    }

    pub fn scan() {
        // Scan things here
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before><commit_msg>Support for the FRC target<commit_after><|endoftext|>