<commit_before>use std::ffi::CString;
use std::os::raw::{c_void, c_long};
use std::ptr;
use std::rc::Rc;
use winapi;
use winapi::um::d3d11::ID3D11Device;
use winapi::um::d3d11::ID3D11Texture2D;

pub struct SharedEglThings {
    functions: Egl,
    display: types::EGLDisplay,
    config: types::EGLConfig,
}

fn cast_attributes(slice: &[types::EGLenum]) -> &EGLint {
    unsafe {
        &*(slice.as_ptr() as *const EGLint)
    }
}

macro_rules! attributes {
    ($( $key: expr => $value: expr, )*) => {
        cast_attributes(&[
            $( $key, $value, )*
            NONE,
        ])
    }
}

impl SharedEglThings {
    pub unsafe fn new(d3d_device: *mut ID3D11Device) -> Rc<Self> {
        let functions = Egl;

        let device = functions.check_mut_ptr(eglCreateDeviceANGLE(
            D3D11_DEVICE_ANGLE,
            d3d_device,
            ptr::null(),
        ));
        let display = functions.check_ptr(functions.GetPlatformDisplayEXT(
            PLATFORM_DEVICE_EXT,
            device,
            attributes! [
                EXPERIMENTAL_PRESENT_PATH_ANGLE => EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE,
            ],
        ));
        functions.check_bool(functions.Initialize(display, ptr::null_mut(), ptr::null_mut()));

        // Adapted from
        // https://searchfox.org/mozilla-central/rev/056a4057/gfx/gl/GLContextProviderEGL.cpp#635
        let mut configs = [ptr::null(); 64];
        let mut num_configs = 0;
        functions.check_bool(functions.ChooseConfig(
            display,
            attributes! [
                SURFACE_TYPE => WINDOW_BIT,
                RENDERABLE_TYPE => OPENGL_ES2_BIT,
                RED_SIZE => 8,
                GREEN_SIZE => 8,
                BLUE_SIZE => 8,
                ALPHA_SIZE => 8,
            ],
            configs.as_mut_ptr(),
            configs.len() as i32,
            &mut num_configs,
        ));
        assert!(num_configs >= 0);
        // FIXME: pick a preferable config?
        let config = configs[0];

        Rc::new(SharedEglThings { functions, display, config })
    }

    pub fn get_proc_address(&self, name: &str) -> *const c_void {
        let name = CString::new(name.as_bytes()).unwrap();
        unsafe {
            self.functions.GetProcAddress(name.as_ptr()) as *const _ as _
        }
    }
}

pub struct PerVisualEglThings {
    shared: Rc<SharedEglThings>,
    context: types::EGLContext,
    surface: types::EGLSurface,
}

impl PerVisualEglThings {
    pub unsafe fn new(shared: Rc<SharedEglThings>, buffer: *const ID3D11Texture2D,
           width: u32, height: u32)
           -> Self {
        let shared = shared.clone();
        let context = shared.functions.check_ptr(shared.functions.CreateContext(
            shared.display,
            shared.config,
            NO_CONTEXT,
            attributes![],
        ));

        let surface = shared.functions.check_ptr(shared.functions.CreatePbufferFromClientBuffer(
            shared.display,
            D3D_TEXTURE_ANGLE,
            buffer as types::EGLClientBuffer,
            shared.config,
            attributes! [
                WIDTH => width,
                HEIGHT => height,
                FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE => TRUE,
            ],
        ));

        PerVisualEglThings { shared, context, surface }
    }

    pub fn make_current(&self) {
        unsafe {
            self.shared.functions.check_bool(self.shared.functions.MakeCurrent(
                self.shared.display, self.surface, self.surface, self.context
            ))
        }
    }
}

impl Egl {
    fn check_error(&self) {
        unsafe {
            let error = self.GetError() as types::EGLenum;
            assert_eq!(error, SUCCESS, "0x{:x} != 0x{:x}", error, SUCCESS);
        }
    }

    fn check_ptr(&self, p: *const c_void) -> *const c_void {
        self.check_error();
        assert!(!p.is_null());
        p
    }

    fn check_mut_ptr(&self, p: *mut c_void) -> *mut c_void {
        self.check_error();
        assert!(!p.is_null());
        p
    }

    fn check_bool(&self, bool_result: types::EGLBoolean) {
        self.check_error();
        assert_eq!(bool_result, TRUE);
    }
}

// Adapted from https://github.com/tomaka/glutin/blob/1f3b8360cb/src/api/egl/ffi.rs
#[allow(non_camel_case_types)] pub type khronos_utime_nanoseconds_t = khronos_uint64_t;
#[allow(non_camel_case_types)] pub type khronos_uint64_t = u64;
#[allow(non_camel_case_types)] pub type khronos_ssize_t = c_long;
pub type EGLint = i32;
pub type EGLNativeDisplayType = *const c_void;
pub type EGLNativePixmapType = *const c_void;
pub type EGLNativeWindowType = winapi::shared::windef::HWND;
pub type NativeDisplayType = EGLNativeDisplayType;
pub type NativePixmapType = EGLNativePixmapType;
pub type NativeWindowType = EGLNativeWindowType;

include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs"));

// Adapted from https://chromium.googlesource.com/angle/angle/+/master/include/EGL/eglext_angle.h
type EGLDeviceEXT = *mut c_void;
const EXPERIMENTAL_PRESENT_PATH_ANGLE: types::EGLenum = 0x33A4;
const EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE: types::EGLenum = 0x33A9;
const D3D_TEXTURE_ANGLE: types::EGLenum = 0x33A3;
const FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: types::EGLenum = 0x33A6;

extern "C" {
    fn eglCreateDeviceANGLE(
        device_type: types::EGLenum,
        device: *mut ID3D11Device,
        attrib_list: *const types::EGLAttrib,
    ) -> EGLDeviceEXT;
}
<commit_msg>Destroy EGL things in Drop<commit_after>use std::ffi::CString;
use std::os::raw::{c_void, c_long};
use std::ptr;
use std::rc::Rc;
use winapi;
use winapi::um::d3d11::ID3D11Device;
use winapi::um::d3d11::ID3D11Texture2D;

pub struct SharedEglThings {
    functions: Egl,
    device: EGLDeviceEXT,
    display: types::EGLDisplay,
    config: types::EGLConfig,
}

fn cast_attributes(slice: &[types::EGLenum]) -> &EGLint {
    unsafe {
        &*(slice.as_ptr() as *const EGLint)
    }
}

macro_rules! attributes {
    ($( $key: expr => $value: expr, )*) => {
        cast_attributes(&[
            $( $key, $value, )*
            NONE,
        ])
    }
}

impl SharedEglThings {
    pub unsafe fn new(d3d_device: *mut ID3D11Device) -> Rc<Self> {
        let functions = Egl;

        let device = functions.check_mut_ptr(eglCreateDeviceANGLE(
            D3D11_DEVICE_ANGLE,
            d3d_device,
            ptr::null(),
        ));
        let display = functions.check_ptr(functions.GetPlatformDisplayEXT(
            PLATFORM_DEVICE_EXT,
            device,
            attributes! [
                EXPERIMENTAL_PRESENT_PATH_ANGLE => EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE,
            ],
        ));
        functions.check_bool(functions.Initialize(display, ptr::null_mut(), ptr::null_mut()));

        // Adapted from
        // https://searchfox.org/mozilla-central/rev/056a4057/gfx/gl/GLContextProviderEGL.cpp#635
        let mut configs = [ptr::null(); 64];
        let mut num_configs = 0;
        functions.check_bool(functions.ChooseConfig(
            display,
            attributes! [
                SURFACE_TYPE => WINDOW_BIT,
                RENDERABLE_TYPE => OPENGL_ES2_BIT,
                RED_SIZE => 8,
                GREEN_SIZE => 8,
                BLUE_SIZE => 8,
                ALPHA_SIZE => 8,
            ],
            configs.as_mut_ptr(),
            configs.len() as i32,
            &mut num_configs,
        ));
        assert!(num_configs >= 0);
        // FIXME: pick a preferable config?
        let config = configs[0];

        Rc::new(SharedEglThings { functions, device, display, config })
    }

    pub fn get_proc_address(&self, name: &str) -> *const c_void {
        let name = CString::new(name.as_bytes()).unwrap();
        unsafe {
            self.functions.GetProcAddress(name.as_ptr()) as *const _ as _
        }
    }
}

impl Drop for SharedEglThings {
    fn drop(&mut self) {
        unsafe {
            self.functions.check_bool(eglReleaseDeviceANGLE(self.device))
        }
    }
}

pub struct PerVisualEglThings {
    shared: Rc<SharedEglThings>,
    context: types::EGLContext,
    surface: types::EGLSurface,
}

impl PerVisualEglThings {
    pub unsafe fn new(shared: Rc<SharedEglThings>, buffer: *const ID3D11Texture2D,
           width: u32, height: u32)
           -> Self {
        let shared = shared.clone();
        let context = shared.functions.check_ptr(shared.functions.CreateContext(
            shared.display,
            shared.config,
            NO_CONTEXT,
            attributes![],
        ));

        let surface = shared.functions.check_ptr(shared.functions.CreatePbufferFromClientBuffer(
            shared.display,
            D3D_TEXTURE_ANGLE,
            buffer as types::EGLClientBuffer,
            shared.config,
            attributes! [
                WIDTH => width,
                HEIGHT => height,
                FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE => TRUE,
            ],
        ));

        PerVisualEglThings { shared, context, surface }
    }

    pub fn make_current(&self) {
        unsafe {
            self.shared.functions.check_bool(self.shared.functions.MakeCurrent(
                self.shared.display, self.surface, self.surface, self.context,
            ))
        }
    }
}

impl Drop for PerVisualEglThings {
    fn drop(&mut self) {
        unsafe {
            if self.shared.functions.GetCurrentContext() == self.context {
                // release the current context without assigning a new one
                self.shared.functions.check_bool(self.shared.functions.MakeCurrent(
                    self.shared.display, NO_SURFACE, NO_SURFACE, NO_CONTEXT,
                ))
            }
            self.shared.functions.check_bool(self.shared.functions.DestroyContext(
                self.shared.display, self.context,
            ));
            self.shared.functions.check_bool(self.shared.functions.DestroySurface(
                self.shared.display, self.surface,
            ));
        }
    }
}

impl Egl {
    fn check_error(&self) {
        unsafe {
            let error = self.GetError() as types::EGLenum;
            assert_eq!(error, SUCCESS, "0x{:x} != 0x{:x}", error, SUCCESS);
        }
    }

    fn check_ptr(&self, p: *const c_void) -> *const c_void {
        self.check_error();
        assert!(!p.is_null());
        p
    }

    fn check_mut_ptr(&self, p: *mut c_void) -> *mut c_void {
        self.check_error();
        assert!(!p.is_null());
        p
    }

