<commit_before>use crate::{Env, Error, NifResult, Term};

#[macro_use]
pub mod atom;
pub use crate::types::atom::Atom;

#[doc(hidden)]
pub mod binary;
pub use crate::types::binary::{Binary, OwnedBinary};

#[doc(hidden)]
pub mod list;
pub use crate::types::list::ListIterator;

#[doc(hidden)]
pub mod map;
pub use self::map::MapIterator;

#[doc(hidden)]
pub mod primitive;
#[doc(hidden)]
pub mod string;
pub mod tuple;

#[doc(hidden)]
pub mod local_pid;
pub use self::local_pid::LocalPid;

#[deprecated(since = "0.22", note = "Please use local_pid instead")]
pub mod pid {
    #[deprecated(since = "0.22", note = "Please use LocalPid instead")]
    pub use super::LocalPid as Pid;
}
#[deprecated(since = "0.22", note = "Please use LocalPid instead")]
pub use self::LocalPid as Pid;

pub mod truthy;

pub mod elixir_struct;

pub trait Encoder {
    fn encode<'a>(&self, env: Env<'a>) -> Term<'a>;
}
pub trait Decoder<'a>: Sized + 'a {
    fn decode(term: Term<'a>) -> NifResult<Self>;
}

impl<'a> Encoder for Term<'a> {
    fn encode<'b>(&self, env: Env<'b>) -> Term<'b> {
        self.in_env(env)
    }
}
impl<'a> Decoder<'a> for Term<'a> {
    fn decode(term: Term<'a>) -> NifResult<Self> {
        Ok(term)
    }
}

impl<'a, T> Encoder for &'a T
where
    T: Encoder,
{
    fn encode<'c>(&self, env: Env<'c>) -> Term<'c> {
        <T as Encoder>::encode(self, env)
    }
}

impl<T> Encoder for Option<T>
where
    T: Encoder,
{
    fn encode<'c>(&self, env: Env<'c>) -> Term<'c> {
        match *self {
            Some(ref value) => value.encode(env),
            None => atom::nil().encode(env),
        }
    }
}

impl<'a, T> Decoder<'a> for Option<T>
where
    T: Decoder<'a>,
{
    fn decode(term: Term<'a>) -> NifResult<Self> {
        if let Ok(term) = term.decode::<T>() {
            Ok(Some(term))
        } else {
            let decoded_atom: atom::Atom = term.decode()?;
            if decoded_atom == atom::nil() {
                Ok(None)
            } else {
                Err(Error::BadArg)
            }
        }
    }
}

impl<T, E> Encoder for Result<T, E>
where
    T: Encoder,
    E: Encoder,
{
    fn encode<'c>(&self, env: Env<'c>) -> Term<'c> {
        match *self {
            Ok(ref value) => (atom::ok().encode(env), value.encode(env)).encode(env),
            Err(ref err) => (atom::error().encode(env), err.encode(env)).encode(env),
        }
    }
}

impl<'a, T, E> Decoder<'a> for Result<T, E>
where
    T: Decoder<'a>,
    E: Decoder<'a>,
{
    fn decode(term: Term<'a>) -> NifResult<Self> {
        let (decoded_atom, inner_term): (atom::Atom, Term) = term.decode()?;
        if decoded_atom == atom::ok() {
            let ok_value: T = inner_term.decode()?;
            Ok(Ok(ok_value))
        } else if decoded_atom == atom::error() {
            let err_value: E = inner_term.decode()?;
            Ok(Err(err_value))
        } else {
            Err(Error::BadArg)
        }
    }
}
<commit_msg>Fix clippy warnings<commit_after>use crate::{Env, Error, NifResult, Term};

#[macro_use]
pub mod atom;
pub use crate::types::atom::Atom;

#[doc(hidden)]
pub mod binary;
pub use crate::types::binary::{Binary, OwnedBinary};

#[doc(hidden)]
pub mod list;
pub use crate::types::list::ListIterator;

#[doc(hidden)]
pub mod map;
pub use self::map::MapIterator;

#[doc(hidden)]
pub mod primitive;
#[doc(hidden)]
pub mod string;
pub mod tuple;

#[doc(hidden)]
pub mod local_pid;
pub use self::local_pid::LocalPid;

#[deprecated(since = "0.22.0", note = "Please use local_pid instead")]
pub mod pid {
    #[deprecated(since = "0.22.0", note = "Please use LocalPid instead")]
    pub use super::LocalPid as Pid;
}
#[deprecated(since = "0.22.0", note = "Please use LocalPid instead")]
pub use self::LocalPid as Pid;

pub mod truthy;

pub mod elixir_struct;

pub trait Encoder {
    fn encode<'a>(&self, env: Env<'a>) -> Term<'a>;
}
pub trait Decoder<'a>: Sized + 'a {
    fn decode(term: Term<'a>) -> NifResult<Self>;
}

impl<'a> Encoder for Term<'a> {
    fn encode<'b>(&self, env: Env<'b>) -> Term<'b> {
        self.in_env(env)
    }
}
impl<'a> Decoder<'a> for Term<'a> {
    fn decode(term: Term<'a>) -> NifResult<Self> {
        Ok(term)
    }
}

impl<'a, T> Encoder for &'a T
where
    T: Encoder,
{
    fn encode<'c>(&self, env: Env<'c>) -> Term<'c> {
        <T as Encoder>::encode(self, env)
    }
}

impl<T> Encoder for Option<T>
where
    T: Encoder,
{
    fn encode<'c>(&self, env: Env<'c>) -> Term<'c> {
        match *self {
            Some(ref value) => value.encode(env),
            None => atom::nil().encode(env),
        }
    }
}

impl<'a, T> Decoder<'a> for Option<T>
where
    T: Decoder<'a>,
{
    fn decode(term: Term<'a>) -> NifResult<Self> {
        if let Ok(term) = term.decode::<T>() {
            Ok(Some(term))
        } else {
            let decoded_atom: atom::Atom = term.decode()?;
            if decoded_atom == atom::nil() {
                Ok(None)
            } else {
                Err(Error::BadArg)
            }
        }
    }
}

impl<T, E> Encoder for Result<T, E>
where
    T: Encoder,
    E: Encoder,
{
    fn encode<'c>(&self, env: Env<'c>) -> Term<'c> {
        match *self {
            Ok(ref value) => (atom::ok().encode(env), value.encode(env)).encode(env),
            Err(ref err) => (atom::error().encode(env), err.encode(env)).encode(env),
        }
    }
}

impl<'a, T, E> Decoder<'a> for Result<T, E>
where
    T: Decoder<'a>,
    E: Decoder<'a>,
{
    fn decode(term: Term<'a>) -> NifResult<Self> {
        let (decoded_atom, inner_term): (atom::Atom, Term) = term.decode()?;
        if decoded_atom == atom::ok() {
            let ok_value: T = inner_term.decode()?;
            Ok(Ok(ok_value))
        } else if decoded_atom == atom::error() {
            let err_value: E = inner_term.decode()?;
            Ok(Err(err_value))
        } else {
            Err(Error::BadArg)
        }
    }
}
<|endoftext|>


<commit_before>pub use self::imp::Sha256;

// Someone upstream will link to OpenSSL, so we don't need to explicitly
// link to it ourselves. Hence we pick up Sha256 digests from OpenSSL
#[cfg(not(windows))]
#[allow(bad_style)]
mod imp {
    use libc;

    enum EVP_MD_CTX {}
    enum EVP_MD {}
    enum ENGINE {}

    extern {
        fn EVP_DigestInit_ex(ctx: *mut EVP_MD_CTX,
                             kind: *const EVP_MD,
                             imp: *mut ENGINE) -> libc::c_int;
        fn EVP_DigestUpdate(ctx: *mut EVP_MD_CTX,
                            d: *const libc::c_void,
                            cnt: libc::size_t) -> libc::c_int;
        fn EVP_DigestFinal_ex(ctx: *mut EVP_MD_CTX, md: *mut libc::c_uchar,
                              s: *mut libc::c_uint) -> libc::c_int;
        fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX;
        fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX);
        fn EVP_sha256() -> *const EVP_MD;
    }

    pub struct Sha256 { ctx: *mut EVP_MD_CTX }

    impl Sha256 {
        pub fn new() -> Sha256 {
            unsafe {
                let ctx = EVP_MD_CTX_create();
                assert!(!ctx.is_null());
                let ret = Sha256 { ctx: ctx };
                let n = EVP_DigestInit_ex(ret.ctx, EVP_sha256(), 0 as *mut _);
                assert_eq!(n, 1);
                return ret;
            }
        }

        pub fn update(&mut self, bytes: &[u8]) {
            unsafe {
                let n = EVP_DigestUpdate(self.ctx, bytes.as_ptr() as *const _,
                                         bytes.len() as libc::size_t);
                assert_eq!(n, 1);
            }
        }

        pub fn finish(&mut self) -> [u8; 32] {
            unsafe {
                let mut ret = [0u8; 32];
                let mut out = 0;
                let n = EVP_DigestFinal_ex(self.ctx, ret.as_mut_ptr(), &mut out);
                assert_eq!(n, 1);
                assert_eq!(out, 32);
                return ret;
            }
        }
    }

    impl Drop for Sha256 {
        fn drop(&mut self) {
            unsafe { EVP_MD_CTX_destroy(self.ctx) }
        }
    }
}

// Leverage the crypto APIs that windows has built in.
#[cfg(windows)]
mod imp {
    extern crate winapi;
    extern crate advapi32;
    use std::io;
    use std::ptr;

    use self::winapi::{DWORD, HCRYPTPROV, HCRYPTHASH};
    use self::winapi::{PROV_RSA_AES, CRYPT_SILENT, CRYPT_VERIFYCONTEXT, CALG_SHA_256, HP_HASHVAL};
    use self::advapi32::{CryptAcquireContextW, CryptCreateHash, CryptDestroyHash};
    use self::advapi32::{CryptGetHashParam, CryptHashData, CryptReleaseContext};

    macro_rules! call{ ($e:expr) => ({
        if $e == 0 {
            panic!("failed {}: {}", stringify!($e), io::Error::last_os_error())
        }
    }) }

    pub struct Sha256 {
        hcryptprov: HCRYPTPROV,
        hcrypthash: HCRYPTHASH,
    }

