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

//! Servo's internal preferences are not C-compatible. To expose the preference to the embedder,
//! we keep a C-compatible copy of the preferences alive (LOCALCPREFS). The embedder can
//! retrieve an array (CPREFS) of struct of pointers (CPrefs) to the C-compatible preferences
//! (LocalCPref).

use crate::simpleservo::{self, PrefValue};
use std::cell::RefCell;
use std::collections::{BTreeMap, HashMap};
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_void};

thread_local! {
    // CPREFS keeps alive a set of CPref that are sent over to the embedder.
    // The CPREFS are structs holding pointers to values held alive by LOCALCPREFS.
    // This is emptied in free_prefs the next time perform_updates is called.
    static CPREFS: RefCell<Vec<CPref>> = RefCell::new(Vec::new());
    static LOCALCPREFS: RefCell<BTreeMap<String, LocalCPref>> = RefCell::new(BTreeMap::new());
}

struct LocalCPref {
    key: CString,
    value: LocalCPrefValue,
    is_default: bool,
}

#[derive(Debug)]
enum LocalCPrefValue {
    Float(f64),
    Int(i64),
    Str(CString),
    Bool(bool),
    Missing,
}

impl LocalCPrefValue {
    pub fn new(v: &PrefValue) -> LocalCPrefValue {
        match v {
            PrefValue::Float(v) => LocalCPrefValue::Float(*v),
            PrefValue::Int(v) => LocalCPrefValue::Int(*v),
            PrefValue::Str(v) => LocalCPrefValue::Str(CString::new(v.clone()).unwrap()),
            PrefValue::Bool(v) => LocalCPrefValue::Bool(*v),
            PrefValue::Missing => LocalCPrefValue::Missing,
        }
    }
}

#[repr(C)]
pub struct CPrefList {
    pub len: usize,
    pub list: *const CPref,
}

impl CPrefList {
    pub fn convert(&self) -> HashMap<String, PrefValue> {
        let slice = unsafe { std::slice::from_raw_parts(self.list, self.len) };
        slice.iter().map(|cpref| cpref.convert()).collect()
    }
}

#[repr(C)]
pub struct CPref {
    pub pref_type: CPrefType,
    pub key: *const c_char,
    pub value: *const c_void,
    pub is_default: bool,
}

impl CPref {
    fn new(local: &LocalCPref) -> CPref {
        let (pref_type, value) = match &local.value {
            LocalCPrefValue::Float(v) => (CPrefType::Float, v as *const f64 as *const c_void),
            LocalCPrefValue::Int(v) => (CPrefType::Int, v as *const i64 as *const c_void),
            LocalCPrefValue::Bool(v) => (CPrefType::Bool, v as *const bool as *const c_void),
            LocalCPrefValue::Str(v) => (CPrefType::Str, v.as_ptr() as *const c_void),
            LocalCPrefValue::Missing => (CPrefType::Missing, std::ptr::null()),
        };
        CPref {
            key: local.key.as_ptr(),
            is_default: local.is_default,
            pref_type,
            value,
        }
    }
    fn convert(&self) -> (String, PrefValue) {
        let key = unsafe { CStr::from_ptr(self.key) };
        let key = key.to_str().expect("Can't read string").to_string();
        let value = unsafe {
            match self.pref_type {
                CPrefType::Float => PrefValue::Float(*(self.value as *const f64)),
                CPrefType::Int => PrefValue::Int(*(self.value as *const i64)),
                CPrefType::Bool => PrefValue::Bool(*(self.value as *const bool)),
                CPrefType::Str => PrefValue::Str({
                    let value = CStr::from_ptr(self.value as *const c_char);
                    value.to_str().expect("Can't read string").to_string()
                }),
                CPrefType::Missing => PrefValue::Missing,
            }
        };
        (key, value)
    }
}

#[repr(C)]
pub enum CPrefType {
    Float,
    Int,
    Str,
    Bool,
    Missing,
}

#[no_mangle]
pub extern "C" fn get_pref_as_float(ptr: *const c_void) -> *const f64 {
    ptr as *const f64
}

#[no_mangle]
pub extern "C" fn get_pref_as_int(ptr: *const c_void) -> *const i64 {
    ptr as *const i64
}

#[no_mangle]
pub extern "C" fn get_pref_as_str(ptr: *const c_void) -> *const c_char {
    ptr as *const c_char
}

#[no_mangle]
pub extern "C" fn get_pref_as_bool(ptr: *const c_void) -> *const bool {
    ptr as *const bool
}

#[no_mangle]
pub extern "C" fn reset_all_prefs() {
    debug!("reset_all_prefs");
    simpleservo::reset_all_prefs()
}

#[no_mangle]
pub extern "C" fn reset_pref(key: *const c_char) -> bool {
    debug!("reset_pref");
    let key = unsafe { CStr::from_ptr(key) };
    let key = key.to_str().expect("Can't read string");
    simpleservo::reset_pref(key)
}

#[no_mangle]
pub extern "C" fn get_pref(key: *const c_char) -> CPref {
    debug!("get_pref");
    LOCALCPREFS.with(|localmap| {
        let key = unsafe { CStr::from_ptr(key) };
        let key = key.to_str().expect("Can't read string");
        let (value, is_default) = simpleservo::get_pref(key);
        let local = LocalCPref {
            key: CString::new(key).unwrap(),
            value: LocalCPrefValue::new(&value),
            is_default: is_default,
        };
        let cpref = CPref::new(&local);
        localmap.borrow_mut().insert(key.to_string(), local);
        cpref
    })
}

fn set_pref(key: *const c_char, value: PrefValue) -> bool {
    debug!("set_pref");
    let key = unsafe { CStr::from_ptr(key) };
    let key = key.to_str().expect("Can't read string");
    simpleservo::set_pref(key, value).is_ok()
}

#[no_mangle]
pub extern "C" fn set_float_pref(key: *const c_char, value: f64) -> bool {
    set_pref(key, PrefValue::Float(value))
}

#[no_mangle]
pub extern "C" fn set_int_pref(key: *const c_char, value: i64) -> bool {
    set_pref(key, PrefValue::Int(value))
}

#[no_mangle]
pub extern "C" fn set_bool_pref(key: *const c_char, value: bool) -> bool {
    set_pref(key, PrefValue::Bool(value))
}

#[no_mangle]
pub extern "C" fn set_str_pref(key: *const c_char, value: *const c_char) -> bool {
    let value = unsafe { CStr::from_ptr(value) };
    let value = value.to_str().expect("Can't read string").to_string();
    set_pref(key, PrefValue::Str(value))
}

#[no_mangle]
pub extern "C" fn get_prefs() -> CPrefList {
    // Called from any thread
    debug!("get_prefs");
    let map = simpleservo::get_prefs();
    let local: BTreeMap<String, LocalCPref> = map
        .into_iter()
        .map(|(key, (value, is_default))| {
            let l = LocalCPref {
                key: CString::new(key.clone()).unwrap(),
                value: LocalCPrefValue::new(&value),
                is_default: is_default,
            };
            (key, l)
        })
        .collect();

    let ptrs: Vec<CPref> = local.iter().map(|(_, local)| CPref::new(&local)).collect();

    let list = CPrefList {
        len: ptrs.len(),
        list: ptrs.as_ptr(),
    };

    LOCALCPREFS.with(|p| *p.borrow_mut() = local);
    CPREFS.with(|p| *p.borrow_mut() = ptrs);

    list
}

pub(crate) fn free_prefs() {
    LOCALCPREFS.with(|p| p.borrow_mut().clear());
    CPREFS.with(|p| p.borrow_mut().clear());
}
<commit_msg>Box C preferences to avoid dangling pointers<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

//! Servo's internal preferences are not C-compatible. To expose the preference to the embedder,
//! we keep a C-compatible copy of the preferences alive (LOCALCPREFS). The embedder can
//! retrieve an array (CPREFS) of struct of pointers (CPrefs) to the C-compatible preferences
//! (LocalCPref).

use crate::simpleservo::{self, PrefValue};
use std::cell::RefCell;
use std::collections::{BTreeMap, HashMap};
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_void};

thread_local! {
    // CPREFS keeps alive a set of CPref that are sent over to the embedder.
    // The CPREFS are structs holding pointers to values held alive by LOCALCPREFS.
    // This is emptied in free_prefs the next time perform_updates is called.
    static CPREFS: RefCell<Vec<CPref>> = RefCell::new(Vec::new());
    static LOCALCPREFS: RefCell<BTreeMap<String, Box<LocalCPref>>> = RefCell::new(BTreeMap::new());
}

struct LocalCPref {
    key: CString,
    value: LocalCPrefValue,
    is_default: bool,
}

#[derive(Debug)]
enum LocalCPrefValue {
    Float(f64),
    Int(i64),
    Str(CString),
    Bool(bool),
    Missing,
}

impl LocalCPrefValue {
    pub fn new(v: &PrefValue) -> LocalCPrefValue {
        match v {
            PrefValue::Float(v) => LocalCPrefValue::Float(*v),
            PrefValue::Int(v) => LocalCPrefValue::Int(*v),
            PrefValue::Str(v) => LocalCPrefValue::Str(CString::new(v.clone()).unwrap()),
            PrefValue::Bool(v) => LocalCPrefValue::Bool(*v),
            PrefValue::Missing => LocalCPrefValue::Missing,
        }
    }
}

#[repr(C)]
pub struct CPrefList {
    pub len: usize,
    pub list: *const CPref,
}

impl CPrefList {
    pub fn convert(&self) -> HashMap<String, PrefValue> {
        let slice = unsafe { std::slice::from_raw_parts(self.list, self.len) };
        slice.iter().map(|cpref| cpref.convert()).collect()
    }
}

#[repr(C)]
pub struct CPref {
    pub pref_type: CPrefType,
    pub key: *const c_char,
    pub value: *const c_void,
    pub is_default: bool,
}

impl CPref {
    fn new(local: &Box<LocalCPref>) -> CPref {
        let (pref_type, value) = match &local.value {
            LocalCPrefValue::Float(v) => (CPrefType::Float, v as *const f64 as *const c_void),
            LocalCPrefValue::Int(v) => (CPrefType::Int, v as *const i64 as *const c_void),
            LocalCPrefValue::Bool(v) => (CPrefType::Bool, v as *const bool as *const c_void),
            LocalCPrefValue::Str(v) => (CPrefType::Str, v.as_ptr() as *const c_void),
            LocalCPrefValue::Missing => (CPrefType::Missing, std::ptr::null()),
        };
        CPref {
            key: local.key.as_ptr(),
            is_default: local.is_default,
            pref_type,
            value,
        }
    }
    fn convert(&self) -> (String, PrefValue) {
        let key = unsafe { CStr::from_ptr(self.key) };
        let key = key.to_str().expect("Can't read string").to_string();
        let value = unsafe {
            match self.pref_type {
                CPrefType::Float => PrefValue::Float(*(self.value as *const f64)),
                CPrefType::Int => PrefValue::Int(*(self.value as *const i64)),
                CPrefType::Bool => PrefValue::Bool(*(self.value as *const bool)),
                CPrefType::Str => PrefValue::Str({
                    let value = CStr::from_ptr(self.value as *const c_char);
                    value.to_str().expect("Can't read string").to_string()
                }),
                CPrefType::Missing => PrefValue::Missing,
            }
        };
        (key, value)
    }
}

