<commit_before>use config::{Config, File, FileStoredFormat, Format, Map, Value, ValueKind};

fn main() {
    let config = Config::builder()
        .add_source(File::from_str("bad", MyFormat))
        .add_source(File::from_str("good", MyFormat))
        .build();

    match config {
        Ok(cfg) => println!("A config: {:#?}", cfg),
        Err(e) => println!("An error: {}", e),
    }
}

#[derive(Debug, Clone)]
pub struct MyFormat;

impl Format for MyFormat {
    fn parse(
        &self,
        uri: Option<&String>,
        text: &str,
    ) -> Result<Map<String, config::Value>, Box<dyn std::error::Error + Send + Sync>> {
        // Let's assume our format is somewhat crippled, but this is fine
        // In real life anything can be used here - nom, serde or other.
        //
        // For some more real-life examples refer to format implementation within the library code
        let mut result = Map::new();

        if text == "good" {
            result.insert(
                "key".to_string(),
                Value::new(uri, ValueKind::String(text.into())),
            );
        } else {
            println!("Something went wrong in {:?}", uri);
        }

        Ok(result)
    }
}

// As crazy as it seems for config sourced from a string, legacy demands its sacrifice
// It is only required for File source, custom sources can use Format without caring for extensions
static MY_FORMAT_EXT: Vec<&'static str> = vec![];
impl FileStoredFormat for MyFormat {
    fn file_extensions(&self) -> &'static [&'static str] {
        &MY_FORMAT_EXT
    }
}
<commit_msg>reduce use of outdated language<commit_after>use config::{Config, File, FileStoredFormat, Format, Map, Value, ValueKind};

fn main() {
    let config = Config::builder()
        .add_source(File::from_str("bad", MyFormat))
        .add_source(File::from_str("good", MyFormat))
        .build();

    match config {
        Ok(cfg) => println!("A config: {:#?}", cfg),
        Err(e) => println!("An error: {}", e),
    }
}

#[derive(Debug, Clone)]
pub struct MyFormat;

impl Format for MyFormat {
    fn parse(
        &self,
        uri: Option<&String>,
        text: &str,
    ) -> Result<Map<String, config::Value>, Box<dyn std::error::Error + Send + Sync>> {
        // Let's assume our format is somewhat malformed, but this is fine
        // In real life anything can be used here - nom, serde or other.
        //
        // For some more real-life examples refer to format implementation within the library code
        let mut result = Map::new();

        if text == "good" {
            result.insert(
                "key".to_string(),
                Value::new(uri, ValueKind::String(text.into())),
            );
        } else {
            println!("Something went wrong in {:?}", uri);
        }

        Ok(result)
    }
}

// As strange as it seems for config sourced from a string, legacy demands its sacrifice
// It is only required for File source, custom sources can use Format without caring for extensions
static MY_FORMAT_EXT: Vec<&'static str> = vec![];
impl FileStoredFormat for MyFormat {
    fn file_extensions(&self) -> &'static [&'static str] {
        &MY_FORMAT_EXT
    }
}
<|endoftext|>


<commit_before>//! Logging scopes for slog-rs
//!
//! Logging scopes are convinience functionality for slog-rs that free user from manually passing
//! `Logger` objects around.
//!
//! Set of macros is also provided as an alternative to original `slog` crate macros, for logging
//! directly to `Logger` of the current logging scope.
//!
//! Note: Part of a `slog` logging philosophy is ability to freelly express logging contexts
//! acording to logical structure, rather than code structure. By using logging scopes logging
//! context is tied to code flow again, which is less expressive.
//!
//! ```
//! #[macro_use(o, slog_info, slog_log)]
//! extern crate slog;
//! #[macro_use]
//! extern crate slog_scope;
//! extern crate slog_term;
//!
//! use slog::DrainExt;
//!
//! fn foo() {
//!     slog_info!(slog_scope::logger(), "foo");
//!     info!("foo"); // Same as above, but more ergonomic.
//! }
//!
//! fn main() {
//!     let log = slog::Logger::root(slog_term::streamer().stderr().build().fuse(), o!("version" => "0.5"));
//!
//!     slog_scope::set_global_logger(log);
//!     slog_scope::scope(slog_scope::logger().new(o!("scope" => "1")),
//!         || foo()
//!     );
//! }

#![warn(missing_docs)]

#[macro_use(o, slog_log, slog_trace, slog_debug, slog_info, slog_warn, slog_error)]
extern crate slog;
#[macro_use]
extern crate lazy_static;
extern crate crossbeam;

use slog::*;

use std::sync::Arc;
use std::cell::RefCell;
use crossbeam::sync::ArcCell;

/// Log a critical level message using current scope logger
#[macro_export] macro_rules! crit( ($($args:tt)+) => { slog_crit![$crate::logger(), $($args)+]; };);
/// Log a error level message using current scope logger
#[macro_export] macro_rules! error( ($($args:tt)+) => { slog_error![$crate::logger(), $($args)+]; };);
/// Log a warning level message using current scope logger
#[macro_export] macro_rules! warn( ($($args:tt)+) => { slog_warn![$crate::logger(), $($args)+]; };);
/// Log a info level message using current scope logger
#[macro_export] macro_rules! info( ($($args:tt)+) => { slog_info![$crate::logger(), $($args)+]; };);
/// Log a debug level message using current scope logger
#[macro_export] macro_rules! debug( ($($args:tt)+) => { slog_debug![$crate::logger(), $($args)+]; };);
/// Log a trace level message using current scope logger
#[macro_export] macro_rules! trace( ($($args:tt)+) => { slog_trace![$crate::logger(), $($args)+]; };);

thread_local! {
    static TL_SCOPES: RefCell<Vec<slog::Logger>> = RefCell::new(Vec::with_capacity(8))
}

lazy_static! {
    static ref GLOBAL_LOGGER : ArcCell<slog::Logger> = ArcCell::new(
        Arc::new(
            slog::Logger::root(slog::Discard, o!())
        )
    );
}

/// Set global `Logger` that is returned by calls like `logger()` outside of any logging scope.
pub fn set_global_logger(l: slog::Logger) {
    let _ = GLOBAL_LOGGER.set(Arc::new(l));
}

struct ScopeGuard;

impl ScopeGuard {
    fn new(logger: slog::Logger) -> Self {
        TL_SCOPES.with(|s| {
            s.borrow_mut().push(logger);
        });

        ScopeGuard
    }
}

impl Drop for ScopeGuard {
    fn drop(&mut self) {
        TL_SCOPES.with(|s| {
            s.borrow_mut().pop().expect("TL_SCOPES should contain a logger");
        })
    }
}

/// Access the `Logger` for the current logging scope
pub fn logger() -> Logger {
    TL_SCOPES.with(|s| {
        let s = s.borrow();
        match s.last() {
          Some(logger) => logger.clone(),
          None => (*GLOBAL_LOGGER.get()).clone(),
        }
    })
}