    impl Sha256 {
        pub fn new() -> Sha256 {
            let mut hcp = 0;
            call!(unsafe {
                CryptAcquireContextW(&mut hcp, ptr::null(), ptr::null(),
                                     PROV_RSA_AES,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            });
            let mut ret = Sha256 { hcryptprov: hcp, hcrypthash: 0 };
            call!(unsafe {
                CryptCreateHash(ret.hcryptprov, CALG_SHA_256,
                                0, 0, &mut ret.hcrypthash)
            });
            return ret;
        }

        pub fn update(&mut self, bytes: &[u8]) {
            call!(unsafe {
                CryptHashData(self.hcrypthash, bytes.as_ptr() as *mut _,
                              bytes.len() as DWORD, 0)
            })
        }

        pub fn finish(&mut self) -> [u8; 32] {
            let mut ret = [0u8; 32];
            let mut len = ret.len() as DWORD;
            call!(unsafe {
                CryptGetHashParam(self.hcrypthash, HP_HASHVAL, ret.as_mut_ptr(),
                                  &mut len, 0)
            });
            assert_eq!(len as usize, ret.len());
            return ret;
        }
    }

    impl Drop for Sha256 {
        fn drop(&mut self) {
            if self.hcrypthash != 0 {
                call!(unsafe { CryptDestroyHash(self.hcrypthash) });
            }
            call!(unsafe { CryptReleaseContext(self.hcryptprov, 0) });
        }
    }
}
<commit_msg>Whitelist improper ctypes to support old rustc versions<commit_after>pub use self::imp::Sha256;

// Someone upstream will link to OpenSSL, so we don't need to explicitly
// link to it ourselves. Hence we pick up Sha256 digests from OpenSSL
#[cfg(not(windows))]
// allow improper ctypes because size_t falls under that in old compilers
#[allow(bad_style, improper_ctypes)]
mod imp {
    use libc;

    enum EVP_MD_CTX {}
    enum EVP_MD {}
    enum ENGINE {}

    extern {
        fn EVP_DigestInit_ex(ctx: *mut EVP_MD_CTX,
                             kind: *const EVP_MD,
                             imp: *mut ENGINE) -> libc::c_int;
        fn EVP_DigestUpdate(ctx: *mut EVP_MD_CTX,
                            d: *const libc::c_void,
                            cnt: libc::size_t) -> libc::c_int;
        fn EVP_DigestFinal_ex(ctx: *mut EVP_MD_CTX, md: *mut libc::c_uchar,
                              s: *mut libc::c_uint) -> libc::c_int;
        fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX;
        fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX);
        fn EVP_sha256() -> *const EVP_MD;
    }

    pub struct Sha256 { ctx: *mut EVP_MD_CTX }

    impl Sha256 {
        pub fn new() -> Sha256 {
            unsafe {
                let ctx = EVP_MD_CTX_create();
                assert!(!ctx.is_null());
                let ret = Sha256 { ctx: ctx };
                let n = EVP_DigestInit_ex(ret.ctx, EVP_sha256(), 0 as *mut _);
                assert_eq!(n, 1);
                return ret;
            }
        }

        pub fn update(&mut self, bytes: &[u8]) {
            unsafe {
                let n = EVP_DigestUpdate(self.ctx, bytes.as_ptr() as *const _,
                                         bytes.len() as libc::size_t);
                assert_eq!(n, 1);
            }
        }

        pub fn finish(&mut self) -> [u8; 32] {
            unsafe {
                let mut ret = [0u8; 32];
                let mut out = 0;
                let n = EVP_DigestFinal_ex(self.ctx, ret.as_mut_ptr(), &mut out);
                assert_eq!(n, 1);
                assert_eq!(out, 32);
                return ret;
            }
        }
    }

    impl Drop for Sha256 {
        fn drop(&mut self) {
            unsafe { EVP_MD_CTX_destroy(self.ctx) }
        }
    }
}

// Leverage the crypto APIs that windows has built in.
#[cfg(windows)]
mod imp {
    extern crate winapi;
    extern crate advapi32;
    use std::io;
    use std::ptr;

    use self::winapi::{DWORD, HCRYPTPROV, HCRYPTHASH};
    use self::winapi::{PROV_RSA_AES, CRYPT_SILENT, CRYPT_VERIFYCONTEXT, CALG_SHA_256, HP_HASHVAL};
    use self::advapi32::{CryptAcquireContextW, CryptCreateHash, CryptDestroyHash};
    use self::advapi32::{CryptGetHashParam, CryptHashData, CryptReleaseContext};

    macro_rules! call{ ($e:expr) => ({
        if $e == 0 {
            panic!("failed {}: {}", stringify!($e), io::Error::last_os_error())
        }
    }) }

    pub struct Sha256 {
        hcryptprov: HCRYPTPROV,
        hcrypthash: HCRYPTHASH,
    }

    impl Sha256 {
        pub fn new() -> Sha256 {
            let mut hcp = 0;
            call!(unsafe {
                CryptAcquireContextW(&mut hcp, ptr::null(), ptr::null(),
                                     PROV_RSA_AES,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            });
            let mut ret = Sha256 { hcryptprov: hcp, hcrypthash: 0 };
            call!(unsafe {
                CryptCreateHash(ret.hcryptprov, CALG_SHA_256,
                                0, 0, &mut ret.hcrypthash)
            });
            return ret;
        }

        pub fn update(&mut self, bytes: &[u8]) {
            call!(unsafe {
                CryptHashData(self.hcrypthash, bytes.as_ptr() as *mut _,
                              bytes.len() as DWORD, 0)
            })
        }

        pub fn finish(&mut self) -> [u8; 32] {
            let mut ret = [0u8; 32];
            let mut len = ret.len() as DWORD;
            call!(unsafe {
                CryptGetHashParam(self.hcrypthash, HP_HASHVAL, ret.as_mut_ptr(),
                                  &mut len, 0)
            });
            assert_eq!(len as usize, ret.len());
            return ret;
        }
    }