#[repr(C)]
pub enum CPrefType {
    Float,
    Int,
    Str,
    Bool,
    Missing,
}

#[no_mangle]
pub extern "C" fn get_pref_as_float(ptr: *const c_void) -> *const f64 {
    ptr as *const f64
}

#[no_mangle]
pub extern "C" fn get_pref_as_int(ptr: *const c_void) -> *const i64 {
    ptr as *const i64
}

#[no_mangle]
pub extern "C" fn get_pref_as_str(ptr: *const c_void) -> *const c_char {
    ptr as *const c_char
}

#[no_mangle]
pub extern "C" fn get_pref_as_bool(ptr: *const c_void) -> *const bool {
    ptr as *const bool
}

#[no_mangle]
pub extern "C" fn reset_all_prefs() {
    debug!("reset_all_prefs");
    simpleservo::reset_all_prefs()
}

#[no_mangle]
pub extern "C" fn reset_pref(key: *const c_char) -> bool {
    debug!("reset_pref");
    let key = unsafe { CStr::from_ptr(key) };
    let key = key.to_str().expect("Can't read string");
    simpleservo::reset_pref(key)
}

#[no_mangle]
pub extern "C" fn get_pref(key: *const c_char) -> CPref {
    debug!("get_pref");
    LOCALCPREFS.with(|localmap| {
        let key = unsafe { CStr::from_ptr(key) };
        let key = key.to_str().expect("Can't read string");
        let (value, is_default) = simpleservo::get_pref(key);
        let local = Box::new(LocalCPref {
            key: CString::new(key).unwrap(),
            value: LocalCPrefValue::new(&value),
            is_default: is_default,
        });
        let cpref = CPref::new(&local);
        localmap.borrow_mut().insert(key.to_string(), local);
        cpref
    })
}

fn set_pref(key: *const c_char, value: PrefValue) -> bool {
    debug!("set_pref");
    let key = unsafe { CStr::from_ptr(key) };
    let key = key.to_str().expect("Can't read string");
    simpleservo::set_pref(key, value).is_ok()
}

#[no_mangle]
pub extern "C" fn set_float_pref(key: *const c_char, value: f64) -> bool {
    set_pref(key, PrefValue::Float(value))
}

#[no_mangle]
pub extern "C" fn set_int_pref(key: *const c_char, value: i64) -> bool {
    set_pref(key, PrefValue::Int(value))
}

#[no_mangle]
pub extern "C" fn set_bool_pref(key: *const c_char, value: bool) -> bool {
    set_pref(key, PrefValue::Bool(value))
}

#[no_mangle]
pub extern "C" fn set_str_pref(key: *const c_char, value: *const c_char) -> bool {
    let value = unsafe { CStr::from_ptr(value) };
    let value = value.to_str().expect("Can't read string").to_string();
    set_pref(key, PrefValue::Str(value))
}

#[no_mangle]
pub extern "C" fn get_prefs() -> CPrefList {
    // Called from any thread
    debug!("get_prefs");
    let map = simpleservo::get_prefs();
    let local: BTreeMap<String, Box<LocalCPref>> = map
        .into_iter()
        .map(|(key, (value, is_default))| {
            let l = Box::new(LocalCPref {
                key: CString::new(key.clone()).unwrap(),
                value: LocalCPrefValue::new(&value),
                is_default: is_default,
            });
            (key, l)
        })
        .collect();

    let ptrs: Vec<CPref> = local.iter().map(|(_, local)| CPref::new(&local)).collect();

    let list = CPrefList {
        len: ptrs.len(),
        list: ptrs.as_ptr(),
    };

    LOCALCPREFS.with(|p| *p.borrow_mut() = local);
    CPREFS.with(|p| *p.borrow_mut() = ptrs);

    list
}

pub(crate) fn free_prefs() {
    LOCALCPREFS.with(|p| p.borrow_mut().clear());
    CPREFS.with(|p| p.borrow_mut().clear());
}
<|endoftext|>


<commit_before>use cargo::core::{Workspace, Source};
use cargo::sources::PathSource;
use syntex_syntax::attr;
use syntex_syntax::visit::{self, Visitor, FnKind};
use syntex_syntax::codemap::{CodeMap, Span, FilePathMapping};
use syntex_syntax::ast::{NodeId, Mac, Attribute, Stmt, StmtKind, FnDecl, Mod,
    StructField, Block, Item, ItemKind};
use syntex_syntax::parse::{self, ParseSess};
use syntex_syntax::errors::Handler;
use syntex_syntax::errors::emitter::ColorConfig;
use std::path::PathBuf;
use std::ffi::OsStr;
use std::rc::Rc;
use std::ops::Deref;
use config::Config;

struct IgnoredLines<'a> {
    lines: Vec<usize>,
    codemap: &'a CodeMap,
    config: &'a Config,
    started: bool,
}

/// Returns a list of files and line numbers to ignore (not indexes!)
pub fn get_lines_to_ignore(project: &Workspace, config: &Config) -> Vec<(PathBuf, usize)> {
    let mut result: Vec<(PathBuf, usize)> = Vec::new();

    let pkg = project.current().unwrap();
    let mut src = PathSource::new(pkg.root(), pkg.package_id().source_id(), project.config());
    // If this fails we should just iterate over no files. No need to care.
    let _ = src.update();

    let codemap = Rc::new(CodeMap::new(FilePathMapping::empty()));
    let handler = Handler::with_tty_emitter(ColorConfig::Auto, false, false, Some(codemap.clone()));
    let parse_session = ParseSess::with_span_handler(handler, codemap.clone());

    for file in src.list_files(&pkg).unwrap().iter() {
        if !(config.ignore_tests && file.starts_with(project.root().join("tests"))) {
            if file.extension() == Some(OsStr::new("rs")) {
                // Rust source file
                let mut parser = parse::new_parser_from_file(&parse_session, &file);
                if let Ok(krate) = parser.parse_crate_mod() {
                    let mut visitor = IgnoredLines::from_session(&parse_session, config);
                    visitor.visit_mod(&krate.module, krate.span, &krate.attrs, NodeId::new(0));
                    result.append(&mut visitor.lines.iter()
                                                    .map(|x| (file.to_path_buf(), *x))
                                                    .collect::<Vec<_>>());
                }
            }
        }
    }
    result
}

impl<'a> IgnoredLines<'a> {
    /// Construct a new ignored lines object for the given project
    fn from_session(session: &'a ParseSess, config: &'a Config) -> IgnoredLines<'a> {
        IgnoredLines {
            lines: vec![],
            codemap: session.codemap(),
            config: config,
            started: false
        }
    }

    fn ignore_lines(&mut self, span: Span) {
        if let Ok(s) = self.codemap.span_to_lines(span) {
            for line in &s.lines {
                // Line number is index+1
                self.lines.push(line.line_index + 1);
            }
        }
    }

    fn contains_cfg_test(&mut self, attrs: &[Attribute]) -> bool {
        attrs.iter()
             .filter(|x| x.path == "cfg")
             .filter_map(|x| x.meta_item_list())
             .flat_map(|x| x)
             .any(|x| {
                 if let Some(w) = x.word() {
                    w.name().as_str() == "test"
                 } else {
                     false
                 }
             })
      }

}

impl<'v, 'a> Visitor<'v> for IgnoredLines<'a> {

    fn visit_item(&mut self, i: &'v Item) {
        match i.node {
            ItemKind::ExternCrate(..) => self.ignore_lines(i.span),
            ItemKind::Fn(_, _, _, _, _, ref block) => {
                if attr::contains_name(&i.attrs, "test") && self.config.ignore_tests {
                    self.ignore_lines(i.span);
                    self.ignore_lines(block.deref().span);
                }
            },
            _ => {},
        }
        visit::walk_item(self, i);
    }

    fn visit_mod(&mut self, m: &'v Mod, s: Span, _attrs: &[Attribute], _n: NodeId) {
        // We want to limit ourselves to only this source file.
        // This avoids repeated hits and issues where there are multiple compilation targets
        if self.started == false {
            self.started = true;
            visit::walk_mod(self, m);
        } else {
            // Needs to be more advanced - cope with mod { .. } in file.
            // Also if mod is cfg(test) and --ignore-tests ignore contents!
            if let Ok(fl) = self.codemap.span_to_lines(s) {
                if fl.lines.len() > 1 {
                    if self.config.ignore_tests && self.contains_cfg_test(_attrs) {
                        self.ignore_lines(s);
                    }
                    visit::walk_mod(self, m);
                } else {
                    // one line mod, so either referencing another file or something
                    // not worth covering.
                    self.ignore_lines(s);
                }
            }
        }
    }

    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, s: Span, _: NodeId) {
        visit::walk_fn(self, fk, fd, s);
    }

    fn visit_stmt(&mut self, s: &Stmt) {
        match s.node {
            StmtKind::Mac(_) => visit::walk_stmt(self, s),
            _ => {},
        }
    }

    fn visit_mac(&mut self, mac: &Mac) {
        // Use this to ignore unreachable lines
        let mac_text = &format!("{}", mac.node.path)[..];
        // TODO unimplemented should have extra logic to exclude the
        // function from coverage
        match mac_text {
            "unimplemented" => self.ignore_lines(mac.span),
            "unreachable" => self.ignore_lines(mac.span),
            _ => {},
        }
        visit::walk_mac(self, mac);
    }

    /// Ignores attributes which may get identified as coverable lines.
    fn visit_attribute(&mut self, attr: &Attribute) {
        if attr.check_name("derive") {
            self.ignore_lines(attr.span);
        }
    }

    /// Struct fields are mistakenly identified as instructions and uncoverable.
    fn visit_struct_field(&mut self, s: &'v StructField) {
        self.ignore_lines(s.span);
        visit::walk_struct_field(self, s);
    }

    fn visit_block(&mut self, b: &'v Block) {

        visit::walk_block(self, b);
    }
}

<commit_msg>Added filtering of close braces and other unimportant lines.<commit_after>use cargo::core::{Workspace, Source};
use cargo::sources::PathSource;
use syntex_syntax::attr;
use syntex_syntax::visit::{self, Visitor, FnKind};
use syntex_syntax::codemap::{CodeMap, Span, FilePathMapping};
use syntex_syntax::ast::{NodeId, Mac, Attribute, Stmt, StmtKind, FnDecl, Mod,
    StructField, Block, Item, ItemKind};
use syntex_syntax::parse::{self, ParseSess};
use syntex_syntax::errors::Handler;
use syntex_syntax::errors::emitter::ColorConfig;
use std::path::PathBuf;
use std::ffi::OsStr;
use std::rc::Rc;
use std::ops::Deref;
use config::Config;

struct IgnoredLines<'a> {
    lines: Vec<usize>,
    codemap: &'a CodeMap,
    config: &'a Config,
    started: bool,
}