    fn check_bool(&self, bool_result: types::EGLBoolean) {
        self.check_error();
        assert_eq!(bool_result, TRUE);
    }
}

// Adapted from https://github.com/tomaka/glutin/blob/1f3b8360cb/src/api/egl/ffi.rs
#[allow(non_camel_case_types)] pub type khronos_utime_nanoseconds_t = khronos_uint64_t;
#[allow(non_camel_case_types)] pub type khronos_uint64_t = u64;
#[allow(non_camel_case_types)] pub type khronos_ssize_t = c_long;
pub type EGLint = i32;
pub type EGLNativeDisplayType = *const c_void;
pub type EGLNativePixmapType = *const c_void;
pub type EGLNativeWindowType = winapi::shared::windef::HWND;
pub type NativeDisplayType = EGLNativeDisplayType;
pub type NativePixmapType = EGLNativePixmapType;
pub type NativeWindowType = EGLNativeWindowType;

include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs"));

// Adapted from https://chromium.googlesource.com/angle/angle/+/master/include/EGL/eglext_angle.h
type EGLDeviceEXT = *mut c_void;
const EXPERIMENTAL_PRESENT_PATH_ANGLE: types::EGLenum = 0x33A4;
const EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE: types::EGLenum = 0x33A9;
const D3D_TEXTURE_ANGLE: types::EGLenum = 0x33A3;
const FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: types::EGLenum = 0x33A6;

extern "C" {
    fn eglCreateDeviceANGLE(
        device_type: types::EGLenum,
        device: *mut ID3D11Device,
        attrib_list: *const types::EGLAttrib,
    ) -> EGLDeviceEXT;

    fn eglReleaseDeviceANGLE(device: EGLDeviceEXT) -> types::EGLBoolean;
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

// Convenience importing of `debug!`/`info!` macros for entire crate.
#[macro_use]
extern crate log;

pub use self::error::{Error, Result};

pub mod binlink;
pub mod channel;
pub mod config;
pub mod crypto;
pub mod env;
pub mod error;
pub mod event;
pub mod fs;
pub mod os;
pub mod output;
pub mod package;
pub mod service;
pub mod url;
pub mod util;

use std::env::VarError;
use std::ffi::OsStr;
use std::fmt;
use std::path::PathBuf;

pub use crate::os::filesystem;
pub use crate::os::users;

pub const AUTH_TOKEN_ENVVAR: &str = "HAB_AUTH_TOKEN";

lazy_static::lazy_static! {
    pub static ref PROGRAM_NAME: String = {
        let arg0 = std::env::args().next().map(PathBuf::from);
        arg0.as_ref()
            .and_then(|p| p.file_stem())
            .and_then(|p| p.to_str())
            .unwrap()
            .to_string()
    };
}

/// A Builder channel
#[derive(Deserialize, Serialize, Clone, Debug, Eq, Hash, PartialEq)]
pub struct ChannelIdent(String);

impl ChannelIdent {
    const LEGACY_ENVVAR: &'static str = "HAB_DEPOT_CHANNEL";
    pub const BLDR_ENVVAR: &'static str = "HAB_BLDR_CHANNEL";
    const UNSTABLE: &'static str = "unstable";
    const STABLE: &'static str = "stable";

    pub fn from_env_var(key: impl AsRef<OsStr>) -> std::result::Result<Self, VarError> {
        crate::env::var(key).map(ChannelIdent)
    }

    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }

    pub fn stable() -> Self {
        Self::from(Self::STABLE)
    }

    pub fn unstable() -> Self {
        Self::from(Self::UNSTABLE)
    }

    fn legacy_default() -> Self {
        ChannelIdent(
            env::var(Self::LEGACY_ENVVAR)
                .ok()
                .and_then(|c| Some(c.to_string()))
                .unwrap_or_else(|| Self::STABLE.to_string()),
        )
    }
}

impl From<&str> for ChannelIdent {
    fn from(s: &str) -> Self {
        ChannelIdent(s.to_string())
    }
}

impl From<String> for ChannelIdent {
    fn from(s: String) -> Self {
        ChannelIdent(s)
    }
}

impl fmt::Display for ChannelIdent {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Default for ChannelIdent {
    fn default() -> Self {
        match env::var(ChannelIdent::BLDR_ENVVAR) {
            Ok(value) => ChannelIdent(value.to_string()),
            Err(_) => ChannelIdent::legacy_default(),
        }
    }
}
<commit_msg>Add missing use statement for serde_derive macros<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

// Convenience importing of `debug!`/`info!` macros for entire crate.
#[macro_use]
extern crate log;

pub use self::error::{Error, Result};

pub mod binlink;
pub mod channel;
pub mod config;
pub mod crypto;
pub mod env;
pub mod error;
pub mod event;
pub mod fs;
pub mod os;
pub mod output;
pub mod package;
pub mod service;
pub mod url;
pub mod util;

use std::env::VarError;
use std::ffi::OsStr;
use std::fmt;
use std::path::PathBuf;

use serde_derive::{Deserialize, Serialize};

pub use crate::os::filesystem;
pub use crate::os::users;

pub const AUTH_TOKEN_ENVVAR: &str = "HAB_AUTH_TOKEN";

lazy_static::lazy_static! {
    pub static ref PROGRAM_NAME: String = {
        let arg0 = std::env::args().next().map(PathBuf::from);
        arg0.as_ref()
            .and_then(|p| p.file_stem())
            .and_then(|p| p.to_str())
            .unwrap()
            .to_string()
    };
}

/// A Builder channel
#[derive(Deserialize, Serialize, Clone, Debug, Eq, Hash, PartialEq)]
pub struct ChannelIdent(String);

impl ChannelIdent {
    const LEGACY_ENVVAR: &'static str = "HAB_DEPOT_CHANNEL";
    pub const BLDR_ENVVAR: &'static str = "HAB_BLDR_CHANNEL";
    const UNSTABLE: &'static str = "unstable";
    const STABLE: &'static str = "stable";

    pub fn from_env_var(key: impl AsRef<OsStr>) -> std::result::Result<Self, VarError> {
        crate::env::var(key).map(ChannelIdent)
    }

    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }

    pub fn stable() -> Self {
        Self::from(Self::STABLE)
    }

    pub fn unstable() -> Self {
        Self::from(Self::UNSTABLE)
    }

    fn legacy_default() -> Self {
        ChannelIdent(
            env::var(Self::LEGACY_ENVVAR)
                .ok()
                .and_then(|c| Some(c.to_string()))
                .unwrap_or_else(|| Self::STABLE.to_string()),
        )
    }
}

impl From<&str> for ChannelIdent {
    fn from(s: &str) -> Self {
        ChannelIdent(s.to_string())
    }
}

impl From<String> for ChannelIdent {
    fn from(s: String) -> Self {
        ChannelIdent(s)
    }
}

