<commit_before>extern crate serde_json;

use application_context::ApplicationContext;
use indy_context::IndyContext;
use command_executor::{Command, CommandMetadata, Group as GroupTrait, GroupMetadata};
use commands::{get_str_param, get_opt_str_param};

use libindy::ErrorCode;
use libindy::pool::Pool;
use utils::table::print_table;

use std::collections::HashMap;
use std::rc::Rc;

pub struct Group {
    metadata: GroupMetadata
}

impl Group {
    pub fn new() -> Group {
        Group {
            metadata: GroupMetadata::new("pool", "Pool management commands")
        }
    }
}

impl GroupTrait for Group {
    fn metadata(&self) -> &GroupMetadata {
        &self.metadata
    }
}

#[derive(Debug)]
pub struct CreateCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct ConnectCommand {
    app_cnxt: Rc<ApplicationContext>,
    indy_cnxt: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct ListCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct DisconnectCommand {
    app_cnxt: Rc<ApplicationContext>,
    indy_cnxt: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct DeleteCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

impl CreateCommand {
    pub fn new(ctx: Rc<IndyContext>) -> CreateCommand {
        CreateCommand {
            ctx,
            metadata: CommandMetadata::build("create", "Create new pool ledger config with specified name")
                .add_main_param("name", "The name of new pool ledger config")
                .add_param("gen_txn_file", true, "Path to file with genesis transactions")
                .finalize()
        }
    }
}

impl Command for CreateCommand {
    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("CreateCommand::execute >> self {:?} params {:?}", self, params);

        let name = get_str_param("name", params).map_err(error_err!())?;
        let gen_txn_file = get_opt_str_param("gen_txn_file", params).map_err(error_err!())?
            .unwrap_or("pool_transactions_genesis");

        let config: String = json!({ "genesis_txn": gen_txn_file }).to_string();

        trace!(r#"Pool::create_pool_ledger_config try: name {}, config {:?}"#, name, config);

        let res = Pool::create_pool_ledger_config(name,
                                                  config.as_str());

        trace!(r#"Pool::create_pool_ledger_config return: {:?}"#, res);

        let res = match res {
            Ok(()) => Ok(println_succ!("Pool config \"{}\" has been created", name)),
            Err(ErrorCode::PoolLedgerConfigAlreadyExistsError) => Err(println_err!("Pool config \"{}\" already exists", name)),
            Err(err) => Err(println_err!("Indy SDK error occurred {:?}", err)),
        };

        trace!("CreateCommand::execute << {:?}", res);
        res
    }

    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }
}

impl ConnectCommand {
    pub fn new(app_cnxt: Rc<ApplicationContext>, indy_cnxt: Rc<IndyContext>) -> ConnectCommand {
        ConnectCommand {
            app_cnxt,
            indy_cnxt,
            metadata: CommandMetadata::build("connect", "Connect to pool with specified name. Also disconnect from previously connected.")
                .add_main_param("name", "The name of pool")
                .finalize()
        }
    }
}

impl Command for ConnectCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("OpenCommand::execute >> self {:?} params {:?}", self, params);

        let name = get_str_param("name", params).map_err(error_err!())?;

        let res = Ok(())
            .and_then(|_| {
                if let Some((name, handle)) = self.indy_cnxt.get_connected_pool() {
                    match Pool::close(handle) {
                        Ok(()) => {
                            self.app_cnxt.unset_sub_prompt(1);
                            self.indy_cnxt.unset_connected_pool();
                            Ok(println_succ!("Pool \"{}\" has been disconnected", name))
                        }
                        Err(err) => Err(println_err!("Indy SDK error occurred {:?}", err))
                    }
                } else {
                    Ok(())
                }
            })
            .and_then(|_| {
                match Pool::open_pool_ledger(name, None) {
                    Ok(handle) => {
                        self.app_cnxt.set_sub_prompt(1, &format!("pool({})", name));
                        self.indy_cnxt.set_connected_pool(name, handle);
                        Ok(println_succ!("Pool \"{}\" has been connected", name))
                    }
                    Err(err) => Err(println_err!("Indy SDK error occurred {:?}", err)),
                }
            });

        trace!("CreateCommand::execute << {:?}", res);
        res
    }
}

impl ListCommand {
    pub fn new(ctx: Rc<IndyContext>) -> ListCommand {
        ListCommand {
            ctx,
            metadata: CommandMetadata::build("list", "List existing pool configs.")
                .finalize()
        }
    }
}

impl Command for ListCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("ListCommand::execute >> self {:?} params {:?}", self, params);

        let res = match Pool::list() {
            Ok(pools) => {
                println!("pools {:?}", pools);
                let pools: Vec<serde_json::Value> = serde_json::from_str(&pools)
                    .map_err(|_| println_err!("Wrong data has been received"))?;

                if pools.len() > 0 {
                    print_table(&pools, &vec![("pool", "Pool")]);
                } else {
                    println_succ!("There are no pool");
                }

                Ok(())
            }
            Err(ErrorCode::CommonIOError) => Err(println_succ!("There are no pool")),
            Err(err) => Err(println_err!("Indy SDK error occurred {:?}", err)),
        };

        trace!("ListCommand::execute << {:?}", res);
        res
    }
}

impl DisconnectCommand {
    pub fn new(app_cnxt: Rc<ApplicationContext>, indy_cnxt: Rc<IndyContext>) -> DisconnectCommand {
        DisconnectCommand {
            app_cnxt,
            indy_cnxt,
            metadata: CommandMetadata::build("disconnect", "Disconnect from current pool.")
                .finalize()
        }
    }
}

impl Command for DisconnectCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("DisconnectCommand::execute >> self {:?} params {:?}", self, params);

        let (name, handle) = if let Some(pool) = self.indy_cnxt.get_connected_pool() {
            pool
        } else {
            return Err(println_err!("There is no connected pool now"));
        };

        let res = match Pool::close(handle) {
            Ok(()) => {
                self.app_cnxt.unset_sub_prompt(1);
                self.indy_cnxt.unset_connected_pool();
                Ok(println_succ!("Pool \"{}\" has been disconnected", name))
            }
            Err(err) => Err(println_err!("Indy SDK error occurred {:?}", err)),
        };

        trace!("DisconnectCommand::execute << {:?}", res);
        res
    }
}

impl DeleteCommand {
    pub fn new(ctx: Rc<IndyContext>) -> DeleteCommand {
        DeleteCommand {
            ctx,
            metadata: CommandMetadata::build("delete", "Delete pool config with specified name")
                .add_main_param("name", "The name of deleted pool config")
                .finalize()
        }
    }
}

impl Command for DeleteCommand {
    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("DeleteCommand::execute >> self {:?} params {:?}", self, params);

        let name = get_str_param("name", params).map_err(error_err!())?;

        trace!(r#"Pool::delete try: name {}"#, name);

        let res = Pool::delete(name);

        trace!(r#"Pool::delete return: {:?}"#, res);

        let res = match res {
            Ok(()) => Ok(println_succ!("Pool \"{}\" has been deleted", name)),
            Err(err) => Err(println_err!("Indy SDK error occurred {:?}", err)),
        };

        trace!("DeleteCommand::execute << {:?}", res);
        res
    }

    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }
}<commit_msg>[cli] Clean-up Pool list command.<commit_after>extern crate serde_json;

use application_context::ApplicationContext;
use indy_context::IndyContext;
use command_executor::{Command, CommandMetadata, Group as GroupTrait, GroupMetadata};
use commands::{get_str_param, get_opt_str_param};

use libindy::ErrorCode;
use libindy::pool::Pool;
use utils::table::print_table;

use std::collections::HashMap;
use std::rc::Rc;

pub struct Group {
    metadata: GroupMetadata
}

impl Group {
    pub fn new() -> Group {
        Group {
            metadata: GroupMetadata::new("pool", "Pool management commands")
        }
    }
}

impl GroupTrait for Group {
    fn metadata(&self) -> &GroupMetadata {
        &self.metadata
    }
}

#[derive(Debug)]
pub struct CreateCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct ConnectCommand {
    app_cnxt: Rc<ApplicationContext>,
    indy_cnxt: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct ListCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct DisconnectCommand {
    app_cnxt: Rc<ApplicationContext>,
    indy_cnxt: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct DeleteCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

impl CreateCommand {
    pub fn new(ctx: Rc<IndyContext>) -> CreateCommand {
        CreateCommand {
            ctx,
            metadata: CommandMetadata::build("create", "Create new pool ledger config with specified name")
                .add_main_param("name", "The name of new pool ledger config")
                .add_param("gen_txn_file", true, "Path to file with genesis transactions")
                .finalize()
        }
    }
}

impl Command for CreateCommand {
    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("CreateCommand::execute >> self {:?} params {:?}", self, params);

        let name = get_str_param("name", params).map_err(error_err!())?;
        let gen_txn_file = get_opt_str_param("gen_txn_file", params).map_err(error_err!())?
            .unwrap_or("pool_transactions_genesis");

        let config: String = json!({ "genesis_txn": gen_txn_file }).to_string();

        trace!(r#"Pool::create_pool_ledger_config try: name {}, config {:?}"#, name, config);

        let res = Pool::create_pool_ledger_config(name,
                                                  config.as_str());

        trace!(r#"Pool::create_pool_ledger_config return: {:?}"#, res);

        let res = match res {
            Ok(()) => Ok(println_succ!("Pool config \"{}\" has been created", name)),
            Err(ErrorCode::PoolLedgerConfigAlreadyExistsError) => Err(println_err!("Pool config \"{}\" already exists", name)),
            Err(err) => Err(println_err!("Indy SDK error occurred {:?}", err)),
        };

        trace!("CreateCommand::execute << {:?}", res);
        res
    }

    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }
}

impl ConnectCommand {
    pub fn new(app_cnxt: Rc<ApplicationContext>, indy_cnxt: Rc<IndyContext>) -> ConnectCommand {
        ConnectCommand {
            app_cnxt,
            indy_cnxt,
            metadata: CommandMetadata::build("connect", "Connect to pool with specified name. Also disconnect from previously connected.")
                .add_main_param("name", "The name of pool")
                .finalize()
        }
    }
}

impl Command for ConnectCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("OpenCommand::execute >> self {:?} params {:?}", self, params);

        let name = get_str_param("name", params).map_err(error_err!())?;

        let res = Ok(())
            .and_then(|_| {
                if let Some((name, handle)) = self.indy_cnxt.get_connected_pool() {
                    match Pool::close(handle) {
                        Ok(()) => {
                            self.app_cnxt.unset_sub_prompt(1);
                            self.indy_cnxt.unset_connected_pool();
                            Ok(println_succ!("Pool \"{}\" has been disconnected", name))
                        }
                        Err(err) => Err(println_err!("Indy SDK error occurred {:?}", err))
                    }
                } else {
                    Ok(())
                }
            })
            .and_then(|_| {
                match Pool::open_pool_ledger(name, None) {
                    Ok(handle) => {
                        self.app_cnxt.set_sub_prompt(1, &format!("pool({})", name));
                        self.indy_cnxt.set_connected_pool(name, handle);
                        Ok(println_succ!("Pool \"{}\" has been connected", name))
                    }
                    Err(err) => Err(println_err!("Indy SDK error occurred {:?}", err)),
                }
            });

        trace!("CreateCommand::execute << {:?}", res);
        res
    }
}