/// Execute code in a logging scope
///
/// Logging scopes allow using a `slog::Logger` without explicitly
/// passing it in the code.
///
/// At any time current active `Logger` for a given thread can be retrived
/// with `logger()` call.
///
/// Logging scopes can be nested and are panic safe.
///
/// `logger` is the `Logger` to use during the duration of `f`.
/// `with_current_logger` can be used to build it as a child of currently active
/// logger.
///
/// `f` is a code to be executed in the logging scope.
///
/// Note: Thread scopes are thread-local. Each newly spawned thread starts
/// with a global logger, as a current logger.
pub fn scope<SF, R>(logger: slog::Logger, f: SF) -> R
    where SF: FnOnce() -> R
{
    let _guard = ScopeGuard::new(logger);
    f()
}
<commit_msg>chore(scope): Tiny documentation fix.<commit_after>//! Logging scopes for slog-rs
//!
//! Logging scopes are convinience functionality for slog-rs to free user from manually passing
//! `Logger` objects around.
//!
//! Set of macros is also provided as an alternative to original `slog` crate macros, for logging
//! directly to `Logger` of the current logging scope.
//!
//! Note: Part of a `slog` logging philosophy is ability to freelly express logging contexts
//! acording to logical structure, rather than code structure. By using logging scopes logging
//! context is tied to code flow again, which is less expressive.
//!
//! ```
//! #[macro_use(o, slog_info, slog_log)]
//! extern crate slog;
//! #[macro_use]
//! extern crate slog_scope;
//! extern crate slog_term;
//!
//! use slog::DrainExt;
//!
//! fn foo() {
//!     slog_info!(slog_scope::logger(), "foo");
//!     info!("foo"); // Same as above, but more ergonomic.
//! }
//!
//! fn main() {
//!     let log = slog::Logger::root(slog_term::streamer().stderr().build().fuse(), o!("version" => "0.5"));
//!
//!     slog_scope::set_global_logger(log);
//!     slog_scope::scope(slog_scope::logger().new(o!("scope" => "1")),
//!         || foo()
//!     );
//! }

#![warn(missing_docs)]

#[macro_use(o, slog_log, slog_trace, slog_debug, slog_info, slog_warn, slog_error)]
extern crate slog;
#[macro_use]
extern crate lazy_static;
extern crate crossbeam;

use slog::*;

use std::sync::Arc;
use std::cell::RefCell;
use crossbeam::sync::ArcCell;

/// Log a critical level message using current scope logger
#[macro_export] macro_rules! crit( ($($args:tt)+) => { slog_crit![$crate::logger(), $($args)+]; };);
/// Log a error level message using current scope logger
#[macro_export] macro_rules! error( ($($args:tt)+) => { slog_error![$crate::logger(), $($args)+]; };);
/// Log a warning level message using current scope logger
#[macro_export] macro_rules! warn( ($($args:tt)+) => { slog_warn![$crate::logger(), $($args)+]; };);
/// Log a info level message using current scope logger
#[macro_export] macro_rules! info( ($($args:tt)+) => { slog_info![$crate::logger(), $($args)+]; };);
/// Log a debug level message using current scope logger
#[macro_export] macro_rules! debug( ($($args:tt)+) => { slog_debug![$crate::logger(), $($args)+]; };);
/// Log a trace level message using current scope logger
#[macro_export] macro_rules! trace( ($($args:tt)+) => { slog_trace![$crate::logger(), $($args)+]; };);

thread_local! {
    static TL_SCOPES: RefCell<Vec<slog::Logger>> = RefCell::new(Vec::with_capacity(8))
}

lazy_static! {
    static ref GLOBAL_LOGGER : ArcCell<slog::Logger> = ArcCell::new(
        Arc::new(
            slog::Logger::root(slog::Discard, o!())
        )
    );
}

/// Set global `Logger` that is returned by calls like `logger()` outside of any logging scope.
pub fn set_global_logger(l: slog::Logger) {
    let _ = GLOBAL_LOGGER.set(Arc::new(l));
}

struct ScopeGuard;

impl ScopeGuard {
    fn new(logger: slog::Logger) -> Self {
        TL_SCOPES.with(|s| {
            s.borrow_mut().push(logger);
        });

        ScopeGuard
    }
}

impl Drop for ScopeGuard {
    fn drop(&mut self) {
        TL_SCOPES.with(|s| {
            s.borrow_mut().pop().expect("TL_SCOPES should contain a logger");
        })
    }
}

/// Access the `Logger` for the current logging scope
pub fn logger() -> Logger {
    TL_SCOPES.with(|s| {
        let s = s.borrow();
        match s.last() {
          Some(logger) => logger.clone(),
          None => (*GLOBAL_LOGGER.get()).clone(),
        }
    })
}

/// Execute code in a logging scope
///
/// Logging scopes allow using a `slog::Logger` without explicitly
/// passing it in the code.
///
/// At any time current active `Logger` for a given thread can be retrived
/// with `logger()` call.
///
/// Logging scopes can be nested and are panic safe.
///
/// `logger` is the `Logger` to use during the duration of `f`.
/// `with_current_logger` can be used to build it as a child of currently active
/// logger.
///
/// `f` is a code to be executed in the logging scope.
///
/// Note: Thread scopes are thread-local. Each newly spawned thread starts
/// with a global logger, as a current logger.
pub fn scope<SF, R>(logger: slog::Logger, f: SF) -> R
    where SF: FnOnce() -> R
{
    let _guard = ScopeGuard::new(logger);
    f()
}
<|endoftext|>


<commit_before>// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::{Ok, Err};
    use slice::SliceExt;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v.slice_from_mut(read));
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0u8; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0u8; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

        static GETRANDOM_CHECKED: AtomicBool = ATOMIC_BOOL_INIT;
        static GETRANDOM_AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

        if !GETRANDOM_CHECKED.load(Ordering::Relaxed) {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Ordering::Relaxed);
            GETRANDOM_CHECKED.store(true, Ordering::Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Ordering::Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::Sync;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    unsafe impl Sync for *const SecRandom {}

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::v1::*;

    use sync::mpsc::channel;
    use rand::Rng;
    use super::OsRng;
    use thread::Thread;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8; 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);

            Thread::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv().unwrap();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                Thread::yield_now();
                let mut v = [0u8; 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    Thread::yield_now();
                    r.next_u64();
                    Thread::yield_now();
                    r.fill_bytes(&mut v);
                    Thread::yield_now();
                }
            }).detach();
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(()).unwrap();
        }
    }
}
<commit_msg>rollup merge of #20482: kmcallister/macro-reform<commit_after>// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::Ok;
    use slice::SliceExt;
    use mem;
    use os::errno;

    // NOTE: for old macros; remove after the next snapshot
    #[cfg(stage0)] use result::Result::Err;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v.slice_from_mut(read));
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0u8; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0u8; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

        static GETRANDOM_CHECKED: AtomicBool = ATOMIC_BOOL_INIT;
        static GETRANDOM_AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

        if !GETRANDOM_CHECKED.load(Ordering::Relaxed) {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Ordering::Relaxed);
            GETRANDOM_CHECKED.store(true, Ordering::Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Ordering::Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::Sync;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    unsafe impl Sync for *const SecRandom {}

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::v1::*;

    use sync::mpsc::channel;
    use rand::Rng;
    use super::OsRng;
    use thread::Thread;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8; 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);

            Thread::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv().unwrap();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                Thread::yield_now();
                let mut v = [0u8; 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    Thread::yield_now();
                    r.next_u64();
                    Thread::yield_now();
                    r.fill_bytes(&mut v);
                    Thread::yield_now();
                }
            }).detach();
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(()).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_must_use)]

extern crate forth;

use forth::{Forth, Error};

#[test]
fn no_input_no_stack() {
    assert_eq!("", Forth::new().format_stack());
}

#[test]
#[ignore]
fn numbers_just_get_pushed_onto_the_stack() {
    let mut f = Forth::new();
    f.eval("1 2 3 4 5 -1");
    assert_eq!("1 2 3 4 5 -1", f.format_stack());
}