impl fmt::Display for ChannelIdent {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Default for ChannelIdent {
    fn default() -> Self {
        match env::var(ChannelIdent::BLDR_ENVVAR) {
            Ok(value) => ChannelIdent(value.to_string()),
            Err(_) => ChannelIdent::legacy_default(),
        }
    }
}
<|endoftext|>


<commit_before>//! An implementation of [FLAC](https://xiph.org/flac), free lossless audio
//! codec, written in Rust.
//!
//! # Examples
//!
//! Basic decoding from a file.
//!
//! ```
//! match flac::Stream::from_file("path/to/file.flac") {
//!   Ok(mut stream) => {
//!     // Copy of `StreamInfo` to help convert to a different audio format.
//!     let info = stream.info();
//!
//!     for sample in stream.iter() {
//!       // Iterate over each decoded sample
//!     }
//!   }
//!   Err(error)     => println!("{}", error),
//! }
//! ```

#[macro_use]
extern crate nom;

#[macro_use]
mod utility;
pub mod metadata;
mod frame;
pub mod subframe;
pub mod stream;

pub use metadata::{metadata_parser, Metadata};
pub use frame::{frame_parser, Frame};
pub use subframe::{subframe_parser, Subframe};
pub use stream::{stream_parser, Stream};
<commit_msg>Remove public export of subframe<commit_after>//! An implementation of [FLAC](https://xiph.org/flac), free lossless audio
//! codec, written in Rust.
//!
//! # Examples
//!
//! Basic decoding from a file.
//!
//! ```
//! match flac::Stream::from_file("path/to/file.flac") {
//!   Ok(mut stream) => {
//!     // Copy of `StreamInfo` to help convert to a different audio format.
//!     let info = stream.info();
//!
//!     for sample in stream.iter() {
//!       // Iterate over each decoded sample
//!     }
//!   }
//!   Err(error)     => println!("{}", error),
//! }
//! ```

#[macro_use]
extern crate nom;

#[macro_use]
mod utility;
pub mod metadata;
mod frame;
mod subframe;
pub mod stream;

pub use metadata::{metadata_parser, Metadata};
pub use frame::{frame_parser, Frame};
pub use subframe::{subframe_parser, Subframe};
pub use stream::{stream_parser, Stream};
<|endoftext|>


<commit_before>#![feature(io)]

use std::fs::File;
use std::io::Read;

struct State {
    stack: Vec<Value>,
    block_nesting: u8,
    temp: Vec<String>
}

impl State {
    fn new() -> Self{
        State {
            block_nesting: 0,
            stack: Vec::new(),
            temp: Vec::new()
        }
    }
}

pub fn run_program(src_file: File) {
    let mut buf = String::new();
    let mut state = State::new();
    let mut is_making_string = false;

    for c in src_file.chars() {
        match c {
            Ok(c) => {
                if c.is_whitespace() && !is_making_string {
                    if !buf.is_empty() {
                        run_command(&mut state, &buf);
                        buf.clear();
                    }
                } else {
                    if c == '"' {
                        is_making_string = !is_making_string;
                    }
                    buf.push(c);
                }
            },
            Err(e) => panic!("{:?}", e)
        }
    }
}

mod value;
use value::Value;
use value::Value::*;

fn binop<T: Into<Value>, F: FnOnce(Value, Value) -> T>(s: &mut State, f: F) {
    let b = s.stack.pop().unwrap();
    let a = s.stack.pop().unwrap();

    s.stack.push(f(a, b).into())
}

use std::ops::*;
use std::mem::replace;

fn run_command(state: &mut State, cmd: &str) {
    if state.block_nesting > 0 {
        if cmd == "}" || cmd == "]" || cmd == "end" {
            state.block_nesting -= 1;
            if state.block_nesting == 0 {
                let t = replace(&mut state.temp, Vec::new());
                state.stack.push(Block(t));
            } else {
                state.temp.push(cmd.to_owned());
            }
        } else {
            match &*cmd.to_lowercase() {
                "{" | "[" | "do" => state.block_nesting += 1,
                _ => ()
            }
            state.temp.push(cmd.to_owned());
        }
        return
    } else if cmd.starts_with('"') {
        state.stack.push(Str(cmd[1..cmd.len()-1].to_owned()));
    } else if let Ok(n) = cmd.parse::<f64>() {
        state.stack.push(Num(n));
    } else {
        match &*cmd.to_lowercase() {
            "{" | "[" | "do" => state.block_nesting = 1,
            "T" | "true" => state.stack.push(Num(1.)),
            "t" | "f" | "false" => state.stack.push(Num(0.)),
            "¤" | "null" | "nil" => state.stack.push(Value::Null),
            ";" | "dup" => {
                let dup = state.stack.last().cloned().unwrap();
                state.stack.push(dup);
            }
            "!" | "not" => {
                let a = state.stack.pop().unwrap();
                state.stack.push(!a);
            }
            "if" | "?" => {
                let when_false = state.stack.pop().unwrap();
                let when_true = state.stack.pop().unwrap();
                let condition = state.stack.pop().unwrap();

                state.stack.push(if condition.as_bool() {
                    when_true
                } else {
                    when_false
                });
            }
            "()" => {
                match state.stack.pop() {
                    Some(Block(b)) => {
                        for cmd in b {
                            run_command(state, &cmd);
                        }
                    }
                    _ => panic!("No block on stack")
                }
            }
            "<" | "read" => {
                let mut line = String::new();
                std::io::stdin().read_line(&mut line).unwrap();
                line = line.trim_right().to_owned();
                state.stack.push(Str(line));
            }
            "$" | "swap" | "exch" => {
                let a = state.stack.pop().unwrap();
                let b = state.stack.pop().unwrap();
                state.stack.push(a);
                state.stack.push(b);
            }
            "drop" => {
                state.stack.pop().unwrap();
            }
            "#" | "num" => state.stack.last_mut().unwrap().make_num(),
            "==" | "=" | "eq" => binop(state, |a, b| a == b),
            "!=" | "~=" | "neq" => binop(state, |a, b| a != b),
            ">" | "wrte" => print!("{}", state.stack.pop().unwrap()),
            "_" | "prnt" => println!("{}", state.stack.pop().unwrap()),
            "||" | "|" | "or" => binop(state, BitOr::bitor),
            "&&" | "&" | "and" => binop(state, BitAnd::bitand),
            "+" | "add" => binop(state, Add::add),
            "-" | "sub" => binop(state, Sub::sub),
            "*" | "mul" => binop(state, Mul::mul),
            "/" | "div" => binop(state, Div::div),
            "%" | "rem" => binop(state, Rem::rem),
            _ => panic!("Unknown cmd `{}'", cmd)
        }
    }
}
<commit_msg>Add shortcut for empty code blocks<commit_after>#![feature(io)]

use std::fs::File;
use std::io::Read;

struct State {
    stack: Vec<Value>,
    block_nesting: u8,
    temp: Vec<String>
}

impl State {
    fn new() -> Self{
        State {
            block_nesting: 0,
            stack: Vec::new(),
            temp: Vec::new()
        }
    }
}

pub fn run_program(src_file: File) {
    let mut buf = String::new();
    let mut state = State::new();
    let mut is_making_string = false;

    for c in src_file.chars() {
        match c {
            Ok(c) => {
                if c.is_whitespace() && !is_making_string {
                    if !buf.is_empty() {
                        run_command(&mut state, &buf);
                        buf.clear();
                    }
                } else {
                    if c == '"' {
                        is_making_string = !is_making_string;
                    }
                    buf.push(c);
                }
            },
            Err(e) => panic!("{:?}", e)
        }
    }
}

mod value;
use value::Value;
use value::Value::*;

fn binop<T: Into<Value>, F: FnOnce(Value, Value) -> T>(s: &mut State, f: F) {
    let b = s.stack.pop().unwrap();
    let a = s.stack.pop().unwrap();

    s.stack.push(f(a, b).into())
}

use std::ops::*;
use std::mem::replace;

fn run_command(state: &mut State, cmd: &str) {
    if state.block_nesting > 0 {
        if cmd == "}" || cmd == "]" || cmd == "end" {
            state.block_nesting -= 1;
            if state.block_nesting == 0 {
                let t = replace(&mut state.temp, Vec::new());
                state.stack.push(Block(t));
            } else {
                state.temp.push(cmd.to_owned());
            }
        } else {
            match &*cmd.to_lowercase() {
                "{" | "[" | "do" => state.block_nesting += 1,
                _ => ()
            }
            state.temp.push(cmd.to_owned());
        }
    } else if cmd.starts_with('"') {
        state.stack.push(Str(cmd[1..cmd.len()-1].to_owned()));
    } else if let Ok(n) = cmd.parse::<f64>() {
        state.stack.push(Num(n));
    } else {
        match &*cmd.to_lowercase() {
            "{" | "[" | "do" => state.block_nesting = 1,
            "{}" | "[]" => state.stack.push(Block(Vec::new())),
            "T" | "true" => state.stack.push(Num(1.)),
            "t" | "f" | "false" => state.stack.push(Num(0.)),
            "¤" | "null" | "nil" => state.stack.push(Value::Null),
            ";" | "dup" => {
                let dup = state.stack.last().cloned().unwrap();
                state.stack.push(dup);
            }
            "!" | "not" => {
                let a = state.stack.pop().unwrap();
                state.stack.push(!a);
            }
            "if" | "?" => {
                let when_false = state.stack.pop().unwrap();
                let when_true = state.stack.pop().unwrap();
                let condition = state.stack.pop().unwrap();

                state.stack.push(if condition.as_bool() {
                    when_true
                } else {
                    when_false
                });
            }
            "()" => {
                match state.stack.pop() {
                    Some(Block(b)) => {
                        for cmd in b {
                            run_command(state, &cmd);
                        }
                    }
                    _ => panic!("No block on stack")
                }
            }
            "<" | "read" => {
                let mut line = String::new();
                std::io::stdin().read_line(&mut line).unwrap();
                line = line.trim_right().to_owned();
                state.stack.push(Str(line));
            }
            "$" | "swap" | "exch" => {
                let a = state.stack.pop().unwrap();
                let b = state.stack.pop().unwrap();
                state.stack.push(a);
                state.stack.push(b);
            }
            "drop" => {
                state.stack.pop().unwrap();
            }
            "#" | "num" => state.stack.last_mut().unwrap().make_num(),
            "==" | "=" | "eq" => binop(state, |a, b| a == b),
            "!=" | "~=" | "neq" => binop(state, |a, b| a != b),
            ">" | "wrte" => print!("{}", state.stack.pop().unwrap()),
            "_" | "prnt" => println!("{}", state.stack.pop().unwrap()),
            "||" | "|" | "or" => binop(state, BitOr::bitor),
            "&&" | "&" | "and" => binop(state, BitAnd::bitand),
            "+" | "add" => binop(state, Add::add),
            "-" | "sub" => binop(state, Sub::sub),
            "*" | "mul" => binop(state, Mul::mul),
            "/" | "div" => binop(state, Div::div),
            "%" | "rem" => binop(state, Rem::rem),
            _ => panic!("Unknown cmd `{}'", cmd)
        }
    }
}
<|endoftext|>


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

#[macro_use]
extern crate log;
extern crate libc;

#[allow(non_camel_case_types)]
pub mod ffiairspy;

use std::mem;
use std::ptr;

#[derive(Debug)]
pub enum AirspyError {
    InvalidParam       = ffiairspy::AIRSPY_ERROR_INVALID_PARAM as isize,
    NotFound           = ffiairspy::AIRSPY_ERROR_NOT_FOUND as isize,
    Busy               = ffiairspy::AIRSPY_ERROR_BUSY as isize,
    NoMem              = ffiairspy::AIRSPY_ERROR_NO_MEM as isize,
    LibUsb             = ffiairspy::AIRSPY_ERROR_LIBUSB as isize,
    Thread             = ffiairspy::AIRSPY_ERROR_THREAD as isize,
    StreamingThreadErr = ffiairspy::AIRSPY_ERROR_STREAMING_THREAD_ERR as isize,
    StreamingStopped   = ffiairspy::AIRSPY_ERROR_STREAMING_STOPPED as isize,
    Other              = ffiairspy::AIRSPY_ERROR_OTHER as isize,
}

#[derive(Debug, Copy, Clone)]
pub enum AirspySamplerate {
    Sps10000000 = 10_000_000,
    Sps2500000  =  2_500_000,
}

#[derive(Debug)]
pub enum AirspySampleType {
    /// 2 * 32bit float per sample
    Float32IQ   = ffiairspy::AIRSPY_SAMPLE_FLOAT32_IQ as isize,
    /// 1 * 32bit float per sample
    Float32Real = ffiairspy::AIRSPY_SAMPLE_FLOAT32_REAL as isize,
    /// 2 * 16bit int per sample
    Int16IQ     = ffiairspy::AIRSPY_SAMPLE_INT16_IQ as isize,
    /// 1 * 16bit int per sample
    Int16Real   = ffiairspy::AIRSPY_SAMPLE_INT16_REAL as isize,
    /// 1 * 16bit unsigned int per sample
    Uint16Real  = ffiairspy::AIRSPY_SAMPLE_UINT16_REAL as isize,
}

pub struct Airspy {
    device: *mut ffiairspy::Struct_airspy_device,
}

impl Airspy {

    pub fn new() -> Result<Airspy, AirspyError> {
        let mut device = ptr::null_mut();

        let error = unsafe {ffiairspy::airspy_open(&mut device)};
        match error {
            ffiairspy::AIRSPY_SUCCESS => Ok(Airspy {device: device}),
            ffiairspy::AIRSPY_ERROR_NO_MEM => Err(AirspyError::NoMem),
            ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
            err => panic!("airspy_open returned error ({:})", err),
        }
    }

    pub fn set_samplerate(&self, samplerate: AirspySamplerate) -> Result<(), AirspyError> {
        let mut supported_samplerates_count: u32 = 0;

        // get count of supported samplerates
        let mut error = unsafe {ffiairspy::airspy_get_samplerates(self.device, &mut supported_samplerates_count as *mut u32, 0)};
        // anything except SUCCESS is library failure, hence panic!
        match error {
            ffiairspy::AIRSPY_SUCCESS => {},
            err => panic!("airspy_get_samplerates returned error ({:})", err),
        }

        assert!(supported_samplerates_count == ffiairspy::AIRSPY_SAMPLERATE_END);

        // get list of supported samplerates
        let mut samplerates: Vec<u32> = vec![0_u32; supported_samplerates_count as usize];
        error = unsafe {ffiairspy::airspy_get_samplerates(self.device, mem::transmute::<&mut u32, *mut u32>(&mut samplerates[0]), supported_samplerates_count)};
        // supported_samplerates_count must be right because we just asked for it from library, there must be lib error if anything other than SUCCESS is returned
        match error {
            ffiairspy::AIRSPY_SUCCESS => {},
            err => panic!("airspy_get_samplerates returned error ({:})", err),
        }

        let sr = samplerate.clone() as u32;
        let mut index: Option<u32> = None;
        for (i, rate) in samplerates.iter().enumerate() {
            if *rate == sr {
                index = Some(i as u32);
                break;
            }
        }

        if index.is_some() {
            let error = unsafe {ffiairspy::airspy_set_samplerate(self.device, index.unwrap())};
            match error {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_samplerate returned error ({:})", err),
            }
        }
        else {
            panic!("samplerate {:?} not supported by libairspy, supported samplerates are {:?}", samplerate, samplerates);
        }
    }