/// Returns a list of files and line numbers to ignore (not indexes!)
pub fn get_lines_to_ignore(project: &Workspace, config: &Config) -> Vec<(PathBuf, usize)> {
    let mut result: Vec<(PathBuf, usize)> = Vec::new();

    let pkg = project.current().unwrap();
    let mut src = PathSource::new(pkg.root(), pkg.package_id().source_id(), project.config());
    // If this fails we should just iterate over no files. No need to care.
    let _ = src.update();

    let codemap = Rc::new(CodeMap::new(FilePathMapping::empty()));
    let handler = Handler::with_tty_emitter(ColorConfig::Auto, false, false, Some(codemap.clone()));
    let parse_session = ParseSess::with_span_handler(handler, codemap.clone());

    for file in src.list_files(&pkg).unwrap().iter() {
        if !(config.ignore_tests && file.starts_with(project.root().join("tests"))) {
            if file.extension() == Some(OsStr::new("rs")) {
                // Rust source file
                let mut parser = parse::new_parser_from_file(&parse_session, &file);
                if let Ok(krate) = parser.parse_crate_mod() {
                    let mut visitor = IgnoredLines::from_session(&parse_session, config);
                    visitor.visit_mod(&krate.module, krate.span, &krate.attrs, NodeId::new(0));
                    result.append(&mut visitor.lines.iter()
                                                    .map(|x| (file.to_path_buf(), *x))
                                                    .collect::<Vec<_>>());
                }
            }
        }
    }
    result
}

impl<'a> IgnoredLines<'a> {
    /// Construct a new ignored lines object for the given project
    fn from_session(session: &'a ParseSess, config: &'a Config) -> IgnoredLines<'a> {
        IgnoredLines {
            lines: vec![],
            codemap: session.codemap(),
            config: config,
            started: false
        }
    }

    /// Add lines to the line ignore list
    fn ignore_lines(&mut self, span: Span) {
        if let Ok(s) = self.codemap.span_to_lines(span) {
            for line in &s.lines {
                // Line number is index+1
                self.lines.push(line.line_index + 1);
            }
        }
    }

    /// Looks for #[cfg(test)] attribute.
    fn contains_cfg_test(&mut self, attrs: &[Attribute]) -> bool {
        attrs.iter()
             .filter(|x| x.path == "cfg")
             .filter_map(|x| x.meta_item_list())
             .flat_map(|x| x)
             .any(|x| {
                 if let Some(w) = x.word() {
                    w.name().as_str() == "test"
                 } else {
                     false
                 }
             })
    }

    /// This function finds ignorable lines within actual coverable code.
    /// As opposed to other functions which find isolated lines that aren't
    /// executed or lines filtered by the user. These lines are things like
    /// close braces that are within coverable code but not coverable.
    fn find_ignorable_lines(&mut self, span: Span) {
        if let Ok(l) = self.codemap.span_to_lines(span) {
            for line in &l.lines {
                if let Some(s) = l.file.get_line(line.line_index) {
                    // Is this one of those pointless {, } or }; only lines?
                    if !s.chars().any(|x| !"{}[];\t ".contains(x)) {
                        self.lines.push(line.line_index + 1);
                    }
                }
            }
        }
    }
}

impl<'v, 'a> Visitor<'v> for IgnoredLines<'a> {

    fn visit_item(&mut self, i: &'v Item) {
        match i.node {
            ItemKind::ExternCrate(..) => self.ignore_lines(i.span),
            ItemKind::Fn(_, _, _, _, _, ref block) => {
                if attr::contains_name(&i.attrs, "test") && self.config.ignore_tests {
                    self.ignore_lines(i.span);
                    self.ignore_lines(block.deref().span);
                }
            },
            _ => {},
        }
        visit::walk_item(self, i);
    }

    fn visit_mod(&mut self, m: &'v Mod, s: Span, _attrs: &[Attribute], _n: NodeId) {
        // We want to limit ourselves to only this source file.
        // This avoids repeated hits and issues where there are multiple compilation targets
        if self.started == false {
            self.started = true;
            visit::walk_mod(self, m);
        } else {
            // Needs to be more advanced - cope with mod { .. } in file.
            // Also if mod is cfg(test) and --ignore-tests ignore contents!
            if let Ok(fl) = self.codemap.span_to_lines(s) {
                if fl.lines.len() > 1 {
                    if self.config.ignore_tests && self.contains_cfg_test(_attrs) {
                        self.ignore_lines(s);
                    }
                    visit::walk_mod(self, m);
                } else {
                    // one line mod, so either referencing another file or something
                    // not worth covering.
                    self.ignore_lines(s);
                }
            }
        }
    }

    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, s: Span, _: NodeId) {
        visit::walk_fn(self, fk, fd, s);
    }

    fn visit_stmt(&mut self, s: &Stmt) {
        match s.node {
            StmtKind::Mac(_) => visit::walk_stmt(self, s),
            _ => {},
        }
    }

    fn visit_mac(&mut self, mac: &Mac) {
        // Use this to ignore unreachable lines
        let mac_text = &format!("{}", mac.node.path)[..];
        // TODO unimplemented should have extra logic to exclude the
        // function from coverage
        match mac_text {
            "unimplemented" => self.ignore_lines(mac.span),
            "unreachable" => self.ignore_lines(mac.span),
            _ => {},
        }
        visit::walk_mac(self, mac);
    }

    /// Ignores attributes which may get identified as coverable lines.
    fn visit_attribute(&mut self, attr: &Attribute) {
        if attr.check_name("derive") {
            self.ignore_lines(attr.span);
        }
    }

    /// Struct fields are mistakenly identified as instructions and uncoverable.
    fn visit_struct_field(&mut self, s: &'v StructField) {
        self.ignore_lines(s.span);
        visit::walk_struct_field(self, s);
    }

    fn visit_block(&mut self, b: &'v Block) {
        self.find_ignorable_lines(b.span);
        visit::walk_block(self, b);
    }
}

<|endoftext|>


<commit_before>use std::collections::HashMap;

use super::common::{Document, Translatable, I18NString};
use super::domain;
use super::xflow;
use super::page;
use super::translation::TranslationDocument;

pub type ModelDocument = Document<Model>;
pub type ModelConfigDocument = Document<ModelConfig>;

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct Model {
    pub config: ModelConfigDocument,
    pub domain: domain::DomainDocument,
    pub xflows: Vec<xflow::XFlowDocument>,
    pub pages: Vec<page::PageDocument>,
    pub translations: Vec<TranslationDocument>,
}

impl Default for Model {
    fn default() -> Self {
        Model {
            config: ModelConfigDocument::default(),
            domain: domain::DomainDocument::default(),
            xflows: Vec::<xflow::XFlowDocument>::new(),
            pages: Vec::<page::PageDocument>::new(),
            translations: Vec::<TranslationDocument>::new(),
        }
    }
}

fn pad_translation_doc(t: &mut TranslationDocument,
                       strings_in_model: &HashMap<String, &I18NString>)
                       -> () {
    for (key, item) in strings_in_model {
        if !t.doc.items.contains_key(key) {
            let value = format!("UNTRANSLATED {:?}", item.value);
            t.doc.items.insert(key.clone(),
                               I18NString {
                                   locale: t.doc.locale.clone(),
                                   key: key.clone(),
                                   value: value,
                               });
        }
    }
}

impl ModelDocument {
    pub fn as_locale(&self, locale: &str) -> Result<ModelDocument, String> {

        match self.get_translation(&locale) {
            Ok(translation) => {
                let mut model = self.clone();
                model.translate_in_place(&translation);
                Ok(model)
            }
            Err(err) => Err(err.to_string()),
        }

    }

    pub fn has_translation(&self, locale: &str) -> bool {
        match self.get_translation(&locale) {
            Ok(_) => true,
            Err(_) => false,
        }
    }

    pub fn get_translation(&self, locale: &str) -> Result<&TranslationDocument, String> {
        let res: Vec<&TranslationDocument> = self.doc
            .translations
            .iter()
            .filter({
                        |t| t.doc.locale == locale
                    })
            .collect();

        match res.len() {
            0 => Err("Locale not available in this document".to_owned()),
            1 => Ok(&res[0]),
            _ => Err("More than one instance of this locale available in this document".to_owned()),
        }
    }

    /*
    pub fn pad_all_translations(&mut self) -> () {
        unimplemented!();
        let mut i18n_items_in_model = HashMap::<String, &I18NString>::new();
        for item in self.all_i18n_strings() {
            i18n_items_in_model.insert(item.key.clone(), item);
        }

        let locales = self.doc.config.doc.locales.clone();

        for locale in locales {
            match self.get_translation(&locale) {
                Ok(ref mut t) => {
                    pad_translation_doc(t, &i18n_items_in_model);
                }
                Err(_) => {
                    let mut t = TranslationDocument::default();
                    t.doc.locale = locale.clone();
                    // self.doc.translations.push(t);
                    // pad_translation_doc(t, &i18n_items_in_model);
                }
            };

        }
    }
    */
}

impl Translatable for ModelDocument {
    fn translate_in_place(&mut self, t: &TranslationDocument) -> () {
        for ref mut page in &mut self.doc.pages {
            page.translate_in_place(&t);
        }
        self.doc.domain.translate_in_place(&t);
    }

    fn translate(&self, t: &TranslationDocument) -> ModelDocument {
        let mut doc = self.clone();
        doc.translate_in_place(&t);
        doc
    }

    fn all_i18n_strings(&self) -> Vec<&I18NString> {
        let mut ts = Vec::<&I18NString>::new();

        for ref page in &self.doc.pages {
            ts.append(&mut page.all_i18n_strings());
        }

        ts.append(&mut self.doc.domain.all_i18n_strings());

        ts
    }
}

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct ModelConfig {
    pub default_locale: String,
    pub active_locale: String,
    pub locales: Vec<String>,
}

impl Default for ModelConfig {
    fn default() -> Self {
        ModelConfig {
            default_locale: "en_US".to_owned(),
            active_locale: "en_US".to_owned(),
            locales: vec!["en_US".to_owned()],
        }
    }
}
<commit_msg>chore: Cleanup translation<commit_after>use std::collections::HashMap;

use super::common::{Document, Translatable, I18NString};
use super::domain;
use super::xflow;
use super::page;
use super::translation::TranslationDocument;

pub type ModelDocument = Document<Model>;
pub type ModelConfigDocument = Document<ModelConfig>;

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct Model {
    pub config: ModelConfigDocument,
    pub domain: domain::DomainDocument,
    pub xflows: Vec<xflow::XFlowDocument>,
    pub pages: Vec<page::PageDocument>,
    pub translations: Vec<TranslationDocument>,
}

impl Default for Model {
    fn default() -> Self {
        Model {
            config: ModelConfigDocument::default(),
            domain: domain::DomainDocument::default(),
            xflows: Vec::<xflow::XFlowDocument>::new(),
            pages: Vec::<page::PageDocument>::new(),
            translations: Vec::<TranslationDocument>::new(),
        }
    }
}

fn pad_translation_doc(t: &mut TranslationDocument,
                       strings_in_model: &HashMap<String, &I18NString>)
                       -> () {
    for (key, item) in strings_in_model {
        if !t.doc.items.contains_key(key) {
            let value = format!("UNTRANSLATED {:?}", item.value);
            let item = I18NString {
                locale: t.doc.locale.clone(),
                key: key.clone(),
                value: value,
            };
            debug!("Untranslated string, locale :'{:?}', value '{:?}'",
                   item.locale,
                   item.value);
            t.doc.items.insert(key.clone(), item);
        }
    }
}