impl ListCommand {
    pub fn new(ctx: Rc<IndyContext>) -> ListCommand {
        ListCommand {
            ctx,
            metadata: CommandMetadata::build("list", "List existing pool configs.")
                .finalize()
        }
    }
}

impl Command for ListCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("ListCommand::execute >> self {:?} params {:?}", self, params);

        let res = match Pool::list() {
            Ok(pools) => {
                trace!("pools {:?}", pools);
                let pools: Vec<serde_json::Value> = serde_json::from_str(&pools)
                    .map_err(|_| println_err!("Wrong data has been received"))?;

                if pools.len() > 0 {
                    print_table(&pools, &vec![("pool", "Pool")]);
                } else {
                    println_succ!("There are no pool");
                }
                if let Some(cur_pool) = self.ctx.get_connected_pool_name() {
                    println_succ!("Current pool \"{}\"", cur_pool);
                }

                Ok(())
            }
            Err(ErrorCode::CommonIOError) => Err(println_succ!("There are no pool")),
            Err(err) => Err(println_err!("Indy SDK error occurred {:?}", err)),
        };

        trace!("ListCommand::execute << {:?}", res);
        res
    }
}

impl DisconnectCommand {
    pub fn new(app_cnxt: Rc<ApplicationContext>, indy_cnxt: Rc<IndyContext>) -> DisconnectCommand {
        DisconnectCommand {
            app_cnxt,
            indy_cnxt,
            metadata: CommandMetadata::build("disconnect", "Disconnect from current pool.")
                .finalize()
        }
    }
}

impl Command for DisconnectCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("DisconnectCommand::execute >> self {:?} params {:?}", self, params);

        let (name, handle) = if let Some(pool) = self.indy_cnxt.get_connected_pool() {
            pool
        } else {
            return Err(println_err!("There is no connected pool now"));
        };

        let res = match Pool::close(handle) {
            Ok(()) => {
                self.app_cnxt.unset_sub_prompt(1);
                self.indy_cnxt.unset_connected_pool();
                Ok(println_succ!("Pool \"{}\" has been disconnected", name))
            }
            Err(err) => Err(println_err!("Indy SDK error occurred {:?}", err)),
        };

        trace!("DisconnectCommand::execute << {:?}", res);
        res
    }
}

impl DeleteCommand {
    pub fn new(ctx: Rc<IndyContext>) -> DeleteCommand {
        DeleteCommand {
            ctx,
            metadata: CommandMetadata::build("delete", "Delete pool config with specified name")
                .add_main_param("name", "The name of deleted pool config")
                .finalize()
        }
    }
}

impl Command for DeleteCommand {
    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("DeleteCommand::execute >> self {:?} params {:?}", self, params);

        let name = get_str_param("name", params).map_err(error_err!())?;

        trace!(r#"Pool::delete try: name {}"#, name);

        let res = Pool::delete(name);

        trace!(r#"Pool::delete return: {:?}"#, res);

        let res = match res {
            Ok(()) => Ok(println_succ!("Pool \"{}\" has been deleted", name)),
            Err(err) => Err(println_err!("Indy SDK error occurred {:?}", err)),
        };

        trace!("DeleteCommand::execute << {:?}", res);
        res
    }

    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }
}<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::shared::get_shuffle_dir;
use anyhow::Result;
use diem_types::on_chain_config::VMPublishingOption;
use std::fs;

pub fn handle() -> Result<()> {
    let shuffle_dir = get_shuffle_dir();
    if !shuffle_dir.is_dir() {
        println!("Creating node config in {}", shuffle_dir.display());
        fs::create_dir_all(&shuffle_dir)?;
    } else {
        println!("Accessing node config in {}", shuffle_dir.display());
    }
    let publishing_option = VMPublishingOption::open();
    diem_node::load_test_environment(
        Some(shuffle_dir.join("nodeconfig")),
        false,
        Some(publishing_option),
        diem_framework_releases::current_module_blobs().to_vec(),
        rand::rngs::OsRng,
    );
    Ok(())
}
<commit_msg>[shuffle] node uses a seed rng for clean reruns<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::shared::get_shuffle_dir;
use anyhow::Result;
use diem_types::on_chain_config::VMPublishingOption;
use rand::SeedableRng;
use std::fs;

pub fn handle() -> Result<()> {
    let shuffle_dir = get_shuffle_dir();
    if !shuffle_dir.is_dir() {
        println!("Creating node config in {}", shuffle_dir.display());
        fs::create_dir_all(&shuffle_dir)?;
    } else {
        println!("Accessing node config in {}", shuffle_dir.display());
    }
    let publishing_option = VMPublishingOption::open();

    // prepare a deterministic generator so that recreated test environments
    // have the same waypoints, configurations, etc
    let rng = rand::rngs::StdRng::seed_from_u64(0);
    diem_node::load_test_environment(
        Some(shuffle_dir.join("nodeconfig")),
        false,
        Some(publishing_option),
        diem_framework_releases::current_module_blobs().to_vec(),
        rng,
    );
    Ok(())
}
<|endoftext|>


<commit_before>use crate::common::util::*;
use std::ffi::OsStr;

#[test]
fn test_directory() {
    new_ucmd!()
        .args(&["/root/alpha/beta/gamma/delta/epsilon/omega/"])
        .succeeds()
        .stdout_only("omega\n");
}

#[test]
fn test_file() {
    new_ucmd!()
        .args(&["/etc/passwd"])
        .succeeds()
        .stdout_only("passwd\n");
}

#[test]
fn test_remove_suffix() {
    new_ucmd!()
        .args(&["/usr/local/bin/reallylongexecutable.exe", ".exe"])
        .succeeds()
        .stdout_only("reallylongexecutable\n");
}

#[test]
fn test_dont_remove_suffix() {
    new_ucmd!()
        .args(&["/foo/bar/baz", "baz"])
        .succeeds()
        .stdout_only("baz\n");
}

#[test]
fn test_multiple_param() {
    for multiple_param in vec!["-a", "--multiple"] {
        let path = "/foo/bar/baz";
        new_ucmd!()
            .args(&[multiple_param, path, path])
            .succeeds()
            .stdout_only("baz\nbaz\n");
    }
}

#[test]
fn test_suffix_param() {
    for suffix_param in vec!["-s", "--suffix"] {
        let path = "/foo/bar/baz.exe";
        new_ucmd!()
            .args(&[suffix_param, ".exe", path, path])
            .succeeds()
            .stdout_only("baz\nbaz\n");
    }
}

#[test]
fn test_zero_param() {
    for zero_param in vec!["-z", "--zero"] {
        let path = "/foo/bar/baz";
        new_ucmd!()
            .args(&[zero_param, "-a", path, path])
            .succeeds()
            .stdout_only("baz\0baz\0");
    }
}

fn expect_error(input: Vec<&str>) {
    assert!(new_ucmd!().args(&input).fails().no_stdout().stderr().len() > 0);
}

#[test]
fn test_invalid_option() {
    let path = "/foo/bar/baz";
    expect_error(vec!["-q", path]);
}

#[test]
fn test_no_args() {
    expect_error(vec![]);
}

#[test]
fn test_too_many_args() {
    expect_error(vec!["a", "b", "c"]);
}

fn test_invalid_utf8_args(os_str: &OsStr) {
    let test_vec = vec![os_str.to_os_string()];
    new_ucmd!().args(&test_vec).succeeds().stdout_is("fo�o\n");
}

#[cfg(any(unix, target_os = "redox"))]
#[test]
fn invalid_utf8_args_unix() {
    use std::os::unix::ffi::OsStrExt;

    let source = [0x66, 0x6f, 0x80, 0x6f];
    let os_str = OsStr::from_bytes(&source[..]);
    test_invalid_utf8_args(os_str);
}
<commit_msg>tests/basename: add tests for --version, --help<commit_after>use crate::common::util::*;
use std::ffi::OsStr;

#[test]
fn test_help() {
    for help_flg in vec!["-h", "--help"] {
        new_ucmd!()
            .arg(&help_flg)
            .succeeds()
            .no_stderr()
            .stdout_contains("USAGE:");
    }
}

#[test]
fn test_version() {
    for version_flg in vec!["-V", "--version"] {
        assert!(new_ucmd!()
            .arg(&version_flg)
            .succeeds()
            .no_stderr()
            .stdout_str()
            .starts_with("basename"));
    }
}

#[test]
fn test_directory() {
    new_ucmd!()
        .args(&["/root/alpha/beta/gamma/delta/epsilon/omega/"])
        .succeeds()
        .stdout_only("omega\n");
}

#[test]
fn test_file() {
    new_ucmd!()
        .args(&["/etc/passwd"])
        .succeeds()
        .stdout_only("passwd\n");
}

#[test]
fn test_remove_suffix() {
    new_ucmd!()
        .args(&["/usr/local/bin/reallylongexecutable.exe", ".exe"])
        .succeeds()
        .stdout_only("reallylongexecutable\n");
}

#[test]
fn test_dont_remove_suffix() {
    new_ucmd!()
        .args(&["/foo/bar/baz", "baz"])
        .succeeds()
        .stdout_only("baz\n");
}

#[test]
fn test_multiple_param() {
    for multiple_param in vec!["-a", "--multiple"] {
        let path = "/foo/bar/baz";
        new_ucmd!()
            .args(&[multiple_param, path, path])
            .succeeds()
            .stdout_only("baz\nbaz\n");
    }
}

#[test]
fn test_suffix_param() {
    for suffix_param in vec!["-s", "--suffix"] {
        let path = "/foo/bar/baz.exe";
        new_ucmd!()
            .args(&[suffix_param, ".exe", path, path])
            .succeeds()
            .stdout_only("baz\nbaz\n");
    }
}

#[test]
fn test_zero_param() {
    for zero_param in vec!["-z", "--zero"] {
        let path = "/foo/bar/baz";
        new_ucmd!()
            .args(&[zero_param, "-a", path, path])
            .succeeds()
            .stdout_only("baz\0baz\0");
    }
}

fn expect_error(input: Vec<&str>) {
    assert!(new_ucmd!().args(&input).fails().no_stdout().stderr().len() > 0);
}

#[test]
fn test_invalid_option() {
    let path = "/foo/bar/baz";
    expect_error(vec!["-q", path]);
}

#[test]
fn test_no_args() {
    expect_error(vec![]);
}