#[test]
#[ignore]
fn non_word_characters_are_separators() {
    let mut f = Forth::new();
    // Note the Ogham Space Mark ( ), this is a spacing character.
    f.eval("1\u{0000}2\u{0001}3\n4\r5 6\t7");
    assert_eq!("1 2 3 4 5 6 7", f.format_stack());
}

#[test]
#[ignore]
fn basic_arithmetic_1() {
    let mut f = Forth::new();
    f.eval("1 2 + 4 -");
    assert_eq!("-1", f.format_stack());
}

#[test]
#[ignore]
fn basic_arithmetic_2() {
    let mut f = Forth::new();
    f.eval("2 4 * 3 /");
    assert_eq!("2", f.format_stack());
}

#[test]
#[ignore]
fn addition_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("+")
    );
}

#[test]
#[ignore]
fn subtraction_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("-")
    );
}

#[test]
#[ignore]
fn multiplication_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("*")
    );
}

#[test]
#[ignore]
fn division_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("/")
    );
}

#[test]
#[ignore]
fn division_by_zero() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::DivisionByZero),
        f.eval("4 2 2 - /")
    );
}

#[test]
#[ignore]
fn dup() {
    let mut f = Forth::new();
    f.eval("1 DUP");
    assert_eq!("1 1", f.format_stack());
}

#[test]
#[ignore]
fn dup_case_insensitive() {
    let mut f = Forth::new();
    f.eval("1 Dup");
    assert_eq!("1 1", f.format_stack());
}

#[test]
#[ignore]
fn dup_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("dup")
    );
}

#[test]
#[ignore]
fn drop() {
    let mut f = Forth::new();
    f.eval("1 drop");
    assert_eq!("", f.format_stack());
}

#[test]
#[ignore]
fn drop_with_two() {
    let mut f = Forth::new();
    f.eval("1 2 drop");
    assert_eq!("1", f.format_stack());
}

#[test]
#[ignore]
fn drop_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("drop")
    );
}

#[test]
#[ignore]
fn swap() {
    let mut f = Forth::new();
    f.eval("1 2 swap");
    assert_eq!("2 1", f.format_stack());
}

#[test]
#[ignore]
fn swap_with_three() {
    let mut f = Forth::new();
    f.eval("1 2 3 swap");
    assert_eq!("1 3 2", f.format_stack());
}

#[test]
#[ignore]
fn swap_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("1 swap")
    );
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("swap")
    );
}

#[test]
#[ignore]
fn over() {
    let mut f = Forth::new();
    f.eval("1 2 over");
    assert_eq!("1 2 1", f.format_stack());
}

#[test]
#[ignore]
fn over_with_three() {
    let mut f = Forth::new();
    f.eval("1 2 3 over");
    assert_eq!("1 2 3 2", f.format_stack());
}

#[test]
#[ignore]
fn over_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("1 over")
    );
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("over")
    );
}

#[test]
#[ignore]
fn defining_a_new_word() {
    let mut f = Forth::new();
    f.eval(": CoUnT 1 2 3 ;");
    f.eval("count COUNT");
    assert_eq!("1 2 3 1 2 3", f.format_stack());
}

#[test]
#[ignore]
fn redefining_an_existing_word() {
    let mut f = Forth::new();
    f.eval(": foo dup ;");
    f.eval(": foo dup dup ;");
    f.eval("1 foo");
    assert_eq!("1 1 1", f.format_stack());
}

#[test]
#[ignore]
fn redefining_an_existing_built_in_word() {
    let mut f = Forth::new();
    f.eval(": swap dup ;");
    f.eval("1 swap");
    assert_eq!("1 1", f.format_stack());
}

#[test]
#[ignore]
fn defining_words_with_odd_characters() {
    let mut f = Forth::new();
    f.eval(": € 220371 ; €");
    assert_eq!("220371", f.format_stack());
}

#[test]
#[ignore]
fn defining_a_number() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::InvalidWord),
        f.eval(": 1 2 ;")
    );
}

#[test]
#[ignore]
fn malformed_word_definition() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::InvalidWord),
        f.eval(":")
    );
    assert_eq!(
        Err(Error::InvalidWord),
        f.eval(": foo")
    );
    assert_eq!(
        Err(Error::InvalidWord),
        f.eval(": foo 1")
    );
}

#[test]
#[ignore]
fn calling_non_existing_word() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::UnknownWord),
        f.eval("1 foo")
    );
}
<commit_msg>forth: assert that eval() returns ok where it should (#296)<commit_after>extern crate forth;

use forth::{Forth, Error};

#[test]
fn no_input_no_stack() {
    assert_eq!("", Forth::new().format_stack());
}

#[test]
#[ignore]
fn numbers_just_get_pushed_onto_the_stack() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 3 4 5 -1").is_ok());
    assert_eq!("1 2 3 4 5 -1", f.format_stack());
}

#[test]
#[ignore]
fn non_word_characters_are_separators() {
    let mut f = Forth::new();
    // Note the Ogham Space Mark ( ), this is a spacing character.
    assert!(f.eval("1\u{0000}2\u{0001}3\n4\r5 6\t7").is_ok());
    assert_eq!("1 2 3 4 5 6 7", f.format_stack());
}

#[test]
#[ignore]
fn basic_arithmetic_1() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 + 4 -").is_ok());
    assert_eq!("-1", f.format_stack());
}

#[test]
#[ignore]
fn basic_arithmetic_2() {
    let mut f = Forth::new();
    assert!(f.eval("2 4 * 3 /").is_ok());
    assert_eq!("2", f.format_stack());
}

#[test]
#[ignore]
fn addition_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("+")
    );
}

#[test]
#[ignore]
fn subtraction_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("-")
    );
}

#[test]
#[ignore]
fn multiplication_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("*")
    );
}

#[test]
#[ignore]
fn division_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("/")
    );
}

#[test]
#[ignore]
fn division_by_zero() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::DivisionByZero),
        f.eval("4 2 2 - /")
    );
}

#[test]
#[ignore]
fn dup() {
    let mut f = Forth::new();
    assert!(f.eval("1 DUP").is_ok());
    assert_eq!("1 1", f.format_stack());
}

#[test]
#[ignore]
fn dup_case_insensitive() {
    let mut f = Forth::new();
    assert!(f.eval("1 Dup").is_ok());
    assert_eq!("1 1", f.format_stack());
}

#[test]
#[ignore]
fn dup_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("dup")
    );
}

#[test]
#[ignore]
fn drop() {
    let mut f = Forth::new();
    assert!(f.eval("1 drop").is_ok());
    assert_eq!("", f.format_stack());
}

#[test]
#[ignore]
fn drop_with_two() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 drop").is_ok());
    assert_eq!("1", f.format_stack());
}

#[test]
#[ignore]
fn drop_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("drop")
    );
}

#[test]
#[ignore]
fn swap() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 swap").is_ok());
    assert_eq!("2 1", f.format_stack());
}

#[test]
#[ignore]
fn swap_with_three() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 3 swap").is_ok());
    assert_eq!("1 3 2", f.format_stack());
}

#[test]
#[ignore]
fn swap_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("1 swap")
    );
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("swap")
    );
}

#[test]
#[ignore]
fn over() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 over").is_ok());
    assert_eq!("1 2 1", f.format_stack());
}

#[test]
#[ignore]
fn over_with_three() {
    let mut f = Forth::new();
    assert!(f.eval("1 2 3 over").is_ok());
    assert_eq!("1 2 3 2", f.format_stack());
}