    pub fn set_sample_type(&self, sampletype: AirspySampleType) -> Result<(), AirspyError> {
        match unsafe {ffiairspy::airspy_set_sample_type(self.device, sampletype as u32)} {
            ffiairspy::AIRSPY_SUCCESS => {
                Ok(())
            },
            err => {
                // airspy_set_sample_type should only return SUCCESS
                // however just in case panic here if for some reason it does anything else
                panic!("airspy_set_sample_type returned error {}", err)
            },
        }
    }

    pub fn set_bias_tee(&self, onoff: bool) -> Result<(), AirspyError> {
        let c_onoff = match onoff {
            true => 1,
            false => 0,
        };

        match unsafe {ffiairspy::airspy_set_rf_bias(self.device, c_onoff)} {
            ffiairspy::AIRSPY_SUCCESS => Ok(()),
            ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
            err => {
                panic!("airspy_set_rf_bias returned error {}", err)
            }
        }
    }

    pub fn set_lna_gain(&self, gain: u8) -> Result<(), AirspyError> {
        if gain > 15 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_lna_gain(self.device, gain)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => {
                    panic!("airspy_set_lna_gain returned error {}", err)
                }
            }
        }
    }

    pub fn set_mixer_gain(&self, gain: u8) -> Result<(), AirspyError> {
        if gain > 15 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_mixer_gain(self.device, gain)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => {
                    panic!("airspy_set_mixer_gain returned error {}", err)
                }
            }
        }
    }

    pub fn set_vga_gain(&self, gain: u8) -> Result<(), AirspyError> {
        if gain > 15 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_vga_gain(self.device, gain)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => {
                    panic!("airspy_set_vga_gain returned error {}", err)
                }
            }
        }
    }

    pub fn set_frequency(&self, freq_hz: u32) -> Result<(), AirspyError> {
        // 24 MHz to 1.8 GHz
        if freq_hz < 24_000_000 || freq_hz > 1_8_00_000_000 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_freq(self.device, freq_hz)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => {
                    panic!("airspy_set_freq returned error {}", err)
                }
            }
        }
    }
}

impl Drop for Airspy {
    fn drop(&mut self) {
        unsafe{ffiairspy::airspy_close(self.device)};
        unsafe{ffiairspy::airspy_exit()};
    }
}
<commit_msg>make Airspy generic and add start_rx method<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#[macro_use]
extern crate log;
extern crate libc;

#[allow(non_camel_case_types)]
pub mod ffiairspy;

use std::mem;
use std::ptr;

#[derive(Debug)]
pub enum AirspyError {
    InvalidParam       = ffiairspy::AIRSPY_ERROR_INVALID_PARAM as isize,
    NotFound           = ffiairspy::AIRSPY_ERROR_NOT_FOUND as isize,
    Busy               = ffiairspy::AIRSPY_ERROR_BUSY as isize,
    NoMem              = ffiairspy::AIRSPY_ERROR_NO_MEM as isize,
    LibUsb             = ffiairspy::AIRSPY_ERROR_LIBUSB as isize,
    Thread             = ffiairspy::AIRSPY_ERROR_THREAD as isize,
    StreamingThreadErr = ffiairspy::AIRSPY_ERROR_STREAMING_THREAD_ERR as isize,
    StreamingStopped   = ffiairspy::AIRSPY_ERROR_STREAMING_STOPPED as isize,
    Other              = ffiairspy::AIRSPY_ERROR_OTHER as isize,
}

#[derive(Debug, Copy, Clone)]
pub enum AirspySamplerate {
    Sps10000000 = 10_000_000,
    Sps2500000  =  2_500_000,
}

#[derive(Debug)]
pub enum AirspySampleType {
    /// 2 * 32bit float per sample
    Float32IQ   = ffiairspy::AIRSPY_SAMPLE_FLOAT32_IQ as isize,
    /// 1 * 32bit float per sample
    Float32Real = ffiairspy::AIRSPY_SAMPLE_FLOAT32_REAL as isize,
    /// 2 * 16bit int per sample
    Int16IQ     = ffiairspy::AIRSPY_SAMPLE_INT16_IQ as isize,
    /// 1 * 16bit int per sample
    Int16Real   = ffiairspy::AIRSPY_SAMPLE_INT16_REAL as isize,
    /// 1 * 16bit unsigned int per sample
    Uint16Real  = ffiairspy::AIRSPY_SAMPLE_UINT16_REAL as isize,
}

#[repr(C)]
pub struct IQ<T> {
    i: T,
    q: T,
}

pub trait AirspySupportedType {
    fn get_sample_type() -> u32;
}

impl AirspySupportedType for IQ<f32> {
    fn get_sample_type() -> u32 {
        ffiairspy::AIRSPY_SAMPLE_FLOAT32_IQ
    }
}
impl AirspySupportedType for f32 {
    fn get_sample_type() -> u32 {
        ffiairspy::AIRSPY_SAMPLE_FLOAT32_REAL
    }
}
impl AirspySupportedType for i16 {
    fn get_sample_type() -> u32 {
        ffiairspy::AIRSPY_SAMPLE_INT16_REAL
    }
}
impl AirspySupportedType for IQ<i16> {
    fn get_sample_type() -> u32 {
        ffiairspy::AIRSPY_SAMPLE_INT16_IQ
    }
}
impl AirspySupportedType for u16 {
    fn get_sample_type() -> u32 {
        ffiairspy::AIRSPY_SAMPLE_UINT16_REAL
    }
}

pub struct Airspy<T: AirspySupportedType> {
    device: *mut ffiairspy::Struct_airspy_device,
    samples: Vec<T>,
}

impl<T: AirspySupportedType> Airspy<T> {
    pub fn new() -> Result<Airspy<T>, AirspyError> {
        let mut device = ptr::null_mut();

        let error = unsafe {ffiairspy::airspy_open(&mut device)};
        match error {
            ffiairspy::AIRSPY_SUCCESS => {
                let airspy = Airspy{device: device, samples: Vec::<T>::new()};

                match unsafe {ffiairspy::airspy_set_sample_type(device, T::get_sample_type())} {
                    ffiairspy::AIRSPY_SUCCESS => {
                        Ok(airspy)
                    },
                    err => {
                        // airspy_set_sample_type should only return SUCCESS
                        // however just in case panic here if for some reason it does anything else
                        panic!("airspy_set_sample_type returned error {}", err)
                    },
                }
            },
            ffiairspy::AIRSPY_ERROR_NO_MEM => Err(AirspyError::NoMem),
            ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
            err => panic!("airspy_open returned error ({:})", err),
        }
    }

    pub fn set_samplerate(&self, samplerate: AirspySamplerate) -> Result<(), AirspyError> {
        let mut supported_samplerates_count: u32 = 0;

        // get count of supported samplerates
        let mut error = unsafe {ffiairspy::airspy_get_samplerates(self.device, &mut supported_samplerates_count as *mut u32, 0)};
        // anything except SUCCESS is library failure, hence panic!
        match error {
            ffiairspy::AIRSPY_SUCCESS => {},
            err => panic!("airspy_get_samplerates returned error ({:})", err),
        }

        assert!(supported_samplerates_count == ffiairspy::AIRSPY_SAMPLERATE_END);

        // get list of supported samplerates
        let mut samplerates: Vec<u32> = vec![0_u32; supported_samplerates_count as usize];
        error = unsafe {ffiairspy::airspy_get_samplerates(self.device, mem::transmute::<&mut u32, *mut u32>(&mut samplerates[0]), supported_samplerates_count)};
        // supported_samplerates_count must be right because we just asked for it from library, there must be lib error if anything other than SUCCESS is returned
        match error {
            ffiairspy::AIRSPY_SUCCESS => {},
            err => panic!("airspy_get_samplerates returned error ({:})", err),
        }

        let sr = samplerate.clone() as u32;
        let mut index: Option<u32> = None;
        for (i, rate) in samplerates.iter().enumerate() {
            if *rate == sr {
                index = Some(i as u32);
                break;
            }
        }

        if index.is_some() {
            let error = unsafe {ffiairspy::airspy_set_samplerate(self.device, index.unwrap())};
            match error {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_samplerate returned error ({:})", err),
            }
        }
        else {
            panic!("samplerate {:?} not supported by libairspy, supported samplerates are {:?}", samplerate, samplerates);
        }
    }

    pub fn set_bias_tee(&self, onoff: bool) -> Result<(), AirspyError> {
        let c_onoff = match onoff {
            true => 1,
            false => 0,
        };

        match unsafe {ffiairspy::airspy_set_rf_bias(self.device, c_onoff)} {
            ffiairspy::AIRSPY_SUCCESS => Ok(()),
            ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
            err => {
                panic!("airspy_set_rf_bias returned error {}", err)
            }
        }
    }

    pub fn set_lna_gain(&self, gain: u8) -> Result<(), AirspyError> {
        if gain > 15 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_lna_gain(self.device, gain)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_lna_gain returned error {}", err),
            }
        }
    }

    pub fn set_mixer_gain(&self, gain: u8) -> Result<(), AirspyError> {
        if gain > 15 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_mixer_gain(self.device, gain)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_mixer_gain returned error {}", err)
            }
        }
    }

    pub fn set_vga_gain(&self, gain: u8) -> Result<(), AirspyError> {
        if gain > 15 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_vga_gain(self.device, gain)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_vga_gain returned error {}", err),
            }
        }
    }

    pub fn set_frequency(&self, freq_hz: u32) -> Result<(), AirspyError> {
        // 24 MHz to 1.8 GHz
        if freq_hz < 24_000_000 || freq_hz > 1_8_00_000_000 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_freq(self.device, freq_hz)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_freq returned error {}", err),
            }
        }
    }

    pub fn start_rx(&self) -> Result<(), AirspyError> {
        match unsafe {ffiairspy::airspy_start_rx(self.device, Some(Self::receive), ptr::null_mut())} {
            ffiairspy::AIRSPY_SUCCESS => Ok(()),
            ffiairspy::AIRSPY_ERROR_BUSY => Err(AirspyError::Busy),
            ffiairspy::AIRSPY_ERROR_THREAD => Err(AirspyError::Thread),
            err => panic!("airspy_start_rx returned error {}", err),
        }
    }

    extern "C" fn receive(transfer: *mut ffiairspy::airspy_transfer) -> libc::c_int {
        info!("receive");
        0
    }
}

