<commit_before>// Bitcoin secp256k1 bindings
// Written in 2015 by
//   Andrew Poelstra
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # ECDH
//! Support for shared secret computations
//!

use core::ptr;
use core::ops::Deref;

use key::{SecretKey, PublicKey};
use ffi::{self, CPtr};

/// A tag used for recovering the public key from a compact signature
#[derive(Copy, Clone)]
pub struct SharedSecret {
    data: [u8; 256],
    len: usize,
}
impl_raw_debug!(SharedSecret);

// This implementes `From<N>` for all `[u8; N]` arrays from 128bits(16 byte) to 2048bits allowing known hash lengths.
// Lower than 128 bits isn't resistant to collisions any more.
impl_from_array_len!(SharedSecret, 256, (16 20 28 32 48 64 96 128 256));

impl SharedSecret {

    /// Create an empty SharedSecret
    pub(crate) fn empty() ->  SharedSecret {
        SharedSecret {
            data: [0u8; 256],
            len: 0,
        }
    }

    /// Get a pointer to the underlying data with the specified capacity.
    pub(crate) fn get_data_mut_ptr(&mut self) -> *mut u8 {
        self.data.as_mut_ptr()
    }

    /// Get the capacity of the underlying data buffer.
    pub fn capacity(&self) -> usize {
        self.data.len()
    }

    /// Get the len of the used data.
    pub fn len(&self) -> usize {
        self.len
    }

    /// Set the length of the object.
    pub(crate) fn set_len(&mut self, len: usize) {
        self.len = len;
    }
}

impl PartialEq for SharedSecret {
    fn eq(&self, other: &SharedSecret) -> bool {
        &self.data[..self.len] == &other.data[..other.len]
    }
}

impl AsRef<[u8]> for SharedSecret {
    fn as_ref(&self) -> &[u8] {
        &self.data[..self.len]
    }
}

impl Deref for SharedSecret {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        &self.data[..self.len]
    }
}

impl SharedSecret {
    /// Creates a new shared secret from a pubkey and secret key
    #[inline]
    pub fn new(point: &PublicKey, scalar: &SecretKey) -> SharedSecret {
        let mut ss = SharedSecret::empty();
        let res = unsafe {
             ffi::secp256k1_ecdh(
                ffi::secp256k1_context_no_precomp,
                ss.get_data_mut_ptr(),
                point.as_c_ptr(),
                scalar.as_c_ptr(),
                ffi::secp256k1_ecdh_hash_function_default,
                ptr::null_mut(),
            )
        };
        debug_assert_eq!(res, 1); // The default `secp256k1_ecdh_hash_function_default` should always return 1.
        ss.set_len(32); // The default hash function is SHA256, which is 32 bytes long.
        ss
    }
}

#[cfg(test)]
mod tests {
    use rand::thread_rng;
    use super::SharedSecret;
    use super::super::Secp256k1;

    #[test]
    fn ecdh() {
        let s = Secp256k1::signing_only();
        let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
        let (sk2, pk2) = s.generate_keypair(&mut thread_rng());

        let sec1 = SharedSecret::new(&pk1, &sk2);
        let sec2 = SharedSecret::new(&pk2, &sk1);
        let sec_odd = SharedSecret::new(&pk1, &sk1);
        assert_eq!(sec1, sec2);
        assert!(sec_odd != sec2);
    }
}

#[cfg(all(test, feature = "unstable"))]
mod benches {
    use rand::thread_rng;
    use test::{Bencher, black_box};

    use super::SharedSecret;
    use super::super::Secp256k1;

    #[bench]
    pub fn bench_ecdh(bh: &mut Bencher) {
        let s = Secp256k1::signing_only();
        let (sk, pk) = s.generate_keypair(&mut thread_rng());

        let s = Secp256k1::new();
        bh.iter( || {
            let res = SharedSecret::new(&pk, &sk);
            black_box(res);
        });
    }
}

<commit_msg>Add 'new_with_hash' function to SharedSecret<commit_after>// Bitcoin secp256k1 bindings
// Written in 2015 by
//   Andrew Poelstra
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # ECDH
//! Support for shared secret computations
//!

use core::ptr;
use core::ops::{FnMut, Deref};

use key::{SecretKey, PublicKey};
use ffi::{self, CPtr};
use secp256k1_sys::types::{c_int, c_uchar, c_void};

/// A tag used for recovering the public key from a compact signature
#[derive(Copy, Clone)]
pub struct SharedSecret {
    data: [u8; 256],
    len: usize,
}
impl_raw_debug!(SharedSecret);

// This implementes `From<N>` for all `[u8; N]` arrays from 128bits(16 byte) to 2048bits allowing known hash lengths.
// Lower than 128 bits isn't resistant to collisions any more.
impl_from_array_len!(SharedSecret, 256, (16 20 28 32 48 64 96 128 256));

impl SharedSecret {

    /// Create an empty SharedSecret
    pub(crate) fn empty() ->  SharedSecret {
        SharedSecret {
            data: [0u8; 256],
            len: 0,
        }
    }

    /// Get a pointer to the underlying data with the specified capacity.
    pub(crate) fn get_data_mut_ptr(&mut self) -> *mut u8 {
        self.data.as_mut_ptr()
    }

    /// Get the capacity of the underlying data buffer.
    pub fn capacity(&self) -> usize {
        self.data.len()
    }

    /// Get the len of the used data.
    pub fn len(&self) -> usize {
        self.len
    }

    /// Set the length of the object.
    pub(crate) fn set_len(&mut self, len: usize) {
        self.len = len;
    }
}

impl PartialEq for SharedSecret {
    fn eq(&self, other: &SharedSecret) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl AsRef<[u8]> for SharedSecret {
    fn as_ref(&self) -> &[u8] {
        &self.data[..self.len]
    }
}

impl Deref for SharedSecret {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        &self.data[..self.len]
    }
}

unsafe extern "C" fn hash_callback<F>(output: *mut c_uchar, x: *const c_uchar, y: *const c_uchar, data: *mut c_void) -> c_int
    where F: FnMut([u8; 32], [u8; 32]) -> SharedSecret {
    let callback: &mut F = &mut *(data as *mut F);

    let mut x_arr = [0; 32];
    let mut y_arr = [0; 32];
    ptr::copy_nonoverlapping(x, x_arr.as_mut_ptr(), 32);
    ptr::copy_nonoverlapping(y, y_arr.as_mut_ptr(), 32);

    let secret = callback(x_arr, y_arr);
    ptr::copy_nonoverlapping(secret.as_ptr(), output as *mut u8, secret.len());

    secret.len() as c_int
}

impl SharedSecret {
    /// Creates a new shared secret from a pubkey and secret key
    #[inline]
    pub fn new(point: &PublicKey, scalar: &SecretKey) -> SharedSecret {
        let mut ss = SharedSecret::empty();
        let res = unsafe {
             ffi::secp256k1_ecdh(
                ffi::secp256k1_context_no_precomp,
                ss.get_data_mut_ptr(),
                point.as_c_ptr(),
                scalar.as_c_ptr(),
                ffi::secp256k1_ecdh_hash_function_default,
                ptr::null_mut(),
            )
        };
        debug_assert_eq!(res, 1); // The default `secp256k1_ecdh_hash_function_default` should always return 1.
        ss.set_len(32); // The default hash function is SHA256, which is 32 bytes long.
        ss
    }

    /// Creates a new shared secret from a pubkey and secret key with applied custom hash function
    /// # Examples
    /// ```
    /// # use secp256k1::ecdh::SharedSecret;
    /// # use secp256k1::{Secp256k1, PublicKey, SecretKey};
    /// # fn sha2(_a: &[u8], _b: &[u8]) -> [u8; 32] {[0u8; 32]}
    /// # let secp = Secp256k1::signing_only();
    /// # let secret_key = SecretKey::from_slice(&[3u8; 32]).unwrap();
    /// # let secret_key2 = SecretKey::from_slice(&[7u8; 32]).unwrap();
    /// # let public_key = PublicKey::from_secret_key(&secp, &secret_key2);
    ///
    /// let secret = SharedSecret::new_with_hash(&public_key, &secret_key, |x,y| {
    ///     let hash: [u8; 32] = sha2(&x,&y);
    ///     hash.into()
    /// });
    ///
    /// ```
    pub fn new_with_hash<F>(point: &PublicKey, scalar: &SecretKey, mut hash_function: F) -> SharedSecret
        where F: FnMut([u8; 32], [u8; 32]) -> SharedSecret
    {
        let mut ss = SharedSecret::empty();
        let hashfp: ffi::EcdhHashFn = hash_callback::<F>;

        let res =  unsafe {
            ffi::secp256k1_ecdh(
                ffi::secp256k1_context_no_precomp,
                ss.get_data_mut_ptr(),
                point.as_ptr(),
                scalar.as_ptr(),
                hashfp,
                &mut hash_function as *mut F as *mut c_void,
            )
        };
        debug_assert!(res >= 16); // 128 bit is the minimum for a secure hash function and the minimum we let users.
        ss.set_len(res as usize);
        ss
    }
}

#[cfg(test)]
mod tests {
    use rand::thread_rng;
    use super::SharedSecret;
    use super::super::Secp256k1;

    #[test]
    fn ecdh() {
        let s = Secp256k1::signing_only();
        let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
        let (sk2, pk2) = s.generate_keypair(&mut thread_rng());

        let sec1 = SharedSecret::new(&pk1, &sk2);
        let sec2 = SharedSecret::new(&pk2, &sk1);
        let sec_odd = SharedSecret::new(&pk1, &sk1);
        assert_eq!(sec1, sec2);
        assert!(sec_odd != sec2);
    }
}

#[cfg(all(test, feature = "unstable"))]
mod benches {
    use rand::thread_rng;
    use test::{Bencher, black_box};

    use super::SharedSecret;
    use super::super::Secp256k1;

    #[bench]
    pub fn bench_ecdh(bh: &mut Bencher) {
        let s = Secp256k1::signing_only();
        let (sk, pk) = s.generate_keypair(&mut thread_rng());

        let s = Secp256k1::new();
        bh.iter( || {
            let res = SharedSecret::new(&pk, &sk);
            black_box(res);
        });
    }
}

<|endoftext|>


<commit_before>#![feature(rustc_private, i128_type)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
extern crate log;

use rustc::session::Session;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use syntax::ast::{MetaItemKind, NestedMetaItemKind, self};
use std::path::PathBuf;

struct MiriCompilerCalls(RustcDefaultCalls);

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType
    ) -> Compilation {
        self.0.early_callback(matches, sopts, cfg, descriptions, output)
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry
    ) -> Option<(Input, Option<PathBuf>)> {
        self.0.no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>
    ) -> Compilation {
        self.0.late_callback(matches, sess, input, odir, ofile)
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> {
        let mut control = self.0.build_controller(sess, matches);
        control.after_hir_lowering.callback = Box::new(after_hir_lowering);
        control.after_analysis.callback = Box::new(after_analysis);
        if std::env::var("MIRI_HOST_TARGET") != Ok("yes".to_owned()) {
            // only fully compile targets on the host
            control.after_analysis.stop = Compilation::Stop;
        }
        control
    }
}

fn after_hir_lowering(state: &mut CompileState) {
    let attr = (String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted);
    state.session.plugin_attributes.borrow_mut().push(attr);
}

fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
    state.session.abort_if_errors();

    let tcx = state.tcx.unwrap();
    miri::run_mir_passes(tcx);
    let limits = resource_limits_from_attributes(state);

    if std::env::args().any(|arg| arg == "--test") {
        struct Visitor<'a, 'tcx: 'a>(miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>);
        impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
            fn visit_item(&mut self, i: &'hir hir::Item) {
                if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node {
                    if i.attrs.iter().any(|attr| attr.value.name == "test") {
                        let did = self.1.hir.body_owner_def_id(body_id);
                        println!("running test: {}", self.1.hir.def_path(did).to_string(self.1));
                        miri::eval_main(self.1, did, self.0);
                        self.2.session.abort_if_errors();
                    }
                }
            }
            fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
            fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
        }
        state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(limits, tcx, state));
    } else {
        if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
            let entry_def_id = tcx.hir.local_def_id(entry_node_id);
            miri::eval_main(tcx, entry_def_id, limits);

            state.session.abort_if_errors();
        } else {
            println!("no main function found, assuming auxiliary build");
        }
    }
}

fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits {
    let mut limits = miri::ResourceLimits::default();
    let krate = state.hir_crate.as_ref().unwrap();
    let err_msg = "miri attributes need to be in the form `miri(key = value)`";
    let extract_int = |lit: &syntax::ast::Lit| -> u128 {
        match lit.node {
            syntax::ast::LitKind::Int(i, _) => i,
            _ => state.session.span_fatal(lit.span, "expected an integer literal"),
        }
    };

    for attr in krate.attrs.iter().filter(|a| a.name() == "miri") {
        if let MetaItemKind::List(ref items) = attr.value.node {
            for item in items {
                if let NestedMetaItemKind::MetaItem(ref inner) = item.node {
                    if let MetaItemKind::NameValue(ref value) = inner.node {
                        match &inner.name().as_str()[..] {
                            "memory_size" => limits.memory_size = extract_int(value) as u64,
                            "step_limit" => limits.step_limit = extract_int(value) as u64,
                            "stack_limit" => limits.stack_limit = extract_int(value) as usize,
                            _ => state.session.span_err(item.span, "unknown miri attribute"),
                        }
                    } else {
                        state.session.span_err(inner.span, err_msg);
                    }
                } else {
                    state.session.span_err(item.span, err_msg);
                }
            }
        } else {
            state.session.span_err(attr.span, err_msg);
        }
    }
    limits
}

fn init_logger() {
    let format = |record: &log::LogRecord| {
        if record.level() == log::LogLevel::Trace {
            // prepend spaces to indent the final string
            let indentation = log_settings::settings().indentation;
            format!(
                "{lvl}:{module}:{indent:<indentation$} {text}",
                lvl = record.level(),
                module = record.location().module_path(),
                indentation = indentation,
                indent = "",
                text = record.args(),
            )
        } else {
            format!(
                "{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.location().module_path(),
                text = record.args(),
            )
        }
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format).filter(None, log::LogLevelFilter::Info);

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init().unwrap();
}

fn find_sysroot() -> String {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    }
}

fn main() {
    init_logger();
    let mut args: Vec<String> = std::env::args().collect();

    let sysroot_flag = String::from("--sysroot");
    if !args.contains(&sysroot_flag) {
        args.push(sysroot_flag);
        args.push(find_sysroot());
    }
    // we run the optimization passes inside miri
    // if we ran them twice we'd get funny failures due to borrowck ElaborateDrops only working on
    // unoptimized MIR
    // FIXME: add an after-mir-passes hook to rustc driver
    args.push("-Zmir-opt-level=0".to_owned());
    // for auxilary builds in unit tests
    args.push("-Zalways-encode-mir".to_owned());

    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls(RustcDefaultCalls), None, None);
}
<commit_msg>ast::Attribute no longer has a 'value' field<commit_after>#![feature(rustc_private, i128_type)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
extern crate log;

use rustc::session::Session;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use syntax::ast::{MetaItemKind, NestedMetaItemKind, self};
use std::path::PathBuf;

struct MiriCompilerCalls(RustcDefaultCalls);

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType
    ) -> Compilation {
        self.0.early_callback(matches, sopts, cfg, descriptions, output)
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry
    ) -> Option<(Input, Option<PathBuf>)> {
        self.0.no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>
    ) -> Compilation {
        self.0.late_callback(matches, sess, input, odir, ofile)
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> {
        let mut control = self.0.build_controller(sess, matches);
        control.after_hir_lowering.callback = Box::new(after_hir_lowering);
        control.after_analysis.callback = Box::new(after_analysis);
        if std::env::var("MIRI_HOST_TARGET") != Ok("yes".to_owned()) {
            // only fully compile targets on the host
            control.after_analysis.stop = Compilation::Stop;
        }
        control
    }
}

fn after_hir_lowering(state: &mut CompileState) {
    let attr = (String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted);
    state.session.plugin_attributes.borrow_mut().push(attr);
}

fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
    state.session.abort_if_errors();

    let tcx = state.tcx.unwrap();
    miri::run_mir_passes(tcx);
    let limits = resource_limits_from_attributes(state);

    if std::env::args().any(|arg| arg == "--test") {
        struct Visitor<'a, 'tcx: 'a>(miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>);
        impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
            fn visit_item(&mut self, i: &'hir hir::Item) {
                if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node {
                    if i.attrs.iter().any(|attr| attr.name().map_or(false, |n| n == "test")) {
                        let did = self.1.hir.body_owner_def_id(body_id);
                        println!("running test: {}", self.1.hir.def_path(did).to_string(self.1));
                        miri::eval_main(self.1, did, self.0);
                        self.2.session.abort_if_errors();
                    }
                }
            }
            fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
            fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
        }
        state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(limits, tcx, state));
    } else {
        if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
            let entry_def_id = tcx.hir.local_def_id(entry_node_id);
            miri::eval_main(tcx, entry_def_id, limits);

            state.session.abort_if_errors();
        } else {
            println!("no main function found, assuming auxiliary build");
        }
    }
}

fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits {
    let mut limits = miri::ResourceLimits::default();
    let krate = state.hir_crate.as_ref().unwrap();
    let err_msg = "miri attributes need to be in the form `miri(key = value)`";
    let extract_int = |lit: &syntax::ast::Lit| -> u128 {
        match lit.node {
            syntax::ast::LitKind::Int(i, _) => i,
            _ => state.session.span_fatal(lit.span, "expected an integer literal"),
        }
    };

    for attr in krate.attrs.iter().filter(|a| a.name().map_or(false, |n| n == "miri")) {
        if let Some(items) = attr.meta_item_list() {
            for item in items {
                if let NestedMetaItemKind::MetaItem(ref inner) = item.node {
                    if let MetaItemKind::NameValue(ref value) = inner.node {
                        match &inner.name().as_str()[..] {
                            "memory_size" => limits.memory_size = extract_int(value) as u64,
                            "step_limit" => limits.step_limit = extract_int(value) as u64,
                            "stack_limit" => limits.stack_limit = extract_int(value) as usize,
                            _ => state.session.span_err(item.span, "unknown miri attribute"),
                        }
                    } else {
                        state.session.span_err(inner.span, err_msg);
                    }
                } else {
                    state.session.span_err(item.span, err_msg);
                }
            }
        } else {
            state.session.span_err(attr.span, err_msg);
        }
    }
    limits
}

fn init_logger() {
    let format = |record: &log::LogRecord| {
        if record.level() == log::LogLevel::Trace {
            // prepend spaces to indent the final string
            let indentation = log_settings::settings().indentation;
            format!(
                "{lvl}:{module}:{indent:<indentation$} {text}",
                lvl = record.level(),
                module = record.location().module_path(),
                indentation = indentation,
                indent = "",
                text = record.args(),
            )
        } else {
            format!(
                "{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.location().module_path(),
                text = record.args(),
            )
        }
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format).filter(None, log::LogLevelFilter::Info);

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init().unwrap();
}

fn find_sysroot() -> String {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    }
}

fn main() {
    init_logger();
    let mut args: Vec<String> = std::env::args().collect();

    let sysroot_flag = String::from("--sysroot");
    if !args.contains(&sysroot_flag) {
        args.push(sysroot_flag);
        args.push(find_sysroot());
    }
    // we run the optimization passes inside miri
    // if we ran them twice we'd get funny failures due to borrowck ElaborateDrops only working on
    // unoptimized MIR
    // FIXME: add an after-mir-passes hook to rustc driver
    args.push("-Zmir-opt-level=0".to_owned());
    // for auxilary builds in unit tests
    args.push("-Zalways-encode-mir".to_owned());

    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls(RustcDefaultCalls), None, None);
}
<|endoftext|>


<commit_before>use serde_json::from_reader;
use std::collections::HashMap;
use std::fs::File;
use std::path::Path;

use compositing::RenderLayer;
use resource::{Load, LoadError, Result, ResCache};

/// Time.
pub type Time = f64;

pub struct Clip<'a, 'b> {
  gen_render_layer: Box<Fn(Time) -> RenderLayer<'a> + 'b>
}

impl<'a, 'b> Clip<'a, 'b> {
  pub fn new<F>(f: F) -> Self where F: 'b + Fn(Time) -> RenderLayer<'a> {
    Clip {
      gen_render_layer: Box::new(f)
    }
  }
}

/// A cut is an object that slices a `Clip` at an *input time* and *output time*. It is instantiated
/// in a `Track` at a given *instance time*.
#[derive(Clone)]
pub struct Cut<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: &'c Clip<'a, 'b>
}

impl<'a, 'b, 'c> Cut<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new(in_time: Time, out_time: Time, inst_time: Time, clip: &'c Clip<'a, 'b>) -> Self {
    assert!(in_time <= out_time);

    Cut {
      in_time: in_time,
      out_time: out_time,
      inst_time: inst_time,
      clip: clip
    }
  }

  /// Duration of the cut.
  pub fn dur(&self) -> Time {
    self.out_time - self.in_time
  }
}

/// A track gathers `Cut`s and its purpose is to be used inside a `Timeline`.
#[derive(Clone)]
pub struct Track<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  cuts: Vec<Cut<'a, 'b, 'c>>
}

impl<'a, 'b, 'c> Track<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new() -> Self {
    Track {
      cuts: Vec::new()
    }
  }

  pub fn add_cut(&mut self, cut: Cut<'a, 'b, 'c>) {
    self.cuts.push(cut);
  }
}

impl<'a, 'b, 'c, 'd> From<&'d [Cut<'a, 'b, 'c>]> for Track<'a, 'b, 'c> {
  fn from(cuts: &'d [Cut<'a, 'b, 'c>]) -> Self {
    Track {
      cuts: cuts.to_vec()
    }
  }
}

/// A timeline gathers tracks used to build up the visual aspect of the demo.
#[derive(Clone)]
pub struct Timeline<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  tracks: Vec<Track<'a, 'b, 'c>>,
}

impl<'a, 'b, 'c> Timeline<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new() -> Self {
    Timeline {
      tracks: Vec::new(),
    }
  }

  /// Turn a TimelineManifest into a Timeline by providing a mapping between clips’ names and real
  /// clips.
  pub fn from_manifest(manifest: &TimelineManifest, mapping: &HashMap<String, &'c Clip<'a, 'b>>) -> Self {
    let mut timeline = Self::new();

    for track_manifest in &manifest.tracks {
      let mut track = Track::new();

      for cut_manifest in &track_manifest.cuts {
        let in_time = cut_manifest.in_time;
        let out_time = cut_manifest.out_time;
        let inst_time = cut_manifest.inst_time;

        if let Some(clip) = mapping.get(&cut_manifest.clip).cloned() {
          track.add_cut(Cut::new(in_time, out_time, inst_time, clip));
        } else {
          warn!("the clip {:?} doesn’t exist", cut_manifest.clip);
        }
      }

      timeline.add_track(track);
    }

    timeline
  }

  pub fn add_track(&mut self, track: Track<'a, 'b, 'c>) {
    self.tracks.push(track);
  }

  // TODO: currently, we play the first track we find; add transition support
  pub fn play(&self, t: Time) -> Option<RenderLayer<'a>> {
    for track in &self.tracks {
      for cut in &track.cuts {
        if cut.inst_time <= t && t <= cut.inst_time + cut.dur() {
          return Some((cut.clip.gen_render_layer)(t));
        }
      }
    }

    None
  }
}