#[test]
#[ignore]
fn over_error() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("1 over")
    );
    assert_eq!(
        Err(Error::StackUnderflow),
        f.eval("over")
    );
}

#[test]
#[ignore]
fn defining_a_new_word() {
    let mut f = Forth::new();
    assert!(f.eval(": CoUnT 1 2 3 ;").is_ok());
    assert!(f.eval("count COUNT").is_ok());
    assert_eq!("1 2 3 1 2 3", f.format_stack());
}

#[test]
#[ignore]
fn redefining_an_existing_word() {
    let mut f = Forth::new();
    assert!(f.eval(": foo dup ;").is_ok());
    assert!(f.eval(": foo dup dup ;").is_ok());
    assert!(f.eval("1 foo").is_ok());
    assert_eq!("1 1 1", f.format_stack());
}

#[test]
#[ignore]
fn redefining_an_existing_built_in_word() {
    let mut f = Forth::new();
    assert!(f.eval(": swap dup ;").is_ok());
    assert!(f.eval("1 swap").is_ok());
    assert_eq!("1 1", f.format_stack());
}

#[test]
#[ignore]
fn defining_words_with_odd_characters() {
    let mut f = Forth::new();
    assert!(f.eval(": € 220371 ; €").is_ok());
    assert_eq!("220371", f.format_stack());
}

#[test]
#[ignore]
fn defining_a_number() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::InvalidWord),
        f.eval(": 1 2 ;")
    );
}

#[test]
#[ignore]
fn malformed_word_definition() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::InvalidWord),
        f.eval(":")
    );
    assert_eq!(
        Err(Error::InvalidWord),
        f.eval(": foo")
    );
    assert_eq!(
        Err(Error::InvalidWord),
        f.eval(": foo 1")
    );
}

#[test]
#[ignore]
fn calling_non_existing_word() {
    let mut f = Forth::new();
    assert_eq!(
        Err(Error::UnknownWord),
        f.eval("1 foo")
    );
}
<|endoftext|>


<commit_before>// Copyright 2017-2020 Aron Heinecke
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! TS data handling functions

use super::*;
use chrono::naive::NaiveDate;

/// Update unknown_ts_ids table based on member clients
/// Handles known member client_id filtering
/// Allows doubled group IDs in member_clients
pub fn update_unknown_ts_ids(conn: &mut PooledConn, member_clients: &[usize]) -> Result<()> {
    create_temp_ts3_table(conn, "t_member_clients")?;
    {
        // insert every member client id into temp table, ignore multi-group clients
        let mut stmt =
            conn.prepare("INSERT IGNORE INTO `t_member_clients` (`client_id`) VALUES (?)")?;
        for client in member_clients {
            stmt.execute((&client,))?;
        }
    }

    {
        // filter everything out that has a member assigned
        conn.prep_exec("DELETE FROM t1 USING `t_member_clients` t1 INNER JOIN `ts_relation` t2 ON ( t1.client_id = t2.client_id )", ())?;
    }

    {
        // truncate unknown ts ids table
        conn.prep_exec("TRUNCATE `unknown_ts_ids`", ())?;
    }

    {
        // replace with correct values
        conn.prep_exec(
            "INSERT INTO `unknown_ts_ids` SELECT * FROM `t_member_clients`",
            (),
        )?;
    }

    Ok(())
}

/// Creates a temporary, single client_id column table with the specified name
fn create_temp_ts3_table(conn: &mut PooledConn, tbl_name: &'static str) -> Result<()> {
    let mut stmt = conn.prepare(format!(
        "CREATE TEMPORARY TABLE `{}` (
                        `client_id` int(11) NOT NULL PRIMARY KEY
                        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
                        ",
        tbl_name
    ))?;
    stmt.execute(())?;
    Ok(())
}

/// Update/Insert ts3 channel names
pub fn upsert_channels(conn: &mut PooledConn, channels: &[Channel]) -> Result<()> {
    let mut stmt = conn.prepare(
        "INSERT INTO `ts_channels` (`channel_id`,`name`) VALUES (?,?) ON DUPLICATE KEY UPDATE `name`=VALUES(`name`)",
    )?;
    for e in channels {
        stmt.execute((e.id, &e.name))?;
    }
    Ok(())
}

pub fn update_ts_names(conn: &mut PooledConn, names: &[TsClient]) -> Result<()> {
    let mut stm_names = conn.prepare(
        "INSERT INTO `ts_names` (`client_id`,`name`) VALUES (?,?) ON DUPLICATE KEY UPDATE `name` = VALUES(`name`)"
    )?;
    for e in names {
        stm_names.execute((e.clid, &e.name))?;
    }
    Ok(())
}

/// Update ts online times & names
pub fn update_ts_activity(
    conn: &mut PooledConn,
    date: &NaiveDate,
    times: &[TsActivity],
) -> Result<()> {
    let mut transaction = conn.start_transaction(false, None, None)?;
    {
        let mut stm_time = transaction.prepare(
        "INSERT INTO `ts_activity` (`date`,`client_id`,`channel_id`,`time`) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE `time` = `time`+VALUES(`time`)",
        )?;

        for e in times {
            stm_time.execute((date, e.client, e.channel, e.time))?;
        }
    }
    transaction.commit()?;
    Ok(())
}

#[cfg(test)]
mod test {
    use super::*;
    use db::testing::*;
    #[test]
    fn test_create_temp_ts3_table() {
        let (mut conn, _guard) = setup_db();
        create_temp_ts3_table(&mut conn, "temp_table").unwrap();
    }

    #[test]
    fn test_update_unknown_ts_ids() {
        let (mut conn, _guard) = setup_db();
        {
            // insert some ids into member ts relation
            let mut stmt = conn
                .prepare("INSERT INTO `ts_relation` (`client_id`,`id`) VALUES (?,1)")
                .unwrap();
            for i in 0..5 {
                stmt.execute((i,)).unwrap();
            }
        }

        {
            // insert some "old" values into the table
            let mut stmt = conn
                .prepare("INSERT INTO `unknown_ts_ids` (`client_id`) VALUES (?)")
                .unwrap();
            for i in 0..10 {
                stmt.execute((i,)).unwrap();
            }
        }

        // include double ids, allows two relevant groups for same client
        update_unknown_ts_ids(&mut conn, &vec![2, 3, 6, 4, 5, 6]).unwrap();

        let res = conn
            .prep_exec(
                "SELECT client_id FROM `unknown_ts_ids` ORDER BY client_id",
                (),
            )
            .unwrap();
        let data: Vec<isize> = res
            .map(|row| {
                let id = from_row(row.unwrap());
                id
            })
            .collect();

        assert_eq!(data, vec![5, 6]);
    }

    fn get_channels_ordered(conn: &mut PooledConn) -> Result<Vec<(ChannelID, String)>> {
        let res = conn.prep_exec(
            "SELECT channel_id,name FROM `ts_channels` ORDER BY channel_id",
            (),
        )?;
        let data: Vec<_> = res
            .map(|row| {
                let row: (ChannelID, String) = from_row(row.unwrap());
                row
            })
            .collect();
        Ok(data)
    }