    impl Drop for Sha256 {
        fn drop(&mut self) {
            if self.hcrypthash != 0 {
                call!(unsafe { CryptDestroyHash(self.hcrypthash) });
            }
            call!(unsafe { CryptReleaseContext(self.hcryptprov, 0) });
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};

use env::Env;
use file_saver::save_to_file;
use regex::Regex;

pub fn generate(env: &Env) {
    println!(
        "generating sys build script for {}",
        env.config.library_name
    );

    let path = env.config.target_path.join("build.rs");

    println!("Generating file {:?}", path);
    save_to_file(
        &path,
        env.config.make_backup,
        |w| generate_build_script(w, env),
    );
}

fn generate_build_script(w: &mut Write, env: &Env) -> Result<()> {
    try!(write!(
        w,
        "{}",
        r##"extern crate pkg_config;

use pkg_config::{Config, Error};
use std::env;
use std::io::prelude::*;
use std::io;
use std::process;

fn main() {
    if let Err(s) = find() {
        let _ = writeln!(io::stderr(), "{}", s);
        process::exit(1);
    }
}

fn find() -> Result<(), Error> {
"##
    ));

    let ns = env.namespaces.main();
    let regex = Regex::new(r"^lib(.+)\.so.*$").expect("Regex failed");
    let shared_libs: Vec<_> = ns.shared_libs
        .iter()
        .map(|s| {
            if !regex.is_match(s) {
                panic!("A 'shared-library' in the GIR file doesn't match the following form: '^lib(.+)\\.so.*$'");
            }
            regex.replace(s, "\"$1\"")
        })
        .collect();

    try!(writeln!(
        w,
        "\tlet package_name = \"{}\";",
        ns.package_name
            .as_ref()
            .expect("Package name doesn't exist")
    ));
    try!(writeln!(
        w,
        "\tlet shared_libs = [{}];",
        shared_libs.join(", ")
    ));
    try!(write!(w, "\tlet version = "));
    let versions = ns.versions
        .iter()
        .filter(|v| **v >= env.config.min_cfg_version)
        .skip(1)
        .collect::<Vec<_>>();
    for v in versions.iter().rev() {
        try!(write!(
            w,
            "if cfg!({}) {{\n\t\t\"{}\"\n\t}} else ",
            v.to_cfg(),
            v
        ));
    }
    try!(writeln!(
        w,
        "{{\n\t\t\"{}\"\n\t}};",
        env.config.min_cfg_version
    ));

    writeln!(
        w,
        "{}",
        r##"
    if let Ok(lib_dir) = env::var("GTK_LIB_DIR") {
        for lib_ in shared_libs.iter() {
            println!("cargo:rustc-link-lib=dylib={}", lib_);
        }
        println!("cargo:rustc-link-search=native={}", lib_dir);
        return Ok(())
    }

    let target = env::var("TARGET").expect("TARGET environment variable doesn't exist");
    let hardcode_shared_libs = target.contains("windows");

    let mut config = Config::new();
    config.atleast_version(version);
    if hardcode_shared_libs {
        config.cargo_metadata(false);
    }
    match config.probe(package_name) {
        Ok(library) => {
            if hardcode_shared_libs {
                for lib_ in shared_libs.iter() {
                    println!("cargo:rustc-link-lib=dylib={}", lib_);
                }
                for path in library.link_paths.iter() {
                    println!("cargo:rustc-link-search=native={}",
                             path.to_str().expect("library path doesn't exist"));
                }
            }
            Ok(())
        }
        Err(Error::EnvNoPkgConfig(_)) | Err(Error::Command { .. }) => {
            for lib_ in shared_libs.iter() {
                println!("cargo:rustc-link-lib=dylib={}", lib_);
            }
            Ok(())
        }
        Err(err) => Err(err),
    }
}
"##
    )
}
<commit_msg>Use `Path` for extracting shared-library name<commit_after>use std::io::{Result, Write};
use std::path::Path;

use env::Env;
use file_saver::save_to_file;
use regex::Regex;

pub fn generate(env: &Env) {
    println!(
        "generating sys build script for {}",
        env.config.library_name
    );

    let path = env.config.target_path.join("build.rs");

    println!("Generating file {:?}", path);
    save_to_file(
        &path,
        env.config.make_backup,
        |w| generate_build_script(w, env),
    );
}

fn generate_build_script(w: &mut Write, env: &Env) -> Result<()> {
    try!(write!(
        w,
        "{}",
        r##"extern crate pkg_config;

use pkg_config::{Config, Error};
use std::env;
use std::io::prelude::*;
use std::io;
use std::process;

fn main() {
    if let Err(s) = find() {
        let _ = writeln!(io::stderr(), "{}", s);
        process::exit(1);
    }
}

fn find() -> Result<(), Error> {
"##
    ));

    let ns = env.namespaces.main();
    let regex = Regex::new(r"^lib(.+)\.(so.*|dylib)$").expect("Regex failed");
    let shared_libs: Vec<_> = ns.shared_libs
        .iter()
        .map(|s| {
            let lib_path = Path::new(s);
            let lib_file_name = lib_path
                .file_name()
                .expect("A 'shared-library' in the GIR file has an invalid form")
                .to_str()
                .expect("Failed to convert OsStr to str");
            regex.replace(lib_file_name, "\"$1\"")
        })
        .collect();

    try!(writeln!(
        w,
        "\tlet package_name = \"{}\";",
        ns.package_name
            .as_ref()
            .expect("Package name doesn't exist")
    ));
    try!(writeln!(
        w,
        "\tlet shared_libs = [{}];",
        shared_libs.join(", ")
    ));
    try!(write!(w, "\tlet version = "));
    let versions = ns.versions
        .iter()
        .filter(|v| **v >= env.config.min_cfg_version)
        .skip(1)
        .collect::<Vec<_>>();
    for v in versions.iter().rev() {
        try!(write!(
            w,
            "if cfg!({}) {{\n\t\t\"{}\"\n\t}} else ",
            v.to_cfg(),
            v
        ));
    }
    try!(writeln!(
        w,
        "{{\n\t\t\"{}\"\n\t}};",
        env.config.min_cfg_version
    ));

    writeln!(
        w,
        "{}",
        r##"
    if let Ok(lib_dir) = env::var("GTK_LIB_DIR") {
        for lib_ in shared_libs.iter() {
            println!("cargo:rustc-link-lib=dylib={}", lib_);
        }
        println!("cargo:rustc-link-search=native={}", lib_dir);
        return Ok(())
    }

    let target = env::var("TARGET").expect("TARGET environment variable doesn't exist");
    let hardcode_shared_libs = target.contains("windows");

    let mut config = Config::new();
    config.atleast_version(version);
    if hardcode_shared_libs {
        config.cargo_metadata(false);
    }
    match config.probe(package_name) {
        Ok(library) => {
            if hardcode_shared_libs {
                for lib_ in shared_libs.iter() {
                    println!("cargo:rustc-link-lib=dylib={}", lib_);
                }
                for path in library.link_paths.iter() {
                    println!("cargo:rustc-link-search=native={}",
                             path.to_str().expect("library path doesn't exist"));
                }
            }
            Ok(())
        }
        Err(Error::EnvNoPkgConfig(_)) | Err(Error::Command { .. }) => {
            for lib_ in shared_libs.iter() {
                println!("cargo:rustc-link-lib=dylib={}", lib_);
            }
            Ok(())
        }
        Err(err) => Err(err),
    }
}
"##
    )
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Link between Vulkan and a window and/or the screen.
//!
//! Before you can draw on the screen or a window, you have to create two objects:
//!
//! - Create a `Surface` object that represents the location where the image will show up (either
//!   a window or a monitor).
//! - Create a `Swapchain` that uses that `Surface`.
//!
//! Creating a surface can be done with only an `Instance` object. However creating a swapchain
//! requires a `Device` object.
//!
//! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them just like
//! you would draw on any other image.
//!
//! # Surfaces
//!
//! A surface is an object that represents a location where to render. It can be created from an
//! instance and either a window handle (in a platform-specific way) or a monitor.
//!
//! In order to use surfaces, you will have to enable the `VK_KHR_surface` extension on the
//! instance. See the `instance` module for more information about how to enable extensions.
//!
//! ## Creating a surface from a window
//!
//! There are 6 extensions that each allow you to create a surface from a type of window:
//!
//! - `VK_KHR_xlib_surface`
//! - `VK_KHR_xcb_surface`
//! - `VK_KHR_wayland_surface`
//! - `VK_KHR_mir_surface`
//! - `VK_KHR_android_surface`
//! - `VK_KHR_win32_surface`
//!
//! For example if you want to create a surface from an Android surface, you will have to enable
//! the `VK_KHR_android_surface` extension and use `Surface::from_anativewindow`.
//! See the documentation of `Surface` for all the possible constructors.
//!
//! Trying to use one of these functions without enabling the proper extension will result in an
//! error.
//!
//! **Note that the `Surface` object is unsafe**. It is your responsibility to keep the window
//! alive for at least as long as the surface exists.
//!
//! ### Example
//!
//! ```no_run
//! use std::ptr;
//! use vulkano::instance::Instance;
//! use vulkano::instance::InstanceExtensions;
//! use vulkano::swapchain::Surface;
//!
//! let instance = {
//!     let extensions = InstanceExtensions {
//!         khr_surface: true,
//!         khr_win32_surface: true,        // If you don't enable this, `from_hwnd` will fail.
//!         .. InstanceExtensions::none()
//!     };
//!
//!      match Instance::new(None, &extensions, None) {
//!         Ok(i) => i,
//!         Err(err) => panic!("Couldn't build instance: {:?}", err)
//!     }
//! };
//!
//! # fn build_window() -> *const u32 { ptr::null() }
//! let window = build_window();        // Third-party function, not provided by vulkano
//! let _surface = unsafe {
//!     let hinstance: *const () = ptr::null();     // Windows-specific object
//!     Surface::from_hwnd(instance.clone(), hinstance, window).unwrap()
//! };
//! ```
//!
//! ## Creating a surface from a monitor
//!
//! Currently no system provides the `VK_KHR_display` extension that contains this feature.
//! This feature is still a work-in-progress in vulkano and will reside in the `display` module.
//!
//! # Swapchains
//!
//! A surface represents a location on the screen and can be created from an instance. Once you
//! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device,
//! and allocates the resources that will be used to display images on the screen.
//!
//! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in
//! turn on the screen, one after another. More information below.
//!
//! Swapchains have several properties:
//!
//!  - The number of images that will cycle on the screen.
//!  - The format of the images.
//!  - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions.
//!  - The usage of the images, similar to creating other images.
//!  - The queue families that are going to use the images, similar to creating other images.
//!  - An additional transformation (rotation or mirroring) to perform on the final output.
//!  - How the alpha of the final output will be interpreted.
//!  - How to perform the cycling between images in regard to vsync.
//!
//! You can query the supported values of all these properties with `Surface::get_capabilities()`.
//!
//! ## Creating a swapchain
//!
//! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension
//! on the device (and not on the instance like `VK_KHR_surface`).
//!
//! Then, you should query the capabilities of the surface with `Surface::get_capabilities()` and
//! choose which values you are going to use. Then, call `Swapchain::new`.
//!
//! TODO: add example here
//!
//! Creating a swapchain not only returns the swapchain object, but also all the images that belong
//! to it.
//!
//! ## Acquiring and presenting images
//!
//! Once you created a swapchain and retreived all the images that belong to it (see previous
//! section), you can draw on it. This is done in three steps:
//!
//!  - Call `swapchain::acquire_next_image`. This function will return the index of the image
//!    (within the list returned by `Swapchain::new`) that is available to draw, plus a future
//!    representing the moment when the GPU will gain access to that image.
//!  - Draw on that image just like you would draw to any other image (see the documentation of
//!    the `pipeline` module). You need to chain the draw after the future that was returned by
//!    `acquire_next_image`.
//!  - Call `Swapchain::present` with the same index and by chaining the futures, in order to tell
//!    the implementation that you are finished drawing to the image and that it can queue a
//!    command to present the image on the screen after the draw operations are finished.
//!
//! TODO: add example here
//! loop {
//!     let index = swapchain::acquire_next_image(None).unwrap();
//!     draw(images[index]);
//!     swapchain::present(queue, index).unwrap();
//! }
//!
//! ## Recreating a swapchain
//!
//! In some situations, the swapchain will become invalid by itself. This includes for example when
//! the window is resized (as the images of the swapchain will no longer match the window's) or,
//! on Android, when the application went to the background and goes back to the foreground.
//!
//! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering
//! to an image of that swapchain will not produce any error, but may or may not work. To continue
//! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing
//! as last parameter the old swapchain.
//!
//! TODO: suboptimal stuff
//!
//! ```
//! # use std::time::Duration;
//! use vulkano::swapchain;
//! use vulkano::swapchain::AcquireError;
//! use vulkano::sync::GpuFuture;
//!
//! // let mut swapchain = Swapchain::new(...);
//! # let mut swapchain: (::std::sync::Arc<::vulkano::swapchain::Swapchain>, _) = return;
//! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return;
//! let mut recreate_swapchain = false;
//!
//! loop {
//!     if recreate_swapchain {
//!         swapchain = swapchain.0.recreate_with_dimension([1024, 768]).unwrap();
//!         recreate_swapchain = false;
//!     }
//!
//!     let (ref swapchain, ref _images) = swapchain;
//!
//!     let (index, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
//!         Ok(r) => r,
//!         Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; },
//!         Err(err) => panic!("{:?}", err)
//!     };
//!
//!     // ...
//!
//!     let final_future = acq_future
//!         // .then_execute(...)
//!         .then_swapchain_present(queue.clone(), swapchain.clone(), index)
//!         .then_signal_fence();
//!
//!     final_future.flush().unwrap();      // TODO: PresentError?
//! }
//! ```
//!

use std::sync::atomic::AtomicBool;

pub use self::capabilities::Capabilities;
pub use self::capabilities::ColorSpace;
pub use self::capabilities::CompositeAlpha;
pub use self::capabilities::PresentMode;
pub use self::capabilities::SupportedCompositeAlpha;
pub use self::capabilities::SupportedCompositeAlphaIter;
pub use self::capabilities::SupportedPresentModes;
pub use self::capabilities::SupportedPresentModesIter;
pub use self::capabilities::SupportedSurfaceTransforms;
pub use self::capabilities::SupportedSurfaceTransformsIter;
pub use self::capabilities::SurfaceTransform;
pub use self::present_region::PresentRegion;
pub use self::present_region::RectangleLayer;
pub use self::surface::CapabilitiesError;
pub use self::surface::Surface;
pub use self::surface::SurfaceCreationError;
pub use self::swapchain::AcquiredImage;
pub use self::swapchain::AcquireError;
pub use self::swapchain::PresentFuture;
pub use self::swapchain::Swapchain;
pub use self::swapchain::SwapchainAcquireFuture;
pub use self::swapchain::SwapchainCreationError;
pub use self::swapchain::acquire_next_image;
pub use self::swapchain::acquire_next_image_raw;
pub use self::swapchain::present;
pub use self::swapchain::present_incremental;

mod capabilities;
pub mod display;
mod present_region;
mod surface;
mod swapchain;

/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
/// flag.
// TODO: use pub(crate) maybe?
unsafe trait SurfaceSwapchainLock {
    fn flag(&self) -> &AtomicBool;
}
<commit_msg>Add more examples to `swapchain` docs (#753)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Link between Vulkan and a window and/or the screen.
//!
//! Before you can draw on the screen or a window, you have to create two objects:
//!
//! - Create a `Surface` object that represents the location where the image will show up (either
//!   a window or a monitor).
//! - Create a `Swapchain` that uses that `Surface`.
//!
//! Creating a surface can be done with only an `Instance` object. However creating a swapchain
//! requires a `Device` object.
//!
//! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them just like
//! you would draw on any other image.
//!
//! # Surfaces
//!
//! A surface is an object that represents a location where to render. It can be created from an
//! instance and either a window handle (in a platform-specific way) or a monitor.
//!
//! In order to use surfaces, you will have to enable the `VK_KHR_surface` extension on the
//! instance. See the `instance` module for more information about how to enable extensions.
//!
//! ## Creating a surface from a window
//!
//! There are 6 extensions that each allow you to create a surface from a type of window:
//!
//! - `VK_KHR_xlib_surface`
//! - `VK_KHR_xcb_surface`
//! - `VK_KHR_wayland_surface`
//! - `VK_KHR_mir_surface`
//! - `VK_KHR_android_surface`
//! - `VK_KHR_win32_surface`
//!
//! For example if you want to create a surface from an Android surface, you will have to enable
//! the `VK_KHR_android_surface` extension and use `Surface::from_anativewindow`.
//! See the documentation of `Surface` for all the possible constructors.
//!
//! Trying to use one of these functions without enabling the proper extension will result in an
//! error.
//!
//! **Note that the `Surface` object is unsafe**. It is your responsibility to keep the window
//! alive for at least as long as the surface exists.
//!
//! ### Example
//!
//! ```no_run
//! use std::ptr;
//! use vulkano::instance::Instance;
//! use vulkano::instance::InstanceExtensions;
//! use vulkano::swapchain::Surface;
//!
//! let instance = {
//!     let extensions = InstanceExtensions {
//!         khr_surface: true,
//!         khr_win32_surface: true,        // If you don't enable this, `from_hwnd` will fail.
//!         .. InstanceExtensions::none()
//!     };
//!
//!      match Instance::new(None, &extensions, None) {
//!         Ok(i) => i,
//!         Err(err) => panic!("Couldn't build instance: {:?}", err)
//!     }
//! };
//!
//! # fn build_window() -> *const u32 { ptr::null() }
//! let window = build_window();        // Third-party function, not provided by vulkano
//! let _surface = unsafe {
//!     let hinstance: *const () = ptr::null();     // Windows-specific object
//!     Surface::from_hwnd(instance.clone(), hinstance, window).unwrap()
//! };
//! ```
//!
//! ## Creating a surface from a monitor
//!
//! Currently no system provides the `VK_KHR_display` extension that contains this feature.
//! This feature is still a work-in-progress in vulkano and will reside in the `display` module.
//!
//! # Swapchains
//!
//! A surface represents a location on the screen and can be created from an instance. Once you
//! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device,
//! and allocates the resources that will be used to display images on the screen.
//!
//! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in
//! turn on the screen, one after another. More information below.
//!
//! Swapchains have several properties:
//!
//!  - The number of images that will cycle on the screen.
//!  - The format of the images.
//!  - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions.
//!  - The usage of the images, similar to creating other images.
//!  - The queue families that are going to use the images, similar to creating other images.
//!  - An additional transformation (rotation or mirroring) to perform on the final output.
//!  - How the alpha of the final output will be interpreted.
//!  - How to perform the cycling between images in regard to vsync.
//!
//! You can query the supported values of all these properties with
//! [`Surface::capabilities()]`](struct.Surface.html#method.capabilities).
//!
//! ## Creating a swapchain
//!
//! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension
//! on the device (and not on the instance like `VK_KHR_surface`):
//!
//! ```no_run
//! # use vulkano::instance::DeviceExtensions;
//! let ext = DeviceExtensions {
//!     khr_swapchain: true,
//!     .. DeviceExtensions::none()
//! };
//! ```
//!
//! Then, query the capabilities of the surface with
//! [`Surface::capabilities()`](struct.Surface.html#method.capabilities)
//! and choose which values you are going to use.
//!
//! ```no_run
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::swapchain::Surface;
//! # use std::cmp::{max, min};
//! # fn choose_caps(device: Arc<Device>, surface: Arc<Surface>) -> Result<(), Box<std::error::Error>> {
//! let caps = surface.capabilities(device.physical_device())?;
//!
//! // Use the current window size or some fixed resolution.
//! let dimensions = caps.current_extent.unwrap_or([640, 480]);
//!
//! // Try to use double-buffering.
//! let buffers_count = max(min(2, caps.min_image_count), caps.max_image_count.unwrap_or(2));
//!
//! // Preserve the current surface transform.
//! let transform = caps.current_transform;
//!
//! // Use the first available format.
//! let (format, color_space) = caps.supported_formats[0];
//! # Ok(())
//! # }
//! ```
//!
//! Then, call [`Swapchain::new()`](struct.Swapchain.html#method.new).
//!
//! ```no_run
//! # use std::sync::Arc;
//! # use vulkano::device::{Device, Queue};
//! # use vulkano::image::ImageUsage;
//! # use vulkano::sync::SharingMode;
//! # use vulkano::format::Format;
//! # use vulkano::swapchain::{Surface, Swapchain, SurfaceTransform, PresentMode, CompositeAlpha};
//! # fn create_swapchain(
//! #     device: Arc<Device>, surface: Arc<Surface>, present_queue: Arc<Queue>,
//! #     buffers_count: u32, format: Format, dimensions: [u32; 2],
//! #     surface_transform: SurfaceTransform, composite_alpha: CompositeAlpha, present_mode: PresentMode
//! # ) -> Result<(), Box<std::error::Error>> {
//! // The created swapchain will be used as a color attachment for rendering.
//! let usage = ImageUsage {
//!     color_attachment: true,
//!     .. ImageUsage::none()
//! };
//!
//! let sharing_mode = SharingMode::Exclusive(present_queue.family().id());
//!
//! // Create the swapchain and its buffers.
//! let (swapchain, buffers) = Swapchain::new(
//!     // Create the swapchain in this `device`'s memory.
//!     device,
//!     // The surface where the images will be presented.
//!     surface,
//!     // How many buffers to use in the swapchain.
//!     buffers_count,
//!     // The format of the images.
//!     format,
//!     // The size of each image.
//!     dimensions,
//!     // How many layers each image has.
//!     1,
//!     // What the images are going to be used for.
//!     usage,
//!     // Describes which queues will interact with the swapchain.
//!     sharing_mode,
//!     // What transformation to use with the surface.
//!     surface_transform,
//!     // How to handle the alpha channel.
//!     composite_alpha,
//!     // How to present images.
//!     present_mode,
//!     // Clip the parts of the buffer which aren't visible.
//!     true,
//!     // No previous swapchain.
//!     None
//! )?;
//!
//! # Ok(())
//! # }
//! ```
//!
//! Creating a swapchain not only returns the swapchain object, but also all the images that belong
//! to it.
//!
//! ## Acquiring and presenting images
//!
//! Once you created a swapchain and retreived all the images that belong to it (see previous
//! section), you can draw on it. This is done in three steps:
//!
//!  - Call `swapchain::acquire_next_image`. This function will return the index of the image
//!    (within the list returned by `Swapchain::new`) that is available to draw, plus a future
//!    representing the moment when the GPU will gain access to that image.
//!  - Draw on that image just like you would draw to any other image (see the documentation of
//!    the `pipeline` module). You need to chain the draw after the future that was returned by
//!    `acquire_next_image`.
//!  - Call `Swapchain::present` with the same index and by chaining the futures, in order to tell
//!    the implementation that you are finished drawing to the image and that it can queue a
//!    command to present the image on the screen after the draw operations are finished.
//!
//! TODO: add example here
//! loop {
//!     let index = swapchain::acquire_next_image(None).unwrap();
//!     draw(images[index]);
//!     swapchain::present(queue, index).unwrap();
//! }
//!
//! ## Recreating a swapchain
//!
//! In some situations, the swapchain will become invalid by itself. This includes for example when
//! the window is resized (as the images of the swapchain will no longer match the window's) or,
//! on Android, when the application went to the background and goes back to the foreground.
//!
//! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering
//! to an image of that swapchain will not produce any error, but may or may not work. To continue
//! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing
//! as last parameter the old swapchain.
//!
//! TODO: suboptimal stuff
//!
//! ```
//! # use std::time::Duration;
//! use vulkano::swapchain;
//! use vulkano::swapchain::AcquireError;
//! use vulkano::sync::GpuFuture;
//!
//! // let mut swapchain = Swapchain::new(...);
//! # let mut swapchain: (::std::sync::Arc<::vulkano::swapchain::Swapchain>, _) = return;
//! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return;
//! let mut recreate_swapchain = false;
//!
//! loop {
//!     if recreate_swapchain {
//!         swapchain = swapchain.0.recreate_with_dimension([1024, 768]).unwrap();
//!         recreate_swapchain = false;
//!     }
//!
//!     let (ref swapchain, ref _images) = swapchain;
//!
//!     let (index, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
//!         Ok(r) => r,
//!         Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; },
//!         Err(err) => panic!("{:?}", err)
//!     };
//!
//!     // ...
//!
//!     let final_future = acq_future
//!         // .then_execute(...)
//!         .then_swapchain_present(queue.clone(), swapchain.clone(), index)
//!         .then_signal_fence();
//!
//!     final_future.flush().unwrap();      // TODO: PresentError?
//! }
//! ```
//!

use std::sync::atomic::AtomicBool;

pub use self::capabilities::Capabilities;
pub use self::capabilities::ColorSpace;
pub use self::capabilities::CompositeAlpha;
pub use self::capabilities::PresentMode;
pub use self::capabilities::SupportedCompositeAlpha;
pub use self::capabilities::SupportedCompositeAlphaIter;
pub use self::capabilities::SupportedPresentModes;
pub use self::capabilities::SupportedPresentModesIter;
pub use self::capabilities::SupportedSurfaceTransforms;
pub use self::capabilities::SupportedSurfaceTransformsIter;
pub use self::capabilities::SurfaceTransform;
pub use self::present_region::PresentRegion;
pub use self::present_region::RectangleLayer;
pub use self::surface::CapabilitiesError;
pub use self::surface::Surface;
pub use self::surface::SurfaceCreationError;
pub use self::swapchain::AcquiredImage;
pub use self::swapchain::AcquireError;
pub use self::swapchain::PresentFuture;
pub use self::swapchain::Swapchain;
pub use self::swapchain::SwapchainAcquireFuture;
pub use self::swapchain::SwapchainCreationError;
pub use self::swapchain::acquire_next_image;
pub use self::swapchain::acquire_next_image_raw;
pub use self::swapchain::present;
pub use self::swapchain::present_incremental;

mod capabilities;
pub mod display;
mod present_region;
mod surface;
mod swapchain;

/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
/// flag.
// TODO: use pub(crate) maybe?
unsafe trait SurfaceSwapchainLock {
    fn flag(&self) -> &AtomicBool;
}
<|endoftext|>


<commit_before>use std::env;
use std::collections::HashMap;
use error::*;
use source::Source;
use value::{Value, ValueKind};

#[derive(Clone, Debug)]
pub struct Environment {
    /// Optional prefix that will limit access to the environment to only keys that
    /// begin with the defined prefix.
    ///
    /// A prefix, followed by `_` (the seperator),
    /// is tested to be present on each key before its considered
    /// to be part of the source environment.
    ///
    /// For example, the key `CONFIG_DEBUG` would become `DEBUG` with a prefix of `config`.
    prefix: Option<String>,

    /// The character sequence that separates each key segment in an environment key pattern.
    /// Consider a nested configuration such as `redis.password`, a separator of `_` would allow
    /// an environment key of `REDIS_PASSWORD` to match.
    ///
    /// The default separator is `_`.
    separator: String,
}

impl Environment {
    pub fn new() -> Self {
        Environment::default()
    }

    pub fn with_prefix(s: &str) -> Self {
        Environment {
            prefix: Some(s.into()),
            ..Environment::default()
        }
    }

    pub fn prefix(&mut self, s: String) -> &mut Self {
        self.prefix = s.into();
        self
    }

    pub fn separator(&mut self, s: String) -> &mut Self {
        self.separator = s;
        self
    }
}

impl Default for Environment {
    fn default() -> Environment {
        Environment {
            prefix: None,
            separator: "_".into(),
        }
    }
}

impl Source for Environment {
    fn clone_into_box(&self) -> Box<Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<HashMap<String, Value>> {
        let mut m = HashMap::new();
        let uri: String = "the environment".into();

        // Define a prefiux pattern to test and exclude from keys
        let prefix_pattern = match self.prefix {
            Some(ref prefix) => Some(prefix.clone() + &self.separator),
            _ => None,
        };

        for (key, value) in env::vars() {
            let mut key = key.to_string();

            // Check for prefix
            if let Some(ref prefix_pattern) = prefix_pattern {
                if key.to_lowercase().starts_with(prefix_pattern) {
                    // Remove this prefix from the key
                    key = key[prefix_pattern.len()..].to_string();
                } else {
                    // Skip this key
                    continue;
                }
            }

            // Replace `separator` with `.`
            key = key.replace(&self.separator, ".");

            m.insert(
                key.to_lowercase(),
                Value::new(Some(&uri), ValueKind::String(value)),
            );
        }

        Ok(m)
    }
}
<commit_msg>make separator optional<commit_after>use std::env;
use std::collections::HashMap;
use error::*;
use source::Source;
use value::{Value, ValueKind};

#[derive(Clone, Debug)]
pub struct Environment {
    /// Optional prefix that will limit access to the environment to only keys that
    /// begin with the defined prefix.
    ///
    /// A prefix is tested to be present on each key before its considered
    /// to be part of the source environment.
    ///
    /// For example, the key `CONFIG_DEBUG` would become `DEBUG` with a prefix of `config_`.
    prefix: Option<String>,

    /// Optional character sequence that separates each key segment in an environment key pattern.
    /// Consider a nested configuration such as `redis.password`, a separator of `_` would allow
    /// an environment key of `REDIS_PASSWORD` to match.
    separator: Option<String>,
}

impl Environment {
    pub fn new() -> Self {
        Environment::default()
    }

    pub fn with_prefix(s: &str) -> Self {
        Environment {
            prefix: Some(s.into()),
            ..Environment::default()
        }
    }

    pub fn prefix(&mut self, s: &str) -> &mut Self {
        self.prefix = Some(s.into());
        self
    }

    pub fn separator(&mut self, s: &str) -> &mut Self {
        self.separator = Some(s.into());
        self
    }
}

impl Default for Environment {
    fn default() -> Environment {
        Environment {
            prefix: None,
            separator: None,
        }
    }
}

impl Source for Environment {
    fn clone_into_box(&self) -> Box<Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<HashMap<String, Value>> {
        let mut m = HashMap::new();
        let uri: String = "the environment".into();

        let separator = match self.separator {
            Some(ref separator) => separator,
            _ => ""
        };

        // Define a prefix pattern to test and exclude from keys
        let prefix_pattern = match self.prefix {
            Some(ref prefix) => Some(prefix.clone() + &separator),
            _ => None,
        };

        for (key, value) in env::vars() {
            let mut key = key.to_string();

            // Check for prefix
            if let Some(ref prefix_pattern) = prefix_pattern {
                if key.to_lowercase().starts_with(&prefix_pattern.to_lowercase()) {
                    // Remove this prefix from the key
                    key = key[prefix_pattern.len()..].to_string();
                } else {
                    // Skip this key
                    continue;
                }
            }

            // If separator is given replace with `.`
            if !separator.is_empty() {
                key = key.replace(separator, ".");
            }

            m.insert(
                key.to_lowercase(),
                Value::new(Some(&uri), ValueKind::String(value)),
            );
        }

        Ok(m)
    }
}
<|endoftext|>


<commit_before>// -*- flycheck-rust-crate-root: "lib.rs" -*-
use libc::{c_char, c_int, c_double, c_void, c_ushort};
use std::ptr;
use std::c_str::ToCStr;

pub struct Document;
pub struct Context;
#[allow(dead_code)]
pub struct XPathObject {
    xpath_type: c_ushort,
    pub node_set: *const NodeSet,
    bool_val: c_int,
    float_val: c_double,
    string_val: *const c_char,
    user: *const c_void,
    index: c_int,
    user2: *const c_void,
    index2: c_int
}
/// The nodeset
#[allow(dead_code)]
pub struct NodeSet {
    node_nr: c_int,
    node_max: c_int,
    node_tab: *mut Node
}

/// A node from the nodeset
#[allow(dead_code)]
pub struct Node {
    private: *const c_void,
    element_type: c_ushort,
    name: *const c_char,
    children: *const Node,
    last: *const Node,
    parent: *const Node,
    next: *const Node,
    prev: *const Node,
    doc: *const Document,
    namespace: *const Namespace,
    content: *const c_char,
    properties: *const Attribute,
    namespace_def: *const Namespace,
    psvi: *const c_void,
    line: c_ushort,
    extra: c_ushort
}
pub struct Namespace;
pub struct Attribute;

#[link(name = "xml2")]
extern {
    pub fn xmlParseDoc(body: *const c_char) -> *const Document;
    pub fn xmlParseFile(filename: *const c_char) -> *const Document;
    pub fn xmlFreeDoc(doc: *const Document);

    pub fn xmlXPathNewContext(doc: *const Document) -> *const Context;
    pub fn xmlXPathFreeContext(context: *const Context);

    pub fn xmlXPathEvalExpression(xpath: *const c_char, context: *const Context)
                                  -> *const XPathObject;
    pub fn xmlXPathFreeObject(object: *const XPathObject);
}

#[inline]
fn xml_xpath_node_set_is_empty(ns: *const NodeSet) -> bool {
    unsafe {
        ns.is_null() || (*ns).node_nr==0 || (*ns).node_tab.is_null()
    }
}

impl XPathObject {
    pub fn from_context(context: *const Context,
                        xpath: &str) -> *const XPathObject
    {
        unsafe {
            let result = xmlXPathEvalExpression(xpath.to_c_str().as_ptr(),
                                                context);
            if result.is_null() {
                ptr::null()
            } else if xml_xpath_node_set_is_empty((*result).node_set) {
                xmlXPathFreeObject(result);
                ptr::null()
            } else {
                result
            }
        }
    }
}

impl<'a> NodeSet {
    /// Gets a vector of nodes from the NodeSet
    pub fn get_nodes(&'a self) -> Vec<&'a Node> {
        unsafe {
            let node_ptr = self.node_tab;
            if node_ptr.is_null() {
                vec![]
            } else {
                range(0, self.node_nr).map(
                    |off| &*self.node_tab.clone().offset(off as int)).collect()
            }
        }
    }
}
<commit_msg>Add repr(C) attribute to FFI types<commit_after>// -*- flycheck-rust-crate-root: "lib.rs" -*-
use libc::{c_char, c_int, c_double, c_void, c_ushort};
use std::ptr;
use std::c_str::ToCStr;

#[repr(C)]
pub struct Document;
#[repr(C)]
pub struct Context;
#[allow(dead_code)]
#[repr(C)]
pub struct XPathObject {
    xpath_type: c_ushort,
    pub node_set: *const NodeSet,
    bool_val: c_int,
    float_val: c_double,
    string_val: *const c_char,
    user: *const c_void,
    index: c_int,
    user2: *const c_void,
    index2: c_int
}
/// The nodeset
#[allow(dead_code)]
#[repr(C)]
pub struct NodeSet {
    node_nr: c_int,
    node_max: c_int,
    node_tab: *mut Node
}

/// A node from the nodeset
#[allow(dead_code)]
#[repr(C)]
pub struct Node {
    private: *const c_void,
    element_type: c_ushort,
    name: *const c_char,
    children: *const Node,
    last: *const Node,
    parent: *const Node,
    next: *const Node,
    prev: *const Node,
    doc: *const Document,
    namespace: *const Namespace,
    content: *const c_char,
    properties: *const Attribute,
    namespace_def: *const Namespace,
    psvi: *const c_void,
    line: c_ushort,
    extra: c_ushort
}
#[repr(C)]
pub struct Namespace;
#[repr(C)]
pub struct Attribute;

#[link(name = "xml2")]
extern {
    pub fn xmlParseDoc(body: *const c_char) -> *const Document;
    pub fn xmlParseFile(filename: *const c_char) -> *const Document;
    pub fn xmlFreeDoc(doc: *const Document);

    pub fn xmlXPathNewContext(doc: *const Document) -> *const Context;
    pub fn xmlXPathFreeContext(context: *const Context);

    pub fn xmlXPathEvalExpression(xpath: *const c_char, context: *const Context)
                                  -> *const XPathObject;
    pub fn xmlXPathFreeObject(object: *const XPathObject);
}

#[inline]
fn xml_xpath_node_set_is_empty(ns: *const NodeSet) -> bool {
    unsafe {
        ns.is_null() || (*ns).node_nr==0 || (*ns).node_tab.is_null()
    }
}

impl XPathObject {
    pub fn from_context(context: *const Context,
                        xpath: &str) -> *const XPathObject
    {
        unsafe {
            let result = xmlXPathEvalExpression(xpath.to_c_str().as_ptr(),
                                                context);
            if result.is_null() {
                ptr::null()
            } else if xml_xpath_node_set_is_empty((*result).node_set) {
                xmlXPathFreeObject(result);
                ptr::null()
            } else {
                result
            }
        }
    }
}

impl<'a> NodeSet {
    /// Gets a vector of nodes from the NodeSet
    pub fn get_nodes(&'a self) -> Vec<&'a Node> {
        unsafe {
            let node_ptr = self.node_tab;
            if node_ptr.is_null() {
                vec![]
            } else {
                range(0, self.node_nr).map(
                    |off| &*self.node_tab.clone().offset(off as int)).collect()
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2019 Rene van der Meer
//
// 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.

//! Miscellaneous `embedded-hal` trait implementations.
//!
//! The `hal` module consists of a collection of `embedded-hal` trait
//! implementations for traits that aren't tied to a specific peripheral.
//!
//! This module is only included when either the `hal` or `hal-unproven` feature
//! flag is enabled.

use std::thread;
use std::time::{Duration, Instant};

use embedded_hal::blocking::delay::{DelayMs, DelayUs};
use embedded_hal::timer::CountDown;
use void::Void;

/// Implements the `embedded-hal` `DelayMs` and `DelayUs` traits.
#[derive(Debug, Default)]
pub struct Delay {}

impl Delay {
    /// Constructs a new `Delay`.
    pub fn new() -> Delay {
        Delay {}
    }
}

impl DelayMs<u8> for Delay {
    fn delay_ms(&mut self, ms: u8) {
        thread::sleep(Duration::from_millis(u64::from(ms)));
    }
}

impl DelayMs<u16> for Delay {
    fn delay_ms(&mut self, ms: u16) {
        thread::sleep(Duration::from_millis(u64::from(ms)));
    }
}

impl DelayMs<u32> for Delay {
    fn delay_ms(&mut self, ms: u32) {
        thread::sleep(Duration::from_millis(u64::from(ms)));
    }
}

impl DelayMs<u64> for Delay {
    fn delay_ms(&mut self, ms: u64) {
        thread::sleep(Duration::from_millis(ms));
    }
}

impl DelayUs<u8> for Delay {
    fn delay_us(&mut self, us: u8) {
        thread::sleep(Duration::from_micros(u64::from(us)));
    }
}

impl DelayUs<u16> for Delay {
    fn delay_us(&mut self, us: u16) {
        thread::sleep(Duration::from_micros(u64::from(us)));
    }
}

impl DelayUs<u32> for Delay {
    fn delay_us(&mut self, us: u32) {
        thread::sleep(Duration::from_micros(u64::from(us)));
    }
}

impl DelayUs<u64> for Delay {
    fn delay_us(&mut self, us: u64) {
        thread::sleep(Duration::from_micros(us));
    }
}

pub struct Hertz(pub f64);

impl From<Hertz> for Duration {
    fn from(item: Hertz) -> Self {
        if item.0 > 0.0 && item.0.is_finite() {
            Duration::from_micros(((1.0 / item.0) * 1_000_000.0) as u64)
        } else {
            Duration::default()
        }
    }
}

/// Implements the `embedded-hal` `CountDown` trait.
#[derive(Debug, Copy, Clone)]
pub struct Timer {
    now: Instant,
    duration: Duration,
}

impl Timer {
    /// Constructs a new `Timer`.
    pub fn new() -> Self {
        Self {
            now: Instant::now(),
            duration: Duration::from_micros(0),
        }
    }
}

impl Default for Timer {
    fn default() -> Self {
        Timer::new()
    }
}

impl CountDown for Timer {
    type Time = Duration;

    /// Starts the timer with a `timeout`.
    fn start<T>(&mut self, timeout: T)
    where
        T: Into<Self::Time>,
    {
        self.duration = timeout.into();
        self.now = Instant::now();
    }

    /// Returns `Ok` if the timer has wrapped.
    fn wait(&mut self) -> nb::Result<(), Void> {
        if self.now.elapsed() >= self.duration {
            Ok(())
        } else {
            Err(nb::Error::WouldBlock)
        }
    }
}
<commit_msg>Update documentation<commit_after>// Copyright (c) 2017-2019 Rene van der Meer
//
// 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.

//! Miscellaneous `embedded-hal` trait implementations.
//!
//! The `hal` module consists of a collection of `embedded-hal` trait
//! implementations for traits that aren't tied to a specific peripheral.
//!
//! This module is only included when either the `hal` or `hal-unproven` feature
//! flag is enabled.

use std::thread;
use std::time::{Duration, Instant};

use embedded_hal::blocking::delay::{DelayMs, DelayUs};
use embedded_hal::timer::CountDown;
use void::Void;

/// Implements the `embedded-hal` `DelayMs` and `DelayUs` traits.
#[derive(Debug, Default)]
pub struct Delay {}

impl Delay {
    /// Constructs a new `Delay`.
    pub fn new() -> Delay {
        Delay {}
    }
}

impl DelayMs<u8> for Delay {
    fn delay_ms(&mut self, ms: u8) {
        thread::sleep(Duration::from_millis(u64::from(ms)));
    }
}

impl DelayMs<u16> for Delay {
    fn delay_ms(&mut self, ms: u16) {
        thread::sleep(Duration::from_millis(u64::from(ms)));
    }
}

impl DelayMs<u32> for Delay {
    fn delay_ms(&mut self, ms: u32) {
        thread::sleep(Duration::from_millis(u64::from(ms)));
    }
}

impl DelayMs<u64> for Delay {
    fn delay_ms(&mut self, ms: u64) {
        thread::sleep(Duration::from_millis(ms));
    }
}

impl DelayUs<u8> for Delay {
    fn delay_us(&mut self, us: u8) {
        thread::sleep(Duration::from_micros(u64::from(us)));
    }
}

impl DelayUs<u16> for Delay {
    fn delay_us(&mut self, us: u16) {
        thread::sleep(Duration::from_micros(u64::from(us)));
    }
}

impl DelayUs<u32> for Delay {
    fn delay_us(&mut self, us: u32) {
        thread::sleep(Duration::from_micros(u64::from(us)));
    }
}

impl DelayUs<u64> for Delay {
    fn delay_us(&mut self, us: u64) {
        thread::sleep(Duration::from_micros(us));
    }
}

/// Newtype that converts into `Duration`.
pub struct Hertz(pub f64);

impl From<Hertz> for Duration {
    fn from(item: Hertz) -> Self {
        if item.0 > 0.0 && item.0.is_finite() {
            Duration::from_micros(((1.0 / item.0) * 1_000_000.0) as u64)
        } else {
            Duration::default()
        }
    }
}

/// Implements the `embedded-hal` `CountDown` trait.
#[derive(Debug, Copy, Clone)]
pub struct Timer {
    now: Instant,
    duration: Duration,
}

impl Timer {
    /// Constructs a new `Timer`.
    pub fn new() -> Self {
        Self {
            now: Instant::now(),
            duration: Duration::from_micros(0),
        }
    }
}

impl Default for Timer {
    fn default() -> Self {
        Timer::new()
    }
}

impl CountDown for Timer {
    type Time = Duration;

    /// Starts the timer with a `timeout`.
    fn start<T>(&mut self, timeout: T)
    where
        T: Into<Self::Time>,
    {
        self.duration = timeout.into();
        self.now = Instant::now();
    }

    /// Returns `Ok` if the timer has wrapped.
    fn wait(&mut self) -> nb::Result<(), Void> {
        if self.now.elapsed() >= self.duration {
            Ok(())
        } else {
            Err(nb::Error::WouldBlock)
        }
    }
}
<|endoftext|>


<commit_before>//! # Example
//!
//! ```rust
//! # extern crate env_logger;
//! # extern crate embed_lang;
//!
//! use embed_lang::{new_vm, run_expr};
//!
//! # fn main() {
//! # let _ = ::env_logger::init();
//!
//! let text = r#"
//! // `type` is used to declare a new type.
//! // In this case we declare `Eq` to be a record with a single field (`==`) which is a function
//! // which takes two arguments of the same type and returns a boolean
//! type Eq a = { (==) : a -> a -> Bool }
//! in
//! // `let` declares new variables.
//! let id x = x
//! and factorial n =
//!         if n < 2
//!         then 1
//!         else n * factorial (n - 1)
//! in
//! let list_module =
//!         // Declare a new type which only exists in the current scope
//!         type List a = | Cons a (List a) | Nil
//!         in
//!         let map f xs =
//!                 case xs of
//!                     | Cons y ys -> Cons (f y) (map f ys)
//!                     | Nil -> Nil
//!         in
//!         let eq eq_a: Eq a -> Eq (List a) =
//!                 let { (==) } = eq_a in
//!                 let (===) l r =
//!                         case l of
//!                             | Cons la lxs ->
//!                                 (case r of
//!                                     | Cons ra rxs -> la == ra && lxs === rxs
//!                                     | Nil -> False)
//!                             | Nil ->
//!                                 (case r of
//!                                     | Cons _ _ -> False
//!                                     | Nil -> True)
//!                 in { (==) = (===) }
//!         in {
//!             // Since `List` is local we export it so its constructors can be used
//!             // outside the current scope
//!             List,
//!             eq,
//!             map
//!         }
//! in
//! // Bring the `List` type and its constructors into scope
//! let { List, eq = list_Eq } = list_module
//! // Create `==` for `List Int`
//! and { (==) }: Eq (List Int) = list_Eq { (==) }
//! in
//! if Cons 1 Nil == Nil then
//!     error "This branch is not executed"
//! else
//!     io.print "Hello world!"
//! "#;
//!
//! let vm = new_vm();
//! match run_expr(&vm, "example", text) {
//!     Ok(value) => {
//!         println!("{:?}", value);
//!     }
//!     Err(err) => {
//!         panic!("{}", err);
//!     }
//! }
//! return;
//!
//! # }
//! ```

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate quick_error;
#[macro_use]
extern crate vm as vm_mod;

mod crates {
    extern crate base;
    extern crate parser;
    extern crate check;
}

pub use crates::base;
pub use crates::parser;
pub use crates::check;
pub use vm_mod as vm;

pub mod import;
mod io;

use base::ast;
use base::types::TcType;
use base::symbol::{Name, NameBuf, Symbol};
use std::result::Result as StdResult;
use std::string::String as StdString;
use std::error::Error as StdError;
use vm::vm::{ClosureDataDef, RootedValue, VM};
use vm::compiler::CompiledFunction;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Parse(err: ::parser::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
        Typecheck(err: ::base::error::InFile<::check::typecheck::TypeError<StdString>>) {
            description(err.description())
            display("{}", err)
            from()
        }
        IO(err: ::std::io::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
        VM(err: ::vm::vm::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
        Macro(err: ::base::error::Errors<::base::macros::Error>) {
            description(err.description())
            display("{}", err)
            from()
        }
    }
}

pub type Result<T> = StdResult<T, Error>;

fn include_implicit_prelude(vm: &VM, name: &str, expr: &mut ast::LExpr<ast::TcIdent<Symbol>>) {
    use std::mem;
    if name == "std.prelude" {
        return;
    }

    let prelude_import = r#"
let __implicit_prelude = import "std/prelude.hs"
and { Num, Eq, Ord, Show, Functor, Monad, Option, Result, not } = __implicit_prelude
in
let { (+), (-), (*), (/) } = __implicit_prelude.num_Int
and { (==) } = __implicit_prelude.eq_Int
and { (<), (<=), (=>), (>) } = __implicit_prelude.make_Ord __implicit_prelude.ord_Int
in
let { (+), (-), (*), (/) } = __implicit_prelude.num_Float
and { (==) } = __implicit_prelude.eq_Float
and { (<), (<=), (=>), (>) } = __implicit_prelude.make_Ord __implicit_prelude.ord_Float
in 0
"#;
    let prelude_expr = parse_expr(vm, "", prelude_import).unwrap();
    let original_expr = mem::replace(expr, prelude_expr);
    fn assign_last_body(l: &mut ast::LExpr<ast::TcIdent<Symbol>>,
                        original_expr: ast::LExpr<ast::TcIdent<Symbol>>) {
        match l.value {
            ast::Expr::Let(_, ref mut e) => {
                assign_last_body(e, original_expr);
            }
            _ => *l = original_expr,
        }
    }
    assign_last_body(expr, original_expr);
}

fn compile_script(vm: &VM,
                  filename: &str,
                  expr: &ast::LExpr<ast::TcIdent<Symbol>>)
                  -> CompiledFunction {
    use base::symbol::SymbolModule;
    use vm::compiler::Compiler;
    debug!("Compile `{}`", filename);
    let mut function = {
        let env = vm.env();
        let mut interner = vm.interner.borrow_mut();
        let mut gc = vm.gc.borrow_mut();
        let mut symbols = vm.get_mut_symbols();
        let name = Name::new(filename);
        let name = NameBuf::from(name.module());
        let symbols = SymbolModule::new(StdString::from(name.as_ref()), &mut symbols);
        let mut compiler = Compiler::new(&env, &mut interner, &mut gc, symbols);
        compiler.compile_expr(&expr)
    };
    function.id = vm.symbol(filename);
    function
}

/// Compiles `input` and if it is successful runs the resulting code and stores the resulting value
/// in the global variable named by running `filename_to_module` on `filename`.
///
/// If at any point the function fails the resulting error is returned and nothing is added to the
/// VM.
pub fn load_script(vm: &VM, filename: &str, input: &str) -> Result<()> {
    load_script2(vm, filename, input, true)
}

pub fn load_script2(vm: &VM, filename: &str, input: &str, implicit_prelude: bool) -> Result<()> {
    let (expr, typ) = try!(typecheck_expr(vm, filename, input, implicit_prelude));
    let function = compile_script(vm, filename, &expr);
    let function = vm.new_function(function);
    let closure = {
        let stack = vm.current_frame();
        vm.alloc(&stack.stack, ClosureDataDef(function, &[]))
    };
    let value = try!(vm.call_module(&typ, closure));
    try!(vm.set_global(function.name, typ, value));
    Ok(())
}

pub fn filename_to_module(filename: &str) -> StdString {
    use std::path::Path;
    let path = Path::new(filename);
    let name = path.extension()
                   .map(|ext| {
                       ext.to_str()
                          .map(|ext| &filename[..filename.len() - ext.len() - 1])
                          .unwrap_or(filename)
                   })
                   .expect("filename");

    name.replace("/", ".")
}

/// Loads `filename` and compiles and runs its input by calling `load_script`
pub fn load_file(vm: &VM, filename: &str) -> Result<()> {
    use std::fs::File;
    use std::io::Read;
    let mut file = try!(File::open(filename));
    let mut buffer = ::std::string::String::new();
    try!(file.read_to_string(&mut buffer));
    drop(file);
    let name = filename_to_module(filename);
    load_script(vm, &name, &buffer)
}

pub fn parse_expr(vm: &VM,
                  file: &str,
                  input: &str)
                  -> StdResult<ast::LExpr<ast::TcIdent<Symbol>>, ::parser::Error> {
    use base::symbol::SymbolModule;
    let mut symbols = vm.get_mut_symbols();
    Ok(try!(::parser::parse_tc(&mut SymbolModule::new(file.into(), &mut symbols), input)))
}

pub fn typecheck_expr<'a>(vm: &VM<'a>,
                          file: &str,
                          expr_str: &str,
                          implicit_prelude: bool)
                          -> Result<(ast::LExpr<ast::TcIdent<Symbol>>, TcType)> {
    use check::typecheck::Typecheck;
    use base::error;
    let mut expr = try!(parse_expr(vm, file, expr_str));
    if implicit_prelude {
        include_implicit_prelude(vm, file, &mut expr);
    }
    try!(vm.get_macros().run(vm, &mut expr));
    let env = vm.env();
    let mut symbols = vm.get_mut_symbols();
    let mut tc = Typecheck::new(file.into(), &mut symbols, &env);
    let typ = try!(tc.typecheck_expr(&mut expr)
                     .map_err(|err| error::InFile::new(StdString::from(file), expr_str, err)));
    Ok((expr, typ))
}

/// Compiles and runs the expression in `expr_str`. If successful the value from running the
/// expression is returned
pub fn run_expr<'a, 'vm>(vm: &'vm VM<'a>,
                         name: &str,
                         expr_str: &str)
                         -> Result<RootedValue<'a, 'vm>> {
    run_expr2(vm, name, expr_str, true)
}

pub fn run_expr2<'a, 'vm>(vm: &'vm VM<'a>,
                      name: &str,
                      expr_str: &str,
                      implicit_prelude: bool)
                      -> Result<RootedValue<'a, 'vm>> {
    let (expr, typ) = try!(typecheck_expr(vm, name, expr_str, implicit_prelude));
    let mut function = compile_script(vm, name, &expr);
    function.id = vm.symbol(name);
    let function = vm.new_function(function);
    let closure = {
        let stack = vm.current_frame();
        vm.alloc(&stack.stack, ClosureDataDef(function, &[]))
    };
    let value = try!(vm.call_module(&typ, closure));
    Ok(vm.root_value(value))
}

pub fn new_vm<'a>() -> VM<'a> {
    let vm = VM::new();
    vm.get_macros().insert(vm.symbol("import"), ::import::Import::new());
    ::vm::primitives::load(&vm).expect("Loaded primitives library");
    ::io::load(&vm).expect("Loaded IO library");
    vm
}
<commit_msg>feat: Re-export VM from the embed_lang crate<commit_after>//! # Example
//!
//! ```rust
//! # extern crate env_logger;
//! # extern crate embed_lang;
//!
//! use embed_lang::{new_vm, run_expr};
//!
//! # fn main() {
//! # let _ = ::env_logger::init();
//!
//! let text = r#"
//! // `type` is used to declare a new type.
//! // In this case we declare `Eq` to be a record with a single field (`==`) which is a function
//! // which takes two arguments of the same type and returns a boolean
//! type Eq a = { (==) : a -> a -> Bool }
//! in
//! // `let` declares new variables.
//! let id x = x
//! and factorial n =
//!         if n < 2
//!         then 1
//!         else n * factorial (n - 1)
//! in
//! let list_module =
//!         // Declare a new type which only exists in the current scope
//!         type List a = | Cons a (List a) | Nil
//!         in
//!         let map f xs =
//!                 case xs of
//!                     | Cons y ys -> Cons (f y) (map f ys)
//!                     | Nil -> Nil
//!         in
//!         let eq eq_a: Eq a -> Eq (List a) =
//!                 let { (==) } = eq_a in
//!                 let (===) l r =
//!                         case l of
//!                             | Cons la lxs ->
//!                                 (case r of
//!                                     | Cons ra rxs -> la == ra && lxs === rxs
//!                                     | Nil -> False)
//!                             | Nil ->
//!                                 (case r of
//!                                     | Cons _ _ -> False
//!                                     | Nil -> True)
//!                 in { (==) = (===) }
//!         in {
//!             // Since `List` is local we export it so its constructors can be used
//!             // outside the current scope
//!             List,
//!             eq,
//!             map
//!         }
//! in
//! // Bring the `List` type and its constructors into scope
//! let { List, eq = list_Eq } = list_module
//! // Create `==` for `List Int`
//! and { (==) }: Eq (List Int) = list_Eq { (==) }
//! in
//! if Cons 1 Nil == Nil then
//!     error "This branch is not executed"
//! else
//!     io.print "Hello world!"
//! "#;
//!
//! let vm = new_vm();
//! match run_expr(&vm, "example", text) {
//!     Ok(value) => {
//!         println!("{:?}", value);
//!     }
//!     Err(err) => {
//!         panic!("{}", err);
//!     }
//! }
//! return;
//!
//! # }
//! ```

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate quick_error;
#[macro_use]
extern crate vm as vm_mod;

mod io;
mod crates {
    extern crate base;
    extern crate parser;
    extern crate check;
}

pub use crates::base;
pub use crates::parser;
pub use crates::check;
pub use vm_mod as vm;

pub mod import;

pub use vm::vm::VM;

use base::ast;
use base::types::TcType;
use base::symbol::{Name, NameBuf, Symbol};
use std::result::Result as StdResult;
use std::string::String as StdString;
use std::error::Error as StdError;
use vm::vm::{ClosureDataDef, RootedValue};
use vm::compiler::CompiledFunction;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Parse(err: ::parser::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
        Typecheck(err: ::base::error::InFile<::check::typecheck::TypeError<StdString>>) {
            description(err.description())
            display("{}", err)
            from()
        }
        IO(err: ::std::io::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
        VM(err: ::vm::vm::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
        Macro(err: ::base::error::Errors<::base::macros::Error>) {
            description(err.description())
            display("{}", err)
            from()
        }
    }
}

pub type Result<T> = StdResult<T, Error>;

fn include_implicit_prelude(vm: &VM, name: &str, expr: &mut ast::LExpr<ast::TcIdent<Symbol>>) {
    use std::mem;
    if name == "std.prelude" {
        return;
    }

    let prelude_import = r#"
let __implicit_prelude = import "std/prelude.hs"
and { Num, Eq, Ord, Show, Functor, Monad, Option, Result, not } = __implicit_prelude
in
let { (+), (-), (*), (/) } = __implicit_prelude.num_Int
and { (==) } = __implicit_prelude.eq_Int
and { (<), (<=), (=>), (>) } = __implicit_prelude.make_Ord __implicit_prelude.ord_Int
in
let { (+), (-), (*), (/) } = __implicit_prelude.num_Float
and { (==) } = __implicit_prelude.eq_Float
and { (<), (<=), (=>), (>) } = __implicit_prelude.make_Ord __implicit_prelude.ord_Float
in 0
"#;
    let prelude_expr = parse_expr(vm, "", prelude_import).unwrap();
    let original_expr = mem::replace(expr, prelude_expr);
    fn assign_last_body(l: &mut ast::LExpr<ast::TcIdent<Symbol>>,
                        original_expr: ast::LExpr<ast::TcIdent<Symbol>>) {
        match l.value {
            ast::Expr::Let(_, ref mut e) => {
                assign_last_body(e, original_expr);
            }
            _ => *l = original_expr,
        }
    }
    assign_last_body(expr, original_expr);
}

fn compile_script(vm: &VM,
                  filename: &str,
                  expr: &ast::LExpr<ast::TcIdent<Symbol>>)
                  -> CompiledFunction {
    use base::symbol::SymbolModule;
    use vm::compiler::Compiler;
    debug!("Compile `{}`", filename);
    let mut function = {
        let env = vm.env();
        let mut interner = vm.interner.borrow_mut();
        let mut gc = vm.gc.borrow_mut();
        let mut symbols = vm.get_mut_symbols();
        let name = Name::new(filename);
        let name = NameBuf::from(name.module());
        let symbols = SymbolModule::new(StdString::from(name.as_ref()), &mut symbols);
        let mut compiler = Compiler::new(&env, &mut interner, &mut gc, symbols);
        compiler.compile_expr(&expr)
    };
    function.id = vm.symbol(filename);
    function
}

/// Compiles `input` and if it is successful runs the resulting code and stores the resulting value
/// in the global variable named by running `filename_to_module` on `filename`.
///
/// If at any point the function fails the resulting error is returned and nothing is added to the
/// VM.
pub fn load_script(vm: &VM, filename: &str, input: &str) -> Result<()> {
    load_script2(vm, filename, input, true)
}

pub fn load_script2(vm: &VM, filename: &str, input: &str, implicit_prelude: bool) -> Result<()> {
    let (expr, typ) = try!(typecheck_expr(vm, filename, input, implicit_prelude));
    let function = compile_script(vm, filename, &expr);
    let function = vm.new_function(function);
    let closure = {
        let stack = vm.current_frame();
        vm.alloc(&stack.stack, ClosureDataDef(function, &[]))
    };
    let value = try!(vm.call_module(&typ, closure));
    try!(vm.set_global(function.name, typ, value));
    Ok(())
}

pub fn filename_to_module(filename: &str) -> StdString {
    use std::path::Path;
    let path = Path::new(filename);
    let name = path.extension()
                   .map(|ext| {
                       ext.to_str()
                          .map(|ext| &filename[..filename.len() - ext.len() - 1])
                          .unwrap_or(filename)
                   })
                   .expect("filename");

    name.replace("/", ".")
}

/// Loads `filename` and compiles and runs its input by calling `load_script`
pub fn load_file(vm: &VM, filename: &str) -> Result<()> {
    use std::fs::File;
    use std::io::Read;
    let mut file = try!(File::open(filename));
    let mut buffer = ::std::string::String::new();
    try!(file.read_to_string(&mut buffer));
    drop(file);
    let name = filename_to_module(filename);
    load_script(vm, &name, &buffer)
}

pub fn parse_expr(vm: &VM,
                  file: &str,
                  input: &str)
                  -> StdResult<ast::LExpr<ast::TcIdent<Symbol>>, ::parser::Error> {
    use base::symbol::SymbolModule;
    let mut symbols = vm.get_mut_symbols();
    Ok(try!(::parser::parse_tc(&mut SymbolModule::new(file.into(), &mut symbols), input)))
}

pub fn typecheck_expr<'a>(vm: &VM<'a>,
                          file: &str,
                          expr_str: &str,
                          implicit_prelude: bool)
                          -> Result<(ast::LExpr<ast::TcIdent<Symbol>>, TcType)> {
    use check::typecheck::Typecheck;
    use base::error;
    let mut expr = try!(parse_expr(vm, file, expr_str));
    if implicit_prelude {
        include_implicit_prelude(vm, file, &mut expr);
    }
    try!(vm.get_macros().run(vm, &mut expr));
    let env = vm.env();
    let mut symbols = vm.get_mut_symbols();
    let mut tc = Typecheck::new(file.into(), &mut symbols, &env);
    let typ = try!(tc.typecheck_expr(&mut expr)
                     .map_err(|err| error::InFile::new(StdString::from(file), expr_str, err)));
    Ok((expr, typ))
}

/// Compiles and runs the expression in `expr_str`. If successful the value from running the
/// expression is returned
pub fn run_expr<'a, 'vm>(vm: &'vm VM<'a>,
                         name: &str,
                         expr_str: &str)
                         -> Result<RootedValue<'a, 'vm>> {
    run_expr2(vm, name, expr_str, true)
}

pub fn run_expr2<'a, 'vm>(vm: &'vm VM<'a>,
                      name: &str,
                      expr_str: &str,
                      implicit_prelude: bool)
                      -> Result<RootedValue<'a, 'vm>> {
    let (expr, typ) = try!(typecheck_expr(vm, name, expr_str, implicit_prelude));
    let mut function = compile_script(vm, name, &expr);
    function.id = vm.symbol(name);
    let function = vm.new_function(function);
    let closure = {
        let stack = vm.current_frame();
        vm.alloc(&stack.stack, ClosureDataDef(function, &[]))
    };
    let value = try!(vm.call_module(&typ, closure));
    Ok(vm.root_value(value))
}

pub fn new_vm<'a>() -> VM<'a> {
    let vm = VM::new();
    vm.get_macros().insert(vm.symbol("import"), ::import::Import::new());
    ::vm::primitives::load(&vm).expect("Loaded primitives library");
    ::io::load(&vm).expect("Loaded IO library");
    vm
}
<|endoftext|>


<commit_before>#![feature(i128_type)]
pub mod bbp;
pub mod bellard;
mod util;
<commit_msg>remove feature(i128_type)<commit_after>pub mod bbp;
pub mod bellard;
mod util;
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate redis;

use std::str;
use std::convert::From;
use std::iter::Iterator;
use std::marker::PhantomData;
use rustc_serialize::json;
use redis::{FromRedisValue, Value, RedisResult, ErrorKind, Commands};

#[derive(RustcDecodable, RustcEncodable)]
struct Job {
    id: u64
}

macro_rules! enqueueable {
    ($typ:ty) => {
        impl FromRedisValue for $typ {
            fn from_redis_value(value: &Value) -> RedisResult<Self> {
                match value {
                    &Value::Data(ref v) => {
                        let s = try!(str::from_utf8(&v));
                        Ok(try!(json::decode(&s).map_err(|_| (ErrorKind::TypeError, "JSON decode failed"))))

                    },
                    v @ _ => {
                        println!("what do we have here: {:?}", v);
                        try!(Err((ErrorKind::TypeError, "Can only decode from a string")))
                    }
                }
            }
        }
    }
}

enqueueable!(Job);

struct Worker<T> {
    queue_name: String,
    client: redis::Connection,
    _job_type: PhantomData<T>,
}

impl<T: FromRedisValue> Worker<T> {
    pub fn new(name: String, client: redis::Connection) -> Worker<T> {
        Worker {
            queue_name: name,
            client: client,
            _job_type: PhantomData,
        }
    }

    fn _next(&self) -> RedisResult<T> {
        let v = Value::Data(vec![123, 34, 105, 100, 34, 58, 52, 50, 125]);
        FromRedisValue::from_redis_value(&v)
    }
}

impl<T: FromRedisValue> Iterator for Worker<T> {
    type Item = RedisResult<T>;

    fn next(&mut self) -> Option<Self::Item> {
        let qname = &self.queue_name[..];

        let v = match self.client.blpop(qname, 0) {
            Ok(v) => v,
            Err(e) => {
                return Some(Err(From::from((ErrorKind::TypeError, "next failed"))));
            }
        };

        let v = match v {
            Value::Bulk(ref v) if v.len() == 2 => &v[1],
            _ => {
                return Some(Err(From::from((ErrorKind::TypeError, "Not a 2-item Bulk reply"))));
            }
        };

        Some(FromRedisValue::from_redis_value(&v))
    }
}

#[test]
fn decodes_job() {
    let client = redis::Client::open("redis://127.0.0.1/").unwrap();
    let con = client.get_connection().unwrap();

    let job = "{\"id\":42}".chars().map(|c| c as u8).collect::<Vec<_>>();

    let mut worker = Worker::<Job>::new("default".into(), con);
    let j : Job = worker.next().unwrap().unwrap();
    assert_eq!(42, j.id);
}
<commit_msg>Accept all decodable objects<commit_after>extern crate rustc_serialize;
extern crate redis;

use std::str;
use std::convert::From;
use std::iter::Iterator;
use std::marker::PhantomData;
use rustc_serialize::{json, Decodable};
use redis::{Value, RedisResult, ErrorKind, Commands};

#[derive(RustcDecodable, RustcEncodable)]
struct Job {
    id: u64
}

pub trait TaskDecodable where Self: Sized {
    fn decode_task(value: &Value) -> RedisResult<Self>;
}

impl<T: Decodable> TaskDecodable for T {
    fn decode_task(value: &Value) -> RedisResult<T> {
        match value {
            &Value::Data(ref v) => {
                let s = try!(str::from_utf8(&v));
                Ok(try!(json::decode(&s).map_err(|_| (ErrorKind::TypeError, "JSON decode failed"))))

            },
            v @ _ => {
                println!("what do we have here: {:?}", v);
                try!(Err((ErrorKind::TypeError, "Can only decode from a string")))
            }
        }
    }
}

struct Worker<T> {
    queue_name: String,
    pub client: redis::Connection,
    _job_type: PhantomData<T>,
}

impl<T: TaskDecodable> Worker<T> {
    pub fn new(name: String, client: redis::Connection) -> Worker<T> {
        Worker {
            queue_name: name,
            client: client,
            _job_type: PhantomData,
        }
    }

    fn _next(&self) -> RedisResult<T> {
        let v = Value::Data(vec![123, 34, 105, 100, 34, 58, 52, 50, 125]);
        T::decode_task(&v)
    }
}

impl<T: TaskDecodable> Iterator for Worker<T> {
    type Item = RedisResult<T>;

    fn next(&mut self) -> Option<Self::Item> {
        let qname = &self.queue_name[..];

        let v = match self.client.blpop(qname, 0) {
            Ok(v) => v,
            Err(e) => {
                return Some(Err(From::from((ErrorKind::TypeError, "next failed"))));
            }
        };

        let v = match v {
            Value::Bulk(ref v) if v.len() == 2 => &v[1],
            _ => {
                return Some(Err(From::from((ErrorKind::TypeError, "Not a 2-item Bulk reply"))));
            }
        };

        Some(T::decode_task(&v))
    }
}

#[test]
fn decodes_job() {
    let client = redis::Client::open("redis://127.0.0.1/").unwrap();
    let con = client.get_connection().unwrap();

    let job = "{\"id\":42}".chars().map(|c| c as u8).collect::<Vec<_>>();

    let mut worker = Worker::<Job>::new("default".into(), con);
    let j : Job = worker.next().unwrap().unwrap();
    assert_eq!(42, j.id);
}
<|endoftext|>