#[test]
fn test_too_many_args() {
    expect_error(vec!["a", "b", "c"]);
}

fn test_invalid_utf8_args(os_str: &OsStr) {
    let test_vec = vec![os_str.to_os_string()];
    new_ucmd!().args(&test_vec).succeeds().stdout_is("fo�o\n");
}

#[cfg(any(unix, target_os = "redox"))]
#[test]
fn invalid_utf8_args_unix() {
    use std::os::unix::ffi::OsStrExt;

    let source = [0x66, 0x6f, 0x80, 0x6f];
    let os_str = OsStr::from_bytes(&source[..]);
    test_invalid_utf8_args(os_str);
}
<|endoftext|>


<commit_before>//! A library for interacting with a HackRF device.
//!
//! ## Examples
//! ```
//! extern crate hackrf;
//!
//! use hackrf::{HackRF, HackRFResult};
//!
//! const SAMP_RATE: u64 = 2_000_000; // 2 MHz
//!
//! fn main() {
//!    if let Err(e) = run() {
//!        println!("{:?}", e);
//!    }
//! }
//!
//! fn run() -> HackRFResult<()> {
//!     let context = try!(hackrf::init());
//!
//!     let mut device = try!(HackRF::open(&context));
//!     try!(device.set_samp_rate(SAMP_RATE as f64));
//!     try!(device.set_freq(150_000_000));
//!
//!     let mut rx_stream = try!(device.rx_stream());
//!
//!     // Take 10 seconds worth of samples
//!     for _ in 0..10 * SAMP_RATE {
//!         let (i, q) = rx_stream.next_sample();
//!         // .. Do something with samples ..
//!     }
//!
//!     Ok(())
//! }
//! ```

extern crate hackrf_sys as ffi;

use std::ffi::CStr;
use std::os::raw::{c_int, c_void};

use std::sync::mpsc::{SyncSender, Receiver, TrySendError, sync_channel};
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

use std::{mem, slice, fmt, error};
use std::rc::Rc;

use ffi::hackrf_error::*;

pub mod util;

/// The maximum size of each of the buffers used for receiving.
/// Note: this must be greater than or equal to the buffer size chosen for libusb.
const BUFFER_SIZE: usize = 262144;

/// An internal macro for handling hackrf errors.
macro_rules! hackrf_try {
    ($e:expr) => ({
        match $e {
            HACKRF_SUCCESS => (),
            error => return Err(parse_error(error)),
        }
    });
}

/// A error that can occur when trying to interact with a HackRF device.
///
/// ## Possible Error Values
///
///     HACKRF_ERROR_INVALID_PARAM = -2
///     HACKRF_ERROR_NOT_FOUND = -5
///     HACKRF_ERROR_BUSY = -6
///     HACKRF_ERROR_NO_MEM = -11
///     HACKRF_ERROR_LIBUSB = -1000
///     HACKRF_ERROR_THREAD = -1001
///     HACKRF_ERROR_STREAMING_THREAD_ERR = -1002
///     HACKRF_ERROR_STREAMING_STOPPED = -1003
///     HACKRF_ERROR_STREAMING_EXIT_CALLED = -1004
///     HACKRF_ERROR_OTHER = -9999
///
/// See [libhackrf](https://github.com/mossmann/hackrf/tree/master/host/libhackrf) for more info.
#[derive(Debug)]
pub struct HackRFError {
    /// The description of the code.
    pub desc: String,

    /// The code returned by `libhackrf`.
    pub code: i32,
}

impl fmt::Display for HackRFError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error({}): {}", self.code, self.desc)
    }
}

impl error::Error for HackRFError {
    fn description(&self) -> &str {
        &self.desc
    }
}

/// A specialized Result type for HackRF operations
pub type HackRFResult<T> = Result<T, HackRFError>;

/// An internal function for obtaining the description from a HackRF error code.
fn parse_error(error_code: ffi::hackrf_error) -> HackRFError {
    unsafe {
        let desc = CStr::from_ptr(ffi::hackrf_error_name(error_code)).to_string_lossy();
        HackRFError {
            desc: desc.to_string(),
            code: error_code as i32,
        }
    }
}

/// Adjust a gain value to the nearest valid step
fn adjust_gain(gain: u32, min: u32, max: u32, step: u32) -> u32 {
    if gain < min { min }
    else if gain > max { max }
    else { (gain as f32 / step as f32).round() as u32 * step }
}

/// The HackRF context.
///
/// This struct is used ensure that `libhackrf` is initialized before it can be used. A context can
/// be obtained by calling hackrf::init().
///
/// ## Example
/// ```
/// let context = try!(hackrf::init());
/// // Use context
/// ```
pub struct HackRFContext(Rc<HackRFContextInner>);

/// Value for keeping track of any object that contains a reference to the context.
///
/// When this value is dropped, `libhackrf` will be closed.
struct HackRFContextInner;

impl Drop for HackRFContextInner {
    fn drop(&mut self) {
        unsafe {
            ffi::hackrf_exit();
        }
    }
}

/// Initialize `libhackrf`, returning a context that can be used to connect to HackRF devices.
/// Once all references to the returned context go out of scope, the library will be closed
/// automatically.
pub fn init() -> HackRFResult<HackRFContext> {
    unsafe {
        hackrf_try!(ffi::hackrf_init());
    }
    Ok(HackRFContext(Rc::new(HackRFContextInner)))
}

/// A structure for managaing a HackRF device.
///
/// This structure contains methods for configuring the various settings of the HackRF. It also
/// provides a method for managing received samples as a blocking stream. Currently transmitting
/// samples and non-blocking streams are not supported.
///
/// ## Implementation notes
///
/// This library is a lightweight wrapper around the basic HackRF FFI interface. In addition to
/// the basic functionality it provides a blocking stream interface for receiving samples (See:
/// [`RxStream`](./struct.RxStream.html)).
///
/// Rust's type system is used to ensure that resources are not destroy or modified while the HackRF
/// is receiving samples (although it is possible there are problems with the implementation.). To
/// stop receiving samples it is sufficient to let the stream drop out of scope. For example:
///
/// ```
/// let context = try!(hackrf::init());
/// let mut device = try!(HackRF::open(&context));
///
/// // Configure HackRF
///
/// {
///     let mut rx_stream = try!(device.rx_stream());
///     // Get samples from rx stream
/// }
///
/// // Re-configure HackRF
///
/// {
///     let mut rx_stream = try!(device.rx_stream());
///     // Get samples from rx stream
/// }
/// ```
pub struct HackRF {
    inner: *mut ffi::hackrf_device,
    _context: Rc<HackRFContextInner>,
}

impl Drop for HackRF {
    fn drop(&mut self) {
        unsafe {
            ffi::hackrf_close(self.inner);
        }
    }
}

static OVERFLOW_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;

impl HackRF {
    /// Attempt to open a connected HackRF device.
    pub fn open(context: &HackRFContext) -> HackRFResult<HackRF> {
        // Reset the overflow counter
        OVERFLOW_COUNT.store(0, Ordering::Relaxed);

        unsafe {
            let mut device = std::mem::zeroed();
            hackrf_try!(ffi::hackrf_open(&mut device));
            Ok(HackRF { inner: device, _context: context.0.clone() })
        }
    }

    /// Sets the center frequency (in Hz) of the HackRF: 5-6800 MHz.
    pub fn set_freq(&mut self, freq: u64) -> HackRFResult<()> {
        // TODO: Consider checking that the frequency is in a valid range.
        unsafe {
            hackrf_try!(ffi::hackrf_set_freq(self.inner, freq));
        }
        Ok(())
    }

    /// Sets amp gain to on/off.
    ///
    /// Warning: Enabling this in the presence of high power signals could damage the HackRF.
    pub fn set_amp_enable(&mut self, amp_enable: bool) -> HackRFResult<()> {
        unsafe {
            let value = if amp_enable { 1 } else { 0 };
            hackrf_try!(ffi::hackrf_set_amp_enable(self.inner, value));
        }
        Ok(())
    }

    /// Set antenna enable to on/off.
    pub fn set_antenna_enable(&mut self, antenna_enable: bool) -> HackRFResult<()> {
        unsafe {
            let value = if antenna_enable { 1 } else { 0 };
            hackrf_try!(ffi::hackrf_set_antenna_enable(self.inner, value));
        }
        Ok(())
    }

    /// Set LNA gain: 0-40 dB, 8dB steps.
    /// If the specified gain falls outside of the valid range, the gain will be clamped.
    pub fn set_lna_gain(&mut self, gain: u32) -> HackRFResult<()> {
        unsafe {
            hackrf_try!(ffi::hackrf_set_lna_gain(self.inner, adjust_gain(gain, 0, 40, 8)));
        }
        Ok(())
    }

    /// Set VGA (IF) gain: 0-62 dB, with 2dB steps.
    /// If the specified gain falls outside of the valid range, the gain will be clamped.
    pub fn set_vga_gain(&mut self, gain: u32) -> HackRFResult<()> {
        unsafe {
            hackrf_try!(ffi::hackrf_set_vga_gain(self.inner, adjust_gain(gain, 0, 62, 2)));
        }
        Ok(())
    }

    /// Sets the sample rate in Hz: 2-20 MHz.
    pub fn set_samp_rate(&mut self, samp_rate: f64) -> HackRFResult<()> {
        unsafe {
            hackrf_try!(ffi::hackrf_set_sample_rate(self.inner, samp_rate));

            // Automatically compute a good baseband filter bandwidth
            let bandwidth = ffi::hackrf_compute_baseband_filter_bw_round_down_lt(samp_rate as u32);
            try!(self.set_baseband_filter_bw(bandwidth));
        }
        Ok(())
    }

    /// Sets the baseband filter bandwidth.
    ///
    /// Note: This must be performed *after* setting the sample rate.
    pub fn set_baseband_filter_bw(&mut self, filter_bw: u32) -> HackRFResult<()> {
        unsafe {
            let adjusted_filter_bw = ffi::hackrf_compute_baseband_filter_bw(filter_bw);
            hackrf_try!(ffi::hackrf_set_baseband_filter_bandwidth(self.inner, adjusted_filter_bw));
        }
        Ok(())
    }

    /// Start an RX stream.
    pub fn rx_stream(&mut self, bound: usize) -> HackRFResult<RxStream> {
        let mut rx_stream = RxStream::new(bound, self);
        let sender = (&mut *rx_stream.sender) as *mut SyncSender<Vec<u8>>;
        unsafe {
            match ffi::hackrf_start_rx(self.inner, rx_callback, sender as *mut c_void) {
                HACKRF_SUCCESS => Ok(rx_stream),
                error => Err(parse_error(error)),
            }
        }
    }

    /// Return how many times the HackRF has dropped data frames
    pub fn overflow_count(&self) -> usize {
        OVERFLOW_COUNT.load(Ordering::Relaxed)
    }
}