impl ModelDocument {
    pub fn as_locale(&self, locale: &str) -> Result<ModelDocument, String> {

        match self.get_translation(&locale) {
            Ok(translation) => {
                let mut model = self.clone();
                model.translate_in_place(&translation);
                Ok(model)
            }
            Err(err) => Err(err.to_string()),
        }

    }

    pub fn has_translation(&self, locale: &str) -> bool {
        match self.get_translation(&locale) {
            Ok(_) => true,
            Err(_) => false,
        }
    }

    pub fn get_translation(&self, locale: &str) -> Result<&TranslationDocument, String> {
        let res: Vec<&TranslationDocument> = self.doc
            .translations
            .iter()
            .filter({
                        |t| t.doc.locale == locale
                    })
            .collect();

        match res.len() {
            0 => Err("Locale not available in this document".to_owned()),
            1 => Ok(&res[0]),
            _ => Err("More than one instance of this locale available in this document".to_owned()),
        }
    }

    /*
    pub fn pad_all_translations(&mut self) -> () {
        unimplemented!();
        let mut i18n_items_in_model = HashMap::<String, &I18NString>::new();
        for item in self.all_i18n_strings() {
            i18n_items_in_model.insert(item.key.clone(), item);
        }

        let locales = self.doc.config.doc.locales.clone();

        for locale in locales {
            match self.get_translation(&locale) {
                Ok(ref mut t) => {
                    pad_translation_doc(t, &i18n_items_in_model);
                }
                Err(_) => {
                    let mut t = TranslationDocument::default();
                    t.doc.locale = locale.clone();
                    // self.doc.translations.push(t);
                    // pad_translation_doc(t, &i18n_items_in_model);
                }
            };

        }
    }
    */
}

impl Translatable for ModelDocument {
    fn translate_in_place(&mut self, t: &TranslationDocument) -> () {
        for ref mut page in &mut self.doc.pages {
            page.translate_in_place(&t);
        }
        self.doc.domain.translate_in_place(&t);
    }

    fn translate(&self, t: &TranslationDocument) -> ModelDocument {
        let mut doc = self.clone();
        doc.translate_in_place(&t);
        doc
    }

    fn all_i18n_strings(&self) -> Vec<&I18NString> {
        let mut ts = Vec::<&I18NString>::new();

        for ref page in &self.doc.pages {
            ts.append(&mut page.all_i18n_strings());
        }

        ts.append(&mut self.doc.domain.all_i18n_strings());

        ts
    }
}

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct ModelConfig {
    pub default_locale: String,
    pub active_locale: String,
    pub locales: Vec<String>,
}

impl Default for ModelConfig {
    fn default() -> Self {
        ModelConfig {
            default_locale: "en_US".to_owned(),
            active_locale: "en_US".to_owned(),
            locales: vec!["en_US".to_owned()],
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::BufReader;

use package::pkg::{ Package, Version };

pub fn get_installed_version(pkg: Package, path: &Path) -> Result<Version, String> {
    let file = get!(File::open(path), "An error occured while opening version list.");
    let file = BufReader::new(file);

    for line in file.lines() {
        let line: String = get!(line, "An error occured while trying to unwrap line.");
        if line.contains(&pkg.name) {
            return Ok(pkg.version)
        }
    }

    return Err("Specified package not found")
}

pub fn update_installed_version(pkg: Package, path: &Path, version: Version) -> Result<bool, String> {
    let file = get!(File::open(path), "An error occured while opening version list.");
    let file = BufReader::new(file);
    let result = get_installed_version(pkg, path);

    return match result {
        Ok(version) => Ok(true),
        Ok(x) => {},
        Err("Specified package not found") => {},
        Err(_) => result
    }
}<commit_msg>Complete implementation of get_installed_version()<commit_after>use std::error::Error;
use std::fs::File;
use std::io::{ BufRead, BufReader };
use std::path::Path;

use package::pkg::{ Package, Version };

const SEPERATION_SYMBOL: &'static str = "=";

pub fn get_installed_version(pkg: Package, path: &Path) -> Result<Version, String> {
    let file = get!(File::open(path), "An error occured while opening version list.");
    let file = BufReader::new(file);

    for line in file.lines() {
        let line: String = get!(line, "An error occured while trying to unwrap line.");
        if line.contains(&pkg.name) {
            let ver: Vec<&str> = line.trim().split(SEPERATION_SYMBOL).collect();
            if ver.len() == 2 {
                return Ok(try!(Version::from_str(ver[1])))
            } else {
                return Err("Wrong version".to_string())
            }
        }
    }

    return Err("Specified package not found".to_string())
}

pub fn update_installed_version(pkg: Package, path: &Path, version: Version) -> Result<bool, String> {

}<|endoftext|>


<commit_before>extern crate html2text;
extern crate termion;
use std::io::{self, Write};

fn main() {
    let stdin = io::stdin();

    let annotated = html2text::from_read_rich(&mut stdin.lock(), 80);
    for line in annotated {
        for (s, tag) in line.iter() {
            write!(io::stdout(), "{}", s);
        }
        write!(io::stdout(), "\n");
    }
}<commit_msg>Crudely underline links.<commit_after>extern crate html2text;
extern crate termion;
use std::io::{self, Write};
use std::fmt::Display;
use html2text::render::text_renderer::{RichAnnotation};

fn to_style(tag: &Vec<RichAnnotation>) -> Box<Display> {
    if tag.len() > 0 {
        Box::new(termion::style::Underline)
    } else {
        Box::new(termion::style::Reset)
    }
}

fn main() {
    let stdin = io::stdin();

    let annotated = html2text::from_read_rich(&mut stdin.lock(), 80);
    for line in annotated {
        for (s, tag) in line.iter() {
            let style = to_style(tag);
            write!(io::stdout(), "{}{}{}", style, s, termion::style::Reset);
        }
        write!(io::stdout(), "\n");
    }
}<|endoftext|>


<commit_before>//! This example uses [hyper][] to create a http server which handles requests asynchronously in
//! gluon. To do this we define a few types and functions in Rust with which we register in gluon
//! so that we can communicate with `hyper`. The rest of the implementation is done in gluon,
//! routing the requests and constructing the responses.
//!
//! [hyper]:https://hyper.rs

extern crate gluon;
extern crate gluon_base as base;
#[macro_use]
extern crate gluon_vm as vm;

#[macro_use]
extern crate collect_mac;
extern crate env_logger;
extern crate futures;
extern crate http;
extern crate hyper;
extern crate tokio;
#[macro_use]
extern crate log;

use std::env;
use std::error::Error as StdError;
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::marker::PhantomData;
use std::sync::{Arc, Mutex};

use hyper::service::Service;
use hyper::Chunk;
use hyper::Server;

use http::StatusCode;

use futures::future::Either;
use futures::stream::Stream;
use futures::sync::oneshot;
use futures::{future, Async, Future};

use base::types::{ArcType, Type};

use vm::{Error as VmError, ExternModule, Result as VmResult};

use gluon::import::add_extern_module;
use vm::api::{
    Function, FutureResult, OpaqueValue, OwnedFunction, PushAsRef, Userdata, VmType, WithVM, IO,
};
use vm::future::FutureValue;
use vm::gc::{Gc, Traverseable};
use vm::thread::{RootedThread, Thread};

use gluon::{new_vm, Compiler};

// `Handler` is a type defined in http.glu but since we need to refer to it in the signature of
// listen we define a phantom type which we can use with `OpaqueValue` to store a `Handler` in Rust
struct Handler<T>(PhantomData<T>);

impl<T: VmType + 'static> VmType for Handler<T> {
    type Type = Self;
    fn make_type(vm: &Thread) -> ArcType {
        let typ = vm
            .find_type_info("examples.http.types.Handler")
            .unwrap_or_else(|err| panic!("{}", err))
            .into_type();
        Type::app(typ, collect![T::make_type(vm)])
    }
}

// Representation of a http body that is in the prograss of being read
pub struct Body(Arc<Mutex<Box<Stream<Item = PushAsRef<Chunk, [u8]>, Error = VmError> + Send>>>);

// By implementing `Userdata` on `Body` it can be automatically pushed and retrieved from gluon
// threads
impl Userdata for Body {}

// Types implementing `Userdata` requires a `std::fmt::Debug` implementation so it can be displayed
impl fmt::Debug for Body {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "hyper::Body")
    }
}

// `Traverseable` is required by `Userdata` so that the garbage collector knows how to scan the
// value for garbage collected references. Normally objects do not contain any references so this
// can be empty
impl Traverseable for Body {
    fn traverse(&self, _: &mut Gc) {}
}

// `VmType` is the last trait required for a type to implement `Userdata` and defines the type used
// in gluon for this Rust type. For opaque `Userdata` values this minimal implementation is enough
// as the default implementation of `make_type` will lookup `VmType::Type` from the virtual machine
// which should have been registered earlier with `Thread::register_type`
impl VmType for Body {
    type Type = Self;
}

// Since `Body` implements `Userdata` gluon will automatically marshal the gluon representation
// into `&Body` argument
fn read_chunk(
    body: &Body,
) -> FutureResult<impl Future<Item = IO<Option<PushAsRef<Chunk, [u8]>>>, Error = VmError>> {
    use futures::future::poll_fn;

    let body = body.0.clone();
    // `FutureResult` is a wrapper type around `Future` which when returned to the interpreter is
    // polled until completion. After `poll` returns `Ready` the value is then returned to the
    // gluon function which called `read_chunk`
    FutureResult(poll_fn(move || {
        let mut stream = body.lock().unwrap();
        stream.poll().map(|async| async.map(IO::Value))
    }))
}

// A http body that is being written
pub struct ResponseBody(Arc<Mutex<Option<hyper::body::Sender>>>);

impl fmt::Debug for ResponseBody {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "hyper::Response")
    }
}

impl Userdata for ResponseBody {}

impl Traverseable for ResponseBody {
    fn traverse(&self, _: &mut Gc) {}
}

impl VmType for ResponseBody {
    type Type = Self;
}

fn write_response(
    response: &ResponseBody,
    bytes: &[u8],
) -> FutureResult<impl Future<Item = IO<()>, Error = VmError>> {
    use futures::future::poll_fn;

    // Turn `bytes´ into a `Chunk` which can be sent to the http body
    let mut unsent_chunk = Some(bytes.to_owned().into());
    let response = response.0.clone();
    FutureResult(poll_fn(move || {
        info!("Starting response send");
        let mut sender = response.lock().unwrap();
        let sender = sender
            .as_mut()
            .expect("Sender has been dropped while still in use");
        let chunk = unsent_chunk
            .take()
            .expect("Attempt to poll after chunk is sent");
        match sender.poll_ready() {
            Ok(Async::NotReady) => {
                unsent_chunk = Some(chunk);
                return Ok(Async::NotReady);
            }
            Ok(Async::Ready(_)) => (),
            Err(_) => {
                info!("Could not send http response");
                return Ok(Async::Ready(IO::Value(())));
            }
        }
        match sender.send_data(chunk) {
            Ok(()) => Ok(Async::Ready(IO::Value(()))),
            Err(chunk) => {
                info!("Could not send http response");
                unsent_chunk = Some(chunk);
                Ok(Async::NotReady)
            }
        }
    }))
}