    #[test]
    fn test_upsert_channels() {
        let (mut conn, _guard) = setup_db();

        let channels = vec![
            Channel {
                id: 2,
                name: "äüö2".to_string(),
            },
            Channel {
                id: 1,
                name: "äöü".to_string(),
            },
        ];

        upsert_channels(&mut conn, &channels).unwrap();

        let data = get_channels_ordered(&mut conn).unwrap();
        assert_eq!(data, vec![(1, "äöü".to_string()), (2, "äüö2".to_string())]);

        // we inserted, let's update one, insert another
        let channels = vec![
            Channel {
                id: 1,
                name: "123".to_string(),
            },
            Channel {
                id: 3,
                name: "345".to_string(),
            },
        ];
        upsert_channels(&mut conn, &channels).unwrap();
        let data = get_channels_ordered(&mut conn).unwrap();
        assert_eq!(
            data,
            vec![
                (1, "123".to_string()),
                (2, "äüö2".to_string()),
                (3, "345".to_string())
            ]
        );
    }

    fn get_ts_activity_ordered(conn: &mut PooledConn) -> Result<Vec<(NaiveDate,TsActivity)>> {
        let res = conn.prep_exec(
            "SELECT client_id,channel_id,time,date FROM `ts_activity` ORDER BY client_id,channel_id",
            (),
        )?;
        let data: Vec<_> = res
            .map(|row| {
                let (client, channel, time,date): (TsClDBID, ChannelID, i32, NaiveDate) = from_row(row.unwrap());
                (date,TsActivity {
                    client,
                    channel,
                    time,
                })
            })
            .collect();
        Ok(data)
    }

    #[test]
    fn test_update_ts_activity() {
        let (mut conn, _guard) = setup_db();

        let data = vec![
            TsActivity {
                client: 1,
                time: 1,
                channel: 1,
            },
            TsActivity {
                client: 1,
                time: 2,
                channel: 2,
            },
            TsActivity {
                client: 2,
                time: 3,
                channel: 1,
            },
        ];
        let date = NaiveDate::from_ymd(2020, 03, 29);
        update_ts_activity(&mut conn, &date, &data).unwrap();

        let res = get_ts_activity_ordered(&mut conn).unwrap();
        for i in 0..res.len() {
            let (r_date,act) = &res[i];
            assert_eq!(*r_date,date);
            assert_eq!(act,&data[i]);
        }

        // now update it
        let data = vec![
            TsActivity {
                client: 1,
                time: 10,
                channel: 1,
            },
            TsActivity {
                client: 2,
                time: 10,
                channel: 1,
            },
        ];
        update_ts_activity(&mut conn, &date, &data).unwrap();
        let res = get_ts_activity_ordered(&mut conn).unwrap();
        let expected: Vec<_> = vec![
            TsActivity {
                client: 1,
                time: 11,
                channel: 1,
            },
            TsActivity {
                client: 1,
                time: 2,
                channel: 2,
            },
            TsActivity {
                client: 2,
                time: 13,
                channel: 1,
            },
        ].drain(..).map(|v|(date.clone(),v)).collect();
        assert_eq!(expected,res);
    }

    fn get_ts_names_ordered(conn: &mut PooledConn) -> Result<Vec<TsClient>> {
        let res = conn.prep_exec(
            "SELECT client_id,name FROM `ts_names` ORDER BY client_id",
            (),
        )?;
        let data: Vec<_> = res
            .map(|row| {
                let (client, name): (TsClDBID, String) = from_row(row.unwrap());
                TsClient {
                    clid: client,
                    name,
                    channel: 0,
                    groups: Vec::new()
                }
            })
            .collect();
        Ok(data)
    }

    #[test]
    fn test_update_ts_names() {
        let (mut conn, _guard) = setup_db();
        let data = vec![
            TsClient {
                channel: 0,
                clid: 1,
                groups: Vec::new(),
                name: "abc".to_string(),
            },
            TsClient {
                channel: 0,
                clid: 2,
                groups: Vec::new(),
                name: "クマ".to_string(),
            },
        ];
        update_ts_names(&mut conn, &data).unwrap();

        let res = get_ts_names_ordered(&mut conn).unwrap();
        assert_eq!(res,data);
        // update
        let data = vec![
            TsClient {
                channel: 0,
                clid: 1,
                groups: Vec::new(),
                name: "def".to_string(),
            },
            TsClient {
                channel: 0,
                clid: 3,
                groups: Vec::new(),
                name: "123".to_string(),
            }
        ];
        update_ts_names(&mut conn, &data).unwrap();
        let res = get_ts_names_ordered(&mut conn).unwrap();
        let expected = vec![
            TsClient {
                channel: 0,
                clid: 1,
                groups: Vec::new(),
                name: "def".to_string(),
            },
            TsClient {
                channel: 0,
                clid: 2,
                groups: Vec::new(),
                name: "クマ".to_string(),
            },
            TsClient {
                channel: 0,
                clid: 3,
                groups: Vec::new(),
                name: "123".to_string(),
            }
        ];
        assert_eq!(res,expected);
    }
}
<commit_msg>cargo fmt<commit_after>// Copyright 2017-2020 Aron Heinecke
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! TS data handling functions

use super::*;
use chrono::naive::NaiveDate;

/// Update unknown_ts_ids table based on member clients
/// Handles known member client_id filtering
/// Allows doubled group IDs in member_clients
pub fn update_unknown_ts_ids(conn: &mut PooledConn, member_clients: &[usize]) -> Result<()> {
    create_temp_ts3_table(conn, "t_member_clients")?;
    {
        // insert every member client id into temp table, ignore multi-group clients
        let mut stmt =
            conn.prepare("INSERT IGNORE INTO `t_member_clients` (`client_id`) VALUES (?)")?;
        for client in member_clients {
            stmt.execute((&client,))?;
        }
    }

    {
        // filter everything out that has a member assigned
        conn.prep_exec("DELETE FROM t1 USING `t_member_clients` t1 INNER JOIN `ts_relation` t2 ON ( t1.client_id = t2.client_id )", ())?;
    }

    {
        // truncate unknown ts ids table
        conn.prep_exec("TRUNCATE `unknown_ts_ids`", ())?;
    }

    {
        // replace with correct values
        conn.prep_exec(
            "INSERT INTO `unknown_ts_ids` SELECT * FROM `t_member_clients`",
            (),
        )?;
    }

    Ok(())
}

/// Creates a temporary, single client_id column table with the specified name
fn create_temp_ts3_table(conn: &mut PooledConn, tbl_name: &'static str) -> Result<()> {
    let mut stmt = conn.prepare(format!(
        "CREATE TEMPORARY TABLE `{}` (
                        `client_id` int(11) NOT NULL PRIMARY KEY
                        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
                        ",
        tbl_name
    ))?;
    stmt.execute(())?;
    Ok(())
}

/// Update/Insert ts3 channel names
pub fn upsert_channels(conn: &mut PooledConn, channels: &[Channel]) -> Result<()> {
    let mut stmt = conn.prepare(
        "INSERT INTO `ts_channels` (`channel_id`,`name`) VALUES (?,?) ON DUPLICATE KEY UPDATE `name`=VALUES(`name`)",
    )?;
    for e in channels {
        stmt.execute((e.id, &e.name))?;
    }
    Ok(())
}

pub fn update_ts_names(conn: &mut PooledConn, names: &[TsClient]) -> Result<()> {
    let mut stm_names = conn.prepare(
        "INSERT INTO `ts_names` (`client_id`,`name`) VALUES (?,?) ON DUPLICATE KEY UPDATE `name` = VALUES(`name`)"
    )?;
    for e in names {
        stm_names.execute((e.clid, &e.name))?;
    }
    Ok(())
}