/// A structure that manages receiving I/Q samples from the HackRF.
pub struct RxStream<'a> {
    hackrf_device: &'a HackRF,
    lookup_table: [f32; 256],
    local_index: usize,
    local_buffer: Vec<u8>,
    sender: Box<SyncSender<Vec<u8>>>,
    receiver: Receiver<Vec<u8>>,
}

impl<'a> RxStream<'a> {
    /// Create a new instance of a RxStream
    fn new(bound: usize, hackrf_device: &'a HackRF) -> RxStream<'a> {
        fn gen_lookup_table() -> [f32; 256] {
            let mut data = [0.0; 256];
            for i in 0..256 {
                data[i] = (i as i8) as f32 / 128.0;
            }
            data
        }

        let (sender, receiver) = sync_channel(bound);
        RxStream {
            hackrf_device: hackrf_device,
            lookup_table: gen_lookup_table(),
            local_index: 0,
            local_buffer: vec![],
            sender: Box::new(sender),
            receiver: receiver,
        }
    }

    // Returns a reference to the internal receiver
    pub fn receiver(&mut self) -> &mut Receiver<Vec<u8>> {
        &mut self.receiver
    }

    /// Return the next I/Q sample converted to floating point numbers. If there is no data
    /// avaliable, then this function is blocking.
    pub fn next_sample(&mut self) -> Option<(f32, f32)> {
        let sample = self.next_sample_raw();
        sample.map(|(i, q)| (self.lookup_table[i as usize], self.lookup_table[q as usize]))
    }

    /// Return the next raw I/Q sample from the HackRF. If there is no data avaliable, then this
    /// function is blocking.
    pub fn next_sample_raw(&mut self) -> Option<(u8, u8)> {
        if self.local_buffer.len() < self.local_index + 1 {
            self.local_buffer = match self.receiver.recv() {
                Ok(buffer) => buffer,
                Err(_) => return None,
            };
            self.local_index = 0;
        }

        let i = self.local_index;
        self.local_index += 2;
        Some((self.local_buffer[i], self.local_buffer[i + 1]))
    }
}

impl<'a> Drop for RxStream<'a> {
    fn drop(&mut self) {
        unsafe {
            // TODO: investigate if this can ever fail under reasonable conditions
            ffi::hackrf_stop_rx(self.hackrf_device.inner);
        }
    }
}

/// The call back that is used in the stream abstraction
unsafe extern "C" fn rx_callback(transfer: *mut ffi::hackrf_transfer) -> c_int {
    let src_buffer = slice::from_raw_parts((*transfer).buffer, (*transfer).valid_length as usize);

    // If the input buffer is too long, then an error has occured somewhere
    if src_buffer.len() > BUFFER_SIZE {
        return -1;
    }

    // Copy the transferred data into an owned structure
    let data = src_buffer.into();

    let sender_raw: *mut SyncSender<Vec<u8>> = mem::transmute((*transfer).rx_ctx);
    let sender = &mut *sender_raw;

    if let Err(e) = sender.try_send(data) {
        match e {
            // If the buffer is full drop the message and increment the overflow count
            TrySendError::Full(_) => { OVERFLOW_COUNT.fetch_add(1, Ordering::Relaxed); },

            // Report an error back to libhackrf
            TrySendError::Disconnected(_) => return -1,
        }
    }

    // Succesfully sent the data
    0
}

#[cfg(test)]
mod test {
    #[test]
    fn init_test() {
        super::init();
    }
}
<commit_msg>Add the ability to check if the HackRF is currently streaming.<commit_after>//! A library for interacting with a HackRF device.
//!
//! ## Examples
//! ```
//! extern crate hackrf;
//!
//! use hackrf::{HackRF, HackRFResult};
//!
//! const SAMP_RATE: u64 = 2_000_000; // 2 MHz
//!
//! fn main() {
//!    if let Err(e) = run() {
//!        println!("{:?}", e);
//!    }
//! }
//!
//! fn run() -> HackRFResult<()> {
//!     let context = try!(hackrf::init());
//!
//!     let mut device = try!(HackRF::open(&context));
//!     try!(device.set_samp_rate(SAMP_RATE as f64));
//!     try!(device.set_freq(150_000_000));
//!
//!     let mut rx_stream = try!(device.rx_stream());
//!
//!     // Take 10 seconds worth of samples
//!     for _ in 0..10 * SAMP_RATE {
//!         let (i, q) = rx_stream.next_sample();
//!         // .. Do something with samples ..
//!     }
//!
//!     Ok(())
//! }
//! ```

extern crate hackrf_sys as ffi;

use std::ffi::CStr;
use std::os::raw::{c_int, c_void};

use std::sync::mpsc::{SyncSender, Receiver, TrySendError, sync_channel};
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

use std::{mem, slice, fmt, error};
use std::rc::Rc;

use ffi::hackrf_error::*;

pub mod util;

/// The maximum size of each of the buffers used for receiving.
/// Note: this must be greater than or equal to the buffer size chosen for libusb.
const BUFFER_SIZE: usize = 262144;

/// An internal macro for handling hackrf errors.
macro_rules! hackrf_try {
    ($e:expr) => ({
        match $e {
            HACKRF_SUCCESS => (),
            error => return Err(parse_error(error)),
        }
    });
}

/// A error that can occur when trying to interact with a HackRF device.
///
/// ## Possible Error Values
///
///     HACKRF_ERROR_INVALID_PARAM = -2
///     HACKRF_ERROR_NOT_FOUND = -5
///     HACKRF_ERROR_BUSY = -6
///     HACKRF_ERROR_NO_MEM = -11
///     HACKRF_ERROR_LIBUSB = -1000
///     HACKRF_ERROR_THREAD = -1001
///     HACKRF_ERROR_STREAMING_THREAD_ERR = -1002
///     HACKRF_ERROR_STREAMING_STOPPED = -1003
///     HACKRF_ERROR_STREAMING_EXIT_CALLED = -1004
///     HACKRF_ERROR_OTHER = -9999
///
/// See [libhackrf](https://github.com/mossmann/hackrf/tree/master/host/libhackrf) for more info.
#[derive(Debug)]
pub struct HackRFError {
    /// The description of the code.
    pub desc: String,

    /// The code returned by `libhackrf`.
    pub code: i32,
}

impl fmt::Display for HackRFError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error({}): {}", self.code, self.desc)
    }
}

impl error::Error for HackRFError {
    fn description(&self) -> &str {
        &self.desc
    }
}

/// A specialized Result type for HackRF operations
pub type HackRFResult<T> = Result<T, HackRFError>;

/// An internal function for obtaining the description from a HackRF error code.
fn parse_error(error_code: ffi::hackrf_error) -> HackRFError {
    unsafe {
        let desc = CStr::from_ptr(ffi::hackrf_error_name(error_code)).to_string_lossy();
        HackRFError {
            desc: desc.to_string(),
            code: error_code as i32,
        }
    }
}

/// Adjust a gain value to the nearest valid step
fn adjust_gain(gain: u32, min: u32, max: u32, step: u32) -> u32 {
    if gain < min { min }
    else if gain > max { max }
    else { (gain as f32 / step as f32).round() as u32 * step }
}

/// The HackRF context.
///
/// This struct is used ensure that `libhackrf` is initialized before it can be used. A context can
/// be obtained by calling hackrf::init().
///
/// ## Example
/// ```
/// let context = try!(hackrf::init());
/// // Use context
/// ```
pub struct HackRFContext(Rc<HackRFContextInner>);

/// Value for keeping track of any object that contains a reference to the context.
///
/// When this value is dropped, `libhackrf` will be closed.
struct HackRFContextInner;

impl Drop for HackRFContextInner {
    fn drop(&mut self) {
        unsafe {
            ffi::hackrf_exit();
        }
    }
}

/// Initialize `libhackrf`, returning a context that can be used to connect to HackRF devices.
/// Once all references to the returned context go out of scope, the library will be closed
/// automatically.
pub fn init() -> HackRFResult<HackRFContext> {
    unsafe {
        hackrf_try!(ffi::hackrf_init());
    }
    Ok(HackRFContext(Rc::new(HackRFContextInner)))
}

/// A structure for managaing a HackRF device.
///
/// This structure contains methods for configuring the various settings of the HackRF. It also
/// provides a method for managing received samples as a blocking stream. Currently transmitting
/// samples and non-blocking streams are not supported.
///
/// ## Implementation notes
///
/// This library is a lightweight wrapper around the basic HackRF FFI interface. In addition to
/// the basic functionality it provides a blocking stream interface for receiving samples (See:
/// [`RxStream`](./struct.RxStream.html)).
///
/// Rust's type system is used to ensure that resources are not destroy or modified while the HackRF
/// is receiving samples (although it is possible there are problems with the implementation.). To
/// stop receiving samples it is sufficient to let the stream drop out of scope. For example:
///
/// ```
/// let context = try!(hackrf::init());
/// let mut device = try!(HackRF::open(&context));
///
/// // Configure HackRF
///
/// {
///     let mut rx_stream = try!(device.rx_stream());
///     // Get samples from rx stream
/// }
///
/// // Re-configure HackRF
///
/// {
///     let mut rx_stream = try!(device.rx_stream());
///     // Get samples from rx stream
/// }
/// ```
pub struct HackRF {
    inner: *mut ffi::hackrf_device,
    _context: Rc<HackRFContextInner>,
}

impl Drop for HackRF {
    fn drop(&mut self) {
        unsafe {
            ffi::hackrf_close(self.inner);
        }
    }
}

static OVERFLOW_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;

impl HackRF {
    /// Attempt to open a connected HackRF device.
    pub fn open(context: &HackRFContext) -> HackRFResult<HackRF> {
        // Reset the overflow counter
        OVERFLOW_COUNT.store(0, Ordering::Relaxed);

        unsafe {
            let mut device = std::mem::zeroed();
            hackrf_try!(ffi::hackrf_open(&mut device));
            Ok(HackRF { inner: device, _context: context.0.clone() })
        }
    }

    /// Sets the center frequency (in Hz) of the HackRF: 5-6800 MHz.
    pub fn set_freq(&mut self, freq: u64) -> HackRFResult<()> {
        // TODO: Consider checking that the frequency is in a valid range.
        unsafe {
            hackrf_try!(ffi::hackrf_set_freq(self.inner, freq));
        }
        Ok(())
    }

    /// Sets amp gain to on/off.
    ///
    /// Warning: Enabling this in the presence of high power signals could damage the HackRF.
    pub fn set_amp_enable(&mut self, amp_enable: bool) -> HackRFResult<()> {
        unsafe {
            let value = if amp_enable { 1 } else { 0 };
            hackrf_try!(ffi::hackrf_set_amp_enable(self.inner, value));
        }
        Ok(())
    }