// Next we define some record types which are marshalled to and from gluon. These have equivalent
// definitions in http_types.glu
field_decl! { method, uri, status, body, request, response }

type Request = record_type!{
    method => String,
    uri => String,
    body => Body
};

type Response = record_type!{
    status => u16
};

type HttpState = record_type!{
    request => Request,
    response => ResponseBody
};

fn listen(
    port: i32,
    value: WithVM<OpaqueValue<RootedThread, Handler<Response>>>,
) -> FutureResult<impl Future<Item = IO<()>, Error = vm::Error> + Send + 'static> {
    let WithVM {
        value: handler,
        vm: thread,
    } = value;

    let thread = match thread.new_thread() {
        Ok(thread) => thread,
        Err(err) => return FutureResult(Either::A(future::err(err))),
    };

    // Retrieve the `handle` function from the http module which we use to evaluate values of type
    // `Handler Response`
    type ListenFn = fn(OpaqueValue<RootedThread, Handler<Response>>, HttpState) -> IO<Response>;
    let handle: Function<RootedThread, ListenFn> = thread
        .get_global("examples.http.http.handle")
        .unwrap_or_else(|err| panic!("{}", err));

    struct Listen {
        handle: Function<RootedThread, ListenFn>,
        handler: OpaqueValue<RootedThread, Handler<Response>>,
    }

    impl Service for Listen {
        type ReqBody = hyper::Body;
        type ResBody = hyper::Body;
        type Error = hyper::Error;
        type Future =
            Box<Future<Item = http::Response<hyper::Body>, Error = hyper::Error> + Send + 'static>;

        fn call(&mut self, request: http::Request<hyper::Body>) -> Self::Future {
            let gluon_request = record_no_decl! {
                method => request.method().as_str().to_owned(),
                uri => request.uri().to_string(),
                // Since `Body` implements `Userdata` it can be directly pushed to gluon
                body => Body(Arc::new(Mutex::new(Box::new(request.into_body()
                    .map_err(|err| VmError::Message(format!("{}", err)))
                    // `PushAsRef` makes the `body` parameter act as a `&[u8]` which means it is
                    // marshalled to `Array Byte` in gluon
                    .map(PushAsRef::<_, [u8]>::new)))))
            };
            let (response_sender, response_body) = hyper::Body::channel();
            let response_sender = Arc::new(Mutex::new(Some(response_sender)));
            let http_state = record_no_decl!{
                request => gluon_request,
                response => ResponseBody(response_sender.clone())
            };

            Box::new(
                self.handle
                    .clone()
                    .call_async(self.handler.clone(), http_state)
                    .then(move |result| match result {
                        Ok(value) => {
                            match value {
                                IO::Value(record_p!{ status }) => {
                                    // Drop the sender to so that it the receiver stops waiting for
                                    // more chunks
                                    *response_sender.lock().unwrap() = None;

                                    let status = StatusCode::from_u16(status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
                                    Ok(
                                        http::Response::builder()
                                            .status(status)
                                            .body(response_body).unwrap(),
                                    )
                                }
                                IO::Exception(err) => {
                                    eprintln!("{}", err);
                                    Ok(
                                        http::Response::builder()
                                            .status(StatusCode::INTERNAL_SERVER_ERROR).body("".into()).unwrap()
                                    )
                                }
                            }
                        }
                        Err(err) => {
                            eprintln!("{}", err);
                            Ok(http::Response::builder()
                                .status(StatusCode::INTERNAL_SERVER_ERROR)
                                .body("".into())
                                .unwrap())
                        }
                    }),
            )
        }
    }

    let addr = format!("127.0.0.1:{}", port).parse().unwrap();

    let (sender, receiver) = oneshot::channel();
    tokio::spawn(
        Server::bind(&addr)
            .serve(move || -> Result<_, hyper::Error> {
                Ok(Listen {
                    handle: handle.clone(),
                    handler: handler.clone(),
                })
            })
            .map_err(|err| {
                error!("{}", err);
            })
            .and_then(|_| sender.send(IO::Value(())).map_err(|_| ())),
    );
    FutureResult(Either::B(
        receiver.map_err(|err| vm::Error::from(format!("Server error: {}", err))),
    ))
}

// To let the `http_types` module refer to `Body` and `ResponseBody` we register these types in a
// separate function which is called before loading `http_types`
pub fn load_types(vm: &Thread) -> VmResult<ExternModule> {
    vm.register_type::<Body>("Body", &[])?;
    vm.register_type::<ResponseBody>("ResponseBody", &[])?;

    ExternModule::new(
        vm,
        record! {
            // Define the types so that they can be used from gluon
            type Body => Body,
            type ResponseBody => ResponseBody,
            type Method => String,
            type StatusCode => u16,
            type Request => Request,
            type Response => Response,
            type HttpState => HttpState
        },
    )
}

pub fn load(vm: &Thread) -> VmResult<ExternModule> {
    ExternModule::new(
        vm,
        record! {
            listen => primitive!(2 listen),
            read_chunk => primitive!(1 read_chunk),
            write_response => primitive!(2 write_response)
        },
    )
}

fn main() {
    env_logger::init();

    let port = env::args()
        .nth(1)
        .map(|port| port.parse::<u16>().expect("port"))
        .unwrap_or(80);

    let thread = new_vm();
    tokio::run(start(&thread, port).map_err(|err| panic!("{}", err)));
}

fn start(
    thread: &Thread,
    port: u16,
) -> impl Future<Item = (), Error = Box<StdError + Send + Sync + 'static>> {
    add_extern_module(&thread, "http.prim_types", load_types);
    add_extern_module(&thread, "http.prim", load);

    let thread = thread.root_thread();
    future::lazy(|| -> Result<_, Box<StdError + Send + Sync>> {
        // Last we run our `http_server.glu` module which returns a function which starts listening
        // on the port we passed from the command line
        let mut expr = String::new();
        {
            let mut file = File::open("examples/http/server.glu")?;
            file.read_to_string(&mut expr)?;
        }
        Ok(expr)
    }).and_then(move |expr| {
        Compiler::new()
            .run_expr_async::<OwnedFunction<fn(u16) -> IO<()>>>(
                &thread,
                "examples/http/server.glu",
                &expr,
            )
            .from_err()
            .and_then(move |(mut listen, _)| {
                FutureValue::Future(listen.call_async(port))
                    .from_err()
                    .map(|_| ())
            })
    })
}

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

    extern crate tokio_retry;

    use std::str;

    use hyper::Client;

    use tokio::runtime::Runtime;

    #[test]
    fn hello_world() {
        let mut runtime = Runtime::new().unwrap();

        let port = 1222;
        let thread = new_vm();

        runtime.spawn(future::lazy(move || {
            start(&thread, port).map_err(|err| panic!("{}", err))
        }));

        let future =
            move || Client::new().get(format!("http://localhost:{}", port).parse().unwrap());

        let retry_strategy = tokio_retry::strategy::FixedInterval::from_millis(400).take(40);

        runtime
            .block_on(
                tokio_retry::Retry::spawn(retry_strategy, future)
                    .map_err(|err| panic!("{}", err))
                    .and_then(|response| {
                        response.into_body().concat2().map(|body| {
                            assert_eq!(str::from_utf8(&body).unwrap(), "Hello World");
                        })
                    }),
            )
            .unwrap();
    }

    #[test]
    fn echo() {
        let mut runtime = Runtime::new().unwrap();

        let port = 1223;
        let thread = new_vm();
        runtime.spawn(future::lazy(move || {
            start(&thread, port).map_err(|err| panic!("{}", err))
        }));

        let future = move || {
            let request = hyper::Request::post(format!("http://localhost:{}/echo", port))
                .body(hyper::Body::from("test"))
                .unwrap();

            Client::new().request(request)
        };

        let retry_strategy = tokio_retry::strategy::FixedInterval::from_millis(400).take(40);

        runtime
            .block_on(
                tokio_retry::Retry::spawn(retry_strategy, future)
                    .map_err(|err| panic!("{}", err))
                    .and_then(|response| {
                        response.into_body().concat2().map(|body| {
                            assert_eq!(str::from_utf8(&body).unwrap(), "test");
                        })
                    }),
            )
            .unwrap();
    }
}
<commit_msg>test: Print an error if the http server can't start<commit_after>//! This example uses [hyper][] to create a http server which handles requests asynchronously in
//! gluon. To do this we define a few types and functions in Rust with which we register in gluon
//! so that we can communicate with `hyper`. The rest of the implementation is done in gluon,
//! routing the requests and constructing the responses.
//!
//! [hyper]:https://hyper.rs

extern crate gluon;
extern crate gluon_base as base;
#[macro_use]
extern crate gluon_vm as vm;

#[macro_use]
extern crate collect_mac;
extern crate env_logger;
extern crate futures;
extern crate http;
extern crate hyper;
extern crate tokio;
#[macro_use]
extern crate log;

use std::env;
use std::error::Error as StdError;
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::marker::PhantomData;
use std::sync::{Arc, Mutex};

use hyper::service::Service;
use hyper::Chunk;
use hyper::Server;

use http::StatusCode;

use futures::future::Either;
use futures::stream::Stream;
use futures::sync::oneshot;
use futures::{future, Async, Future};

use base::types::{ArcType, Type};

use vm::{Error as VmError, ExternModule, Result as VmResult};

use gluon::import::add_extern_module;
use vm::api::{
    Function, FutureResult, OpaqueValue, OwnedFunction, PushAsRef, Userdata, VmType, WithVM, IO,
};
use vm::future::FutureValue;
use vm::gc::{Gc, Traverseable};
use vm::thread::{RootedThread, Thread};

use gluon::{new_vm, Compiler};

// `Handler` is a type defined in http.glu but since we need to refer to it in the signature of
// listen we define a phantom type which we can use with `OpaqueValue` to store a `Handler` in Rust
struct Handler<T>(PhantomData<T>);

impl<T: VmType + 'static> VmType for Handler<T> {
    type Type = Self;
    fn make_type(vm: &Thread) -> ArcType {
        let typ = vm
            .find_type_info("examples.http.types.Handler")
            .unwrap_or_else(|err| panic!("{}", err))
            .into_type();
        Type::app(typ, collect![T::make_type(vm)])
    }
}

// Representation of a http body that is in the prograss of being read
pub struct Body(Arc<Mutex<Box<Stream<Item = PushAsRef<Chunk, [u8]>, Error = VmError> + Send>>>);

// By implementing `Userdata` on `Body` it can be automatically pushed and retrieved from gluon
// threads
impl Userdata for Body {}

// Types implementing `Userdata` requires a `std::fmt::Debug` implementation so it can be displayed
impl fmt::Debug for Body {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "hyper::Body")
    }
}

// `Traverseable` is required by `Userdata` so that the garbage collector knows how to scan the
// value for garbage collected references. Normally objects do not contain any references so this
// can be empty
impl Traverseable for Body {
    fn traverse(&self, _: &mut Gc) {}
}

// `VmType` is the last trait required for a type to implement `Userdata` and defines the type used
// in gluon for this Rust type. For opaque `Userdata` values this minimal implementation is enough
// as the default implementation of `make_type` will lookup `VmType::Type` from the virtual machine
// which should have been registered earlier with `Thread::register_type`
impl VmType for Body {
    type Type = Self;
}