impl<'a, 'b, 'c, 'd> From<&'d [Track<'a, 'b, 'c>]> for Timeline<'a, 'b, 'c> {
  fn from(tracks: &'d [Track<'a, 'b, 'c>]) -> Self {
    Timeline {
      tracks: tracks.to_vec(),
    }
  }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct TimelineManifest {
  pub tracks: Vec<TrackManifest>
}

impl Load for TimelineManifest {
  type Args = ();

  const TY_STR: &'static str = "edit";

  fn load<P>(path: P, _: &mut ResCache, _: Self::Args) -> Result<Self> where P: AsRef<Path> {
    let path = path.as_ref();

    info!("loading timeline: {:?}", path);

    let file = File::open(path).map_err(|e| LoadError::FileNotFound(path.to_path_buf(), format!("{:?}", e)))?;
    from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))
  }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct TrackManifest {
  pub cuts: Vec<CutManifest>
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct CutManifest {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: String
}
<commit_msg>I have a lifetime issue in client code, and I don’t get why.<commit_after>use serde_json::from_reader;
use std::collections::HashMap;
use std::fs::File;
use std::path::Path;

use compositing::RenderLayer;
use resource::{Load, LoadError, Result, ResCache};

/// Time.
pub type Time = f64;

pub struct Clip<'a, 'b> where 'a: 'b {
  gen_render_layer: Box<Fn(Time) -> RenderLayer<'a> + 'b>
}

impl<'a, 'b> Clip<'a, 'b> {
  pub fn new<F>(f: F) -> Self where F: 'b + Fn(Time) -> RenderLayer<'a> {
    Clip {
      gen_render_layer: Box::new(f)
    }
  }
}

/// A cut is an object that slices a `Clip` at an *input time* and *output time*. It is instantiated
/// in a `Track` at a given *instance time*.
#[derive(Clone)]
pub struct Cut<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: &'c Clip<'a, 'b>
}

impl<'a, 'b, 'c> Cut<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new(in_time: Time, out_time: Time, inst_time: Time, clip: &'c Clip<'a, 'b>) -> Self {
    assert!(in_time <= out_time);

    Cut {
      in_time: in_time,
      out_time: out_time,
      inst_time: inst_time,
      clip: clip
    }
  }

  /// Duration of the cut.
  pub fn dur(&self) -> Time {
    self.out_time - self.in_time
  }
}

/// A track gathers `Cut`s and its purpose is to be used inside a `Timeline`.
#[derive(Clone)]
pub struct Track<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  cuts: Vec<Cut<'a, 'b, 'c>>
}

impl<'a, 'b, 'c> Track<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new() -> Self {
    Track {
      cuts: Vec::new()
    }
  }

  pub fn add_cut(&mut self, cut: Cut<'a, 'b, 'c>) {
    self.cuts.push(cut);
  }
}

impl<'a, 'b, 'c, 'd> From<&'d [Cut<'a, 'b, 'c>]> for Track<'a, 'b, 'c> {
  fn from(cuts: &'d [Cut<'a, 'b, 'c>]) -> Self {
    Track {
      cuts: cuts.to_vec()
    }
  }
}

/// A timeline gathers tracks used to build up the visual aspect of the demo.
#[derive(Clone)]
pub struct Timeline<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  tracks: Vec<Track<'a, 'b, 'c>>,
}

impl<'a, 'b, 'c> Timeline<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new() -> Self {
    Timeline {
      tracks: Vec::new(),
    }
  }

  /// Turn a TimelineManifest into a Timeline by providing a mapping between clips’ names and real
  /// clips.
  pub fn from_manifest(manifest: &TimelineManifest, mapping: &HashMap<String, &'c Clip<'a, 'b>>) -> Self {
    let mut timeline = Self::new();

    for track_manifest in &manifest.tracks {
      let mut track = Track::new();

      for cut_manifest in &track_manifest.cuts {
        let in_time = cut_manifest.in_time;
        let out_time = cut_manifest.out_time;
        let inst_time = cut_manifest.inst_time;

        if let Some(clip) = mapping.get(&cut_manifest.clip).cloned() {
          track.add_cut(Cut::new(in_time, out_time, inst_time, clip));
        } else {
          warn!("the clip {:?} doesn’t exist", cut_manifest.clip);
        }
      }

      timeline.add_track(track);
    }

    timeline
  }

  pub fn add_track(&mut self, track: Track<'a, 'b, 'c>) {
    self.tracks.push(track);
  }

  // TODO: currently, we play the first track we find; add transition support
  pub fn play(&self, t: Time) -> Option<RenderLayer<'a>> {
    for track in &self.tracks {
      for cut in &track.cuts {
        if cut.inst_time <= t && t <= cut.inst_time + cut.dur() {
          return Some((cut.clip.gen_render_layer)(t));
        }
      }
    }

    None
  }
}

impl<'a, 'b, 'c, 'd> From<&'d [Track<'a, 'b, 'c>]> for Timeline<'a, 'b, 'c> {
  fn from(tracks: &'d [Track<'a, 'b, 'c>]) -> Self {
    Timeline {
      tracks: tracks.to_vec(),
    }
  }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct TimelineManifest {
  pub tracks: Vec<TrackManifest>
}

impl Load for TimelineManifest {
  type Args = ();

  const TY_STR: &'static str = "edit";