    /// Set antenna enable to on/off.
    pub fn set_antenna_enable(&mut self, antenna_enable: bool) -> HackRFResult<()> {
        unsafe {
            let value = if antenna_enable { 1 } else { 0 };
            hackrf_try!(ffi::hackrf_set_antenna_enable(self.inner, value));
        }
        Ok(())
    }

    /// Set LNA gain: 0-40 dB, 8dB steps.
    /// If the specified gain falls outside of the valid range, the gain will be clamped.
    pub fn set_lna_gain(&mut self, gain: u32) -> HackRFResult<()> {
        unsafe {
            hackrf_try!(ffi::hackrf_set_lna_gain(self.inner, adjust_gain(gain, 0, 40, 8)));
        }
        Ok(())
    }

    /// Set VGA (IF) gain: 0-62 dB, with 2dB steps.
    /// If the specified gain falls outside of the valid range, the gain will be clamped.
    pub fn set_vga_gain(&mut self, gain: u32) -> HackRFResult<()> {
        unsafe {
            hackrf_try!(ffi::hackrf_set_vga_gain(self.inner, adjust_gain(gain, 0, 62, 2)));
        }
        Ok(())
    }

    /// Sets the sample rate in Hz: 2-20 MHz.
    pub fn set_samp_rate(&mut self, samp_rate: f64) -> HackRFResult<()> {
        unsafe {
            hackrf_try!(ffi::hackrf_set_sample_rate(self.inner, samp_rate));

            // Automatically compute a good baseband filter bandwidth
            let bandwidth = ffi::hackrf_compute_baseband_filter_bw_round_down_lt(samp_rate as u32);
            try!(self.set_baseband_filter_bw(bandwidth));
        }
        Ok(())
    }

    /// Sets the baseband filter bandwidth.
    ///
    /// Note: This must be performed *after* setting the sample rate.
    pub fn set_baseband_filter_bw(&mut self, filter_bw: u32) -> HackRFResult<()> {
        unsafe {
            let adjusted_filter_bw = ffi::hackrf_compute_baseband_filter_bw(filter_bw);
            hackrf_try!(ffi::hackrf_set_baseband_filter_bandwidth(self.inner, adjusted_filter_bw));
        }
        Ok(())
    }

    /// Start an RX stream.
    pub fn rx_stream(&self, bound: usize) -> HackRFResult<RxStream> {
        let mut rx_stream = RxStream::new(bound, self);
        let sender = (&mut *rx_stream.sender) as *mut SyncSender<Vec<u8>>;
        unsafe {
            match ffi::hackrf_start_rx(self.inner, rx_callback, sender as *mut c_void) {
                HACKRF_SUCCESS => Ok(rx_stream),
                error => Err(parse_error(error)),
            }
        }
    }

    /// Checks if the hackrf is currently streaming
    pub fn is_streaming(&self) -> HackRFResult<()> {
        unsafe {
            match ffi::hackrf_is_streaming(self.inner) {
                HACKRF_TRUE => Ok(()),
                error => Err(parse_error(error)),
            }
        }
    }

    /// Return how many times the HackRF has dropped data frames
    pub fn overflow_count(&self) -> usize {
        OVERFLOW_COUNT.load(Ordering::Relaxed)
    }
}

/// A structure that manages receiving I/Q samples from the HackRF.
pub struct RxStream<'a> {
    hackrf_device: &'a HackRF,
    lookup_table: [f32; 256],
    local_index: usize,
    local_buffer: Vec<u8>,
    sender: Box<SyncSender<Vec<u8>>>,
    receiver: Receiver<Vec<u8>>,
}

impl<'a> RxStream<'a> {
    /// Create a new instance of a RxStream
    fn new(bound: usize, hackrf_device: &'a HackRF) -> RxStream<'a> {
        fn gen_lookup_table() -> [f32; 256] {
            let mut data = [0.0; 256];
            for i in 0..256 {
                data[i] = (i as i8) as f32 / 128.0;
            }
            data
        }

        let (sender, receiver) = sync_channel(bound);
        RxStream {
            hackrf_device: hackrf_device,
            lookup_table: gen_lookup_table(),
            local_index: 0,
            local_buffer: vec![],
            sender: Box::new(sender),
            receiver: receiver,
        }
    }

    // Returns a reference to the internal receiver
    pub fn receiver(&mut self) -> &mut Receiver<Vec<u8>> {
        &mut self.receiver
    }

    /// Return the next I/Q sample converted to floating point numbers. If there is no data
    /// avaliable, then this function is blocking.
    pub fn next_sample(&mut self) -> Option<(f32, f32)> {
        let sample = self.next_sample_raw();
        sample.map(|(i, q)| (self.lookup_table[i as usize], self.lookup_table[q as usize]))
    }

    /// Return the next raw I/Q sample from the HackRF. If there is no data avaliable, then this
    /// function is blocking.
    pub fn next_sample_raw(&mut self) -> Option<(u8, u8)> {
        if self.local_buffer.len() < self.local_index + 1 {
            self.local_buffer = match self.receiver.recv() {
                Ok(buffer) => buffer,
                Err(_) => return None,
            };
            self.local_index = 0;
        }

        let i = self.local_index;
        self.local_index += 2;
        Some((self.local_buffer[i], self.local_buffer[i + 1]))
    }
}

impl<'a> Drop for RxStream<'a> {
    fn drop(&mut self) {
        unsafe {
            // TODO: investigate if this can ever fail under reasonable conditions
            ffi::hackrf_stop_rx(self.hackrf_device.inner);
        }
    }
}

/// The call back that is used in the stream abstraction
unsafe extern "C" fn rx_callback(transfer: *mut ffi::hackrf_transfer) -> c_int {
    let src_buffer = slice::from_raw_parts((*transfer).buffer, (*transfer).valid_length as usize);

    // If the input buffer is too long, then an error has occured somewhere
    if src_buffer.len() > BUFFER_SIZE {
        return -1;
    }

    // Copy the transferred data into an owned structure
    let data = src_buffer.into();

    let sender_raw: *mut SyncSender<Vec<u8>> = mem::transmute((*transfer).rx_ctx);
    let sender = &mut *sender_raw;

    if let Err(e) = sender.try_send(data) {
        match e {
            // If the buffer is full drop the message and increment the overflow count
            TrySendError::Full(_) => { OVERFLOW_COUNT.fetch_add(1, Ordering::Relaxed); },

            // Report an error back to libhackrf
            TrySendError::Disconnected(_) => return -1,
        }
    }

    // Succesfully sent the data
    0
}

#[cfg(test)]
mod test {
    #[test]
    fn init_test() {
        super::init();
    }
}
<|endoftext|>


<commit_before>
use error::{StoreError, StoreErrorKind};
use std::io::{Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::fs::{File, OpenOptions};

/**
 * LazyFile type
 *
 * A lazy file is either absent, but a path to it is available, or it is present.
 */
#[derive(Debug)]
pub enum LazyFile {
    Absent(PathBuf),
    File(File)
}

fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).open(p)
}

fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).create(true).open(p)
}

impl LazyFile {

    /**
     * Create a new LazyFile instance from a Path
     */
    pub fn new(p: PathBuf) -> LazyFile {
        LazyFile::Absent(p)
    }

    /**
     * Create a new LazyFile instance from an already existing file
     */
    pub fn new_with_file(f: File) -> LazyFile {
        LazyFile::File(f)
    }

    /**
     * Get the file behind a LazyFile object
     */
    pub fn get_file(&mut self) -> Result<&File, StoreError> {
        match self.get_file_mut() {
            Ok(file) => Ok(&*file),
            Err(e) => Err(e)
        }
    }

    /**
     * Get the mutable file behind a LazyFile object
     */
    pub fn get_file_mut(&mut self) -> Result<&mut File, StoreError> {
        debug!("Getting lazy file: {:?}", self);
        let file = match *self {
            LazyFile::File(ref mut f) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                f.seek(SeekFrom::Start(0))
                    .map_err(|e| StoreError::new(StoreErrorKind::FileNotCreated, Some(Box::new(e))))
                    .map(|_| f)
            },
            LazyFile::Absent(ref p) => {
                try!(open_file(p).map_err(|e| {
                    StoreError::new(StoreErrorKind::FileNotFound,
                                    Some(Box::new(e)))
                }))
            }
        };
        *self = LazyFile::File(file);
        if let LazyFile::File(ref mut f) = *self {
            return Ok(f);
        }
        unreachable!()
    }

    /**
     * Create a file out of this LazyFile object
     */
    pub fn create_file(&mut self) -> Result<&mut File, StoreError> {
        debug!("Creating lazy file: {:?}", self);
        let file = match *self {
            LazyFile::File(ref mut f) => return Ok(f),
            LazyFile::Absent(ref p) => {
                try!(create_file(p).map_err(|e| {
                    StoreError::new(StoreErrorKind::FileNotFound,
                                    Some(Box::new(e)))
                }))
            }
        };
        *self = LazyFile::File(file);
        if let LazyFile::File(ref mut f) = *self {
            return Ok(f);
        }
        unreachable!()
    }
}

#[cfg(test)]
mod test {
    use super::LazyFile;
    use std::io::{Read, Write, Seek, SeekFrom};
    use std::path::PathBuf;
    use std::fs::File;
    use tempdir::TempDir;

    fn get_dir() -> TempDir {
        TempDir::new("test-image").unwrap()
    }

    #[test]
    fn lazy_file() {
        let dir = get_dir();
        let mut path = PathBuf::from(dir.path());
        path.set_file_name("test1");
        let mut lf = LazyFile::new(path);

        write!(lf.create_file().unwrap(), "Hello World").unwrap();
        dir.close().unwrap();
    }

    #[test]
    fn lazy_file_with_file() {
        let dir = get_dir();
        let mut path = PathBuf::from(dir.path());
        path.set_file_name("test2");
        let mut lf = LazyFile::new(path.clone());

        {
            let mut file = lf.create_file().unwrap();

            file.write(b"Hello World").unwrap();
            file.sync_all().unwrap();
        }

        {
            let mut file = lf.get_file().unwrap();
            let mut s = Vec::new();
            file.read_to_end(&mut s).unwrap();
            assert_eq!(s, "Hello World".to_string().into_bytes());
        }

        dir.close().unwrap();
    }
}
<commit_msg>Fix: implicitely create directories on file saving<commit_after>
use error::{StoreError, StoreErrorKind};
use std::io::{Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::fs::{File, OpenOptions, create_dir_all};

/**
 * LazyFile type
 *
 * A lazy file is either absent, but a path to it is available, or it is present.
 */
#[derive(Debug)]
pub enum LazyFile {
    Absent(PathBuf),
    File(File)
}

fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).open(p)
}

fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    if let Some(parent) = p.as_ref().parent() {
        debug!("Implicitely creating directory: {:?}", parent);
        if let Err(e) = create_dir_all(parent) {
            return Err(e);
        }
    }
    OpenOptions::new().write(true).read(true).create(true).open(p)
}