// Since `Body` implements `Userdata` gluon will automatically marshal the gluon representation
// into `&Body` argument
fn read_chunk(
    body: &Body,
) -> FutureResult<impl Future<Item = IO<Option<PushAsRef<Chunk, [u8]>>>, Error = VmError>> {
    use futures::future::poll_fn;

    let body = body.0.clone();
    // `FutureResult` is a wrapper type around `Future` which when returned to the interpreter is
    // polled until completion. After `poll` returns `Ready` the value is then returned to the
    // gluon function which called `read_chunk`
    FutureResult(poll_fn(move || {
        let mut stream = body.lock().unwrap();
        stream.poll().map(|async| async.map(IO::Value))
    }))
}

// A http body that is being written
pub struct ResponseBody(Arc<Mutex<Option<hyper::body::Sender>>>);

impl fmt::Debug for ResponseBody {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "hyper::Response")
    }
}

impl Userdata for ResponseBody {}

impl Traverseable for ResponseBody {
    fn traverse(&self, _: &mut Gc) {}
}

impl VmType for ResponseBody {
    type Type = Self;
}

fn write_response(
    response: &ResponseBody,
    bytes: &[u8],
) -> FutureResult<impl Future<Item = IO<()>, Error = VmError>> {
    use futures::future::poll_fn;

    // Turn `bytes´ into a `Chunk` which can be sent to the http body
    let mut unsent_chunk = Some(bytes.to_owned().into());
    let response = response.0.clone();
    FutureResult(poll_fn(move || {
        info!("Starting response send");
        let mut sender = response.lock().unwrap();
        let sender = sender
            .as_mut()
            .expect("Sender has been dropped while still in use");
        let chunk = unsent_chunk
            .take()
            .expect("Attempt to poll after chunk is sent");
        match sender.poll_ready() {
            Ok(Async::NotReady) => {
                unsent_chunk = Some(chunk);
                return Ok(Async::NotReady);
            }
            Ok(Async::Ready(_)) => (),
            Err(_) => {
                info!("Could not send http response");
                return Ok(Async::Ready(IO::Value(())));
            }
        }
        match sender.send_data(chunk) {
            Ok(()) => Ok(Async::Ready(IO::Value(()))),
            Err(chunk) => {
                info!("Could not send http response");
                unsent_chunk = Some(chunk);
                Ok(Async::NotReady)
            }
        }
    }))
}

// Next we define some record types which are marshalled to and from gluon. These have equivalent
// definitions in http_types.glu
field_decl! { method, uri, status, body, request, response }

type Request = record_type!{
    method => String,
    uri => String,
    body => Body
};

type Response = record_type!{
    status => u16
};

type HttpState = record_type!{
    request => Request,
    response => ResponseBody
};

fn listen(
    port: i32,
    value: WithVM<OpaqueValue<RootedThread, Handler<Response>>>,
) -> FutureResult<impl Future<Item = IO<()>, Error = vm::Error> + Send + 'static> {
    let WithVM {
        value: handler,
        vm: thread,
    } = value;

    let thread = match thread.new_thread() {
        Ok(thread) => thread,
        Err(err) => return FutureResult(Either::A(future::err(err))),
    };

    // Retrieve the `handle` function from the http module which we use to evaluate values of type
    // `Handler Response`
    type ListenFn = fn(OpaqueValue<RootedThread, Handler<Response>>, HttpState) -> IO<Response>;
    let handle: Function<RootedThread, ListenFn> = thread
        .get_global("examples.http.http.handle")
        .unwrap_or_else(|err| panic!("{}", err));

    struct Listen {
        handle: Function<RootedThread, ListenFn>,
        handler: OpaqueValue<RootedThread, Handler<Response>>,
    }

    impl Service for Listen {
        type ReqBody = hyper::Body;
        type ResBody = hyper::Body;
        type Error = hyper::Error;
        type Future =
            Box<Future<Item = http::Response<hyper::Body>, Error = hyper::Error> + Send + 'static>;

        fn call(&mut self, request: http::Request<hyper::Body>) -> Self::Future {
            let gluon_request = record_no_decl! {
                method => request.method().as_str().to_owned(),
                uri => request.uri().to_string(),
                // Since `Body` implements `Userdata` it can be directly pushed to gluon
                body => Body(Arc::new(Mutex::new(Box::new(request.into_body()
                    .map_err(|err| VmError::Message(format!("{}", err)))
                    // `PushAsRef` makes the `body` parameter act as a `&[u8]` which means it is
                    // marshalled to `Array Byte` in gluon
                    .map(PushAsRef::<_, [u8]>::new)))))
            };
            let (response_sender, response_body) = hyper::Body::channel();
            let response_sender = Arc::new(Mutex::new(Some(response_sender)));
            let http_state = record_no_decl!{
                request => gluon_request,
                response => ResponseBody(response_sender.clone())
            };

            Box::new(
                self.handle
                    .clone()
                    .call_async(self.handler.clone(), http_state)
                    .then(move |result| match result {
                        Ok(value) => {
                            match value {
                                IO::Value(record_p!{ status }) => {
                                    // Drop the sender to so that it the receiver stops waiting for
                                    // more chunks
                                    *response_sender.lock().unwrap() = None;

                                    let status = StatusCode::from_u16(status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
                                    Ok(
                                        http::Response::builder()
                                            .status(status)
                                            .body(response_body).unwrap(),
                                    )
                                }
                                IO::Exception(err) => {
                                    eprintln!("{}", err);
                                    Ok(
                                        http::Response::builder()
                                            .status(StatusCode::INTERNAL_SERVER_ERROR).body("".into()).unwrap()
                                    )
                                }
                            }
                        }
                        Err(err) => {
                            eprintln!("{}", err);
                            Ok(http::Response::builder()
                                .status(StatusCode::INTERNAL_SERVER_ERROR)
                                .body("".into())
                                .unwrap())
                        }
                    }),
            )
        }
    }

    let addr = format!("127.0.0.1:{}", port).parse().unwrap();

    let (sender, receiver) = oneshot::channel();
    tokio::spawn(
        Server::bind(&addr)
            .serve(move || -> Result<_, hyper::Error> {
                Ok(Listen {
                    handle: handle.clone(),
                    handler: handler.clone(),
                })
            })
            .map_err(|err| {
                error!("{}", err);
            })
            .and_then(|_| sender.send(IO::Value(())).map_err(|_| ())),
    );
    FutureResult(Either::B(
        receiver.map_err(|err| vm::Error::from(format!("Server error: {}", err))),
    ))
}

// To let the `http_types` module refer to `Body` and `ResponseBody` we register these types in a
// separate function which is called before loading `http_types`
pub fn load_types(vm: &Thread) -> VmResult<ExternModule> {
    vm.register_type::<Body>("Body", &[])?;
    vm.register_type::<ResponseBody>("ResponseBody", &[])?;

    ExternModule::new(
        vm,
        record! {
            // Define the types so that they can be used from gluon
            type Body => Body,
            type ResponseBody => ResponseBody,
            type Method => String,
            type StatusCode => u16,
            type Request => Request,
            type Response => Response,
            type HttpState => HttpState
        },
    )
}

pub fn load(vm: &Thread) -> VmResult<ExternModule> {
    ExternModule::new(
        vm,
        record! {
            listen => primitive!(2 listen),
            read_chunk => primitive!(1 read_chunk),
            write_response => primitive!(2 write_response)
        },
    )
}

fn main() {
    env_logger::init();

    let port = env::args()
        .nth(1)
        .map(|port| port.parse::<u16>().expect("port"))
        .unwrap_or(80);

    let thread = new_vm();
    tokio::run(start(&thread, port).map_err(|err| panic!("{}", err)));
}