  fn load<P>(path: P, _: &mut ResCache, _: Self::Args) -> Result<Self> where P: AsRef<Path> {
    let path = path.as_ref();

    info!("loading timeline: {:?}", path);

    let file = File::open(path).map_err(|e| LoadError::FileNotFound(path.to_path_buf(), format!("{:?}", e)))?;
    from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))
  }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct TrackManifest {
  pub cuts: Vec<CutManifest>
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct CutManifest {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: String
}
<|endoftext|>


<commit_before>// This file was generated by gir (310a2da) from gir-files (71d73f0)
// DO NOT EDIT

mod app_launch_context;
pub use self::app_launch_context::AppLaunchContext;

mod cursor;
pub use self::cursor::Cursor;

mod device;
pub use self::device::Device;

mod device_manager;
pub use self::device_manager::DeviceManager;

#[cfg(feature = "v3_22")]
mod device_tool;
#[cfg(feature = "v3_22")]
pub use self::device_tool::DeviceTool;

mod display;
pub use self::display::Display;

mod display_manager;
pub use self::display_manager::DisplayManager;

mod drag_context;
pub use self::drag_context::DragContext;

#[cfg(feature = "v3_8")]
mod frame_clock;
#[cfg(feature = "v3_8")]
pub use self::frame_clock::FrameClock;

#[cfg(feature = "v3_16")]
mod g_l_context;
#[cfg(feature = "v3_16")]
pub use self::g_l_context::GLContext;

mod monitor;
pub use self::monitor::Monitor;

mod screen;
pub use self::screen::Screen;

#[cfg(feature = "v3_20")]
mod seat;
#[cfg(feature = "v3_20")]
pub use self::seat::Seat;

mod visual;
pub use self::visual::Visual;

mod window;
pub use self::window::Window;

#[cfg(feature = "v3_8")]
mod frame_timings;
#[cfg(feature = "v3_8")]
pub use self::frame_timings::FrameTimings;

mod enums;
pub use self::enums::AxisUse;
pub use self::enums::ByteOrder;
pub use self::enums::CrossingMode;
pub use self::enums::CursorType;
#[cfg(feature = "v3_22")]
pub use self::enums::DeviceToolType;
pub use self::enums::DeviceType;
#[cfg(feature = "v3_20")]
pub use self::enums::DragCancelReason;
pub use self::enums::DragProtocol;
pub use self::enums::EventType;
#[cfg(feature = "v3_8")]
pub use self::enums::FullscreenMode;
#[cfg(feature = "v3_16")]
pub use self::enums::GLError;
pub use self::enums::GrabOwnership;
pub use self::enums::GrabStatus;
pub use self::enums::Gravity;
pub use self::enums::InputMode;
pub use self::enums::InputSource;
pub use self::enums::ModifierIntent;
pub use self::enums::NotifyType;
pub use self::enums::OwnerChange;
pub use self::enums::PropertyState;
pub use self::enums::ScrollDirection;
pub use self::enums::SettingAction;
#[cfg(feature = "v3_22")]
pub use self::enums::SubpixelLayout;
pub use self::enums::VisibilityState;
pub use self::enums::VisualType;
pub use self::enums::WindowEdge;
pub use self::enums::WindowType;
pub use self::enums::WindowTypeHint;
pub use self::enums::WindowWindowClass;

mod flags;
#[cfg(feature = "v3_22")]
pub use self::flags::AnchorHints;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_FLIP_X;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_FLIP_Y;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_SLIDE_X;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_SLIDE_Y;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_RESIZE_X;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_RESIZE_Y;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_FLIP;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_SLIDE;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_RESIZE;
#[cfg(feature = "v3_22")]
pub use self::flags::AxisFlags;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_X;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_Y;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_PRESSURE;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_XTILT;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_YTILT;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_WHEEL;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_DISTANCE;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_ROTATION;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_SLIDER;
pub use self::flags::DragAction;
pub use self::flags::ACTION_DEFAULT;
pub use self::flags::ACTION_COPY;
pub use self::flags::ACTION_MOVE;
pub use self::flags::ACTION_LINK;
pub use self::flags::ACTION_PRIVATE;
pub use self::flags::ACTION_ASK;
pub use self::flags::EventMask;
pub use self::flags::EXPOSURE_MASK;
pub use self::flags::POINTER_MOTION_MASK;
pub use self::flags::POINTER_MOTION_HINT_MASK;
pub use self::flags::BUTTON_MOTION_MASK;
pub use self::flags::BUTTON1_MOTION_MASK;
pub use self::flags::BUTTON2_MOTION_MASK;
pub use self::flags::BUTTON3_MOTION_MASK;
pub use self::flags::BUTTON_PRESS_MASK;
pub use self::flags::BUTTON_RELEASE_MASK;
pub use self::flags::KEY_PRESS_MASK;
pub use self::flags::KEY_RELEASE_MASK;
pub use self::flags::ENTER_NOTIFY_MASK;
pub use self::flags::LEAVE_NOTIFY_MASK;
pub use self::flags::FOCUS_CHANGE_MASK;
pub use self::flags::STRUCTURE_MASK;
pub use self::flags::PROPERTY_CHANGE_MASK;
pub use self::flags::VISIBILITY_NOTIFY_MASK;
pub use self::flags::PROXIMITY_IN_MASK;
pub use self::flags::PROXIMITY_OUT_MASK;
pub use self::flags::SUBSTRUCTURE_MASK;
pub use self::flags::SCROLL_MASK;
pub use self::flags::TOUCH_MASK;
pub use self::flags::SMOOTH_SCROLL_MASK;
pub use self::flags::TOUCHPAD_GESTURE_MASK;
pub use self::flags::TABLET_PAD_MASK;
pub use self::flags::ALL_EVENTS_MASK;
#[cfg(feature = "v3_8")]
pub use self::flags::FrameClockPhase;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_NONE;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_FLUSH_EVENTS;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_BEFORE_PAINT;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_UPDATE;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_LAYOUT;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_PAINT;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_RESUME_EVENTS;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_AFTER_PAINT;
pub use self::flags::ModifierType;
pub use self::flags::SHIFT_MASK;
pub use self::flags::LOCK_MASK;
pub use self::flags::CONTROL_MASK;
pub use self::flags::MOD1_MASK;
pub use self::flags::MOD2_MASK;
pub use self::flags::MOD3_MASK;
pub use self::flags::MOD4_MASK;
pub use self::flags::MOD5_MASK;
pub use self::flags::BUTTON1_MASK;
pub use self::flags::BUTTON2_MASK;
pub use self::flags::BUTTON3_MASK;
pub use self::flags::BUTTON4_MASK;
pub use self::flags::BUTTON5_MASK;
pub use self::flags::MODIFIER_RESERVED_13_MASK;
pub use self::flags::MODIFIER_RESERVED_14_MASK;
pub use self::flags::MODIFIER_RESERVED_15_MASK;
pub use self::flags::MODIFIER_RESERVED_16_MASK;
pub use self::flags::MODIFIER_RESERVED_17_MASK;
pub use self::flags::MODIFIER_RESERVED_18_MASK;
pub use self::flags::MODIFIER_RESERVED_19_MASK;
pub use self::flags::MODIFIER_RESERVED_20_MASK;
pub use self::flags::MODIFIER_RESERVED_21_MASK;
pub use self::flags::MODIFIER_RESERVED_22_MASK;
pub use self::flags::MODIFIER_RESERVED_23_MASK;
pub use self::flags::MODIFIER_RESERVED_24_MASK;
pub use self::flags::MODIFIER_RESERVED_25_MASK;
pub use self::flags::SUPER_MASK;
pub use self::flags::HYPER_MASK;
pub use self::flags::META_MASK;
pub use self::flags::MODIFIER_RESERVED_29_MASK;
pub use self::flags::RELEASE_MASK;
pub use self::flags::MODIFIER_MASK;
#[cfg(feature = "v3_20")]
pub use self::flags::SeatCapabilities;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_NONE;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_POINTER;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_TOUCH;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_TABLET_STYLUS;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_KEYBOARD;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_ALL_POINTING;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_ALL;
pub use self::flags::WMDecoration;
pub use self::flags::DECOR_ALL;
pub use self::flags::DECOR_BORDER;
pub use self::flags::DECOR_RESIZEH;
pub use self::flags::DECOR_TITLE;
pub use self::flags::DECOR_MENU;
pub use self::flags::DECOR_MINIMIZE;
pub use self::flags::DECOR_MAXIMIZE;
pub use self::flags::WMFunction;
pub use self::flags::FUNC_ALL;
pub use self::flags::FUNC_RESIZE;
pub use self::flags::FUNC_MOVE;
pub use self::flags::FUNC_MINIMIZE;
pub use self::flags::FUNC_MAXIMIZE;
pub use self::flags::FUNC_CLOSE;
pub use self::flags::WindowHints;
pub use self::flags::HINT_POS;
pub use self::flags::HINT_MIN_SIZE;
pub use self::flags::HINT_MAX_SIZE;
pub use self::flags::HINT_BASE_SIZE;
pub use self::flags::HINT_ASPECT;
pub use self::flags::HINT_RESIZE_INC;
pub use self::flags::HINT_WIN_GRAVITY;
pub use self::flags::HINT_USER_POS;
pub use self::flags::HINT_USER_SIZE;
pub use self::flags::WindowState;
pub use self::flags::WINDOW_STATE_WITHDRAWN;
pub use self::flags::WINDOW_STATE_ICONIFIED;
pub use self::flags::WINDOW_STATE_MAXIMIZED;
pub use self::flags::WINDOW_STATE_STICKY;
pub use self::flags::WINDOW_STATE_FULLSCREEN;
pub use self::flags::WINDOW_STATE_ABOVE;
pub use self::flags::WINDOW_STATE_BELOW;
pub use self::flags::WINDOW_STATE_FOCUSED;
pub use self::flags::WINDOW_STATE_TILED;

#[doc(hidden)]
pub mod traits {
}
<commit_msg>Regen<commit_after>// This file was generated by gir (310a2da) from gir-files (71d73f0)
// DO NOT EDIT

mod app_launch_context;
pub use self::app_launch_context::AppLaunchContext;

mod cursor;
pub use self::cursor::Cursor;

mod device;
pub use self::device::Device;

mod device_manager;
pub use self::device_manager::DeviceManager;

#[cfg(feature = "v3_22")]
mod device_tool;
#[cfg(feature = "v3_22")]
pub use self::device_tool::DeviceTool;

mod display;
pub use self::display::Display;

mod display_manager;
pub use self::display_manager::DisplayManager;

mod drag_context;
pub use self::drag_context::DragContext;

#[cfg(feature = "v3_8")]
mod frame_clock;
#[cfg(feature = "v3_8")]
pub use self::frame_clock::FrameClock;

#[cfg(feature = "v3_16")]
mod g_l_context;
#[cfg(feature = "v3_16")]
pub use self::g_l_context::GLContext;

#[cfg(feature = "v3_22")]
mod monitor;
#[cfg(feature = "v3_22")]
pub use self::monitor::Monitor;

mod screen;
pub use self::screen::Screen;

#[cfg(feature = "v3_20")]
mod seat;
#[cfg(feature = "v3_20")]
pub use self::seat::Seat;

mod visual;
pub use self::visual::Visual;

mod window;
pub use self::window::Window;

#[cfg(feature = "v3_8")]
mod frame_timings;
#[cfg(feature = "v3_8")]
pub use self::frame_timings::FrameTimings;

mod enums;
pub use self::enums::AxisUse;
pub use self::enums::ByteOrder;
pub use self::enums::CrossingMode;
pub use self::enums::CursorType;
#[cfg(feature = "v3_22")]
pub use self::enums::DeviceToolType;
pub use self::enums::DeviceType;
#[cfg(feature = "v3_20")]
pub use self::enums::DragCancelReason;
pub use self::enums::DragProtocol;
pub use self::enums::EventType;
#[cfg(feature = "v3_8")]
pub use self::enums::FullscreenMode;
#[cfg(feature = "v3_16")]
pub use self::enums::GLError;
pub use self::enums::GrabOwnership;
pub use self::enums::GrabStatus;
pub use self::enums::Gravity;
pub use self::enums::InputMode;
pub use self::enums::InputSource;
pub use self::enums::ModifierIntent;
pub use self::enums::NotifyType;
pub use self::enums::OwnerChange;
pub use self::enums::PropertyState;
pub use self::enums::ScrollDirection;
pub use self::enums::SettingAction;
#[cfg(feature = "v3_22")]
pub use self::enums::SubpixelLayout;
pub use self::enums::VisibilityState;
pub use self::enums::VisualType;
pub use self::enums::WindowEdge;
pub use self::enums::WindowType;
pub use self::enums::WindowTypeHint;
pub use self::enums::WindowWindowClass;

mod flags;
#[cfg(feature = "v3_22")]
pub use self::flags::AnchorHints;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_FLIP_X;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_FLIP_Y;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_SLIDE_X;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_SLIDE_Y;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_RESIZE_X;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_RESIZE_Y;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_FLIP;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_SLIDE;
#[cfg(feature = "v3_22")]
pub use self::flags::ANCHOR_RESIZE;
#[cfg(feature = "v3_22")]
pub use self::flags::AxisFlags;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_X;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_Y;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_PRESSURE;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_XTILT;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_YTILT;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_WHEEL;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_DISTANCE;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_ROTATION;
#[cfg(feature = "v3_22")]
pub use self::flags::AXIS_FLAG_SLIDER;
pub use self::flags::DragAction;
pub use self::flags::ACTION_DEFAULT;
pub use self::flags::ACTION_COPY;
pub use self::flags::ACTION_MOVE;
pub use self::flags::ACTION_LINK;
pub use self::flags::ACTION_PRIVATE;
pub use self::flags::ACTION_ASK;
pub use self::flags::EventMask;
pub use self::flags::EXPOSURE_MASK;
pub use self::flags::POINTER_MOTION_MASK;
pub use self::flags::POINTER_MOTION_HINT_MASK;
pub use self::flags::BUTTON_MOTION_MASK;
pub use self::flags::BUTTON1_MOTION_MASK;
pub use self::flags::BUTTON2_MOTION_MASK;
pub use self::flags::BUTTON3_MOTION_MASK;
pub use self::flags::BUTTON_PRESS_MASK;
pub use self::flags::BUTTON_RELEASE_MASK;
pub use self::flags::KEY_PRESS_MASK;
pub use self::flags::KEY_RELEASE_MASK;
pub use self::flags::ENTER_NOTIFY_MASK;
pub use self::flags::LEAVE_NOTIFY_MASK;
pub use self::flags::FOCUS_CHANGE_MASK;
pub use self::flags::STRUCTURE_MASK;
pub use self::flags::PROPERTY_CHANGE_MASK;
pub use self::flags::VISIBILITY_NOTIFY_MASK;
pub use self::flags::PROXIMITY_IN_MASK;
pub use self::flags::PROXIMITY_OUT_MASK;
pub use self::flags::SUBSTRUCTURE_MASK;
pub use self::flags::SCROLL_MASK;
pub use self::flags::TOUCH_MASK;
pub use self::flags::SMOOTH_SCROLL_MASK;
pub use self::flags::TOUCHPAD_GESTURE_MASK;
pub use self::flags::TABLET_PAD_MASK;
pub use self::flags::ALL_EVENTS_MASK;
#[cfg(feature = "v3_8")]
pub use self::flags::FrameClockPhase;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_NONE;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_FLUSH_EVENTS;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_BEFORE_PAINT;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_UPDATE;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_LAYOUT;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_PAINT;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_RESUME_EVENTS;
#[cfg(feature = "v3_8")]
pub use self::flags::FRAME_CLOCK_PHASE_AFTER_PAINT;
pub use self::flags::ModifierType;
pub use self::flags::SHIFT_MASK;
pub use self::flags::LOCK_MASK;
pub use self::flags::CONTROL_MASK;
pub use self::flags::MOD1_MASK;
pub use self::flags::MOD2_MASK;
pub use self::flags::MOD3_MASK;
pub use self::flags::MOD4_MASK;
pub use self::flags::MOD5_MASK;
pub use self::flags::BUTTON1_MASK;
pub use self::flags::BUTTON2_MASK;
pub use self::flags::BUTTON3_MASK;
pub use self::flags::BUTTON4_MASK;
pub use self::flags::BUTTON5_MASK;
pub use self::flags::MODIFIER_RESERVED_13_MASK;
pub use self::flags::MODIFIER_RESERVED_14_MASK;
pub use self::flags::MODIFIER_RESERVED_15_MASK;
pub use self::flags::MODIFIER_RESERVED_16_MASK;
pub use self::flags::MODIFIER_RESERVED_17_MASK;
pub use self::flags::MODIFIER_RESERVED_18_MASK;
pub use self::flags::MODIFIER_RESERVED_19_MASK;
pub use self::flags::MODIFIER_RESERVED_20_MASK;
pub use self::flags::MODIFIER_RESERVED_21_MASK;
pub use self::flags::MODIFIER_RESERVED_22_MASK;
pub use self::flags::MODIFIER_RESERVED_23_MASK;
pub use self::flags::MODIFIER_RESERVED_24_MASK;
pub use self::flags::MODIFIER_RESERVED_25_MASK;
pub use self::flags::SUPER_MASK;
pub use self::flags::HYPER_MASK;
pub use self::flags::META_MASK;
pub use self::flags::MODIFIER_RESERVED_29_MASK;
pub use self::flags::RELEASE_MASK;
pub use self::flags::MODIFIER_MASK;
#[cfg(feature = "v3_20")]
pub use self::flags::SeatCapabilities;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_NONE;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_POINTER;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_TOUCH;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_TABLET_STYLUS;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_KEYBOARD;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_ALL_POINTING;
#[cfg(feature = "v3_20")]
pub use self::flags::SEAT_CAPABILITY_ALL;
pub use self::flags::WMDecoration;
pub use self::flags::DECOR_ALL;
pub use self::flags::DECOR_BORDER;
pub use self::flags::DECOR_RESIZEH;
pub use self::flags::DECOR_TITLE;
pub use self::flags::DECOR_MENU;
pub use self::flags::DECOR_MINIMIZE;
pub use self::flags::DECOR_MAXIMIZE;
pub use self::flags::WMFunction;
pub use self::flags::FUNC_ALL;
pub use self::flags::FUNC_RESIZE;
pub use self::flags::FUNC_MOVE;
pub use self::flags::FUNC_MINIMIZE;
pub use self::flags::FUNC_MAXIMIZE;
pub use self::flags::FUNC_CLOSE;
pub use self::flags::WindowHints;
pub use self::flags::HINT_POS;
pub use self::flags::HINT_MIN_SIZE;
pub use self::flags::HINT_MAX_SIZE;
pub use self::flags::HINT_BASE_SIZE;
pub use self::flags::HINT_ASPECT;
pub use self::flags::HINT_RESIZE_INC;
pub use self::flags::HINT_WIN_GRAVITY;
pub use self::flags::HINT_USER_POS;
pub use self::flags::HINT_USER_SIZE;
pub use self::flags::WindowState;
pub use self::flags::WINDOW_STATE_WITHDRAWN;
pub use self::flags::WINDOW_STATE_ICONIFIED;
pub use self::flags::WINDOW_STATE_MAXIMIZED;
pub use self::flags::WINDOW_STATE_STICKY;
pub use self::flags::WINDOW_STATE_FULLSCREEN;
pub use self::flags::WINDOW_STATE_ABOVE;
pub use self::flags::WINDOW_STATE_BELOW;
pub use self::flags::WINDOW_STATE_FOCUSED;
pub use self::flags::WINDOW_STATE_TILED;

#[doc(hidden)]
pub mod traits {
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use types::*;
use types::RispType::*;
use environment::*;
use core::create_core_environment;
use parse;
use std::rc::Rc;

pub fn eval(ast: RispType, env: &mut Environment) -> RispResult {
    match ast {
        List(list) => {
            let first_element = list.first().ok_or_else(|| error("Empty List"))?;
            match *first_element {
                Symbol(ref symbol) => {
                    match symbol.as_ref() {
                        "def" => {
                            let var = list.get(1).ok_or_else(|| error("Missing variable in def"))?;
                            match *var {
                                Symbol(ref sym_var) => {
                                    let value_ast = list.get(2).ok_or_else(|| error("Missing value in def"))?;
                                    let value = eval(value_ast.clone(), env)?;
                                    env.set(sym_var, value.clone());
                                    Ok(value)
                                }
                                _ => error_result(format!("Expected symbol in def but got {:?}", var))
                            }
                        }
                        "do" => {
                            if let Some((last, elements)) = (&list[1..]).split_last() {
                                for child_ast in elements.iter() {
                                    eval(child_ast.clone(), env)?;
                                }
                                eval(last.clone(), env)
                            } else {
                                error_result("Empty do block")
                            }
                        }
                        "comment" => {
                            Ok(Nil)
                        }
                        "fn" => {
                            let args_risp = list.get(1).ok_or_else(|| error("Missing args in fn"))?;
                            match *args_risp {
                                Vector(ref args_vec) => {
                                    let body = list.get(2).ok_or_else(|| error("Missing body in fn"))?;
                                    Ok(RispFunction(RispFunc {
                                        args: args_vec.clone(),
                                        body: Rc::new(body.clone())
                                    }))
                                }
                                _ => error_result(format!("Expected args vector in fn but got {:?}", args_risp))
                            }
                        }
                        _ => {
                            let evaluated_tail = list[1..].iter()
                                .map(|el| eval(el.clone(), env))
                                .collect::<Result<Vec<_>, _>>()?;
                            let env_value = env.get(symbol).ok_or_else(|| error(format!("Undefined symbol{:?}", symbol)))?;
                            match env_value {
                                Function(function) => function(evaluated_tail.to_vec()),
                                RispFunction(risp_function) => {
                                    let mut inner_env = env.clone();
                                    for (arg, value) in risp_function.args.iter().zip(evaluated_tail.iter()) {
                                        match *arg {
                                            Symbol(ref arg_string) => {
                                                inner_env.set(arg_string, value.clone())
                                            },
                                            _ => {
                                                return error_result(format!("Expected symbol in args list got {:?}", arg));
                                            }
                                        }
                                    }
                                    eval((*risp_function.body).clone(), &mut inner_env)
                                },
                                _ => error_result(format!("Expected function but got {:?}", env_value))
                            }
                        }
                    }
                }
                _ => error_result(format!("Expected symbol but got {:?}", first_element))
            }
        }
        Vector(vector) => {
            let evaluated_vector = vector.iter()
                .map(|el| eval(el.clone(), env))
                .collect::<Result<Vec<_>, _>>()?;
            Ok(Vector(evaluated_vector))
        }

        Map(map_value) => {
            let evaluated_map = map_value.iter()
                .map(|(key, val)|
                    eval(val.clone(), env).map(|evaluated_value|
                        (key.to_string(), evaluated_value)))
                .collect::<Result<HashMap<String, RispType>, _>>()?;
            Ok(Map(evaluated_map))
        }

        Symbol(symbol) => {
            env.get(&symbol).ok_or_else(|| error(format!("symbol '{:?}' is undefined", symbol)))
        }
        other => Ok(other)
    }
}

/* ------------------------------ Tests ----------------------------------------------- */

#[allow(dead_code)]
fn eval_test(ast: RispType) -> RispResult {
    eval(ast, &mut create_core_environment())
}

#[allow(dead_code)]
fn eval_str(risp: &str) -> RispResult {
    let ast = parse::parse(risp)?;
    eval(ast, &mut create_core_environment())
}

#[test]
fn test_eval_number() {
    assert_eq!(eval_test(Int(23)), Ok(Int(23)));
}

#[test]
fn test_eval_math() {
    assert_eq!(eval_test(List(vec![Symbol("+".to_string()), Int(1), Int(2)])), Ok(Int(3)));
}

#[test]
fn test_nested_math() {
    assert_eq!(eval_test(List(vec![
        Symbol("+".to_string()), Int(1),
        List(vec![Symbol("+".to_string()), Int(10), Int(100)])
    ])), Ok(Int(111)));
}

#[test]
fn test_mul() {
    assert_eq!(eval_test(List(vec![
        Symbol("+".to_string()), Int(1),
        List(vec![Symbol("*".to_string()), Int(10), Int(23)])
    ])), Ok(Int(231)));
}

#[test]
fn test_def() {
    let variable = "variable";
    let variable_value = Int(23);
    let mut env = create_core_environment();

    assert_eq!(eval(List(vec![
        symbol("def"),
        symbol(variable),
        variable_value.clone()
    ]), &mut env), Ok(variable_value.clone()));

    assert_eq!(env.get(variable), Some(variable_value));
}

#[test]
fn test_def_evaluated() {
    let variable = "variable";
    let mut env = create_core_environment();

    assert_eq!(eval(List(vec![
        symbol("def"),
        symbol(variable),
        List(vec![symbol("+"), Int(1), Int(2)])
    ]), &mut env), Ok(Int(3)));

    assert_eq!(env.get(variable), Some(Int(3)));
}

#[test]
fn test_eval_simple_vector() {
    let simple_vector = Vector(vec![Int(1), Int(2)]);
    assert_eq!(eval_test(simple_vector.clone()), Ok(simple_vector));
}

#[test]
fn test_eval_nested_vector() {
    let simple_vector = Vector(vec![Int(1), List(vec![symbol("+"), Int(1), Int(2)])]);
    assert_eq!(eval_test(simple_vector.clone()), Ok(Vector(vec![Int(1), Int(3)])));
}

#[test]
fn test_eval_simple_map() {
    let simple_map = map(vec![
        ("key1", Int(1)),
        ("key2", Int(2))
    ]);
    assert_eq!(eval_test(simple_map.clone()), Ok(simple_map));
}

#[test]
fn test_eval_nested_map() {
    let input_map = map(vec![
        ("key", List(vec![symbol("+"), Int(1), Int(2)]))
    ]);
    let expected_output_map = map(vec![
        ("key", Int(3))
    ]);
    assert_eq!(eval_test(input_map.clone()), Ok(expected_output_map));
}

#[test]
fn test_ignore_comments() {
    assert_eq!(eval_str("(comment)"), Ok(Nil));
    assert_eq!(eval_str("(comment bla)"), Ok(Nil));
    assert_eq!(eval_str("(comment (bla 1 2))"), Ok(Nil));
}

#[test]
fn test_risp_function_no_args() {
    assert_eq!(eval_str("(fn [] 23)"), Ok(RispFunction(RispFunc {
        args: vec![],
        body: Rc::new(Int(23))
    })));

    assert_eq!(eval_str("(fn [] (+ 40 2))"), Ok(RispFunction(RispFunc {
        args: vec![],
        body: Rc::new(List(vec![symbol("+"), Int(40), Int(2)]))
    })));
}

#[test]
fn test_risp_function_error() {
    assert_eq!(eval_str("(fn)"), error_result("Missing args in fn"));
    assert_eq!(eval_str("(fn 23)"), error_result("Expected args vector in fn but got Int(23)"));
    assert_eq!(eval_str("(fn [])"), error_result("Missing body in fn"));
}

#[test]
fn test_eval_risp_function_no_args() {
    assert_eq!(eval_str(r"
    (do
        (def f23 (fn [] 23))
        (f23)
    )
    "), Ok(Int(23)));

    assert_eq!(eval_str(r"
    (do
        (def f23 (fn [] (+ 20 3)))
        (f23)
    )
    "), Ok(Int(23)));
}

#[test]
fn test_eval_risp_function_with_args() {
    assert_eq!(eval_str(r"
    (do
        (def plus20 (fn [x y] (+ x y 20)))
        (plus20 1 2)
    )
    "), Ok(Int(23)));
}

#[test]
fn test_eval_risp_function_does_not_change_surrounding_env() {
    assert_eq!(eval_str(r"
    (do
        (def x 1234)
        (def plus20 (fn [x y] (+ x y 20)))
        (plus20 1 2)
        x
    )
    "), Ok(Int(1234)));
}<commit_msg>test_eval_risp_function_with_args_error<commit_after>use std::collections::HashMap;
use types::*;
use types::RispType::*;
use environment::*;
use core::create_core_environment;
use parse;
use std::rc::Rc;

pub fn eval(ast: RispType, env: &mut Environment) -> RispResult {
    match ast {
        List(list) => {
            let first_element = list.first().ok_or_else(|| error("Empty List"))?;
            match *first_element {
                Symbol(ref symbol) => {
                    match symbol.as_ref() {
                        "def" => {
                            let var = list.get(1).ok_or_else(|| error("Missing variable in def"))?;
                            match *var {
                                Symbol(ref sym_var) => {
                                    let value_ast = list.get(2).ok_or_else(|| error("Missing value in def"))?;
                                    let value = eval(value_ast.clone(), env)?;
                                    env.set(sym_var, value.clone());
                                    Ok(value)
                                }
                                _ => error_result(format!("Expected symbol in def but got {:?}", var))
                            }
                        }
                        "do" => {
                            if let Some((last, elements)) = (&list[1..]).split_last() {
                                for child_ast in elements.iter() {
                                    eval(child_ast.clone(), env)?;
                                }
                                eval(last.clone(), env)
                            } else {
                                error_result("Empty do block")
                            }
                        }
                        "comment" => {
                            Ok(Nil)
                        }
                        "fn" => {
                            let args_risp = list.get(1).ok_or_else(|| error("Missing args in fn"))?;
                            match *args_risp {
                                Vector(ref args_vec) => {
                                    let body = list.get(2).ok_or_else(|| error("Missing body in fn"))?;
                                    Ok(RispFunction(RispFunc {
                                        args: args_vec.clone(),
                                        body: Rc::new(body.clone())
                                    }))
                                }
                                _ => error_result(format!("Expected args vector in fn but got {:?}", args_risp))
                            }
                        }
                        _ => {
                            let evaluated_tail = list[1..].iter()
                                .map(|el| eval(el.clone(), env))
                                .collect::<Result<Vec<_>, _>>()?;
                            let env_value = env.get(symbol).ok_or_else(|| error(format!("Undefined symbol{:?}", symbol)))?;
                            match env_value {
                                Function(function) => function(evaluated_tail.to_vec()),
                                RispFunction(risp_function) => {
                                    let mut inner_env = env.clone();
                                    for (arg, value) in risp_function.args.iter().zip(evaluated_tail.iter()) {
                                        match *arg {
                                            Symbol(ref arg_string) => {
                                                inner_env.set(arg_string, value.clone())
                                            },
                                            _ => {
                                                return error_result(format!("Expected symbol in args list got {:?}", arg));
                                            }
                                        }
                                    }
                                    eval((*risp_function.body).clone(), &mut inner_env)
                                },
                                _ => error_result(format!("Expected function but got {:?}", env_value))
                            }
                        }
                    }
                }
                _ => error_result(format!("Expected symbol but got {:?}", first_element))
            }
        }
        Vector(vector) => {
            let evaluated_vector = vector.iter()
                .map(|el| eval(el.clone(), env))
                .collect::<Result<Vec<_>, _>>()?;
            Ok(Vector(evaluated_vector))
        }

        Map(map_value) => {
            let evaluated_map = map_value.iter()
                .map(|(key, val)|
                    eval(val.clone(), env).map(|evaluated_value|
                        (key.to_string(), evaluated_value)))
                .collect::<Result<HashMap<String, RispType>, _>>()?;
            Ok(Map(evaluated_map))
        }

        Symbol(symbol) => {
            env.get(&symbol).ok_or_else(|| error(format!("symbol '{:?}' is undefined", symbol)))
        }
        other => Ok(other)
    }
}

/* ------------------------------ Tests ----------------------------------------------- */

#[allow(dead_code)]
fn eval_test(ast: RispType) -> RispResult {
    eval(ast, &mut create_core_environment())
}

#[allow(dead_code)]
fn eval_str(risp: &str) -> RispResult {
    let ast = parse::parse(risp)?;
    eval(ast, &mut create_core_environment())
}

#[test]
fn test_eval_number() {
    assert_eq!(eval_test(Int(23)), Ok(Int(23)));
}

#[test]
fn test_eval_math() {
    assert_eq!(eval_test(List(vec![Symbol("+".to_string()), Int(1), Int(2)])), Ok(Int(3)));
}

#[test]
fn test_nested_math() {
    assert_eq!(eval_test(List(vec![
        Symbol("+".to_string()), Int(1),
        List(vec![Symbol("+".to_string()), Int(10), Int(100)])
    ])), Ok(Int(111)));
}

#[test]
fn test_mul() {
    assert_eq!(eval_test(List(vec![
        Symbol("+".to_string()), Int(1),
        List(vec![Symbol("*".to_string()), Int(10), Int(23)])
    ])), Ok(Int(231)));
}

#[test]
fn test_def() {
    let variable = "variable";
    let variable_value = Int(23);
    let mut env = create_core_environment();

    assert_eq!(eval(List(vec![
        symbol("def"),
        symbol(variable),
        variable_value.clone()
    ]), &mut env), Ok(variable_value.clone()));

    assert_eq!(env.get(variable), Some(variable_value));
}

#[test]
fn test_def_evaluated() {
    let variable = "variable";
    let mut env = create_core_environment();

    assert_eq!(eval(List(vec![
        symbol("def"),
        symbol(variable),
        List(vec![symbol("+"), Int(1), Int(2)])
    ]), &mut env), Ok(Int(3)));

    assert_eq!(env.get(variable), Some(Int(3)));
}

#[test]
fn test_eval_simple_vector() {
    let simple_vector = Vector(vec![Int(1), Int(2)]);
    assert_eq!(eval_test(simple_vector.clone()), Ok(simple_vector));
}

#[test]
fn test_eval_nested_vector() {
    let simple_vector = Vector(vec![Int(1), List(vec![symbol("+"), Int(1), Int(2)])]);
    assert_eq!(eval_test(simple_vector.clone()), Ok(Vector(vec![Int(1), Int(3)])));
}

#[test]
fn test_eval_simple_map() {
    let simple_map = map(vec![
        ("key1", Int(1)),
        ("key2", Int(2))
    ]);
    assert_eq!(eval_test(simple_map.clone()), Ok(simple_map));
}

#[test]
fn test_eval_nested_map() {
    let input_map = map(vec![
        ("key", List(vec![symbol("+"), Int(1), Int(2)]))
    ]);
    let expected_output_map = map(vec![
        ("key", Int(3))
    ]);
    assert_eq!(eval_test(input_map.clone()), Ok(expected_output_map));
}

#[test]
fn test_ignore_comments() {
    assert_eq!(eval_str("(comment)"), Ok(Nil));
    assert_eq!(eval_str("(comment bla)"), Ok(Nil));
    assert_eq!(eval_str("(comment (bla 1 2))"), Ok(Nil));
}

#[test]
fn test_risp_function_no_args() {
    assert_eq!(eval_str("(fn [] 23)"), Ok(RispFunction(RispFunc {
        args: vec![],
        body: Rc::new(Int(23))
    })));

    assert_eq!(eval_str("(fn [] (+ 40 2))"), Ok(RispFunction(RispFunc {
        args: vec![],
        body: Rc::new(List(vec![symbol("+"), Int(40), Int(2)]))
    })));
}

#[test]
fn test_risp_function_error() {
    assert_eq!(eval_str("(fn)"), error_result("Missing args in fn"));
    assert_eq!(eval_str("(fn 23)"), error_result("Expected args vector in fn but got Int(23)"));
    assert_eq!(eval_str("(fn [])"), error_result("Missing body in fn"));
}

#[test]
fn test_eval_risp_function_no_args() {
    assert_eq!(eval_str(r"
    (do
        (def f23 (fn [] 23))
        (f23)
    )
    "), Ok(Int(23)));

    assert_eq!(eval_str(r"
    (do
        (def f23 (fn [] (+ 20 3)))
        (f23)
    )
    "), Ok(Int(23)));
}

#[test]
fn test_eval_risp_function_with_args() {
    assert_eq!(eval_str(r"
    (do
        (def plus20 (fn [x y] (+ x y 20)))
        (plus20 1 2)
    )
    "), Ok(Int(23)));
}

#[test]
fn test_eval_risp_function_with_args_error() {
    assert_eq!(eval_str(r#"
    (do
        (def plus20 (fn ["12" y] (+ x y 20)))
        (plus20 1 2)
    )
    "#), error_result("Expected symbol in args list got Str(\"12\")"));
}

#[test]
fn test_eval_risp_function_does_not_change_surrounding_env() {
    assert_eq!(eval_str(r"
    (do
        (def x 1234)
        (def plus20 (fn [x y] (+ x y 20)))
        (plus20 1 2)
        x
    )
    "), Ok(Int(1234)));
}<|endoftext|>


<commit_before>use ast::{Expr, ConstExpr, BlockExpr, LocalExpr, GetConstFieldExpr, GetFieldExpr, CallExpr, WhileLoopExpr, IfExpr, SwitchExpr, ObjectDeclExpr, ArrayDeclExpr, FunctionDeclExpr, NumOpExpr, BitOpExpr, ConstructExpr, ReturnExpr, ThrowExpr, AssignExpr};
use ast::{CNum, CInt, CString, CBool, CRegExp, CNull, CUndefined};
use ast::{OpSub, OpAdd, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor, BitShl, BitShr};
use js::value::{Value, VNull, VUndefined, VNumber, VString, VObject, VBoolean, VFunction, ResultValue};
use js::object::ObjectData;
use js::function::{RegularFunc, RegularFunction};
use js::{console, math, object, array, function, json};
use collections::treemap::TreeMap;
use std::vec::Vec;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;
/// An execution engine
pub trait Executor {
	/// Makes a new execution engine
	fn new() -> ~Self;
	/// Sets a global variable
	fn set_global(&mut self, name:~str, val:Value) -> ();
	/// Gets a global variable
	fn get_global(&self, name:~str) -> Value;
	/// Make a new scope
	fn make_scope(&mut self) -> Gc<RefCell<ObjectData>>;
	/// Destroy the current scope
	fn destroy_scope(&mut self) -> ();
	/// Runs the expression
	fn run(&mut self, expr:&Expr) -> ResultValue;
}
/// An intepreter
pub struct Interpreter {
	/// A hash map representing the global variables
	globals: ObjectData,
	/// The scopes
	scopes: Vec<Gc<RefCell<ObjectData>>>,
}
impl Executor for Interpreter {
	fn new() -> ~Interpreter {
		let mut globals : ObjectData = TreeMap::new();
		globals.swap(~"NaN", Gc::new(VNumber(f64::NAN)));
		globals.swap(~"Infinity", Gc::new(VNumber(f64::INFINITY)));
		globals.swap(~"console", console::_create());
		globals.swap(~"Math", math::_create());
		globals.swap(~"Object", object::_create());
		globals.swap(~"Array", array::_create());
		globals.swap(~"Function", function::_create());
		globals.swap(~"JSON", json::_create());
		return ~Interpreter {globals: globals, scopes: Vec::new()};
	}
	fn set_global(&mut self, name:~str, val:Value) {
		self.globals.swap(name, val);
	}
	fn get_global(&self, name:~str) -> Value {
		match self.globals.find(&name) {
			None => Gc::new(VUndefined),
			Some(ref g) => **g
		}
	}
	fn make_scope(&mut self) -> Gc<RefCell<ObjectData>> {
		let mut data = TreeMap::new();
		let value = Gc::new(RefCell::new(data));
		self.scopes.push(value.clone());
		value
	}
	fn destroy_scope(&mut self) -> () {
		self.scopes.pop();
	}
	fn run(&mut self, expr:&Expr) -> ResultValue {
		match *expr {
			ConstExpr(CNull) => Ok(Gc::new(VNull)),
			ConstExpr(CUndefined) => Ok(Gc::new(VUndefined)),
			ConstExpr(CNum(num)) => Ok(Gc::new(VNumber(num))),
			ConstExpr(CInt(num)) => Ok(Gc::new(VNumber(num as f64))),
			ConstExpr(CString(ref str)) => Ok(Gc::new(VString(str.to_owned()))),
			ConstExpr(CBool(val)) => Ok(Gc::new(VBoolean(val))),
			ConstExpr(CRegExp(ref reg, _, _)) => Ok(Gc::new(VBoolean(true))),
			BlockExpr(ref es) => {
				let mut obj = Gc::new(VNull);
				for e in es.iter() {
					let val = try!(self.run(*e));
					if e == es.last().unwrap() {
						obj = val;
					}
				}
				Ok(obj)
			},
			LocalExpr(ref name) => {
				let mut value = Gc::new(VUndefined);
				for scope in self.scopes.iter().rev() {
					match scope.borrow().borrow().find(name) {
						Some(v) => {
							value = v.clone();
							break;
						}
						None => ()
					}
				}
				Ok(if value.borrow() == &VUndefined {
					match self.globals.find(name) {
						None => Gc::new(VUndefined),
						Some(v) => v.clone()
					}
				} else {
					value
				})
			},
			GetConstFieldExpr(ref obj, ref field) => {
				let val_obj = try!(self.run(*obj));
				Ok(val_obj.borrow().get_field(field.clone()))
			},
			GetFieldExpr(ref obj, ref field) => {
				let val_obj = try!(self.run(*obj));
				let val_field = try!(self.run(*field));
				Ok(val_obj.borrow().get_field(val_field.borrow().to_str()))
			},
			CallExpr(ref callee, ref args) => {
				let func = try!(self.run(callee.clone()));
				let mut v_args = Vec::with_capacity(args.len());
				for arg in args.iter() {
					v_args.push(try!(self.run(*arg)));
				}
				Ok(match *func.borrow() {
					VFunction(ref func) => {
						let globals = self.globals.clone();
						func.borrow().call(self, Gc::new(VObject(RefCell::new(globals))), Gc::new(VNull), v_args).unwrap()
					},
					_ => Gc::new(VUndefined)
				})
			},
			WhileLoopExpr(ref cond, ref expr) => {
				let mut result = Gc::new(VUndefined);
				while try!(self.run(*cond)).borrow().is_true() {
					result = try!(self.run(*expr));
				}
				Ok(result)
			},
			IfExpr(ref cond, ref expr, None) => {
				Ok(if try!(self.run(*cond)).borrow().is_true() {
					try!(self.run(*expr))
				} else {
					Gc::new(VUndefined)
				})
			},
			IfExpr(ref cond, ref expr, Some(ref else_e)) => {
				Ok(if try!(self.run(*cond)).borrow().is_true() {
					try!(self.run(*expr))
				} else {
					try!(self.run(*else_e))
				})
			},
			SwitchExpr(ref val_e, ref vals, ref default) => {
				let val = try!(self.run(*val_e)).borrow().clone();
				let mut result = Gc::new(VNull);
				let mut matched = false;
				for tup in vals.iter() {
					let tup:&(~Expr, Vec<~Expr>) = tup;
					match *tup {
						(ref cond, ref block) if(val == *try!(self.run(*cond)).borrow()) => {
							matched = true;
							let last_expr = block.last().unwrap();
							for expr in block.iter() {
								let e_result = try!(self.run(*expr));
								if expr == last_expr {
									result = e_result;
								}
							}
						},
						_ => ()
					}
				}
				if !matched && default.is_some() {
					result = try!(self.run(*default.as_ref().unwrap()));
				}
				Ok(result)
			},
			ObjectDeclExpr(ref map) => {
				let mut obj = TreeMap::new();
				for (key, val) in map.iter() {
					obj.insert(key.clone(), try!(self.run(val.clone())));
				}
				obj.swap(~"__proto__", self.globals.find(&~"Object").unwrap().clone());
				Ok(Gc::new(VObject(RefCell::new(obj))))
			},
			ArrayDeclExpr(ref arr) => {
				let mut arr_map = TreeMap::new();
				let mut index = 0;
				for val in arr.iter() {
					let val = try!(self.run(val.clone()));
					arr_map.insert(index.to_str(), val);
					index += 1;
				}
				arr_map.swap(~"__proto__", self.globals.find(&~"Array").unwrap().clone());
				Ok(Gc::new(VObject(RefCell::new(arr_map))))
			},
			FunctionDeclExpr(ref name, ref args, ref expr) => {
				let function = RegularFunc(RegularFunction::new(*expr.clone(), args.clone()));
				let val = Gc::new(VFunction(RefCell::new(function)));
				if name.is_some() {
					self.globals.swap(name.clone().unwrap(), val);
				}
				Ok(val)
			},
			NumOpExpr(ref op, ref a, ref b) => {
				let v_a = try!(self.run(*a)).borrow().clone();
				let v_b = try!(self.run(*b)).borrow().clone();
				Ok(Gc::new(match *op {
					OpAdd => v_a + v_b,
					OpSub => v_a - v_b,
					OpMul => v_a * v_b,
					OpDiv => v_a / v_b,
					OpMod => v_a % v_b
				}))
			},
			BitOpExpr(ref op, ref a, ref b) => {
				let v_a = try!(self.run(*a)).borrow().clone();
				let v_b = try!(self.run(*b)).borrow().clone();
				Ok(Gc::new(match *op {
					BitAnd => v_a & v_b,
					BitOr => v_a | v_b,
					BitXor => v_a ^ v_b,
					BitShl => v_a << v_b,
					BitShr => v_a >> v_b
				}))
			},
			ConstructExpr(ref func, ref args) => {
				Ok(Gc::new(VNull))
			},
			ReturnExpr(ref ret) => {
				let v_ret = try!(self.run(ret.clone().unwrap()));
				Ok(Gc::new(VNull))
			},
			ThrowExpr(ref ex) => Err(try!(self.run(*ex))),
			AssignExpr(ref ref_e, ref val_e) => {
				let val = try!(self.run(*val_e));
				match **ref_e {
					LocalExpr(ref name) => {
						self.globals.insert(name.clone(), val);
					},
					_ => ()
				}
				Ok(val)
			}
		}
	}
}<commit_msg>Return now works for single-line functions<commit_after>use ast::{Expr, ConstExpr, BlockExpr, LocalExpr, GetConstFieldExpr, GetFieldExpr, CallExpr, WhileLoopExpr, IfExpr, SwitchExpr, ObjectDeclExpr, ArrayDeclExpr, FunctionDeclExpr, NumOpExpr, BitOpExpr, ConstructExpr, ReturnExpr, ThrowExpr, AssignExpr};
use ast::{CNum, CInt, CString, CBool, CRegExp, CNull, CUndefined};
use ast::{OpSub, OpAdd, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor, BitShl, BitShr};
use js::value::{Value, VNull, VUndefined, VNumber, VString, VObject, VBoolean, VFunction, ResultValue};
use js::object::ObjectData;
use js::function::{RegularFunc, RegularFunction};
use js::{console, math, object, array, function, json};
use collections::treemap::TreeMap;
use std::vec::Vec;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;
/// An execution engine
pub trait Executor {
	/// Makes a new execution engine
	fn new() -> ~Self;
	/// Sets a global variable
	fn set_global(&mut self, name:~str, val:Value) -> ();
	/// Gets a global variable
	fn get_global(&self, name:~str) -> Value;
	/// Make a new scope
	fn make_scope(&mut self) -> Gc<RefCell<ObjectData>>;
	/// Destroy the current scope
	fn destroy_scope(&mut self) -> ();
	/// Runs the expression
	fn run(&mut self, expr:&Expr) -> ResultValue;
}
/// An intepreter
pub struct Interpreter {
	/// A hash map representing the global variables
	globals: ObjectData,
	/// The scopes
	scopes: Vec<Gc<RefCell<ObjectData>>>,
}
impl Executor for Interpreter {
	fn new() -> ~Interpreter {
		let mut globals : ObjectData = TreeMap::new();
		globals.swap(~"NaN", Gc::new(VNumber(f64::NAN)));
		globals.swap(~"Infinity", Gc::new(VNumber(f64::INFINITY)));
		globals.swap(~"console", console::_create());
		globals.swap(~"Math", math::_create());
		globals.swap(~"Object", object::_create());
		globals.swap(~"Array", array::_create());
		globals.swap(~"Function", function::_create());
		globals.swap(~"JSON", json::_create());
		return ~Interpreter {globals: globals, scopes: Vec::new()};
	}
	fn set_global(&mut self, name:~str, val:Value) {
		self.globals.swap(name, val);
	}
	fn get_global(&self, name:~str) -> Value {
		match self.globals.find(&name) {
			None => Gc::new(VUndefined),
			Some(ref g) => **g
		}
	}
	fn make_scope(&mut self) -> Gc<RefCell<ObjectData>> {
		let mut data = TreeMap::new();
		let value = Gc::new(RefCell::new(data));
		self.scopes.push(value.clone());
		value
	}
	fn destroy_scope(&mut self) -> () {
		self.scopes.pop();
	}
	fn run(&mut self, expr:&Expr) -> ResultValue {
		match *expr {
			ConstExpr(CNull) => Ok(Gc::new(VNull)),
			ConstExpr(CUndefined) => Ok(Gc::new(VUndefined)),
			ConstExpr(CNum(num)) => Ok(Gc::new(VNumber(num))),
			ConstExpr(CInt(num)) => Ok(Gc::new(VNumber(num as f64))),
			ConstExpr(CString(ref str)) => Ok(Gc::new(VString(str.to_owned()))),
			ConstExpr(CBool(val)) => Ok(Gc::new(VBoolean(val))),
			ConstExpr(CRegExp(ref reg, _, _)) => Ok(Gc::new(VBoolean(true))),
			BlockExpr(ref es) => {
				let mut obj = Gc::new(VNull);
				for e in es.iter() {
					let val = try!(self.run(*e));
					if e == es.last().unwrap() {
						obj = val;
					}
				}
				Ok(obj)
			},
			LocalExpr(ref name) => {
				let mut value = Gc::new(VUndefined);
				for scope in self.scopes.iter().rev() {
					match scope.borrow().borrow().find(name) {
						Some(v) => {
							value = v.clone();
							break;
						}
						None => ()
					}
				}
				Ok(if value.borrow() == &VUndefined {
					match self.globals.find(name) {
						None => Gc::new(VUndefined),
						Some(v) => v.clone()
					}
				} else {
					value
				})
			},
			GetConstFieldExpr(ref obj, ref field) => {
				let val_obj = try!(self.run(*obj));
				Ok(val_obj.borrow().get_field(field.clone()))
			},
			GetFieldExpr(ref obj, ref field) => {
				let val_obj = try!(self.run(*obj));
				let val_field = try!(self.run(*field));
				Ok(val_obj.borrow().get_field(val_field.borrow().to_str()))
			},
			CallExpr(ref callee, ref args) => {
				let func = try!(self.run(callee.clone()));
				let mut v_args = Vec::with_capacity(args.len());
				for arg in args.iter() {
					v_args.push(try!(self.run(*arg)));
				}
				Ok(match *func.borrow() {
					VFunction(ref func) => {
						let globals = self.globals.clone();
						func.borrow().call(self, Gc::new(VObject(RefCell::new(globals))), Gc::new(VNull), v_args).unwrap()
					},
					_ => Gc::new(VUndefined)
				})
			},
			WhileLoopExpr(ref cond, ref expr) => {
				let mut result = Gc::new(VUndefined);
				while try!(self.run(*cond)).borrow().is_true() {
					result = try!(self.run(*expr));
				}
				Ok(result)
			},
			IfExpr(ref cond, ref expr, None) => {
				Ok(if try!(self.run(*cond)).borrow().is_true() {
					try!(self.run(*expr))
				} else {
					Gc::new(VUndefined)
				})
			},
			IfExpr(ref cond, ref expr, Some(ref else_e)) => {
				Ok(if try!(self.run(*cond)).borrow().is_true() {
					try!(self.run(*expr))
				} else {
					try!(self.run(*else_e))
				})
			},
			SwitchExpr(ref val_e, ref vals, ref default) => {
				let val = try!(self.run(*val_e)).borrow().clone();
				let mut result = Gc::new(VNull);
				let mut matched = false;
				for tup in vals.iter() {
					let tup:&(~Expr, Vec<~Expr>) = tup;
					match *tup {
						(ref cond, ref block) if(val == *try!(self.run(*cond)).borrow()) => {
							matched = true;
							let last_expr = block.last().unwrap();
							for expr in block.iter() {
								let e_result = try!(self.run(*expr));
								if expr == last_expr {
									result = e_result;
								}
							}
						},
						_ => ()
					}
				}
				if !matched && default.is_some() {
					result = try!(self.run(*default.as_ref().unwrap()));
				}
				Ok(result)
			},
			ObjectDeclExpr(ref map) => {
				let mut obj = TreeMap::new();
				for (key, val) in map.iter() {
					obj.insert(key.clone(), try!(self.run(val.clone())));
				}
				obj.swap(~"__proto__", self.globals.find(&~"Object").unwrap().clone());
				Ok(Gc::new(VObject(RefCell::new(obj))))
			},
			ArrayDeclExpr(ref arr) => {
				let mut arr_map = TreeMap::new();
				let mut index = 0;
				for val in arr.iter() {
					let val = try!(self.run(val.clone()));
					arr_map.insert(index.to_str(), val);
					index += 1;
				}
				arr_map.swap(~"__proto__", self.globals.find(&~"Array").unwrap().clone());
				Ok(Gc::new(VObject(RefCell::new(arr_map))))
			},
			FunctionDeclExpr(ref name, ref args, ref expr) => {
				let function = RegularFunc(RegularFunction::new(*expr.clone(), args.clone()));
				let val = Gc::new(VFunction(RefCell::new(function)));
				if name.is_some() {
					self.globals.swap(name.clone().unwrap(), val);
				}
				Ok(val)
			},
			NumOpExpr(ref op, ref a, ref b) => {
				let v_a = try!(self.run(*a)).borrow().clone();
				let v_b = try!(self.run(*b)).borrow().clone();
				Ok(Gc::new(match *op {
					OpAdd => v_a + v_b,
					OpSub => v_a - v_b,
					OpMul => v_a * v_b,
					OpDiv => v_a / v_b,
					OpMod => v_a % v_b
				}))
			},
			BitOpExpr(ref op, ref a, ref b) => {
				let v_a = try!(self.run(*a)).borrow().clone();
				let v_b = try!(self.run(*b)).borrow().clone();
				Ok(Gc::new(match *op {
					BitAnd => v_a & v_b,
					BitOr => v_a | v_b,
					BitXor => v_a ^ v_b,
					BitShl => v_a << v_b,
					BitShr => v_a >> v_b
				}))
			},
			ConstructExpr(ref func, ref args) => {
				Ok(Gc::new(VNull))
			},
			ReturnExpr(ref ret) => {
				match *ret {
					Some(ref v) =>
						self.run(v.clone()),
					None => Ok(Gc::new(VUndefined))
				}
			},
			ThrowExpr(ref ex) => Err(try!(self.run(*ex))),
			AssignExpr(ref ref_e, ref val_e) => {
				let val = try!(self.run(*val_e));
				match **ref_e {
					LocalExpr(ref name) => {
						self.globals.insert(name.clone(), val);
					},
					_ => ()
				}
				Ok(val)
			}
		}
	}
}<|endoftext|>


<commit_before>use std;
use hb;
use libc::c_void;

use std::marker::PhantomData;
use std::path::Path;
use std::io;

use blob::Blob;
use common::{HarfbuzzObject, Owned, Shared, Tag};

/// A wrapper around `hb_face_t`.
#[derive(Debug)]
pub struct Face<'a> {
    hb_face: hb::hb_face_t,
    _marker: PhantomData<&'a [u8]>,
}

impl<'a> Face<'a> {
    /// Create a new `Face` from the data in `bytes`.
    pub fn new<'b, T: Into<Shared<Blob<'b>>>>(bytes: T, index: u32) -> Owned<Face<'b>> {
        let blob = bytes.into();
        let hb_face = unsafe { hb::hb_face_create(Shared::into_raw(blob), index) };
        unsafe { Owned::from_raw(hb_face) }
    }

    /// Create a new face from the contents of the file at `path`.
    pub fn from_file<P: AsRef<Path>>(path: P, index: u32) -> std::io::Result<Owned<Face<'static>>> {
        let blob = Blob::from_file(path)?;
        Ok(Face::new(blob, index))
    }

    pub fn from_bytes<'b>(bytes: &'b [u8], index: u32) -> Owned<Face<'b>> {
        let blob = Blob::with_bytes(bytes);
        Face::new(blob, index)
    }

    /// Create a new face from a closure that returns a raw [`Blob`](struct.Blob.html) of table
    pub fn from_table_func<'b, F>(func: F) -> Owned<Face<'b>>
    where
        F: 'b + Send + Sync + FnMut(Tag) -> Option<Shared<Blob<'b>>>,
    {
        extern "C" fn destroy_box<U>(ptr: *mut c_void) {
            unsafe { Box::from_raw(ptr as *mut U) };
        }
        extern "C" fn table_func<'b, F>(
            _: *mut hb::hb_face_t,
            tag: hb::hb_tag_t,
            user_data: *mut c_void,
        ) -> *mut hb::hb_blob_t
        where
            F: FnMut(Tag) -> Option<Shared<Blob<'b>>>,
        {
            let tag = Tag(tag);
            let closure = unsafe { &mut *(user_data as *mut F) };
            let blob = closure(tag);
            match blob {
                Some(blob) => Shared::into_raw(blob),
                None => std::ptr::null_mut(),
            }
        }
        let boxed_closure = Box::new(func);
        unsafe {
            let face = hb::hb_face_create_for_tables(
                Some(table_func::<'b, F>),
                Box::into_raw(boxed_closure) as *mut _,
                Some(destroy_box::<F>),
            );
            Owned::from_raw(face)
        }
    }

    //    /// Create a `Font` of this face. By default this will use harfbuzz' included opentype
    // font
    //    /// funcs for shaping and have no scale value set so that the returned values will be in
    // font
    //    /// space.
    //    pub fn create_font(self) -> Owned<Font<'a>> {
    //        Font::new(self)
    //    }

    pub fn face_data(&self) -> &'a [u8] {
        unsafe {
            let raw_blob = hb::hb_face_reference_blob(self.as_raw());
            Blob::from_raw(raw_blob).get_data()
        }
    }

    pub fn table_with_tag(&self, tag: Tag) -> Option<&[u8]> {
        unsafe {
            let raw_blob = hb::hb_face_reference_table(self.as_raw(), tag.0);
            if raw_blob.is_null() {
                None
            } else {
                let blob = Blob::from_raw(raw_blob);
                if blob.is_empty() {
                    None
                } else {
                    Some(blob.get_data())
                }
            }
        }
    }

    pub fn index(&self) -> u32 {
        unsafe { hb::hb_face_get_index(self.as_raw()) }
    }

    pub fn set_upem(&mut self, upem: u32) {
        unsafe { hb::hb_face_set_upem(self.as_raw(), upem) };
    }

    pub fn upem(&self) -> u32 {
        unsafe { hb::hb_face_get_upem(self.as_raw()) }
    }

    pub fn set_glyph_count(&mut self, count: u32) {
        unsafe { hb::hb_face_set_glyph_count(self.as_raw(), count) };
    }

    pub fn glyph_count(&self) -> u32 {
        unsafe { hb::hb_face_get_glyph_count(self.as_raw()) }
    }
}

impl<'a> HarfbuzzObject for Face<'a> {
    type Raw = hb::hb_face_t;

    unsafe fn reference(&self) {
        hb::hb_face_reference(self.as_raw());
    }

    unsafe fn dereference(&self) {
        hb::hb_face_destroy(self.as_raw());
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use common::Tag;

    #[test]
    fn test_face_from_table_func() {
        let face = Face::from_table_func(|table_tag| {
            let content = format!("{}-table", table_tag);
            Some(content.into_bytes().into())
        });

        let maxp_table = face.table_with_tag(Tag::new('m', 'a', 'x', 'p')).unwrap();
        assert_eq!(maxp_table, b"maxp-table");

        let maxp_table = face.table_with_tag(Tag::new('h', 'h', 'e', 'a')).unwrap();
        assert_eq!(maxp_table, b"hhea-table");
    }
}
<commit_msg>remove unused import<commit_after>use std;
use hb;
use libc::c_void;

use std::marker::PhantomData;
use std::path::Path;

use blob::Blob;
use common::{HarfbuzzObject, Owned, Shared, Tag};

/// A wrapper around `hb_face_t`.
#[derive(Debug)]
pub struct Face<'a> {
    hb_face: hb::hb_face_t,
    _marker: PhantomData<&'a [u8]>,
}

impl<'a> Face<'a> {
    /// Create a new `Face` from the data in `bytes`.
    pub fn new<'b, T: Into<Shared<Blob<'b>>>>(bytes: T, index: u32) -> Owned<Face<'b>> {
        let blob = bytes.into();
        let hb_face = unsafe { hb::hb_face_create(Shared::into_raw(blob), index) };
        unsafe { Owned::from_raw(hb_face) }
    }

    /// Create a new face from the contents of the file at `path`.
    pub fn from_file<P: AsRef<Path>>(path: P, index: u32) -> std::io::Result<Owned<Face<'static>>> {
        let blob = Blob::from_file(path)?;
        Ok(Face::new(blob, index))
    }

    pub fn from_bytes<'b>(bytes: &'b [u8], index: u32) -> Owned<Face<'b>> {
        let blob = Blob::with_bytes(bytes);
        Face::new(blob, index)
    }

    /// Create a new face from a closure that returns a raw [`Blob`](struct.Blob.html) of table
    pub fn from_table_func<'b, F>(func: F) -> Owned<Face<'b>>
    where
        F: 'b + Send + Sync + FnMut(Tag) -> Option<Shared<Blob<'b>>>,
    {
        extern "C" fn destroy_box<U>(ptr: *mut c_void) {
            unsafe { Box::from_raw(ptr as *mut U) };
        }
        extern "C" fn table_func<'b, F>(
            _: *mut hb::hb_face_t,
            tag: hb::hb_tag_t,
            user_data: *mut c_void,
        ) -> *mut hb::hb_blob_t
        where
            F: FnMut(Tag) -> Option<Shared<Blob<'b>>>,
        {
            let tag = Tag(tag);
            let closure = unsafe { &mut *(user_data as *mut F) };
            let blob = closure(tag);
            match blob {
                Some(blob) => Shared::into_raw(blob),
                None => std::ptr::null_mut(),
            }
        }
        let boxed_closure = Box::new(func);
        unsafe {
            let face = hb::hb_face_create_for_tables(
                Some(table_func::<'b, F>),
                Box::into_raw(boxed_closure) as *mut _,
                Some(destroy_box::<F>),
            );
            Owned::from_raw(face)
        }
    }

    //    /// Create a `Font` of this face. By default this will use harfbuzz' included opentype
    // font
    //    /// funcs for shaping and have no scale value set so that the returned values will be in
    // font
    //    /// space.
    //    pub fn create_font(self) -> Owned<Font<'a>> {
    //        Font::new(self)
    //    }

    pub fn face_data(&self) -> &'a [u8] {
        unsafe {
            let raw_blob = hb::hb_face_reference_blob(self.as_raw());
            Blob::from_raw(raw_blob).get_data()
        }
    }

    pub fn table_with_tag(&self, tag: Tag) -> Option<&[u8]> {
        unsafe {
            let raw_blob = hb::hb_face_reference_table(self.as_raw(), tag.0);
            if raw_blob.is_null() {
                None
            } else {
                let blob = Blob::from_raw(raw_blob);
                if blob.is_empty() {
                    None
                } else {
                    Some(blob.get_data())
                }
            }
        }
    }

    pub fn index(&self) -> u32 {
        unsafe { hb::hb_face_get_index(self.as_raw()) }
    }

    pub fn set_upem(&mut self, upem: u32) {
        unsafe { hb::hb_face_set_upem(self.as_raw(), upem) };
    }

    pub fn upem(&self) -> u32 {
        unsafe { hb::hb_face_get_upem(self.as_raw()) }
    }

    pub fn set_glyph_count(&mut self, count: u32) {
        unsafe { hb::hb_face_set_glyph_count(self.as_raw(), count) };
    }

    pub fn glyph_count(&self) -> u32 {
        unsafe { hb::hb_face_get_glyph_count(self.as_raw()) }
    }
}

impl<'a> HarfbuzzObject for Face<'a> {
    type Raw = hb::hb_face_t;

    unsafe fn reference(&self) {
        hb::hb_face_reference(self.as_raw());
    }

    unsafe fn dereference(&self) {
        hb::hb_face_destroy(self.as_raw());
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use common::Tag;

    #[test]
    fn test_face_from_table_func() {
        let face = Face::from_table_func(|table_tag| {
            let content = format!("{}-table", table_tag);
            Some(content.into_bytes().into())
        });

        let maxp_table = face.table_with_tag(Tag::new('m', 'a', 'x', 'p')).unwrap();
        assert_eq!(maxp_table, b"maxp-table");

        let maxp_table = face.table_with_tag(Tag::new('h', 'h', 'e', 'a')).unwrap();
        assert_eq!(maxp_table, b"hhea-table");
    }
}
<|endoftext|>