impl LazyFile {

    /**
     * Create a new LazyFile instance from a Path
     */
    pub fn new(p: PathBuf) -> LazyFile {
        LazyFile::Absent(p)
    }

    /**
     * Create a new LazyFile instance from an already existing file
     */
    pub fn new_with_file(f: File) -> LazyFile {
        LazyFile::File(f)
    }

    /**
     * Get the file behind a LazyFile object
     */
    pub fn get_file(&mut self) -> Result<&File, StoreError> {
        match self.get_file_mut() {
            Ok(file) => Ok(&*file),
            Err(e) => Err(e)
        }
    }

    /**
     * Get the mutable file behind a LazyFile object
     */
    pub fn get_file_mut(&mut self) -> Result<&mut File, StoreError> {
        debug!("Getting lazy file: {:?}", self);
        let file = match *self {
            LazyFile::File(ref mut f) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                f.seek(SeekFrom::Start(0))
                    .map_err(|e| StoreError::new(StoreErrorKind::FileNotCreated, Some(Box::new(e))))
                    .map(|_| f)
            },
            LazyFile::Absent(ref p) => {
                try!(open_file(p).map_err(|e| {
                    StoreError::new(StoreErrorKind::FileNotFound,
                                    Some(Box::new(e)))
                }))
            }
        };
        *self = LazyFile::File(file);
        if let LazyFile::File(ref mut f) = *self {
            return Ok(f);
        }
        unreachable!()
    }

    /**
     * Create a file out of this LazyFile object
     */
    pub fn create_file(&mut self) -> Result<&mut File, StoreError> {
        debug!("Creating lazy file: {:?}", self);
        let file = match *self {
            LazyFile::File(ref mut f) => return Ok(f),
            LazyFile::Absent(ref p) => {
                try!(create_file(p).map_err(|e| {
                    StoreError::new(StoreErrorKind::FileNotFound,
                                    Some(Box::new(e)))
                }))
            }
        };
        *self = LazyFile::File(file);
        if let LazyFile::File(ref mut f) = *self {
            return Ok(f);
        }
        unreachable!()
    }
}

#[cfg(test)]
mod test {
    use super::LazyFile;
    use std::io::{Read, Write, Seek, SeekFrom};
    use std::path::PathBuf;
    use std::fs::File;
    use tempdir::TempDir;

    fn get_dir() -> TempDir {
        TempDir::new("test-image").unwrap()
    }

    #[test]
    fn lazy_file() {
        let dir = get_dir();
        let mut path = PathBuf::from(dir.path());
        path.set_file_name("test1");
        let mut lf = LazyFile::new(path);

        write!(lf.create_file().unwrap(), "Hello World").unwrap();
        dir.close().unwrap();
    }

    #[test]
    fn lazy_file_with_file() {
        let dir = get_dir();
        let mut path = PathBuf::from(dir.path());
        path.set_file_name("test2");
        let mut lf = LazyFile::new(path.clone());

        {
            let mut file = lf.create_file().unwrap();

            file.write(b"Hello World").unwrap();
            file.sync_all().unwrap();
        }

        {
            let mut file = lf.get_file().unwrap();
            let mut s = Vec::new();
            file.read_to_end(&mut s).unwrap();
            assert_eq!(s, "Hello World".to_string().into_bytes());
        }

        dir.close().unwrap();
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Functions for dealing with stratis and device mapper names.

use std::fmt;
use std::fmt::Display;
use std::path::Path;

use devicemapper::{DmNameBuf, DmUuidBuf};

use stratis::{ErrorEnum, StratisError, StratisResult};

use super::super::super::engine::{FilesystemUuid, PoolUuid};

const FORMAT_VERSION: u16 = 1;

#[derive(Clone, Copy)]
pub enum FlexRole {
    MetadataVolume,
    ThinData,
    ThinMeta,
    ThinMetaSpare,
}

impl Display for FlexRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FlexRole::MetadataVolume => write!(f, "mdv"),
            FlexRole::ThinData => write!(f, "thindata"),
            FlexRole::ThinMeta => write!(f, "thinmeta"),
            FlexRole::ThinMetaSpare => write!(f, "thinmetaspare"),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinRole {
    Filesystem(FilesystemUuid),
}

impl Display for ThinRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinRole::Filesystem(uuid) => write!(f, "fs-{}", uuid.simple().to_string()),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinPoolRole {
    Pool,
}

impl Display for ThinPoolRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinPoolRole::Pool => write!(f, "pool"),
        }
    }
}

/// The various roles taken on by DM devices in the cache tier.
#[derive(Clone, Copy)]
pub enum CacheRole {
    /// The DM cache device, contains the other three devices.
    #[allow(dead_code)]
    Cache,
    /// The cache sub-device of the DM cache device.
    #[allow(dead_code)]
    CacheSub,
    /// The meta sub-device of the DM cache device.
    #[allow(dead_code)]
    MetaSub,
    /// The origin sub-device of the DM cache device, holds the actual data.
    OriginSub,
}

impl Display for CacheRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CacheRole::Cache => write!(f, "cache"),
            CacheRole::CacheSub => write!(f, "cachesub"),
            CacheRole::MetaSub => write!(f, "metasub"),
            CacheRole::OriginSub => write!(f, "originsub"),
        }
    }
}

/// Format a name & uuid for the flex layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("flex")                            4
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(FlexRole))                     13
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 60 (61 for UUID)
pub fn format_flex_ids(pool_uuid: PoolUuid, role: FlexRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-private-{}-flex-{}",
        FORMAT_VERSION,
        pool_uuid.simple().to_string(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 60"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 61"),
    )
}

/// Format a name & uuid for the thin layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("thin")                            4
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(ThinRole))                     35
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 46 (47 for UUID)
pub fn format_thin_ids(pool_uuid: PoolUuid, role: ThinRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-{}-thin-{}",
        FORMAT_VERSION,
        pool_uuid.simple().to_string(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 46"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 47"),
    )
}

/// Format a name & uuid for the thin pool layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("thinpool")                        8
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(ThinPoolRole))                 4
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 65 (66 for UUID)
pub fn format_thinpool_ids(pool_uuid: PoolUuid, role: ThinPoolRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-private-{}-thinpool-{}",
        FORMAT_VERSION,
        pool_uuid.simple().to_string(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 65"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 66"),
    )
}

/// Format a name & uuid for dm devices in the backstore.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("physical")                        8
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(CacheRole))                    9
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 60 (61 for UUID)
pub fn format_backstore_ids(pool_uuid: PoolUuid, role: CacheRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-private-{}-physical-{}",
        FORMAT_VERSION,
        pool_uuid.simple().to_string(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 60"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 61"),
    )
}

/// Validate a path for use as a Pool or Filesystem name.
pub fn validate_name(name: &str) -> StratisResult<()> {
    let name_path = Path::new(name);
    if name.contains('\u{0}') {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name contains NULL characters : {}", name),
        ));
    }
    if name_path.components().collect::<Vec<_>>().len() != 1 {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name is a path with 0 or more than 1 components : {}", name),
        ));
    }
    if name_path.is_absolute() {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name is an absolute path : {}", name),
        ));
    }
    if name == "." || name == ".." {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name is . or .. : {}", name),
        ));
    }
    // Linux has a maximum filename length of 255 bytes
    if name.len() > 255 {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name has more than 255 characters : {}", name),
        ));
    }

    if name.len() != name.trim().len() {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name contains leading or trailing space : {}", name),
        ));
    }
    if name.chars().any(|c| c.is_control()) {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name contains control characters : {}", name),
        ));
    }
    Ok(())
}
<commit_msg>Add unit test for validate_name()<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Functions for dealing with stratis and device mapper names.

use std::fmt;
use std::fmt::Display;
use std::path::Path;

use devicemapper::{DmNameBuf, DmUuidBuf};

use stratis::{ErrorEnum, StratisError, StratisResult};

use super::super::super::engine::{FilesystemUuid, PoolUuid};

const FORMAT_VERSION: u16 = 1;

#[derive(Clone, Copy)]
pub enum FlexRole {
    MetadataVolume,
    ThinData,
    ThinMeta,
    ThinMetaSpare,
}

impl Display for FlexRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FlexRole::MetadataVolume => write!(f, "mdv"),
            FlexRole::ThinData => write!(f, "thindata"),
            FlexRole::ThinMeta => write!(f, "thinmeta"),
            FlexRole::ThinMetaSpare => write!(f, "thinmetaspare"),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinRole {
    Filesystem(FilesystemUuid),
}

impl Display for ThinRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinRole::Filesystem(uuid) => write!(f, "fs-{}", uuid.simple().to_string()),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinPoolRole {
    Pool,
}

impl Display for ThinPoolRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinPoolRole::Pool => write!(f, "pool"),
        }
    }
}

/// The various roles taken on by DM devices in the cache tier.
#[derive(Clone, Copy)]
pub enum CacheRole {
    /// The DM cache device, contains the other three devices.
    #[allow(dead_code)]
    Cache,
    /// The cache sub-device of the DM cache device.
    #[allow(dead_code)]
    CacheSub,
    /// The meta sub-device of the DM cache device.
    #[allow(dead_code)]
    MetaSub,
    /// The origin sub-device of the DM cache device, holds the actual data.
    OriginSub,
}

impl Display for CacheRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CacheRole::Cache => write!(f, "cache"),
            CacheRole::CacheSub => write!(f, "cachesub"),
            CacheRole::MetaSub => write!(f, "metasub"),
            CacheRole::OriginSub => write!(f, "originsub"),
        }
    }
}

/// Format a name & uuid for the flex layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("flex")                            4
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(FlexRole))                     13
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 60 (61 for UUID)
pub fn format_flex_ids(pool_uuid: PoolUuid, role: FlexRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-private-{}-flex-{}",
        FORMAT_VERSION,
        pool_uuid.simple().to_string(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 60"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 61"),
    )
}

/// Format a name & uuid for the thin layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("thin")                            4
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(ThinRole))                     35
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 46 (47 for UUID)
pub fn format_thin_ids(pool_uuid: PoolUuid, role: ThinRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-{}-thin-{}",
        FORMAT_VERSION,
        pool_uuid.simple().to_string(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 46"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 47"),
    )
}

/// Format a name & uuid for the thin pool layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("thinpool")                        8
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(ThinPoolRole))                 4
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 65 (66 for UUID)
pub fn format_thinpool_ids(pool_uuid: PoolUuid, role: ThinPoolRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-private-{}-thinpool-{}",
        FORMAT_VERSION,
        pool_uuid.simple().to_string(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 65"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 66"),
    )
}

/// Format a name & uuid for dm devices in the backstore.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("physical")                        8
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(CacheRole))                    9
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 60 (61 for UUID)
pub fn format_backstore_ids(pool_uuid: PoolUuid, role: CacheRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-private-{}-physical-{}",
        FORMAT_VERSION,
        pool_uuid.simple().to_string(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 60"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 61"),
    )
}