fn start(
    thread: &Thread,
    port: u16,
) -> impl Future<Item = (), Error = Box<StdError + Send + Sync + 'static>> {
    add_extern_module(&thread, "http.prim_types", load_types);
    add_extern_module(&thread, "http.prim", load);

    let thread = thread.root_thread();
    future::lazy(|| -> Result<_, Box<StdError + Send + Sync>> {
        // Last we run our `http_server.glu` module which returns a function which starts listening
        // on the port we passed from the command line
        let mut expr = String::new();
        {
            let mut file = File::open("examples/http/server.glu")?;
            file.read_to_string(&mut expr)?;
        }
        Ok(expr)
    }).and_then(move |expr| {
        Compiler::new()
            .run_expr_async::<OwnedFunction<fn(u16) -> IO<()>>>(
                &thread,
                "examples/http/server.glu",
                &expr,
            )
            .from_err()
            .and_then(move |(mut listen, _)| {
                FutureValue::Future(listen.call_async(port))
                    .from_err()
                    .map(|_| ())
            })
    })
}

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

    extern crate tokio_retry;

    use std::str;

    use hyper::Client;

    use tokio::runtime::Runtime;

    #[test]
    fn hello_world() {
        let mut runtime = Runtime::new().unwrap();

        let port = 1222;
        let thread = new_vm();

        runtime.spawn(future::lazy(move || {
            start(&thread, port).map_err(|err| error!("{}", err))
        }));

        let future =
            move || Client::new().get(format!("http://localhost:{}", port).parse().unwrap());

        let retry_strategy = tokio_retry::strategy::FixedInterval::from_millis(400).take(40);

        runtime
            .block_on(
                tokio_retry::Retry::spawn(retry_strategy, future)
                    .map_err(|err| panic!("{}", err))
                    .and_then(|response| {
                        response.into_body().concat2().map(|body| {
                            assert_eq!(str::from_utf8(&body).unwrap(), "Hello World");
                        })
                    }),
            )
            .unwrap();
    }

    #[test]
    fn echo() {
        let mut runtime = Runtime::new().unwrap();

        let port = 1223;
        let thread = new_vm();
        runtime.spawn(future::lazy(move || {
            start(&thread, port).map_err(|err| error!("{}", err))
        }));

        let future = move || {
            let request = hyper::Request::post(format!("http://localhost:{}/echo", port))
                .body(hyper::Body::from("test"))
                .unwrap();

            Client::new().request(request)
        };

        let retry_strategy = tokio_retry::strategy::FixedInterval::from_millis(400).take(40);

        runtime
            .block_on(
                tokio_retry::Retry::spawn(retry_strategy, future)
                    .map_err(|err| panic!("{}", err))
                    .and_then(|response| {
                        response.into_body().concat2().map(|body| {
                            assert_eq!(str::from_utf8(&body).unwrap(), "test");
                        })
                    }),
            )
            .unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate mpi;

use std::mem;

use mpi::traits::*;
use mpi::request::{CancelGuard, WaitGuard};

fn main() {
    let universe = mpi::initialize().unwrap();
    let world = universe.world();

    let x = 3.1415f32;
    let mut y: f32 = 0.0;

    {
        let mut sreq = world.this_process().immediate_send(&x);
        let rreq = world.immediate_receive_into(&mut y);
        rreq.wait();
        loop {
            match sreq.test() {
                Ok(_) => { break; }
                Err(req) => { sreq = req; }
            }
        }
    }
    assert_eq!(x, y);

    y = 0.0;
    {
        let rreq = WaitGuard::from(world.immediate_receive_into(&mut y));
        let sreq = WaitGuard::from(world.this_process().immediate_ready_send(&x));
        mem::drop(sreq);
        mem::drop(rreq);
    }
    assert_eq!(x, y);

    assert!(world.immediate_probe().is_none());
    assert!(world.immediate_matched_probe().is_none());

    y = 0.0;
    {
        let sreq: WaitGuard<_> = world.this_process().immediate_synchronous_send(&x).into();
        let preq = world.immediate_matched_probe();
        assert!(preq.is_some());
        let (msg, _) = preq.unwrap();
        let rreq: WaitGuard<_> = msg.immediate_matched_receive_into(&mut y).into();
        mem::drop(sreq);
        mem::drop(rreq);
    }
    assert_eq!(x, y);

    let future = world.immediate_receive();
    world.this_process().send(&x);
    let (msg, _) = future.get();
    assert!(msg.is_some());
    assert_eq!(x, msg.unwrap());

    let future = world.immediate_receive();
    let res = future.try();
    assert!(res.is_err());
    let mut future = res.err().unwrap();
    world.this_process().send(&x);
    loop {
        match future.try() {
            Ok((msg, _)) => {
                assert!(msg.is_some());
                assert_eq!(x, msg.unwrap());
                break;
            }
            Err(f) => { future = f; }
        }
    }

    let sreq = world.this_process().immediate_send(&x);
    sreq.cancel();

    let sreq = CancelGuard::from(world.this_process().immediate_receive_into(&mut y));
    mem::drop(sreq);
}
<commit_msg>Do not use mem::drop() explicitly on request guards in example.<commit_after>extern crate mpi;

use mpi::traits::*;
use mpi::request::{CancelGuard, WaitGuard};

fn main() {
    let universe = mpi::initialize().unwrap();
    let world = universe.world();

    let x = 3.1415f32;
    let mut y: f32 = 0.0;

    {
        let mut sreq = world.this_process().immediate_send(&x);
        let rreq = world.immediate_receive_into(&mut y);
        rreq.wait();
        loop {
            match sreq.test() {
                Ok(_) => { break; }
                Err(req) => { sreq = req; }
            }
        }
    }
    assert_eq!(x, y);

    y = 0.0;
    {
        let _rreq = WaitGuard::from(world.immediate_receive_into(&mut y));
        let _sreq = WaitGuard::from(world.this_process().immediate_ready_send(&x));
    }
    assert_eq!(x, y);

    assert!(world.immediate_probe().is_none());
    assert!(world.immediate_matched_probe().is_none());

    y = 0.0;
    {
        let _sreq: WaitGuard<_> = world.this_process().immediate_synchronous_send(&x).into();
        let preq = world.immediate_matched_probe();
        assert!(preq.is_some());
        let (msg, _) = preq.unwrap();
        let _rreq: WaitGuard<_> = msg.immediate_matched_receive_into(&mut y).into();
    }
    assert_eq!(x, y);

    let future = world.immediate_receive();
    world.this_process().send(&x);
    let (msg, _) = future.get();
    assert!(msg.is_some());
    assert_eq!(x, msg.unwrap());

    let future = world.immediate_receive();
    let res = future.try();
    assert!(res.is_err());
    let mut future = res.err().unwrap();
    world.this_process().send(&x);
    loop {
        match future.try() {
            Ok((msg, _)) => {
                assert!(msg.is_some());
                assert_eq!(x, msg.unwrap());
                break;
            }
            Err(f) => { future = f; }
        }
    }

    let sreq = world.this_process().immediate_send(&x);
    sreq.cancel();

    let _sreq = CancelGuard::from(world.this_process().immediate_receive_into(&mut y));
}
<|endoftext|>


<commit_before>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::ffi::CString;
use std::cmp::Ordering;
use std::mem;

use libc::c_uint;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , ModuleRef
                      , ValueRef
                      , BuilderRef
                      , TypeRef
                      };

use errors::ExpectICE;
use forktable::ForkTable;
use position::Positional;
use ast::{ Node
         , Form
         , DefForm
         , Ident
         , Function };

use semantic::annotations::{ ScopedState
                           , Scoped
                           };
use semantic::types::*;

/// Result type for compiling an AST node to LLVM IR
///
/// An `IRResult` contains either a `ValueRef`, if compilation was successful,
/// or a `Positional<String>` containing an error message and the position of
/// the line of code which could not be compiled.
pub type IRResult = Result<ValueRef, Vec<Positional<String>>>;

/// Result type for compiling a type to an LLVM `TypeRef`.
pub type TypeResult = Result<TypeRef, Positional<String>>;

pub type NamedValues<'a> = ForkTable<'a, &'a str, ValueRef>;

#[inline] fn word_size() -> usize { mem::size_of::<isize>() }

/// Trait for that which may join in The Great Work
pub trait Compile {
    /// Compile `self` to an LLVM `ValueRef`
    ///
    /// # Returns:
    ///   - `Ok` containing a `ValueRef` if this was compiled correctly.
    ///   - An `Err` with a vector of error messages containing any
    ///     errors that occured during compilation.
    ///
    /// # Panics:
    ///   - If something has gone horribly wrong. This does NOT panic if the
    ///     code could not be compiled because it was incorrect, but it will
    ///     panic in the event of an internal compiler error.
    fn to_ir(&self, context: LLVMContext) -> IRResult;
}

/// Trait for type tags that can be translated to LLVM
pub trait TranslateType {
    /// Translate `self` to an LLVM `TypeRef`
    ///
    /// # Returns:
    ///   - `Ok` containing a `TypeRef` if this was compiled correctly.
    ///   - An `Err` with a positional error message in the event of
    ///     a type error.
    ///
    /// # Panics:
    ///   - In the event of an internal compiler error (i.e. if a well-formed
    ///     type could not be gotten from LLVM correctly).
    fn translate_type(&self, context: LLVMContext) -> TypeResult;
}

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> { pub llctx: ContextRef
                           , pub llmod: ModuleRef
                           , pub llbuilder: BuilderRef
                           , pub names: NamedValues<'a>
                           }

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            ice!( "assertion failed: {} returned null!"
                , stringify!($target)
                );
        } else { e }
    })
}

/// converts a raw pointer that may be null to an Option
/// the compiler will yell about this, claiming that it involves
/// an unused unsafe block, but the unsafe block is usually necessary.
macro_rules! optionalise {
    ($target:expr) => ({
            let e = unsafe { $target };
            if e.is_null() {
                None
            } else { Some(e) }
    })
}

macro_rules! try_vec {
    ($expr:expr) => ({
        if !$expr.is_empty() {
            return Err($expr)
        }
    })
}

impl<'a> LLVMContext<'a> {

    /// Constructs a new LLVM context.
    ///
    /// # Returns:
    ///   - An `LLVMContext`
    ///
    /// # Panics:
    ///   - If the LLVM C ABI returned a null value for the `Context`,
    ///     `Builder`, or `Module`
    pub fn new(module_name: &str) -> Self {
        let name = CString::new(module_name)
                    .expect_ice( &format!(
                                "Could not create C string for module name: {:?}"
                                , module_name
                                ));
        unsafe {
            let ctx = not_null!(llvm::LLVMContextCreate());
            LLVMContext {
                llctx: ctx
              , llmod: not_null!(llvm::LLVMModuleCreateWithNameInContext(name.into_raw(), ctx))
              , llbuilder: not_null!(llvm::LLVMCreateBuilderInContext(ctx))
              , names: NamedValues::new()
            }
        }
    }

    /// Dump the module's contents to stderr for debugging
    ///
    /// Apparently this is the only reasonable way to get a textual
    /// representation of a `ModuleRef` in `librustc_llvm`...
    pub fn dump(&self) {
        unsafe { llvm::LLVMDumpModule(self.llmod); }
    }

    pub fn int_type(&self, size: usize) -> Option<TypeRef> {
        optionalise!(llvm::LLVMIntTypeInContext(self.llctx, size as c_uint))
    }

    pub fn float_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMFloatTypeInContext(self.llctx))
    }
    pub fn double_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMDoubleTypeInContext(self.llctx))
    }
    pub fn byte_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMInt8TypeInContext(self.llctx))
    }

    /// Get any existing declarations for a given function name.
    ///
    /// # Returns:
    ///   - `Some` if there is an existing previous declaration
    ///     for this function.
    ///   - `None` if the function has not been declared previously.
    ///
    /// # Panics:
    ///   - If the C string representation for the function name could
    ///     not be created.
    pub fn existing_decl(&self, name: &Ident) -> Option<ValueRef> {
        CString::new((&name.value).clone())
            .map(|s| optionalise!(s.as_ptr()))
            .map(|o| o.and_then(|p|
                        optionalise!(llvm::LLVMGetNamedFunction(self.llmod, p)))
                )
            .expect_ice(&format!(
                         "Could not create C string for function name: {:?}"
                        , name
                        ))
    }
}

impl<'a> Drop for LLVMContext<'a> {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMDisposeBuilder(self.llbuilder);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}

impl<'a> Compile for Scoped<'a, Form<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            Form::Define(ref form) => unimplemented!()
          , Form::Let(ref form) => unimplemented!()
          , Form::If { .. } => unimplemented!()
          , Form::Call { .. } => unimplemented!()
          , Form::Lambda(ref fun) => unimplemented!()
          , Form::Logical(ref exp) => unimplemented!()
          , Form::Lit(ref c) => unimplemented!()
          , Form::NameRef(ref form) => unimplemented!()
        }
    }
}

impl<'a> Compile for Scoped<'a, DefForm<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            DefForm::TopLevel { ref name, ref value, .. } =>
                unimplemented!()
         ,  DefForm::Function { ref name, ref fun } => {
                match context.existing_decl(name) {
                    Some(previous) => unimplemented!()
                  , None => unimplemented!()
                }
            }
        }
    }
}

impl<'a> Compile for Scoped<'a, Function<'a, ScopedState>> {

    fn to_ir(&self, context: LLVMContext) -> IRResult {
        let mut errs: Vec<Positional<String>> = vec![];
        // Check to see if the pattern binds an equivalent number of arguments
        // as the function signature (minus one, which is the return type).
        for e in &self.equations {
            match e.pattern_length()
                   .cmp(&self.arity()) {
                // the equation's pattern is shorter than the function's arity
                // eventually, we'll autocurry this, but for now, we error.
                // TODO: maybe there should be a warning as well?
                Ordering::Less => errs.push(Positional {
                    pos: e.position.clone()
                  , value: format!( "[error] equation had fewer bindings \
                                     than function arity\n \
                                     [error] auto-currying is not currently \
                                     implemented.\n \
                                     signature: {}\nfunction: {}\n"
                                  , self.sig
                                  , (*e).to_sexpr(0)
                                  )
                  })
                // the equation's pattern is longer than the function's arity
                // this is super wrong and always an error.
              , Ordering::Greater => errs.push(Positional {
                  pos: e.position.clone()
                , value: format!( "[error] equation bound too many arguments\n \
                                   signature: {}\nfunction: {}\n"
                                , self.sig
                                , (*e).to_sexpr(0)
                                )
              })
            , _ =>  {}
            }
        }
        // TODO: this could be made way more idiomatic...
        try_vec!(errs);
        unimplemented!()
    }

}