/// Update ts online times & names
pub fn update_ts_activity(
    conn: &mut PooledConn,
    date: &NaiveDate,
    times: &[TsActivity],
) -> Result<()> {
    let mut transaction = conn.start_transaction(false, None, None)?;
    {
        let mut stm_time = transaction.prepare(
        "INSERT INTO `ts_activity` (`date`,`client_id`,`channel_id`,`time`) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE `time` = `time`+VALUES(`time`)",
        )?;

        for e in times {
            stm_time.execute((date, e.client, e.channel, e.time))?;
        }
    }
    transaction.commit()?;
    Ok(())
}

#[cfg(test)]
mod test {
    use super::*;
    use db::testing::*;
    #[test]
    fn test_create_temp_ts3_table() {
        let (mut conn, _guard) = setup_db();
        create_temp_ts3_table(&mut conn, "temp_table").unwrap();
    }

    #[test]
    fn test_update_unknown_ts_ids() {
        let (mut conn, _guard) = setup_db();
        {
            // insert some ids into member ts relation
            let mut stmt = conn
                .prepare("INSERT INTO `ts_relation` (`client_id`,`id`) VALUES (?,1)")
                .unwrap();
            for i in 0..5 {
                stmt.execute((i,)).unwrap();
            }
        }

        {
            // insert some "old" values into the table
            let mut stmt = conn
                .prepare("INSERT INTO `unknown_ts_ids` (`client_id`) VALUES (?)")
                .unwrap();
            for i in 0..10 {
                stmt.execute((i,)).unwrap();
            }
        }

        // include double ids, allows two relevant groups for same client
        update_unknown_ts_ids(&mut conn, &vec![2, 3, 6, 4, 5, 6]).unwrap();

        let res = conn
            .prep_exec(
                "SELECT client_id FROM `unknown_ts_ids` ORDER BY client_id",
                (),
            )
            .unwrap();
        let data: Vec<isize> = res
            .map(|row| {
                let id = from_row(row.unwrap());
                id
            })
            .collect();

        assert_eq!(data, vec![5, 6]);
    }

    fn get_channels_ordered(conn: &mut PooledConn) -> Result<Vec<(ChannelID, String)>> {
        let res = conn.prep_exec(
            "SELECT channel_id,name FROM `ts_channels` ORDER BY channel_id",
            (),
        )?;
        let data: Vec<_> = res
            .map(|row| {
                let row: (ChannelID, String) = from_row(row.unwrap());
                row
            })
            .collect();
        Ok(data)
    }

    #[test]
    fn test_upsert_channels() {
        let (mut conn, _guard) = setup_db();

        let channels = vec![
            Channel {
                id: 2,
                name: "äüö2".to_string(),
            },
            Channel {
                id: 1,
                name: "äöü".to_string(),
            },
        ];

        upsert_channels(&mut conn, &channels).unwrap();

        let data = get_channels_ordered(&mut conn).unwrap();
        assert_eq!(data, vec![(1, "äöü".to_string()), (2, "äüö2".to_string())]);

        // we inserted, let's update one, insert another
        let channels = vec![
            Channel {
                id: 1,
                name: "123".to_string(),
            },
            Channel {
                id: 3,
                name: "345".to_string(),
            },
        ];
        upsert_channels(&mut conn, &channels).unwrap();
        let data = get_channels_ordered(&mut conn).unwrap();
        assert_eq!(
            data,
            vec![
                (1, "123".to_string()),
                (2, "äüö2".to_string()),
                (3, "345".to_string())
            ]
        );
    }

    fn get_ts_activity_ordered(conn: &mut PooledConn) -> Result<Vec<(NaiveDate, TsActivity)>> {
        let res = conn.prep_exec(
            "SELECT client_id,channel_id,time,date FROM `ts_activity` ORDER BY client_id,channel_id",
            (),
        )?;
        let data: Vec<_> = res
            .map(|row| {
                let (client, channel, time, date): (TsClDBID, ChannelID, i32, NaiveDate) =
                    from_row(row.unwrap());
                (
                    date,
                    TsActivity {
                        client,
                        channel,
                        time,
                    },
                )
            })
            .collect();
        Ok(data)
    }

    #[test]
    fn test_update_ts_activity() {
        let (mut conn, _guard) = setup_db();

        let data = vec![
            TsActivity {
                client: 1,
                time: 1,
                channel: 1,
            },
            TsActivity {
                client: 1,
                time: 2,
                channel: 2,
            },
            TsActivity {
                client: 2,
                time: 3,
                channel: 1,
            },
        ];
        let date = NaiveDate::from_ymd(2020, 03, 29);
        update_ts_activity(&mut conn, &date, &data).unwrap();

        let res = get_ts_activity_ordered(&mut conn).unwrap();
        for i in 0..res.len() {
            let (r_date, act) = &res[i];
            assert_eq!(*r_date, date);
            assert_eq!(act, &data[i]);
        }

        // now update it
        let data = vec![
            TsActivity {
                client: 1,
                time: 10,
                channel: 1,
            },
            TsActivity {
                client: 2,
                time: 10,
                channel: 1,
            },
        ];
        update_ts_activity(&mut conn, &date, &data).unwrap();
        let res = get_ts_activity_ordered(&mut conn).unwrap();
        let expected: Vec<_> = vec![
            TsActivity {
                client: 1,
                time: 11,
                channel: 1,
            },
            TsActivity {
                client: 1,
                time: 2,
                channel: 2,
            },
            TsActivity {
                client: 2,
                time: 13,
                channel: 1,
            },
        ]
        .drain(..)
        .map(|v| (date.clone(), v))
        .collect();
        assert_eq!(expected, res);
    }

    fn get_ts_names_ordered(conn: &mut PooledConn) -> Result<Vec<TsClient>> {
        let res = conn.prep_exec(
            "SELECT client_id,name FROM `ts_names` ORDER BY client_id",
            (),
        )?;
        let data: Vec<_> = res
            .map(|row| {
                let (client, name): (TsClDBID, String) = from_row(row.unwrap());
                TsClient {
                    clid: client,
                    name,
                    channel: 0,
                    groups: Vec::new(),
                }
            })
            .collect();
        Ok(data)
    }

    #[test]
    fn test_update_ts_names() {
        let (mut conn, _guard) = setup_db();
        let data = vec![
            TsClient {
                channel: 0,
                clid: 1,
                groups: Vec::new(),
                name: "abc".to_string(),
            },
            TsClient {
                channel: 0,
                clid: 2,
                groups: Vec::new(),
                name: "クマ".to_string(),
            },
        ];
        update_ts_names(&mut conn, &data).unwrap();

        let res = get_ts_names_ordered(&mut conn).unwrap();
        assert_eq!(res, data);
        // update
        let data = vec![
            TsClient {
                channel: 0,
                clid: 1,
                groups: Vec::new(),
                name: "def".to_string(),
            },
            TsClient {
                channel: 0,
                clid: 3,
                groups: Vec::new(),
                name: "123".to_string(),
            },
        ];
        update_ts_names(&mut conn, &data).unwrap();
        let res = get_ts_names_ordered(&mut conn).unwrap();
        let expected = vec![
            TsClient {
                channel: 0,
                clid: 1,
                groups: Vec::new(),
                name: "def".to_string(),
            },
            TsClient {
                channel: 0,
                clid: 2,
                groups: Vec::new(),
                name: "クマ".to_string(),
            },
            TsClient {
                channel: 0,
                clid: 3,
                groups: Vec::new(),
                name: "123".to_string(),
            },
        ];
        assert_eq!(res, expected);
    }
}
<|endoftext|>