/// Validate a path for use as a Pool or Filesystem name.
pub fn validate_name(name: &str) -> StratisResult<()> {
    let name_path = Path::new(name);
    if name.contains('\u{0}') {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name contains NULL characters : {}", name),
        ));
    }
    if name_path.components().collect::<Vec<_>>().len() != 1 {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name is a path with 0 or more than 1 components : {}", name),
        ));
    }
    if name_path.is_absolute() {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name is an absolute path : {}", name),
        ));
    }
    if name == "." || name == ".." {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name is . or .. : {}", name),
        ));
    }
    // Linux has a maximum filename length of 255 bytes
    if name.len() > 255 {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name has more than 255 characters : {}", name),
        ));
    }

    if name.len() != name.trim().len() {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name contains leading or trailing space : {}", name),
        ));
    }
    if name.chars().any(|c| c.is_control()) {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name contains control characters : {}", name),
        ));
    }
    Ok(())
}

#[cfg(test)]
mod tests {

    use engine::strat_engine::names::validate_name;

    #[test]
    pub fn test_validate_name() {
        assert!(validate_name(&'\u{0}'.to_string()).is_err());
        assert!(validate_name("./some").is_err());
        assert!(validate_name("../../root").is_err());
        assert!(validate_name("/").is_err());
        assert!(validate_name("\u{1c}\u{7}").is_err());
        assert!(validate_name("./foo/bar.txt").is_err());
        assert!(validate_name(".").is_err());
        assert!(validate_name("..").is_err());
        assert!(validate_name("/dev/sdb").is_err());
        assert!(validate_name("").is_err());
        assert!(validate_name("/").is_err());
        assert!(validate_name(" leading_space").is_err());
        assert!(validate_name("trailing_space ").is_err());
        assert!(validate_name("\u{0}leading_null").is_err());
        assert!(validate_name("trailing_null\u{0}").is_err());
        assert!(validate_name("middle\u{0}_null").is_err());
        assert!(validate_name("\u{0}multiple\u{0}_null\u{0}").is_err());
        assert!(validate_name(&"𐌏".repeat(64)).is_err());

        assert!(validate_name(&"𐌏".repeat(63)).is_ok());
        assert!(validate_name(&'\u{10fff8}'.to_string()).is_ok());
        assert!(validate_name("*< ? >").is_ok());
        assert!(validate_name("...").is_ok());
        assert!(validate_name("ok.name").is_ok());
        assert!(validate_name("ok name with spaces").is_ok());
        assert!(validate_name("\\\\").is_ok());
        assert!(validate_name("\u{211D}").is_ok());
        assert!(validate_name("☺").is_ok());
        assert!(validate_name("ok_name").is_ok());
    }
}
<|endoftext|>


<commit_before>#![no_std]
#![no_main]
#![feature(asm, const_fn, lang_items, compiler_builtins_lib, const_cell_new)]

extern crate capsules;
extern crate compiler_builtins;
extern crate hotel;
#[macro_use(debug,static_init)]
extern crate kernel;

#[macro_use]
pub mod io;

pub mod rng_test;
//pub mod digest;
//pub mod aes;

use kernel::{Chip, Platform};
use kernel::mpu::MPU;
use kernel::hil::gpio::Pin;
use kernel::hil::uart::UART;
use kernel::hil::rng::RNG;

// State for loading apps
const NUM_PROCS: usize = 2;

// how should the kernel respond when a process faults
const FAULT_RESPONSE: kernel::process::FaultResponse = kernel::process::FaultResponse::Panic;

#[link_section = ".app_memory"]
static mut APP_MEMORY: [u8; 16384] = [0; 16384];