impl<T: AirspySupportedType> Drop for Airspy<T> {
    fn drop(&mut self) {
        unsafe{ffiairspy::airspy_close(self.device)};
        unsafe{ffiairspy::airspy_exit()};
    }
}
<|endoftext|>


<commit_before>//! Rust implementation of JMESPath.
//!
//! # Compiling JMESPath expressions
//!
//! Use the `jmespath::Expression` struct to compile and execute JMESPath
//! expressions. The `Expression` struct can be used multiple times.
//!
//! # Parser
//!
//! Use the `parse()` function to parse a JMESPath expressions into an
//! abstract syntax tree (AST).
//!
//! ## Examples
//!
//! The following example parses a JMESPath expression into an AST.
//!
//! ```
//! use jmespath;
//!
//! let ast = jmespath::parse("foo.bar | baz");
//! ```

pub use parser::parse;
pub use variable::Variable;

use std::fmt;
use std::rc::Rc;

use ast::Ast;
use parser::ParseError;
use interpreter::interpret;

pub mod ast;
pub mod functions;
pub mod interpreter;
pub mod lexer;
pub mod parser;
mod variable;

/// A compiled JMESPath expression.
#[derive(Clone)]
pub struct Expression {
    ast: Ast,
    original: String
}

impl Expression {
    /// Creates a new JMESPath expression from an expression string.
    pub fn new(expression: &str) -> Result<Expression, ParseError> {
        Ok(Expression {
            original: expression.to_string(),
            ast: try!(parse(expression))
        })
    }

    /// Returns the result of searching data with the compiled expression.
    pub fn search(&self, data: Rc<Variable>) -> Result<Rc<Variable>, String> {
        interpret(data, &self.ast)
    }

    /// Returns the original string of this JMESPath expression.
    pub fn as_str<'a>(&'a self) -> &'a str {
        &self.original
    }
}

impl fmt::Display for Expression {
    /// Shows the original jmespath expression.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

impl fmt::Debug for Expression {
    /// Shows the original regular expression.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

/// Equality comparison is based on the original string.
impl PartialEq for Expression {
    fn eq(&self, other: &Expression) -> bool {
        self.as_str() == other.as_str()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::rc::Rc;

    #[test] fn formats_expression_as_string() {
        let expr = Expression::new("foo | baz").unwrap();
        assert_eq!("foo | baz/foo | baz", format!("{}/{:?}", expr, expr));
    }

    #[test] fn implements_partial_eq() {
        let a = Expression::new("@").unwrap();
        let b = Expression::new("@").unwrap();
        assert!(a == b);
    }

    #[test] fn can_evaluate_jmespath_expression() {
        let expr = Expression::new("foo.bar").unwrap();
        let var = Rc::new(Variable::from_str("{\"foo\":{\"bar\":true}}").unwrap());
        assert_eq!(Rc::new(Variable::Boolean(true)), expr.search(var).unwrap());
    }
}
<commit_msg>Not exporting interpreter and functions as public API<commit_after>//! Rust implementation of JMESPath.
//!
//! # Compiling JMESPath expressions
//!
//! Use the `jmespath::Expression` struct to compile and execute JMESPath
//! expressions. The `Expression` struct can be used multiple times.
//!
//! # Parser
//!
//! Use the `parse()` function to parse a JMESPath expressions into an
//! abstract syntax tree (AST).
//!
//! ## Examples
//!
//! The following example parses a JMESPath expression into an AST.
//!
//! ```
//! use jmespath;
//!
//! let ast = jmespath::parse("foo.bar | baz");
//! ```

pub use parser::parse;
pub use variable::Variable;

use std::fmt;
use std::rc::Rc;

use ast::Ast;
use parser::ParseError;
use interpreter::interpret;

pub mod ast;
mod functions;
mod interpreter;
pub mod lexer;
pub mod parser;
mod variable;

/// A compiled JMESPath expression.
#[derive(Clone)]
pub struct Expression {
    ast: Ast,
    original: String
}

impl Expression {
    /// Creates a new JMESPath expression from an expression string.
    pub fn new(expression: &str) -> Result<Expression, ParseError> {
        Ok(Expression {
            original: expression.to_string(),
            ast: try!(parse(expression))
        })
    }

    /// Returns the result of searching data with the compiled expression.
    pub fn search(&self, data: Rc<Variable>) -> Result<Rc<Variable>, String> {
        interpret(data, &self.ast)
    }

    /// Returns the original string of this JMESPath expression.
    pub fn as_str<'a>(&'a self) -> &'a str {
        &self.original
    }
}

impl fmt::Display for Expression {
    /// Shows the original jmespath expression.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

impl fmt::Debug for Expression {
    /// Shows the original regular expression.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

/// Equality comparison is based on the original string.
impl PartialEq for Expression {
    fn eq(&self, other: &Expression) -> bool {
        self.as_str() == other.as_str()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::rc::Rc;

    #[test] fn formats_expression_as_string() {
        let expr = Expression::new("foo | baz").unwrap();
        assert_eq!("foo | baz/foo | baz", format!("{}/{:?}", expr, expr));
    }

    #[test] fn implements_partial_eq() {
        let a = Expression::new("@").unwrap();
        let b = Expression::new("@").unwrap();
        assert!(a == b);
    }

    #[test] fn can_evaluate_jmespath_expression() {
        let expr = Expression::new("foo.bar").unwrap();
        let var = Rc::new(Variable::from_str("{\"foo\":{\"bar\":true}}").unwrap());
        assert_eq!(Rc::new(Variable::Boolean(true)), expr.search(var).unwrap());
    }
}
<|endoftext|>


<commit_before>
pub extern crate crypto;

use crypto::digest::Digest;

pub trait Hashable {
    fn to_bytes(&self) -> &[u8];
}

impl Hashable for String {
    fn to_bytes(&self) -> &[u8] {
        return self.as_bytes();
    }
}

impl Hashable for str {
    fn to_bytes(&self) -> &[u8] {
        return self.as_bytes();
    }
}

#[derive(Clone)]
enum Tree<T> where T: Hashable + Clone {
    Leaf {
        hash: Vec<u8>,
        value: T
    },

    Node {
        hash: Vec<u8>,
        left: Box<Tree<T>>,
        right: Box<Tree<T>>
    }
}

impl <T> Tree<T> where T: Hashable + Clone {
    fn get_hash<'a>(&'a self) -> &'a Vec<u8> {
        match *self {
            Tree::Leaf { hash: ref hash, value: _ }          => hash,
            Tree::Node { hash: ref hash, left: _, right: _ } => hash
        }
    }
}

pub struct MerkleTree<D, T> where D: Digest + Clone, T: Hashable + Clone {
    digest: D,
    tree: Tree<T>
}

impl <T> Tree<T> where T: Hashable + Clone {

    // fn from_chunks<D>(digest: D, iter: Chunks<Tree<T>>) -> Tree<T> where D: Digest {

    // }

}

fn make_hash<D, T>(mut digest: D, bytes: &[u8]) -> Vec<u8> where D: Digest, T: Hashable + Clone {
    let mut hash = Vec::with_capacity(digest.output_bytes());
    digest.reset();
    digest.input(bytes);
    digest.result(hash.as_mut_slice());
    digest.reset();
    return hash;
}

fn combine_hashes<D>(mut digest: D, left: &[u8], right: &[u8]) -> Vec<u8> where D: Digest {
    let mut hash = Vec::with_capacity(digest.output_bytes());
    digest.reset();
    digest.input(left);
    digest.input(right);
    digest.result(hash.as_mut_slice());
    digest.reset();
    return hash;
}

fn make_leaf<D, T>(digest: D, value: T) -> Tree<T> where D: Digest + Clone, T: Hashable + Clone {
    return Tree::Leaf {
        hash: make_hash::<D, T>(digest, value.to_bytes()),
        value: value
    };
}

impl <D, T> MerkleTree<D, T> where D: Digest + Clone, T: Hashable + Clone {

    // TODO: Don't clone all the things
    pub fn from_vec(digest: D, values: Vec<T>) -> MerkleTree<D, T> {
        let leafs: Vec<Tree<T>> = values.iter().map(|v| make_leaf::<D, T>(digest.clone(), v.clone())).collect();

        for chunk in leafs.chunks(2) {
            if chunk.len() == 1 {

            } else {
                let left: Tree<T>  = chunk[0].clone();
                let right: Tree<T> = chunk[1].clone();

                let combined_hash = combine_hashes::<D>(digest.clone(), left.get_hash().as_slice(), right.get_hash().as_slice());
                let node = Tree::Node {
                   hash: combined_hash,
                   left: Box::new(left),
                   right: Box::new(right)
                };
            }
        }

        return MerkleTree {
            digest: digest.clone(),
            tree: make_leaf::<D, T>(digest, values[0].clone())
        };

    }

}

#[cfg(test)]
use crypto::sha3::Sha3;

#[test]
fn test_stuff() {
}

#[cfg(test)]
pub mod tests;
<commit_msg>cut down all the trees<commit_after>
pub extern crate crypto;

use crypto::digest::Digest;

pub trait Hashable {
    fn to_bytes(&self) -> &[u8];
}

impl Hashable for String {
    fn to_bytes(&self) -> &[u8] {
        return self.as_bytes();
    }
}

impl Hashable for str {
    fn to_bytes(&self) -> &[u8] {
        return self.as_bytes();
    }
}

#[derive(Clone)]
enum Tree<T> where T: Hashable + Clone {
    Leaf {
        hash: Vec<u8>,
        value: T
    },

    Node {
        hash: Vec<u8>,
        left: Box<Tree<T>>,
        right: Box<Tree<T>>
    }
}

impl <T> Tree<T> where T: Hashable + Clone {
    fn get_hash<'a>(&'a self) -> &'a Vec<u8> {
        match *self {
            Tree::Leaf { hash: ref hash, value: _ }          => hash,
            Tree::Node { hash: ref hash, left: _, right: _ } => hash
        }
    }
}

pub struct MerkleTree<D, T> where D: Digest + Clone, T: Hashable + Clone {
    digest: D,
    tree: Tree<T>
}

impl <T> Tree<T> where T: Hashable + Clone {

    // fn from_chunks<D>(digest: D, iter: Chunks<Tree<T>>) -> Tree<T> where D: Digest {

    // }

}

fn make_hash<D, T>(mut digest: D, bytes: &[u8]) -> Vec<u8> where D: Digest, T: Hashable + Clone {
    let mut hash = Vec::with_capacity(digest.output_bytes());
    digest.reset();
    digest.input(bytes);
    digest.result(hash.as_mut_slice());
    digest.reset();
    return hash;
}