<commit_before>extern crate extra;

use std::from_str::from_str;
use std::io::net::tcp::{TcpListener,TcpStream};
use std::io::{Acceptor,Listener};
use std::run::{Process,ProcessOptions};

use extra::url::Url;

// Note: Error handling could be improved
fn main() {
	let browserCommand = "firefox";
	let address = "127.0.0.1:7777";

	// Prepare a socket listening on localhost:7777
	let addr = from_str(address).expect(format!("Invalid address: {}", address));
	let listener = TcpListener::bind(addr).unwrap();
	let mut acceptor = listener.listen().unwrap();

	// Infinite loop to keep handling new connections.
	loop {
		let tcpStream = acceptor.accept().unwrap();
		debug!("Accepted new connection");
		spawn(proc() {
			handleClient(tcpStream, browserCommand)
		});
	}
}

// Accept a new connection and listen for URLs
fn handleClient(tcpStream: TcpStream, browserCommand: &'static str) {
	debug!("Spawned new task");

	let mut tcpStream = tcpStream;

	// Note that as soon as read_to_str() returns, everything sent
	// to the socket after this point will be discarded as once
	// we're done working with the content we've just read, the
	// tcpStream will be freed.
	let message = tcpStream.read_to_str().unwrap();

	// Iterate over the lines in the received message
	for line in message.lines() {
		debug!("Current line is: {}", line);

		// This tries to convert the line to a Url struct
		let url = from_str(line);

		// On failure it returns None; on success a valid URL
		match url {
			None     => { info!("No Url found") }
			Some(u)  => {
				debug!("Found Url in: {}", line);
				if checkUrl(&u) {
					spawnProcess(&u, browserCommand)
				}
			}
		}
	}
}

// Check that the URL is actually usable
fn checkUrl(u: &Url) -> bool {
	(u.scheme == ~"http" || u.scheme == ~"https" ) && u.host != ~""
}

// Spawn a browser to access the URL
fn spawnProcess(u: &Url, command: &'static str) {
	debug!("Spawning process {} {}", command, u.to_str());
	let pOptions = ProcessOptions::new();
	let mut child = Process::new(command, [u.to_str()], pOptions).unwrap();
	child.finish();
}
<commit_msg>Update for Rust 0.10<commit_after>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate url;

use std::from_str::from_str;
use std::io::net::tcp::{TcpListener,TcpStream};
use std::io::{Acceptor,Listener,Process};
use url::Url;

// Note: Error handling could be improved
fn main() {
	let browserCommand = "firefox";
	let address = "127.0.0.1:7777";

	// Prepare a socket listening on localhost:7777
	let addr = from_str(address).expect(format!("Invalid address: {}", address));
	let listener = TcpListener::bind(addr).unwrap();
	let mut acceptor = listener.listen().unwrap();

	// Infinite loop to keep handling new connections.
	loop {
		let tcpStream = acceptor.accept().unwrap();
		debug!("Accepted new connection");
		spawn(proc() {
			handleClient(tcpStream, browserCommand)
		});
	}
}

// Accept a new connection and listen for URLs
fn handleClient(tcpStream: TcpStream, browserCommand: &'static str) {
	debug!("Spawned new task");

	let mut tcpStream = tcpStream;

	// Note that as soon as read_to_str() returns, everything sent
	// to the socket after this point will be discarded as once
	// we're done working with the content we've just read, the
	// tcpStream will be freed.
	let message = tcpStream.read_to_str().unwrap();

	// Iterate over the lines in the received message
	for line in message.lines() {
		debug!("Current line is: {}", line);

		// This tries to convert the line to a Url struct
		let url = from_str(line);

		// On failure it returns None; on success a valid URL
		match url {
			None     => { info!("No Url found") }
			Some(u)  => {
				debug!("Found Url in: {}", line);
				if checkUrl(&u) {
					spawnProcess(&u, browserCommand)
				}
			}
		}
	}
}

// Check that the URL is actually usable
fn checkUrl(u: &Url) -> bool {
	(u.scheme == ~"http" || u.scheme == ~"https" ) && u.host != ~""
}

// Spawn a browser to access the URL
fn spawnProcess(u: &Url, command: &'static str) {
	debug!("Spawning process {} {}", command, u.to_str());
	let mut child = Process::new(command, [u.to_str()]).unwrap();
	child.wait();
}
<|endoftext|>


<commit_before>use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg};
use if_chain::if_chain;
use rustc::ty::DefIdTree;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_item, NestedVisitorMap, Visitor};
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{symbol::Symbol, BytePos};

declare_clippy_lint! {
    /// **What it does:** Checks for wildcard imports `use _::*`.
    ///
    /// **Why is this bad?** wildcard imports can polute the namespace. This is especially bad if
    /// you try to import something through a wildcard, that already has been imported by name from
    /// a different source:
    ///
    /// ```rust,ignore
    /// use crate1::foo; // Imports a function named foo
    /// use crate2::*; // Has a function named foo
    ///
    /// foo(); // Calls crate1::foo
    /// ```
    ///
    /// This can lead to confusing error messages at best and to unexpected behavior at worst.
    ///
    /// **Known problems:** If macros are imported through the wildcard, this macro is not included
    /// by the suggestion and has to be added by hand.
    ///
    /// **Example:**
    ///
    /// Bad:
    /// ```rust,ignore
    /// use crate1::*;
    ///
    /// foo();
    /// ```
    ///
    /// Good:
    /// ```rust,ignore
    /// use crate1::foo;
    ///
    /// foo();
    /// ```
    pub WILDCARD_IMPORTS,
    pedantic,
    "lint `use _::*` statements"
}

declare_lint_pass!(WildcardImports => [WILDCARD_IMPORTS]);