static mut PROCESSES: [Option<kernel::Process<'static>>; NUM_PROCS] = [None, None];

pub struct Golf {
    console: &'static capsules::console::Console<'static, hotel::uart::UART>,
    gpio: &'static capsules::gpio::GPIO<'static, hotel::gpio::GPIOPin>,
    timer: &'static capsules::alarm::AlarmDriver<'static, hotel::timels::Timels<'static>>,
    ipc: kernel::ipc::IPC,
//    digest: &'static digest::DigestDriver<'static, hotel::crypto::sha::ShaEngine>,
//    aes: &'static aes::AesDriver<'static>,
    rng: &'static capsules::rng::SimpleRng<'static, hotel::trng::Trng<'static>>,
}

#[no_mangle]
pub unsafe fn reset_handler() {
    hotel::init();

    let timerhs = {
        use hotel::pmu::*;
        use hotel::timeus::Timeus;
        Clock::new(PeripheralClock::Bank1(PeripheralClock1::TimeUs0Timer)).enable();
        Clock::new(PeripheralClock::Bank1(PeripheralClock1::TimeLs0)).enable();
        let timer = Timeus::new(0);
        timer
    };

    timerhs.start();
    let start = timerhs.now();

    {
        use hotel::pmu::*;
        Clock::new(PeripheralClock::Bank0(PeripheralClock0::Gpio0)).enable();
        let pinmux = &mut *hotel::pinmux::PINMUX;
        // LED_0
        pinmux.dioa11.select.set(hotel::pinmux::Function::Gpio0Gpio0);

        // SW1
        pinmux.gpio0_gpio1.select.set(hotel::pinmux::SelectablePin::Diom2);
        pinmux.diom2.select.set(hotel::pinmux::Function::Gpio0Gpio1);
        pinmux.diom2.control.set(1 << 2 | 1 << 4);

        pinmux.diob1.select.set(hotel::pinmux::Function::Uart0Tx);
        pinmux.diob6.control.set(1 << 2 | 1 << 4);
        pinmux.uart0_rx.select.set(hotel::pinmux::SelectablePin::Diob6);
    }

    let console = static_init!(
        capsules::console::Console<'static, hotel::uart::UART>,
        capsules::console::Console::new(&hotel::uart::UART0,
                                        115200,
                                       &mut capsules::console::WRITE_BUF,
                                       kernel::grant::Grant::create()),
        24);
    hotel::uart::UART0.set_client(console);
    console.initialize();
    let kc = static_init!(capsules::console::App, capsules::console::App::default());
    kernel::debug::assign_console_driver(Some(console), kc);

    let gpio_pins = static_init!(
        [&'static hotel::gpio::GPIOPin; 2],
        [&hotel::gpio::PORT0.pins[0], &hotel::gpio::PORT0.pins[1]],
        8);

    let gpio = static_init!(
        capsules::gpio::GPIO<'static, hotel::gpio::GPIOPin>,
        capsules::gpio::GPIO::new(gpio_pins),
        20);
    for pin in gpio_pins.iter() {
        pin.set_client(gpio)
    }

    let timer = static_init!(
        capsules::alarm::AlarmDriver<'static, hotel::timels::Timels<'static>>,
        capsules::alarm::AlarmDriver::new(
            &hotel::timels::TIMELS0, kernel::Grant::create()),
        12);
    hotel::timels::TIMELS0.set_client(timer);
/*
    let digest = static_init!(
        digest::DigestDriver<'static, hotel::crypto::sha::ShaEngine>,
        digest::DigestDriver::new(
                &mut hotel::crypto::sha::KEYMGR0_SHA,
                kernel::Container::create()),
        16);

    let aes = static_init!(
        aes::AesDriver,
        aes::AesDriver::new(&mut hotel::crypto::aes::KEYMGR0_AES, kernel::Container::create()),
        16);
    hotel::crypto::aes::KEYMGR0_AES.set_client(aes);
*/
    hotel::trng::TRNG0.init();
    let rng = static_init!(
        capsules::rng::SimpleRng<'static, hotel::trng::Trng>,
        capsules::rng::SimpleRng::new(&mut hotel::trng::TRNG0, kernel::grant::Grant::create()),
        8);
    hotel::trng::TRNG0.set_client(rng);

    let golf2 = static_init!(Golf, Golf {
        console: console,
        gpio: gpio,
        timer: timer,
        ipc: kernel::ipc::IPC::new(),
//        digest: digest,
//        aes: aes,
        rng: rng,
    }, 8);
/*
    hotel::usb::USB0.init(&mut hotel::usb::OUT_DESCRIPTORS,
                          &mut hotel::usb::OUT_BUFFERS,
                          &mut hotel::usb::IN_DESCRIPTORS,
                          &mut hotel::usb::IN_BUFFERS,
                          hotel::usb::PHY::A,
                          None,
                          Some(0x0011),
                          Some(0x7788));
*/

    let end = timerhs.now();

    println!("Tock 1.0 booting. Initialization took {} tics.\r",
              end.wrapping_sub(start));

    let mut chip = hotel::chip::Hotel::new();
    chip.mpu().enable_mpu();

//    rng_test::run_rng();

    extern "C" {
        /// Beginning of the ROM region containing app images.
        static _sapps: u8;
    }

    kernel::process::load_processes(
        &_sapps as *const u8,
        &mut APP_MEMORY,
        &mut PROCESSES,
        FAULT_RESPONSE,
    );

    debug!("Loaded processes: finish boot sequence.\r");
    kernel::main(golf2, &mut chip, &mut PROCESSES, &golf2.ipc);
}

impl Platform for Golf {
    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
        where F: FnOnce(Option<&kernel::Driver>) -> R
    {
        debug!("Received system call for device {}", driver_num);
        match driver_num {
            capsules::console::DRIVER_NUM => f(Some(self.console)),
            capsules::gpio::DRIVER_NUM  => f(Some(self.gpio)),
//            2 => f(Some(self.digest)),
            capsules::alarm::DRIVER_NUM => f(Some(self.timer)),
//            4 => f(Some(self.aes)),
            capsules::rng::DRIVER_NUM   => f(Some(self.rng)),
            kernel::ipc::DRIVER_NUM     => f(Some(&self.ipc)),
            _ => f(None),
        }
    }
}
<commit_msg>Stop tracking system calls, they are working.<commit_after>#![no_std]
#![no_main]
#![feature(asm, const_fn, lang_items, compiler_builtins_lib, const_cell_new)]

extern crate capsules;
extern crate compiler_builtins;
extern crate hotel;
#[macro_use(debug,static_init)]
extern crate kernel;

#[macro_use]
pub mod io;

pub mod rng_test;
//pub mod digest;
//pub mod aes;

use kernel::{Chip, Platform};
use kernel::mpu::MPU;
use kernel::hil::gpio::Pin;
use kernel::hil::uart::UART;
use kernel::hil::rng::RNG;

// State for loading apps
const NUM_PROCS: usize = 2;

// how should the kernel respond when a process faults
const FAULT_RESPONSE: kernel::process::FaultResponse = kernel::process::FaultResponse::Panic;

#[link_section = ".app_memory"]
static mut APP_MEMORY: [u8; 16384] = [0; 16384];

static mut PROCESSES: [Option<kernel::Process<'static>>; NUM_PROCS] = [None, None];

pub struct Golf {
    console: &'static capsules::console::Console<'static, hotel::uart::UART>,
    gpio: &'static capsules::gpio::GPIO<'static, hotel::gpio::GPIOPin>,
    timer: &'static capsules::alarm::AlarmDriver<'static, hotel::timels::Timels<'static>>,
    ipc: kernel::ipc::IPC,
//    digest: &'static digest::DigestDriver<'static, hotel::crypto::sha::ShaEngine>,
//    aes: &'static aes::AesDriver<'static>,
    rng: &'static capsules::rng::SimpleRng<'static, hotel::trng::Trng<'static>>,
}

#[no_mangle]
pub unsafe fn reset_handler() {
    hotel::init();

    let timerhs = {
        use hotel::pmu::*;
        use hotel::timeus::Timeus;
        Clock::new(PeripheralClock::Bank1(PeripheralClock1::TimeUs0Timer)).enable();
        Clock::new(PeripheralClock::Bank1(PeripheralClock1::TimeLs0)).enable();
        let timer = Timeus::new(0);
        timer
    };

    timerhs.start();
    let start = timerhs.now();

    {
        use hotel::pmu::*;
        Clock::new(PeripheralClock::Bank0(PeripheralClock0::Gpio0)).enable();
        let pinmux = &mut *hotel::pinmux::PINMUX;
        // LED_0
        pinmux.dioa11.select.set(hotel::pinmux::Function::Gpio0Gpio0);

        // SW1
        pinmux.gpio0_gpio1.select.set(hotel::pinmux::SelectablePin::Diom2);
        pinmux.diom2.select.set(hotel::pinmux::Function::Gpio0Gpio1);
        pinmux.diom2.control.set(1 << 2 | 1 << 4);

        pinmux.diob1.select.set(hotel::pinmux::Function::Uart0Tx);
        pinmux.diob6.control.set(1 << 2 | 1 << 4);
        pinmux.uart0_rx.select.set(hotel::pinmux::SelectablePin::Diob6);
    }

    let console = static_init!(
        capsules::console::Console<'static, hotel::uart::UART>,
        capsules::console::Console::new(&hotel::uart::UART0,
                                        115200,
                                       &mut capsules::console::WRITE_BUF,
                                       kernel::grant::Grant::create()),
        24);
    hotel::uart::UART0.set_client(console);
    console.initialize();
    let kc = static_init!(capsules::console::App, capsules::console::App::default());
    kernel::debug::assign_console_driver(Some(console), kc);

    let gpio_pins = static_init!(
        [&'static hotel::gpio::GPIOPin; 2],
        [&hotel::gpio::PORT0.pins[0], &hotel::gpio::PORT0.pins[1]],
        8);

    let gpio = static_init!(
        capsules::gpio::GPIO<'static, hotel::gpio::GPIOPin>,
        capsules::gpio::GPIO::new(gpio_pins),
        20);
    for pin in gpio_pins.iter() {
        pin.set_client(gpio)
    }

    let timer = static_init!(
        capsules::alarm::AlarmDriver<'static, hotel::timels::Timels<'static>>,
        capsules::alarm::AlarmDriver::new(
            &hotel::timels::TIMELS0, kernel::Grant::create()),
        12);
    hotel::timels::TIMELS0.set_client(timer);
/*
    let digest = static_init!(
        digest::DigestDriver<'static, hotel::crypto::sha::ShaEngine>,
        digest::DigestDriver::new(
                &mut hotel::crypto::sha::KEYMGR0_SHA,
                kernel::Container::create()),
        16);

    let aes = static_init!(
        aes::AesDriver,
        aes::AesDriver::new(&mut hotel::crypto::aes::KEYMGR0_AES, kernel::Container::create()),
        16);
    hotel::crypto::aes::KEYMGR0_AES.set_client(aes);
*/
    hotel::trng::TRNG0.init();
    let rng = static_init!(
        capsules::rng::SimpleRng<'static, hotel::trng::Trng>,
        capsules::rng::SimpleRng::new(&mut hotel::trng::TRNG0, kernel::grant::Grant::create()),
        8);
    hotel::trng::TRNG0.set_client(rng);

    let golf2 = static_init!(Golf, Golf {
        console: console,
        gpio: gpio,
        timer: timer,
        ipc: kernel::ipc::IPC::new(),
//        digest: digest,
//        aes: aes,
        rng: rng,
    }, 8);
/*
    hotel::usb::USB0.init(&mut hotel::usb::OUT_DESCRIPTORS,
                          &mut hotel::usb::OUT_BUFFERS,
                          &mut hotel::usb::IN_DESCRIPTORS,
                          &mut hotel::usb::IN_BUFFERS,
                          hotel::usb::PHY::A,
                          None,
                          Some(0x0011),
                          Some(0x7788));
*/

    let end = timerhs.now();

    println!("Tock 1.0 booting. Initialization took {} tics.\r",
              end.wrapping_sub(start));

    let mut chip = hotel::chip::Hotel::new();
    chip.mpu().enable_mpu();

//    rng_test::run_rng();

    extern "C" {
        /// Beginning of the ROM region containing app images.
        static _sapps: u8;
    }

    kernel::process::load_processes(
        &_sapps as *const u8,
        &mut APP_MEMORY,
        &mut PROCESSES,
        FAULT_RESPONSE,
    );

    debug!("Loaded processes: finish boot sequence.\r");
    kernel::main(golf2, &mut chip, &mut PROCESSES, &golf2.ipc);
}

impl Platform for Golf {
    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
        where F: FnOnce(Option<&kernel::Driver>) -> R
    {
        match driver_num {
            capsules::console::DRIVER_NUM => f(Some(self.console)),
            capsules::gpio::DRIVER_NUM  => f(Some(self.gpio)),
//            2 => f(Some(self.digest)),
            capsules::alarm::DRIVER_NUM => f(Some(self.timer)),
//            4 => f(Some(self.aes)),
            capsules::rng::DRIVER_NUM   => f(Some(self.rng)),
            kernel::ipc::DRIVER_NUM     => f(Some(&self.ipc)),
            _ => f(None),
        }
    }
}
<|endoftext|>


<commit_before>use types::Value;

use super::array::Array;
use super::boolean::Boolean;
use super::class::Class;
use super::fixnum::Fixnum;
use super::hash::Hash;
use super::string::RString;
use super::symbol::Symbol;

use super::traits::Object;

#[derive(Clone)]
pub struct AnyObject {
    value: Value
}

impl AnyObject {
    pub fn as_array(&self) -> Array {
        Array::from(self.value)
    }

    pub fn as_boolean(&self) -> Boolean {
        Boolean::from(self.value)
    }

    pub fn as_class(&self) -> Class {
        Class::from(self.value)
    }

    pub fn as_fixnum(&self) -> Fixnum {
        Fixnum::from(self.value)
    }

    pub fn as_hash(&self) -> Hash {
        Hash::from(self.value)
    }

    pub fn as_string(&self) -> RString {
        RString::from(self.value)
    }

    pub fn as_symbol(&self) -> Symbol {
        Symbol::from(self.value)
    }
}

impl From<Value> for AnyObject {
    fn from(value: Value) -> Self {
        AnyObject {
            value: value
        }
    }
}

impl Object for AnyObject {
    fn value(&self) -> Value {
        self.value
    }
}
<commit_msg>Create documentation for AnyObject<commit_after>use types::Value;

use super::array::Array;
use super::boolean::Boolean;
use super::class::Class;
use super::fixnum::Fixnum;
use super::hash::Hash;
use super::string::RString;
use super::symbol::Symbol;

use super::traits::Object;

/// Representation of any Ruby object while its type is unknown
///
/// As Ruby is a dynamically typed language, at some points Ruru does not know the exact Ruby type
/// of the object. It happens in the following cases:
///
/// - Retrieving an object from array
///
/// - Retrieving an object from hash
///
/// - Receiving arguments to callback
///
/// - Initializing new instance of a class which is not present in Ruru
///
/// - and some other places you can find in Ruru documentation
///
/// In these cases you should cast `AnyObject` to the type to which the object belongs
/// using functions below.
///
/// # Examples
///
/// ## Retrieving an object from `Array`
///
/// ```
/// use ruru::{Array, Fixnum, VM};
/// # VM::init();
///
/// let array = Array::new().push(Fixnum::new(1));
/// let value = array.at(0).as_fixnum(); // `Array::at()` returns `AnyObject`
///
/// assert_eq!(value.to_i64(), 1);
/// ```
///
/// ## Retrieving an object from `Hash`
///
/// ```no_run
/// use ruru::{Fixnum, Hash, Symbol, VM};
/// # VM::init();
///
/// let mut hash = Hash::new();
///
/// hash.store(Symbol::new("key"), Fixnum::new(1));
///
/// // `Hash::at()` returns `AnyObject`
/// let value = hash.at(Symbol::new("key")).as_fixnum();
///
/// assert_eq!(value, Fixnum::new(1));
/// ```
///
/// ## Receiving arguments from Ruby to Ruru callback
///
/// ```no_run
/// use ruru::types::Argc;
/// use ruru::{AnyObject, Boolean, Class, RString, VM};
///
/// #[no_mangle]
/// pub extern fn string_eq(argc: Argc, argv: *const AnyObject, itself: RString) -> Boolean {
///     // `VM::parse_arguments()` returns `Vec<AnyObject>`
///     let argv = VM::parse_arguments(argc, argv);
///     let other_string = argv[0].as_string();
///
///     Boolean::new(itself.to_string() == other_string.to_string())
/// }
///
/// fn main() {
///     Class::from_existing("String").define_method("==", string_eq);
/// }
/// ```
#[derive(Clone)]
pub struct AnyObject {
    value: Value
}

impl AnyObject {
    /// Casts to `Array`.
    pub fn as_array(&self) -> Array {
        Array::from(self.value)
    }

    /// Casts to `Boolean`.
    pub fn as_boolean(&self) -> Boolean {
        Boolean::from(self.value)
    }

    /// Casts to `Class`.
    pub fn as_class(&self) -> Class {
        Class::from(self.value)
    }

    /// Casts to `Fixnum`.
    pub fn as_fixnum(&self) -> Fixnum {
        Fixnum::from(self.value)
    }

    /// Casts to `Hash`.
    pub fn as_hash(&self) -> Hash {
        Hash::from(self.value)
    }

    /// Casts to `String`.
    pub fn as_string(&self) -> RString {
        RString::from(self.value)
    }

    /// Casts to `Symbol`.
    pub fn as_symbol(&self) -> Symbol {
        Symbol::from(self.value)
    }
}

impl From<Value> for AnyObject {
    fn from(value: Value) -> Self {
        AnyObject {
            value: value
        }
    }
}

impl Object for AnyObject {
    fn value(&self) -> Value {
        self.value
    }
}
<|endoftext|>