fn combine_hashes<D>(mut digest: D, left: &[u8], right: &[u8]) -> Vec<u8> where D: Digest {
    let mut hash = Vec::with_capacity(digest.output_bytes());
    digest.reset();
    digest.input(left);
    digest.input(right);
    digest.result(hash.as_mut_slice());
    digest.reset();
    return hash;
}

fn make_leaf<D, T>(digest: D, value: T) -> Tree<T> where D: Digest + Clone, T: Hashable + Clone {
    return Tree::Leaf {
        hash: make_hash::<D, T>(digest, value.to_bytes()),
        value: value
    };
}

impl <D, T> MerkleTree<D, T> where D: Digest + Clone, T: Hashable + Clone {

    // TODO: Don't clone all the things
    pub fn from_vec(digest: D, values: Vec<T>) -> MerkleTree<D, T> {
        let leafs: Vec<Tree<T>> = values.iter().map(|v| make_leaf::<D, T>(digest.clone(), v.clone())).collect();

        for chunk in leafs.chunks(2) {
            if chunk.len() == 1 {

            } else {
                let left  = chunk[0].clone();
                let right = chunk[1].clone();

                let combined_hash = combine_hashes::<D>(digest.clone(), left.get_hash().as_slice(), right.get_hash().as_slice());
                let node = Tree::Node {
                   hash: combined_hash,
                   left: Box::new(left),
                   right: Box::new(right)
                };
            }
        }

        return MerkleTree {
            digest: digest.clone(),
            tree: make_leaf::<D, T>(digest, values[0].clone())
        };

    }

}

#[cfg(test)]
use crypto::sha3::Sha3;

#[test]
fn test_stuff() {
}

#[cfg(test)]
pub mod tests;
<|endoftext|>


<commit_before>extern crate libc;
extern crate time;

mod error;
pub mod cpu;
pub mod disk_stats;
pub mod disk_usage;
pub mod load;
pub mod memory;
pub mod network;
pub mod process_memory;

use std::fs;
use std::io;
use std::io::Read;
use std::path::Path;
use std::result;

pub use error::ProbeError;

pub type Result<T> = result::Result<T, error::ProbeError>;

#[inline]
fn file_to_string(path: &Path) -> io::Result<String> {
    let mut file = try!(fs::File::open(path));
    let mut read = String::new();
    try!(file.read_to_string(&mut read));
    Ok(read)
}

#[inline]
fn file_to_buf_reader(path: &Path) -> io::Result<io::BufReader<fs::File>> {
    fs::File::open(path).and_then(|f| Ok(io::BufReader::new(f)))
}

#[inline]
fn calculate_time_difference(first_time: u64, second_time: u64) -> Result<u64> {
    if first_time > second_time {
        Err(ProbeError::InvalidInput("first time was after second time".to_string()))
    } else {
        Ok(second_time - first_time)
    }
}

#[inline]
fn time_adjusted(field_name: &str, first_value: u64, second_value: u64, time_difference_ns: u64) -> Result<u64> {
    if first_value < second_value {
        Err(ProbeError::UnexpectedContent(format!("First value was lower than second value for '{}'", field_name)))
    } else {
        Ok((first_value - second_value) * time_difference_ns / 60_000_000)
    }
}

#[inline]
fn parse_u64(segment: &str) -> Result<u64> {
    segment.parse().map_err(|_| {
        ProbeError::UnexpectedContent(format!("Could not parse '{}' as u64", segment).to_owned())
    })
}

#[cfg(test)]
mod tests {
    use error::ProbeError;

    #[test]
    fn test_calculate_time_difference() {
        assert_eq!(100, super::calculate_time_difference(100, 200).unwrap());
        assert!(super::calculate_time_difference(200, 100).is_err());
    }

    #[test]
    fn test_time_adjusted() {
        assert_eq!(1200, super::time_adjusted("field", 2400, 1200, 60_000_000).unwrap());
        assert_eq!(600, super::time_adjusted("field", 2400, 1200, 30_000_000).unwrap());
        assert_eq!(300, super::time_adjusted("field", 2400, 1200, 15_000_000).unwrap());
    }

    #[test]
    fn test_time_adjusted_first_higher_than_lower() {
        match super::time_adjusted("field", 1200, 2400, 60_000_000) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_parse_u64() {
        assert_eq!(100, super::parse_u64("100").unwrap());
        assert!(super::parse_u64("something").is_err());
    }
}
<commit_msg>Show values in time difference errors<commit_after>extern crate libc;
extern crate time;

mod error;
pub mod cpu;
pub mod disk_stats;
pub mod disk_usage;
pub mod load;
pub mod memory;
pub mod network;
pub mod process_memory;

use std::fs;
use std::io;
use std::io::Read;
use std::path::Path;
use std::result;

pub use error::ProbeError;

pub type Result<T> = result::Result<T, error::ProbeError>;

#[inline]
fn file_to_string(path: &Path) -> io::Result<String> {
    let mut file = try!(fs::File::open(path));
    let mut read = String::new();
    try!(file.read_to_string(&mut read));
    Ok(read)
}

#[inline]
fn file_to_buf_reader(path: &Path) -> io::Result<io::BufReader<fs::File>> {
    fs::File::open(path).and_then(|f| Ok(io::BufReader::new(f)))
}

#[inline]
fn calculate_time_difference(first_time: u64, second_time: u64) -> Result<u64> {
    if first_time > second_time {
        Err(ProbeError::InvalidInput(format!("first time {} was after second time {}", first_time, second_time)))
    } else {
        Ok(second_time - first_time)
    }
}

#[inline]
fn time_adjusted(field_name: &str, first_value: u64, second_value: u64, time_difference_ns: u64) -> Result<u64> {
    if first_value < second_value {
        Err(ProbeError::UnexpectedContent(format!("First value {} was lower than second value {} for '{}'", first_value, second_value, field_name)))
    } else {
        Ok((first_value - second_value) * time_difference_ns / 60_000_000)
    }
}

#[inline]
fn parse_u64(segment: &str) -> Result<u64> {
    segment.parse().map_err(|_| {
        ProbeError::UnexpectedContent(format!("Could not parse '{}' as u64", segment).to_owned())
    })
}

#[cfg(test)]
mod tests {
    use error::ProbeError;

    #[test]
    fn test_calculate_time_difference() {
        assert_eq!(100, super::calculate_time_difference(100, 200).unwrap());
        assert!(super::calculate_time_difference(200, 100).is_err());
    }

    #[test]
    fn test_time_adjusted() {
        assert_eq!(1200, super::time_adjusted("field", 2400, 1200, 60_000_000).unwrap());
        assert_eq!(600, super::time_adjusted("field", 2400, 1200, 30_000_000).unwrap());
        assert_eq!(300, super::time_adjusted("field", 2400, 1200, 15_000_000).unwrap());
    }

    #[test]
    fn test_time_adjusted_first_higher_than_lower() {
        match super::time_adjusted("field", 1200, 2400, 60_000_000) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_parse_u64() {
        assert_eq!(100, super::parse_u64("100").unwrap());
        assert!(super::parse_u64("something").is_err());
    }
}
<|endoftext|>


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

#![allow(let_and_return)]

/*
 * TODO: Show the current shortcut in the status bar.
 * TODO: Set a fixed height to the status bar.
 * TODO: Try to return an Application directly instead of an Rc<Application>.
 * TODO: support shortcuts with number like "50G".
 * TODO: Associate a color with modes.
 */

//! Minimal UI library based on GTK+.

#![warn(missing_docs)]

extern crate gdk;
extern crate gdk_sys;
extern crate glib;
extern crate gobject_sys;
extern crate gtk;
extern crate gtk_sys;
extern crate libc;
extern crate mg_settings;

mod key_converter;
mod gobject;
mod style_context;
#[macro_use]
mod widget;
mod status_bar;

use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use std::rc::Rc;

use gdk::{EventKey, RGBA, CONTROL_MASK};
use gdk::enums::key::{Escape, colon};
use gdk_sys::GdkRGBA;
use gtk::{ContainerExt, Grid, Inhibit, IsA, Settings, Widget, WidgetExt, Window, WindowExt, WindowType, STATE_FLAG_NORMAL};
use gtk::prelude::WidgetExtManual;
use mg_settings::{Config, EnumFromStr, Parser};
use mg_settings::Command::{Custom, Include, Map, Set, Unmap};
use mg_settings::error::{Error, Result};
use mg_settings::error::ErrorType::{MissingArgument, NoCommand, Parse, UnknownCommand};
use mg_settings::key::Key;

use key_converter::gdk_key_to_key;
use gobject::ObjectExtManual;
use self::ShortcutCommand::{Complete, Incomplete};
use status_bar::{StatusBar, StatusBarItem};
use style_context::StyleContextExtManual;

#[macro_export]
macro_rules! hash {
    ($($key:expr => $value:expr),* $(,)*) => {{
        let mut hashmap = std::collections::HashMap::new();
        $(hashmap.insert($key.into(), $value.into());)*
        hashmap
    }};
}

type Modes = HashMap<String, String>;

const RED: &'static GdkRGBA = &GdkRGBA { red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0 };
const TRANSPARENT: &'static GdkRGBA = &GdkRGBA { red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0 };
const WHITE: &'static GdkRGBA = &GdkRGBA { red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0 };

/// A command from a map command.
#[derive(Debug)]
enum ShortcutCommand {
    /// A complete command that is to be executed.
    Complete(String),
    /// An incomplete command where the user needs to complete it and press Enter.
    Incomplete(String),
}

/// Create a new MG application window.
/// This window contains a status bar where the user can type a command and a central widget.
pub struct Application<T> {
    command_callback: RefCell<Option<Box<Fn(T)>>>,
    current_mode: RefCell<String>,
    current_shortcut: RefCell<Vec<Key>>,
    foreground_color: RefCell<RGBA>,
    mappings: RefCell<HashMap<String, HashMap<Vec<Key>, String>>>,
    modes: Modes,
    message: StatusBarItem,
    settings_parser: RefCell<Parser<T>>,
    status_bar: StatusBar,
    vbox: Grid,
    variables: RefCell<HashMap<String, Box<Fn() -> String>>>,
    window: Window,
}

impl<T: EnumFromStr + 'static> Application<T> {
    /// Create a new application.
    #[allow(new_without_default)]
    pub fn new() -> Rc<Self> {
        Application::new_with_config(hash!{})
    }