impl TranslateType for Type {
    fn translate_type(&self, context: LLVMContext) -> TypeResult {
        match *self {
            Type::Ref(ref reference)  => reference.translate_type(context)
          , Type::Prim(ref primitive) => primitive.translate_type(context)
          , _ => unimplemented!() // TODO: figure this out
        }
    }
}

impl TranslateType for Reference {
    fn translate_type(&self, context: LLVMContext) -> TypeResult {
        unimplemented!() // TODO: figure this out
    }
}

impl TranslateType for Primitive {
    fn translate_type(&self, context: LLVMContext) -> TypeResult {
        Ok(match *self { Primitive::IntSize => context.int_type(word_size())
                    , Primitive::UintSize   => context.int_type(word_size())
                    , Primitive::Int(bits)  => context.int_type(bits as usize)
                    , Primitive::Uint(bits) => context.int_type(bits as usize)
                    , Primitive::Float      => context.float_type()
                    , Primitive::Double     => context.double_type()
                    , Primitive::Byte       => context.byte_type()
                    , _ => unimplemented!() // TODO: figure this out
                    }
            .expect_ice( &format!( "Could not get {:?} type from LLVM"
                                 , *self)
                       )
            )
    }
}
<commit_msg>Begin porting codegen to `iron_llvm`<commit_after>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::ffi::CString;
use std::cmp::Ordering;
use std::mem;

use libc::c_uint;
use llvm_sys::prelude::LLVMValueRef;

use iron_llvm::core;
use iron_llvm::core::types::{ Type
                            , TypeCtor
                            , RealTypeCtor
                            , RealTypeRef
                            , IntTypeCtor
                            , IntTypeRef
                            };
use iron_llvm::{LLVMRef, LLVMRefCtor};

use errors::ExpectICE;
use forktable::ForkTable;
use position::Positional;
use ast::{ Node
         , Form
         , DefForm
         , Ident
         , Function };

use semantic::annotations::{ ScopedState
                           , Scoped
                           };
use semantic::types;
use semantic::types::{ Primitive
                    , Reference
                    };

/// Result type for compiling an AST node to LLVM IR
///
/// An `IRResult` contains either a `ValueRef`, if compilation was successful,
/// or a `Positional<String>` containing an error message and the position of
/// the line of code which could not be compiled.
pub type IRResult = Result<LLVMValueRef, Vec<Positional<String>>>;

/// Result type for compiling a type to an LLVM `TypeRef`.
pub type TypeResult<T: Type + Sized> = Result<T, Positional<String>>;

pub type NamedValues<'a> = ForkTable<'a, &'a str, LLVMValueRef>;

#[inline] fn word_size() -> usize { mem::size_of::<isize>() }

/// Trait for that which may join in The Great Work
pub trait Compile {
    /// Compile `self` to an LLVM `ValueRef`
    ///
    /// # Returns:
    ///   - `Ok` containing a `ValueRef` if this was compiled correctly.
    ///   - An `Err` with a vector of error messages containing any
    ///     errors that occured during compilation.
    ///
    /// # Panics:
    ///   - If something has gone horribly wrong. This does NOT panic if the
    ///     code could not be compiled because it was incorrect, but it will
    ///     panic in the event of an internal compiler error.
    fn to_ir(&self, context: LLVMContext) -> IRResult;
}

/// Trait for type tags that can be translated to LLVM
// pub trait TranslateType {
//     /// Translate `self` to an LLVM `TypeRef`
//     ///
//     /// # Returns:
//     ///   - `Ok` containing a `TypeRef` if this was compiled correctly.
//     ///   - An `Err` with a positional error message in the event of
//     ///     a type error.
//     ///
//     /// # Panics:
//     ///   - In the event of an internal compiler error (i.e. if a well-formed
//     ///     type could not be gotten from LLVM correctly).
//     fn translate_type(&self, context: LLVMContext) -> TypeResult;
// }

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> { llctx: core::Context
                           , llmod: core::Module
                           , llbuilder: core::Builder
                           , named_vals: NamedValues<'a>
                           }

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            ice!( "assertion failed: {} returned null!"
                , stringify!($target)
                );
        } else { e }
    })
}

/// converts a raw pointer that may be null to an Option
/// the compiler will yell about this, claiming that it involves
/// an unused unsafe block, but the unsafe block is usually necessary.
macro_rules! optionalise {
    ($target:expr) => ({
            let e = unsafe { $target };
            if e.is_null() {
                None
            } else { Some(e) }
    })
}

macro_rules! try_vec {
    ($expr:expr) => ({
        if !$expr.is_empty() {
            return Err($expr)
        }
    })
}

impl<'a> LLVMContext<'a> {

    /// Constructs a new LLVM context.
    ///
    /// # Returns:
    ///   - An `LLVMContext`
    ///
    /// # Panics:
    ///   - If the LLVM C ABI returned a null value for the `Context`,
    ///     `Builder`, or `Module`
    pub fn new(module_name: &str) -> Self {
        LLVMContext { llctx: core::Context::get_global()
                    , llmod: core::Module::new(module_name)
                    , llbuilder: core::Builder::new()
                    , named_vals: NamedValues::new()
                    }
    }

    /// Dump the module's contents to stderr for debugging
    ///
    /// Apparently this is the only reasonable way to get a textual
    /// representation of a `Module` in LLVM
    pub fn dump(&self) { self.llmod.dump() }

    pub fn int_type(&self, size: usize) -> IntTypeRef {
        IntTypeRef::get_int_in_context(&self.llctx, size as c_uint)
    }

    pub fn float_type(&self) -> RealTypeRef {
        RealTypeRef::get_float_in_context(&self.llctx)
    }
    pub fn double_type(&self) -> RealTypeRef {
        RealTypeRef::get_double_in_context(&self.llctx)
    }
    pub fn byte_type(&self) -> IntTypeRef {
        IntTypeRef::get_int8_in_context(&self.llctx)
    }

    /// Get any existing declarations for a given function name.
    ///
    /// # Returns:
    ///   - `Some` if there is an existing previous declaration
    ///     for this function.
    ///   - `None` if the function has not been declared previously.
    ///
    /// # Panics:
    ///   - If the C string representation for the function name could
    ///     not be created.
    pub fn get_fn(&self, name: &Ident) -> Option<core::FunctionRef> {
        self.llmod.get_function_by_name(name.value.as_ref())
    }
}

impl<'a> Compile for Scoped<'a, Form<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            Form::Define(ref form) => unimplemented!()
          , Form::Let(ref form) => unimplemented!()
          , Form::If { .. } => unimplemented!()
          , Form::Call { .. } => unimplemented!()
          , Form::Lambda(ref fun) => unimplemented!()
          , Form::Logical(ref exp) => unimplemented!()
          , Form::Lit(ref c) => unimplemented!()
          , Form::NameRef(ref form) => unimplemented!()
        }
    }
}

impl<'a> Compile for Scoped<'a, DefForm<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            DefForm::TopLevel { ref name, ref value, .. } =>
                unimplemented!()
         ,  DefForm::Function { ref name, ref fun } => {
                match context.get_fn(name) {
                    Some(previous) => unimplemented!()
                  , None => unimplemented!()
                }
            }
        }
    }
}

impl<'a> Compile for Scoped<'a, Function<'a, ScopedState>> {

    fn to_ir(&self, context: LLVMContext) -> IRResult {
        let mut errs: Vec<Positional<String>> = vec![];
        // Check to see if the pattern binds an equivalent number of arguments
        // as the function signature (minus one, which is the return type).
        for e in &self.equations {
            match e.pattern_length()
                   .cmp(&self.arity()) {
                // the equation's pattern is shorter than the function's arity
                // eventually, we'll autocurry this, but for now, we error.
                // TODO: maybe there should be a warning as well?
                Ordering::Less => errs.push(Positional {
                    pos: e.position.clone()
                  , value: format!( "[error] equation had fewer bindings \
                                     than function arity\n \
                                     [error] auto-currying is not currently \
                                     implemented.\n \
                                     signature: {}\nfunction: {}\n"
                                  , self.sig
                                  , (*e).to_sexpr(0)
                                  )
                  })
                // the equation's pattern is longer than the function's arity
                // this is super wrong and always an error.
              , Ordering::Greater => errs.push(Positional {
                  pos: e.position.clone()
                , value: format!( "[error] equation bound too many arguments\n \
                                   signature: {}\nfunction: {}\n"
                                , self.sig
                                , (*e).to_sexpr(0)
                                )
              })
            , _ =>  {}
            }
        }
        // TODO: this could be made way more idiomatic...
        try_vec!(errs);
        unimplemented!()
    }

}

// impl TranslateType for types::Type {
//     fn translate_type(&self, context: LLVMContext) -> TypeResult {
//         match *self {
//             types::Type::Ref(ref r) => r.translate_type(context)
//           , types::Type::Prim(ref p) => p.translate_type(context)
//           , _ => unimplemented!() // TODO: figure this out
//         }
//     }
// }

// impl TranslateType for Reference {
//     fn translate_type(&self, context: LLVMContext) -> TypeResult {
//         unimplemented!() // TODO: figure this out
//     }
// }

// impl TranslateType for Primitive {
//     fn translate_type(&self, context: LLVMContext) -> TypeResult {
//     //     Ok(match *self {
//     //         Primitive::IntSize => context.int_type(word_size())
//     //       , Primitive::UintSize => context.int_type(word_size())
//     //       , Primitive::Int(bits) => context.int_type(bits as usize)
//     //       , Primitive::Uint(bits) => context.int_type(bits as usize)
//     //       , Primitive::Float => context.float_type()
//     //       , Primitive::Double => context.double_type()
//     //       , Primitive::Byte => context.byte_type()
//     //       , _ => unimplemented!() // TODO: figure this out
//     //   })
//         unimplemented!()
//     }
// }
<|endoftext|>


<commit_before>use std::fmt::{self, Formatter, Debug};

use gc_error::GcError;
use super::binding::Binding;
use super::js_var::{JsPtrEnum, JsVar};

pub trait JsScope {
    fn alloc(&mut self, var: JsVar);
    fn load(&self, bnd: &Binding) -> Result<(JsVar, Option<JsPtrEnum>), GcError>;
    fn store(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<(), GcError>;
}

#[derive(Clone)]
pub struct NativeFn(fn(Box<JsScope>, Vec<JsVar>) -> JsVar);

impl Debug for NativeFn {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "[native_code]")
    }
}
<commit_msg>fix inconsistency between JsScope and ScopeManager<commit_after>use std::fmt::{self, Formatter, Debug};

use gc_error::GcError;
use super::binding::Binding;
use super::js_var::{JsPtrEnum, JsVar};

pub trait JsScope {
    fn alloc(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<Binding, GcError>;
    fn load(&self, bnd: &Binding) -> Result<(JsVar, Option<JsPtrEnum>), GcError>;
    fn store(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<(), GcError>;
}

#[derive(Clone)]
pub struct NativeFn(fn(Box<JsScope>, Vec<JsVar>) -> JsVar);

impl Debug for NativeFn {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "[native_code]")
    }
}
<|endoftext|>