impl LateLintPass<'_, '_> for WildcardImports {
    fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item<'_>) {
        if item.vis.node.is_pub() || item.vis.node.is_pub_restricted() {
            return;
        }
        if_chain! {
            if !in_macro(item.span);
            if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
            if let Some(def_id) = use_path.res.opt_def_id();
            then {
                let hir = cx.tcx.hir();
                let parent_id = hir.get_parent_item(item.hir_id);
                let (items, in_module) = if parent_id == CRATE_HIR_ID {
                    let items = hir
                        .krate()
                        .module
                        .item_ids
                        .iter()
                        .map(|item_id| hir.get(item_id.id))
                        .filter_map(|node| {
                            if let Node::Item(item) = node {
                                Some(item)
                            } else {
                                None
                            }
                        })
                        .collect();
                    (items, true)
                } else if let Node::Item(item) = hir.get(parent_id) {
                    (vec![item], false)
                } else {
                    (vec![], false)
                };

                let mut import_used_visitor = ImportsUsedVisitor {
                    cx,
                    wildcard_def_id: def_id,
                    in_module,
                    used_imports: FxHashSet::default(),
                };
                for item in items {
                    import_used_visitor.visit_item(item);
                }

                if !import_used_visitor.used_imports.is_empty() {
                    let module_name = use_path
                        .segments
                        .iter()
                        .last()
                        .expect("path has at least one segment")
                        .ident
                        .name;

                    let mut applicability = Applicability::MachineApplicable;
                    let import_source = snippet_with_applicability(cx, use_path.span, "..", &mut applicability);
                    let (span, braced_glob) = if import_source.is_empty() {
                        // This is a `_::{_, *}` import
                        // Probably it's `_::{self, *}`, in that case we don't want to suggest to
                        // import `self`.
                        // If it is something else, we also don't want to include `self` in the
                        // suggestion, since either it was imported through another use statement:
                        // ```
                        // use foo::bar;
                        // use foo::bar::{baz, *};
                        // ```
                        // or it couldn't be used anywhere.
                        (
                            use_path.span.with_hi(use_path.span.hi() + BytePos(1)),
                            true,
                        )
                    } else {
                        (
                            use_path.span.with_hi(use_path.span.hi() + BytePos(3)),
                            false,
                        )
                    };

                    let imports_string = if import_used_visitor.used_imports.len() == 1 {
                        // We don't need to check for accidental suggesting the module name instead
                        // of `self` here, since if `used_imports.len() == 1`, and the only usage
                        // is `self`, then it's not through a `*` and if there is a `*`, it gets
                        // already linted by `unused_imports` of rustc.
                        import_used_visitor.used_imports.iter().next().unwrap().to_string()
                    } else {
                        let mut imports = import_used_visitor
                            .used_imports
                            .iter()
                            .filter_map(|import_name| {
                                if braced_glob && *import_name == module_name {
                                    None
                                } else if *import_name == module_name {
                                    Some("self".to_string())
                                } else {
                                    Some(import_name.to_string())
                                }
                            })
                            .collect::<Vec<_>>();
                        imports.sort();
                        if braced_glob {
                            imports.join(", ")
                        } else {
                            format!("{{{}}}", imports.join(", "))
                        }
                    };

                    let sugg = if import_source.is_empty() {
                        imports_string
                    } else {
                        format!("{}::{}", import_source, imports_string)
                    };

                    span_lint_and_sugg(
                        cx,
                        WILDCARD_IMPORTS,
                        span,
                        "usage of wildcard import",
                        "try",
                        sugg,
                        applicability,
                    );
                }
            }
        }
    }
}

struct ImportsUsedVisitor<'a, 'tcx> {
    cx: &'a LateContext<'a, 'tcx>,
    wildcard_def_id: def_id::DefId,
    in_module: bool,
    used_imports: FxHashSet<Symbol>,
}

impl<'a, 'tcx> Visitor<'tcx> for ImportsUsedVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_item(&mut self, item: &'tcx Item<'_>) {
        match item.kind {
            ItemKind::Use(..) => {},
            ItemKind::Mod(..) if self.in_module => {},
            ItemKind::Mod(..) => self.in_module = true,
            _ => walk_item(self, item),
        }
    }

    fn visit_path(&mut self, path: &Path<'_>, _: HirId) {
        if let Some(def_id) = self.first_path_segment_def_id(path) {
            // Check if the function/enum/... was exported
            if let Some(exports) = self.cx.tcx.module_exports(self.wildcard_def_id) {
                for export in exports {
                    if let Some(export_def_id) = export.res.opt_def_id() {
                        if export_def_id == def_id {
                            self.used_imports.insert(
                                path.segments
                                    .iter()
                                    .next()
                                    .expect("path has at least one segment")
                                    .ident
                                    .name,
                            );
                            return;
                        }
                    }
                }
            }

            // Check if it is directly in the module
            if let Some(parent_def_id) = self.cx.tcx.parent(def_id) {
                if self.wildcard_def_id == parent_def_id {
                    self.used_imports.insert(
                        path.segments
                            .iter()
                            .next()
                            .expect("path has at least one segment")
                            .ident
                            .name,
                    );
                }
            }
        }
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
        NestedVisitorMap::All(&self.cx.tcx.hir())
    }
}

impl ImportsUsedVisitor<'_, '_> {
    fn skip_def_id(&self, def_id: DefId) -> DefId {
        let def_key = self.cx.tcx.def_key(def_id);
        match def_key.disambiguated_data.data {
            DefPathData::Ctor => {
                if let Some(def_id) = self.cx.tcx.parent(def_id) {
                    self.skip_def_id(def_id)
                } else {
                    def_id
                }
            },
            _ => def_id,
        }
    }

    fn first_path_segment_def_id(&self, path: &Path<'_>) -> Option<DefId> {
        path.res.opt_def_id().and_then(|mut def_id| {
            def_id = self.skip_def_id(def_id);
            for _ in path.segments.iter().skip(1) {
                def_id = self.skip_def_id(def_id);
                if let Some(parent_def_id) = self.cx.tcx.parent(def_id) {
                    def_id = parent_def_id;
                } else {
                    return None;
                }
            }

            Some(def_id)
        })
    }
}
<commit_msg>Let's do it the easy way<commit_after>use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::BytePos;

declare_clippy_lint! {
    /// **What it does:** Checks for wildcard imports `use _::*`.
    ///
    /// **Why is this bad?** wildcard imports can polute the namespace. This is especially bad if
    /// you try to import something through a wildcard, that already has been imported by name from
    /// a different source:
    ///
    /// ```rust,ignore
    /// use crate1::foo; // Imports a function named foo
    /// use crate2::*; // Has a function named foo
    ///
    /// foo(); // Calls crate1::foo
    /// ```
    ///
    /// This can lead to confusing error messages at best and to unexpected behavior at worst.
    ///
    /// **Known problems:** If macros are imported through the wildcard, this macro is not included
    /// by the suggestion and has to be added by hand.
    ///
    /// **Example:**
    ///
    /// Bad:
    /// ```rust,ignore
    /// use crate1::*;
    ///
    /// foo();
    /// ```
    ///
    /// Good:
    /// ```rust,ignore
    /// use crate1::foo;
    ///
    /// foo();
    /// ```
    pub WILDCARD_IMPORTS,
    pedantic,
    "lint `use _::*` statements"
}

declare_lint_pass!(WildcardImports => [WILDCARD_IMPORTS]);

impl LateLintPass<'_, '_> for WildcardImports {
    fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item<'_>) {
        if item.vis.node.is_pub() || item.vis.node.is_pub_restricted() {
            return;
        }
        if_chain! {
            if !in_macro(item.span);
            if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
            let used_imports = cx.tcx.names_imported_by_glob_use(item.hir_id.owner_def_id());
            if !used_imports.is_empty(); // Already handled by `unused_imports`
            then {
                let mut applicability = Applicability::MachineApplicable;
                let import_source = snippet_with_applicability(cx, use_path.span, "..", &mut applicability);
                let (span, braced_glob) = if import_source.is_empty() {
                    // This is a `_::{_, *}` import
                    (
                        use_path.span.with_hi(use_path.span.hi() + BytePos(1)),
                        true,
                    )
                } else {
                    (
                        use_path.span.with_hi(use_path.span.hi() + BytePos(3)),
                        false,
                    )
                };

                let imports_string = if used_imports.len() == 1 {
                    used_imports.iter().next().unwrap().to_string()
                } else {
                    let mut imports = used_imports
                        .iter()
                        .map(ToString::to_string)
                        .collect::<Vec<_>>();
                    imports.sort();
                    if braced_glob {
                        imports.join(", ")
                    } else {
                        format!("{{{}}}", imports.join(", "))
                    }
                };

                let sugg = if import_source.is_empty() {
                    imports_string
                } else {
                    format!("{}::{}", import_source, imports_string)
                };

                span_lint_and_sugg(
                    cx,
                    WILDCARD_IMPORTS,
                    span,
                    "usage of wildcard import",
                    "try",
                    sugg,
                    applicability,
                );
            }
        }
    }
}
<|endoftext|>