    /// Create a new application with configuration.
    pub fn new_with_config(mut modes: Modes) -> Rc<Self> {
        modes.insert("n".to_string(), "normal".to_string());
        modes.insert("c".to_string(), "command".to_string());
        let config = Config {
            mapping_modes: modes.keys().cloned().collect(),
        };
        let window = Window::new(WindowType::Toplevel);
        window.connect_delete_event(|_, _| {
            gtk::main_quit();
            Inhibit(false)
        });

        let grid = Grid::new();
        window.add(&grid);

        let status_bar = StatusBar::new();
        grid.attach(&status_bar, 0, 1, 1, 1);
        window.show_all();
        status_bar.hide();

        let foreground_color = Application::<T>::get_foreground_color(&window);

        let message = StatusBarItem::new().left();

        let app = Rc::new(Application {
            command_callback: RefCell::new(None),
            current_mode: RefCell::new("normal".to_string()),
            current_shortcut: RefCell::new(vec![]),
            foreground_color: RefCell::new(foreground_color),
            mappings: RefCell::new(HashMap::new()),
            modes: modes,
            message: message,
            settings_parser: RefCell::new(Parser::new_with_config(config)),
            status_bar: status_bar,
            vbox: grid,
            variables: RefCell::new(HashMap::new()),
            window: window,
        });

        app.status_bar.add_item(&app.message);

        {
            let instance = app.clone();
            app.status_bar.connect_activate(move |command| instance.handle_command(command));
        }

        {
            let instance = app.clone();
            app.window.connect_key_press_event(move |_, key| instance.key_press(key));
        }

        app
    }

    /// Convert an action String to a command String.
    fn action_to_command(&self, action: &str) -> ShortcutCommand {
        if let Some(':') = action.chars().next() {
            if let Some(index) = action.find("<Enter>") {
                Complete(action[1..index].to_string())
            }
            else {
                Incomplete(action[1..].to_string())
            }
        }
        else {
            Complete(action.to_string())
        }
    }

    /// Create a new status bar item.
    pub fn add_statusbar_item(&self) -> StatusBarItem {
        let item = StatusBarItem::new();
        self.status_bar.add_item(&item);
        item
    }

    /// Add the key to the current shortcut.
    fn add_to_shortcut(&self, key: Key) {
        let mut shortcut = self.current_shortcut.borrow_mut();
        shortcut.push(key);
    }

    /// Add a variable that can be used in mappings.
    /// The placeholder will be replaced by the value return by the function.
    pub fn add_variable<F: Fn() -> String + 'static>(&self, variable_name: &str, function: F) {
        let mut variables = self.variables.borrow_mut();
        variables.insert(variable_name.to_string(), Box::new(function));
    }

    /// Add a callback to the command event.
    pub fn connect_command<F: Fn(T) + 'static>(&self, callback: F) {
        *self.command_callback.borrow_mut() = Some(Box::new(callback));
    }

    /// Show an error to the user.
    pub fn error(&self, error: &str) {
        self.message.set_text(error);
        self.status_bar.override_background_color(STATE_FLAG_NORMAL, RED);
        self.status_bar.override_color(STATE_FLAG_NORMAL, WHITE);
    }

    /// Get the color of the text.
    fn get_foreground_color(window: &Window) -> RGBA {
        let style_context = window.get_style_context().unwrap();
        style_context.get_color(STATE_FLAG_NORMAL)
    }

    /// Handle the command activate event.
    fn handle_command(&self, command: Option<String>) {
        if let Some(command) = command {
            if let Some(ref callback) = *self.command_callback.borrow() {
                let result = self.settings_parser.borrow_mut().parse_line(&command);
                match result {
                    Ok(command) => {
                        match command {
                            Custom(command) => callback(command),
                            _ => unimplemented!(),
                        }
                    },
                    Err(error) => {
                        if let Some(error) = error.downcast_ref::<Error>() {
                            let message =
                                match error.typ {
                                    MissingArgument => "Argument required".to_string(),
                                    NoCommand => return,
                                    Parse => format!("Parse error: unexpected {}, expecting: {}", error.unexpected, error.expected),
                                    UnknownCommand => format!("Not a command: {}", error.unexpected),
                                };
                            self.set_mode("normal");
                            self.error(&message);
                        }
                    },
                }
            }
            self.status_bar.hide_entry();
        }
    }

    /// Handle a possible input of a shortcut.
    fn handle_shortcut(&self, key: &EventKey) -> Inhibit {
        if !self.status_bar.entry_shown() {
            let control_pressed = key.get_state() & CONTROL_MASK == CONTROL_MASK;
            if let Some(key) = gdk_key_to_key(key.get_keyval(), control_pressed) {
                self.add_to_shortcut(key);
                let action = {
                    let shortcut = self.current_shortcut.borrow();
                    let mappings = self.mappings.borrow();
                    mappings.get(&*self.current_mode.borrow())
                        .and_then(|mappings| mappings.get(&*shortcut).cloned())
                };
                if let Some(action) = action {
                    self.reset();
                    match self.action_to_command(&action) {
                        Complete(command) => self.handle_command(Some(command)),
                        Incomplete(command) => {
                            self.input_command(&command);
                            return Inhibit(true);
                        },
                    }
                }
                else if self.no_possible_shortcut() {
                    self.reset();
                }
            }
        }
        Inhibit(false)
    }

    /// Input the specified command.
    fn input_command(&self, command: &str) {
        self.status_bar.show_entry();
        let variables = self.variables.borrow();
        let mut command = command.to_string();
        for (variable, function) in variables.iter() {
            command = command.replace(&format!("<{}>", variable), &function());
        }
        let text: Cow<str> =
            if command.contains(' ') {
                command.into()
            }
            else {
                format!("{} ", command).into()
            };
        self.status_bar.set_command(&text);
    }

    /// Handle the key press event.
    #[allow(non_upper_case_globals)]
    fn key_press(&self, key: &EventKey) -> Inhibit {
        let mode = self.current_mode.borrow().clone();
        match mode.as_ref() {
            "normal" => {
                match key.get_keyval() {
                    colon => {
                        self.set_mode("command");
                        self.reset();
                        self.status_bar.show_entry();
                        Inhibit(true)
                    },
                    Escape => {
                        self.reset();
                        Inhibit(true)
                    },
                    _ => self.handle_shortcut(key),
                }
            },
            "command" => {
                match key.get_keyval() {
                    Escape => {
                        self.set_mode("normal");
                        self.reset();
                        Inhibit(true)
                    },
                    _ => self.handle_shortcut(key),
                }
            },
            _ => self.handle_shortcut(key)
        }
    }

    /// Check if there are no possible shortcuts.
    fn no_possible_shortcut(&self) -> bool {
        let current_shortcut = self.current_shortcut.borrow();
        let mappings = self.mappings.borrow();
        if let Some(mappings) = mappings.get(&*self.current_mode.borrow()) {
            for key in mappings.keys() {
                if key.starts_with(&*current_shortcut) {
                    return false;
                }
            }
        }
        true
    }

    /// Parse a configuration file.
    pub fn parse_config<P: AsRef<Path>>(&self, filename: P) -> Result<()> {
        let file = try!(File::open(filename));
        let buf_reader = BufReader::new(file);
        let commands = try!(self.settings_parser.borrow_mut().parse(buf_reader));
        for command in commands {
            match command {
                Custom(_) => (), // TODO: call the callback?
                Include(_) => (), // TODO: parse the included file.
                Map { action, keys, mode } => {
                    let mut mappings = self.mappings.borrow_mut();
                    let mappings = mappings.entry(self.modes[&mode].clone()).or_insert_with(HashMap::new);
                    mappings.insert(keys, action);
                },
                Set(_, _) => (), // TODO: set settings.
                Unmap { .. } => (), // TODO
            }
        }
        Ok(())
    }

    /// Handle the escape event.
    fn reset(&self) {
        self.status_bar.override_background_color(STATE_FLAG_NORMAL, TRANSPARENT);
        self.status_bar.override_color(STATE_FLAG_NORMAL, &self.foreground_color.borrow());
        self.status_bar.hide();
        self.show_mode();
        let mut shortcut = self.current_shortcut.borrow_mut();
        shortcut.clear();
    }

    /// Set the current mode.
    pub fn set_mode(&self, mode: &str) {
        *self.current_mode.borrow_mut() = mode.to_string();
        self.show_mode();
    }

    /// Set the main widget.
    pub fn set_view<W: IsA<Widget> + WidgetExt>(&self, view: &W) {
        view.set_hexpand(true);
        view.set_vexpand(true);
        view.show_all();
        self.vbox.attach(view, 0, 0, 1, 1);
    }

    /// Set the window title.
    pub fn set_window_title(&self, title: &str) {
        self.window.set_title(title);
    }

    /// Show the current mode if it is not the normal mode.
    fn show_mode(&self) {
        let mode = self.current_mode.borrow();
        if *mode != "normal" && *mode != "command" {
            self.message.set_text(&mode);
        }
        else {
            self.message.set_text("");
        }
    }

    /// Use the dark variant of the theme if available.
    pub fn use_dark_theme(&self) {
        let settings = Settings::get_default().unwrap();
        settings.set_data("gtk-application-prefer-dark-theme", 1);
        *self.foreground_color.borrow_mut() = Application::<T>::get_foreground_color(&self.window);
    }

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

#![allow(let_and_return)]

/*
 * TODO: Show the current shortcut in the status bar.
 * TODO: Set a fixed height to the status bar.
 * TODO: Try to return an Application directly instead of an Rc<Application>.
 * TODO: support shortcuts with number like "50G".
 * TODO: Associate a color with modes.
 */

//! Minimal UI library based on GTK+.

#![warn(missing_docs)]

extern crate gdk;
extern crate gdk_sys;
extern crate glib;
extern crate gobject_sys;
extern crate gtk;
extern crate gtk_sys;
extern crate libc;
extern crate mg_settings;

mod key_converter;
mod gobject;
mod style_context;
#[macro_use]
mod widget;
mod status_bar;

use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use std::rc::Rc;

use gdk::{EventKey, RGBA, CONTROL_MASK};
use gdk::enums::key::{Escape, colon};
use gdk_sys::GdkRGBA;
use gtk::{ContainerExt, Grid, Inhibit, IsA, Settings, Widget, WidgetExt, Window, WindowExt, WindowType, STATE_FLAG_NORMAL};
use gtk::prelude::WidgetExtManual;
use mg_settings::{Config, EnumFromStr, Parser};
use mg_settings::Command::{Custom, Include, Map, Set, Unmap};
use mg_settings::error::{Error, Result};
use mg_settings::error::ErrorType::{MissingArgument, NoCommand, Parse, UnknownCommand};
use mg_settings::key::Key;

use key_converter::gdk_key_to_key;
use gobject::ObjectExtManual;
use self::ShortcutCommand::{Complete, Incomplete};
use status_bar::{StatusBar, StatusBarItem};
use style_context::StyleContextExtManual;

#[macro_export]
macro_rules! hash {
    ($($key:expr => $value:expr),* $(,)*) => {{
        let mut hashmap = ::std::collections::HashMap::new();
        $(hashmap.insert($key.into(), $value.into());)*
        hashmap
    }};
}

type Modes = HashMap<String, String>;

const RED: &'static GdkRGBA = &GdkRGBA { red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0 };
const TRANSPARENT: &'static GdkRGBA = &GdkRGBA { red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0 };
const WHITE: &'static GdkRGBA = &GdkRGBA { red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0 };

/// A command from a map command.
#[derive(Debug)]
enum ShortcutCommand {
    /// A complete command that is to be executed.
    Complete(String),
    /// An incomplete command where the user needs to complete it and press Enter.
    Incomplete(String),
}

/// Create a new MG application window.
/// This window contains a status bar where the user can type a command and a central widget.
pub struct Application<T> {
    command_callback: RefCell<Option<Box<Fn(T)>>>,
    current_mode: RefCell<String>,
    current_shortcut: RefCell<Vec<Key>>,
    foreground_color: RefCell<RGBA>,
    mappings: RefCell<HashMap<String, HashMap<Vec<Key>, String>>>,
    modes: Modes,
    message: StatusBarItem,
    settings_parser: RefCell<Parser<T>>,
    status_bar: StatusBar,
    vbox: Grid,
    variables: RefCell<HashMap<String, Box<Fn() -> String>>>,
    window: Window,
}

impl<T: EnumFromStr + 'static> Application<T> {
    /// Create a new application.
    #[allow(new_without_default)]
    pub fn new() -> Rc<Self> {
        Application::new_with_config(hash!{})
    }

    /// Create a new application with configuration.
    pub fn new_with_config(mut modes: Modes) -> Rc<Self> {
        modes.insert("n".to_string(), "normal".to_string());
        modes.insert("c".to_string(), "command".to_string());
        let config = Config {
            mapping_modes: modes.keys().cloned().collect(),
        };
        let window = Window::new(WindowType::Toplevel);
        window.connect_delete_event(|_, _| {
            gtk::main_quit();
            Inhibit(false)
        });

        let grid = Grid::new();
        window.add(&grid);

        let status_bar = StatusBar::new();
        grid.attach(&status_bar, 0, 1, 1, 1);
        window.show_all();
        status_bar.hide();

        let foreground_color = Application::<T>::get_foreground_color(&window);

        let message = StatusBarItem::new().left();

        let app = Rc::new(Application {
            command_callback: RefCell::new(None),
            current_mode: RefCell::new("normal".to_string()),
            current_shortcut: RefCell::new(vec![]),
            foreground_color: RefCell::new(foreground_color),
            mappings: RefCell::new(HashMap::new()),
            modes: modes,
            message: message,
            settings_parser: RefCell::new(Parser::new_with_config(config)),
            status_bar: status_bar,
            vbox: grid,
            variables: RefCell::new(HashMap::new()),
            window: window,
        });

        app.status_bar.add_item(&app.message);

        {
            let instance = app.clone();
            app.status_bar.connect_activate(move |command| instance.handle_command(command));
        }

        {
            let instance = app.clone();
            app.window.connect_key_press_event(move |_, key| instance.key_press(key));
        }

        app
    }

    /// Convert an action String to a command String.
    fn action_to_command(&self, action: &str) -> ShortcutCommand {
        if let Some(':') = action.chars().next() {
            if let Some(index) = action.find("<Enter>") {
                Complete(action[1..index].to_string())
            }
            else {
                Incomplete(action[1..].to_string())
            }
        }
        else {
            Complete(action.to_string())
        }
    }

    /// Create a new status bar item.
    pub fn add_statusbar_item(&self) -> StatusBarItem {
        let item = StatusBarItem::new();
        self.status_bar.add_item(&item);
        item
    }

    /// Add the key to the current shortcut.
    fn add_to_shortcut(&self, key: Key) {
        let mut shortcut = self.current_shortcut.borrow_mut();
        shortcut.push(key);
    }

    /// Add a variable that can be used in mappings.
    /// The placeholder will be replaced by the value return by the function.
    pub fn add_variable<F: Fn() -> String + 'static>(&self, variable_name: &str, function: F) {
        let mut variables = self.variables.borrow_mut();
        variables.insert(variable_name.to_string(), Box::new(function));
    }

    /// Add a callback to the command event.
    pub fn connect_command<F: Fn(T) + 'static>(&self, callback: F) {
        *self.command_callback.borrow_mut() = Some(Box::new(callback));
    }

    /// Show an error to the user.
    pub fn error(&self, error: &str) {
        self.message.set_text(error);
        self.status_bar.override_background_color(STATE_FLAG_NORMAL, RED);
        self.status_bar.override_color(STATE_FLAG_NORMAL, WHITE);
    }

    /// Get the color of the text.
    fn get_foreground_color(window: &Window) -> RGBA {
        let style_context = window.get_style_context().unwrap();
        style_context.get_color(STATE_FLAG_NORMAL)
    }

    /// Handle the command activate event.
    fn handle_command(&self, command: Option<String>) {
        if let Some(command) = command {
            if let Some(ref callback) = *self.command_callback.borrow() {
                let result = self.settings_parser.borrow_mut().parse_line(&command);
                match result {
                    Ok(command) => {
                        match command {
                            Custom(command) => callback(command),
                            _ => unimplemented!(),
                        }
                    },
                    Err(error) => {
                        if let Some(error) = error.downcast_ref::<Error>() {
                            let message =
                                match error.typ {
                                    MissingArgument => "Argument required".to_string(),
                                    NoCommand => return,
                                    Parse => format!("Parse error: unexpected {}, expecting: {}", error.unexpected, error.expected),
                                    UnknownCommand => format!("Not a command: {}", error.unexpected),
                                };
                            self.set_mode("normal");
                            self.error(&message);
                        }
                    },
                }
            }
            self.status_bar.hide_entry();
        }
    }

    /// Handle a possible input of a shortcut.
    fn handle_shortcut(&self, key: &EventKey) -> Inhibit {
        if !self.status_bar.entry_shown() {
            let control_pressed = key.get_state() & CONTROL_MASK == CONTROL_MASK;
            if let Some(key) = gdk_key_to_key(key.get_keyval(), control_pressed) {
                self.add_to_shortcut(key);
                let action = {
                    let shortcut = self.current_shortcut.borrow();
                    let mappings = self.mappings.borrow();
                    mappings.get(&*self.current_mode.borrow())
                        .and_then(|mappings| mappings.get(&*shortcut).cloned())
                };
                if let Some(action) = action {
                    self.reset();
                    match self.action_to_command(&action) {
                        Complete(command) => self.handle_command(Some(command)),
                        Incomplete(command) => {
                            self.input_command(&command);
                            return Inhibit(true);
                        },
                    }
                }
                else if self.no_possible_shortcut() {
                    self.reset();
                }
            }
        }
        Inhibit(false)
    }

    /// Input the specified command.
    fn input_command(&self, command: &str) {
        self.status_bar.show_entry();
        let variables = self.variables.borrow();
        let mut command = command.to_string();
        for (variable, function) in variables.iter() {
            command = command.replace(&format!("<{}>", variable), &function());
        }
        let text: Cow<str> =
            if command.contains(' ') {
                command.into()
            }
            else {
                format!("{} ", command).into()
            };
        self.status_bar.set_command(&text);
    }

    /// Handle the key press event.
    #[allow(non_upper_case_globals)]
    fn key_press(&self, key: &EventKey) -> Inhibit {
        let mode = self.current_mode.borrow().clone();
        match mode.as_ref() {
            "normal" => {
                match key.get_keyval() {
                    colon => {
                        self.set_mode("command");
                        self.reset();
                        self.status_bar.show_entry();
                        Inhibit(true)
                    },
                    Escape => {
                        self.reset();
                        Inhibit(true)
                    },
                    _ => self.handle_shortcut(key),
                }
            },
            "command" => {
                match key.get_keyval() {
                    Escape => {
                        self.set_mode("normal");
                        self.reset();
                        Inhibit(true)
                    },
                    _ => self.handle_shortcut(key),
                }
            },
            _ => self.handle_shortcut(key)
        }
    }

    /// Check if there are no possible shortcuts.
    fn no_possible_shortcut(&self) -> bool {
        let current_shortcut = self.current_shortcut.borrow();
        let mappings = self.mappings.borrow();
        if let Some(mappings) = mappings.get(&*self.current_mode.borrow()) {
            for key in mappings.keys() {
                if key.starts_with(&*current_shortcut) {
                    return false;
                }
            }
        }
        true
    }

    /// Parse a configuration file.
    pub fn parse_config<P: AsRef<Path>>(&self, filename: P) -> Result<()> {
        let file = try!(File::open(filename));
        let buf_reader = BufReader::new(file);
        let commands = try!(self.settings_parser.borrow_mut().parse(buf_reader));
        for command in commands {
            match command {
                Custom(_) => (), // TODO: call the callback?
                Include(_) => (), // TODO: parse the included file.
                Map { action, keys, mode } => {
                    let mut mappings = self.mappings.borrow_mut();
                    let mappings = mappings.entry(self.modes[&mode].clone()).or_insert_with(HashMap::new);
                    mappings.insert(keys, action);
                },
                Set(_, _) => (), // TODO: set settings.
                Unmap { .. } => (), // TODO
            }
        }
        Ok(())
    }

    /// Handle the escape event.
    fn reset(&self) {
        self.status_bar.override_background_color(STATE_FLAG_NORMAL, TRANSPARENT);
        self.status_bar.override_color(STATE_FLAG_NORMAL, &self.foreground_color.borrow());
        self.status_bar.hide();
        self.show_mode();
        let mut shortcut = self.current_shortcut.borrow_mut();
        shortcut.clear();
    }

    /// Set the current mode.
    pub fn set_mode(&self, mode: &str) {
        *self.current_mode.borrow_mut() = mode.to_string();
        self.show_mode();
    }

    /// Set the main widget.
    pub fn set_view<W: IsA<Widget> + WidgetExt>(&self, view: &W) {
        view.set_hexpand(true);
        view.set_vexpand(true);
        view.show_all();
        self.vbox.attach(view, 0, 0, 1, 1);
    }

    /// Set the window title.
    pub fn set_window_title(&self, title: &str) {
        self.window.set_title(title);
    }

    /// Show the current mode if it is not the normal mode.
    fn show_mode(&self) {
        let mode = self.current_mode.borrow();
        if *mode != "normal" && *mode != "command" {
            self.message.set_text(&mode);
        }
        else {
            self.message.set_text("");
        }
    }

    /// Use the dark variant of the theme if available.
    pub fn use_dark_theme(&self) {
        let settings = Settings::get_default().unwrap();
        settings.set_data("gtk-application-prefer-dark-theme", 1);
        *self.foreground_color.borrow_mut() = Application::<T>::get_foreground_color(&self.window);
    }

    /// Get the application window.
    pub fn window(&self) -> &Window {
        &self.window
    }
}
<|endoftext|>