<commit_before>use std::collections::HashMap;
use std::fs;
use std::path::*;
use std::io::{Result, Write};
use case::CaseExt;

use analysis::rust_type::parameter_rust_type;
use env::Env;
use file_saver::*;
use library;
use nameutil::*;
use super::ffi_type::ffi_type;
use super::functions;
use super::statics;
use super::super::general::{self, tabs};
use traits::*;

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

    let path =  PathBuf::from(&env.config.target_path)
        .join(file_name_sys("lib"));

    let parent = path.parent().unwrap();
    //TODO: do only if not exists
    let _ = fs::create_dir_all(parent);

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

fn generate_lib<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    try!(general::start_comments(w, &env.config));
    try!(statics::begin(w));

    try!(generate_extern_crates(w, env));
    try!(statics::after_extern_crates(w));

    if env.config.library_name != "GLib" {
        try!(statics::use_glib(w));
    }
    match &*env.config.library_name {
        "GLib" => try!(statics::only_for_glib(w)),
        "GObject" => try!(statics::only_for_gobject(w)),
        "Gtk" => try!(statics::only_for_gtk(w)),
        _ => (),
    }

    let ns = env.library.namespace(library::MAIN_NAMESPACE);
    let records = prepare(ns);
    let classes = prepare(ns);
    let interfaces = prepare(ns);

    try!(generate_aliases(w, env, &prepare(ns)));
    try!(generate_enums(w, &prepare(ns)));
    try!(generate_constants(w, env, &ns.constants));
    try!(generate_bitfields(w, &prepare(ns)));
    try!(generate_unions(w, &prepare(ns)));
    try!(functions::generate_callbacks(w, env, &prepare(ns)));
    try!(generate_records(w, env, &records));
    try!(generate_classes_structs(w, &classes));
    try!(generate_interfaces_structs(w, &interfaces));

    try!(writeln!(w, ""));
    try!(writeln!(w, "extern \"C\" {{"));
    try!(functions::generate_records_funcs(w, env, &records));
    try!(functions::generate_classes_funcs(w, env, &classes));
    try!(functions::generate_interfaces_funcs(w, env, &interfaces));
    try!(functions::generate_other_funcs(w, env, &ns.functions));

    try!(writeln!(w, "\n}}"));

    Ok(())
}

fn generate_extern_crates<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    for library_name in &env.config.external_libraries {
        try!(writeln!(w, "extern crate {0}_sys as {0};", crate_name(library_name)));
    }

    Ok(())
}

fn prepare<T: Ord>(ns: &library::Namespace) -> Vec<&T>
where library::Type: MaybeRef<T> {
    let mut vec: Vec<&T> = Vec::with_capacity(ns.types.len());
    for typ in ns.types.iter().filter_map(|t| t.as_ref()) {
        if let Some(ref x) = typ.maybe_ref() {
            vec.push(x);
        }
    }
    vec.sort();
    vec
}

fn generate_aliases<W: Write>(w: &mut W, env: &Env, items: &[&library::Alias])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        let (comment, c_type) = match ffi_type(env, item.typ, &item.target_c_type) {
            Ok(x) => ("", x),
            Err(x) => ("//", x),
        };
        try!(writeln!(w, "{}pub type {} = {};", comment, item.c_identifier, c_type));
    }

    Ok(())
}

fn generate_bitfields<W: Write>(w: &mut W, items: &[&library::Bitfield])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        try!(writeln!(w, "bitflags! {{\n{}#[repr(C)]\n{0}flags {}: c_uint {{",
                      tabs(1), item.c_type));
        for member in &item.members {
            let val: i64 = member.value.parse().unwrap();
            try!(writeln!(w, "{}const {} = {},", tabs(2), member.c_identifier, val as u32));
        }
        try!(writeln!(w, "{}}}\n}}", tabs(1)));
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_constants<W: Write>(w: &mut W, env: &Env, constants: &[library::Constant]) -> Result<()> {
    try!(writeln!(w, ""));
    for constant in constants {
        let (mut comment, mut type_) = match parameter_rust_type(env, constant.typ, library::ParameterDirection::In) {
            Ok(x) => ("", x),
            Err(x) => ("//", x),
        };
        if env.type_status_sys(&format!("{}.{}", env.config.library_name,
            constant.name)).ignored() {
            comment = "//";
        }
        let mut value = constant.value.clone();
        if type_ == "&str" {
            type_ = "&'static str".into();
            value = format!("r##\"{}\"##", value);
        }
        try!(writeln!(w, "{}pub const {}: {} = {};", comment,
            constant.c_identifier, type_, value));
    }

    Ok(())
}

fn generate_enums<W: Write>(w: &mut W, items: &[&library::Enumeration])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        if item.members.len() == 1 {
            try!(writeln!(w, "pub type {} = c_int;", item.name));
            try!(writeln!(w, "pub const {}: {} = {};",
                          item.members[0].c_identifier, item.name, item.members[0].value));
            try!(writeln!(w, "pub type {} = {};", item.c_type, item.name));
            try!(writeln!(w, ""));
            continue;
        }

        let mut vals = HashMap::new();
        try!(writeln!(w, "#[derive(Clone, Copy, Debug, Eq, PartialEq)]\n#[repr(C)]"));
        try!(writeln!(w, "pub enum {} {{", item.c_type));
        for member in &item.members {
            if vals.get(&member.value).is_some() {
                continue;
            }
            try!(writeln!(w, "{}{} = {},",
                          tabs(1), &prepare_enum_member_name(&member.name), member.value));
            vals.insert(member.value.clone(), member.name.clone());
        }
        try!(writeln!(w, "}}"));
        for member in &item.members {
            try!(writeln!(w, "pub const {}: {} = {1}::{};", member.c_identifier, item.c_type,
                          &prepare_enum_member_name(vals.get(&member.value).unwrap())));
        }
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_unions<W: Write>(w: &mut W, items: &[&library::Union])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        if let Some(ref c_type) = item.c_type {
            try!(writeln!(w, "pub type {} = c_void; // union", c_type));
        }
    }
    try!(writeln!(w, ""));

    Ok(())
}

fn prepare_enum_member_name(name: &str) -> String {
    let cameled = name.to_camel();
    if name.chars().next().unwrap().is_digit(10) {
        format!("_{}", cameled)
    } else {
        cameled
    }
}

fn generate_classes_structs<W: Write>(w: &mut W, classes: &[&library::Class]) -> Result<()> {
    try!(writeln!(w, ""));
    for klass in classes {
        try!(writeln!(w, "#[repr(C)]\npub struct {};", klass.c_type));
    }

    Ok(())
}

fn generate_interfaces_structs<W: Write>(w: &mut W, interfaces: &[&library::Interface]) -> Result<()> {
    try!(writeln!(w, ""));
    for interface in interfaces {
        try!(writeln!(w, "#[repr(C)]\npub struct {};", interface.c_type));
    }

    Ok(())
}

fn generate_records<W: Write>(w: &mut W, env: &Env, records: &[&library::Record]) -> Result<()> {
    try!(writeln!(w, ""));
    for record in records {
        let mut lines = Vec::new();
        let mut commented = false;
        let mut truncated = false;
        for field in &record.fields {
            let is_union = env.library.type_(field.typ).maybe_ref_as::<library::Union>().is_some();
            let is_bits = field.bits.is_some();
            if !truncated && (is_union || is_bits) {
                warn!("Record `{}` field `{}` not expressible in Rust, truncated",
                      record.name, field.name);
                lines.push(format!("{}_truncated_record_marker: (),", tabs(1)));
                truncated = true;
            }
            if truncated {
                if is_union {
                    lines.push(format!("{}//union,", tabs(1)));
                }
                else {
                    let bits = field.bits.map(|n| format!(": {}", n)).unwrap_or("".into());
                    lines.push(
                        format!("{}//{}: {}{},", tabs(1), field.name,
                                field.c_type.as_ref().map(|s| &s[..]).unwrap_or("fn"), bits));
                };
                continue;
            }

            let vis = if field.private { "" } else { "pub " };

            if let Some(ref c_type) = field.c_type {
                let name = mangle_keywords(&*field.name);
                let c_type = ffi_type(env, field.typ, c_type);
                lines.push(format!("{}{}{}: {},", tabs(1), vis, name, c_type.as_str()));
                if c_type.is_err() {
                    commented = true;
                }
            }
            else {
                let name = mangle_keywords(&*field.name);
                if let Some(ref func) =
                        env.library.type_(field.typ).maybe_ref_as::<library::Function>() {
                    let (com, sig) = functions::function_signature(env, func, true);
                    lines.push(format!("{}{}{}: Option<unsafe extern \"C\" fn{}>,", tabs(1), vis, name, sig));
                    commented |= com;
                }
                else if let Some(c_type) = env.library.type_(field.typ).get_glib_name() {
                    warn!("Record `{}`, field `{}` missing c:type assumed `{}`",
                          record.name, field.name, c_type);
                    let c_type = ffi_type(env, field.typ, c_type);
                    lines.push(format!("{}{}{}: {},", tabs(1), vis, name, c_type.as_str()));
                    if c_type.is_err() {
                        commented = true;
                    }
                }
                else {
                    lines.push(format!("{}{}{}: [{:?} {}],", tabs(1),
                        vis, name, field.typ, field.typ.full_name(&env.library)));
                    commented = true;
                }
            }
        }
        let comment = if commented { "//" } else { "" };
        if lines.is_empty() {
            try!(writeln!(w, "{}#[repr(C)]\n{0}pub struct {};\n", comment, record.c_type));
        }
        else {
            try!(writeln!(w, "{}#[repr(C)]\n{0}pub struct {} {{", comment, record.c_type));
            for line in lines {
                try!(writeln!(w, "{}{}", comment, line));
            }
            try!(writeln!(w, "{}}}\n", comment));
        }
    }
    Ok(())
}
<commit_msg>sys: use c_void instead of empty Rust types<commit_after>use std::collections::HashMap;
use std::fs;
use std::path::*;
use std::io::{Result, Write};
use case::CaseExt;

use analysis::rust_type::parameter_rust_type;
use env::Env;
use file_saver::*;
use library;
use nameutil::*;
use super::ffi_type::ffi_type;
use super::functions;
use super::statics;
use super::super::general::{self, tabs};
use traits::*;

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

    let path =  PathBuf::from(&env.config.target_path)
        .join(file_name_sys("lib"));

    let parent = path.parent().unwrap();
    //TODO: do only if not exists
    let _ = fs::create_dir_all(parent);

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

fn generate_lib<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    try!(general::start_comments(w, &env.config));
    try!(statics::begin(w));

    try!(generate_extern_crates(w, env));
    try!(statics::after_extern_crates(w));

    if env.config.library_name != "GLib" {
        try!(statics::use_glib(w));
    }
    match &*env.config.library_name {
        "GLib" => try!(statics::only_for_glib(w)),
        "GObject" => try!(statics::only_for_gobject(w)),
        "Gtk" => try!(statics::only_for_gtk(w)),
        _ => (),
    }

    let ns = env.library.namespace(library::MAIN_NAMESPACE);
    let records = prepare(ns);
    let classes = prepare(ns);
    let interfaces = prepare(ns);

    try!(generate_aliases(w, env, &prepare(ns)));
    try!(generate_enums(w, &prepare(ns)));
    try!(generate_constants(w, env, &ns.constants));
    try!(generate_bitfields(w, &prepare(ns)));
    try!(generate_unions(w, &prepare(ns)));
    try!(functions::generate_callbacks(w, env, &prepare(ns)));
    try!(generate_records(w, env, &records));
    try!(generate_classes_structs(w, &classes));
    try!(generate_interfaces_structs(w, &interfaces));

    try!(writeln!(w, ""));
    try!(writeln!(w, "extern \"C\" {{"));
    try!(functions::generate_records_funcs(w, env, &records));
    try!(functions::generate_classes_funcs(w, env, &classes));
    try!(functions::generate_interfaces_funcs(w, env, &interfaces));
    try!(functions::generate_other_funcs(w, env, &ns.functions));

    try!(writeln!(w, "\n}}"));

    Ok(())
}

fn generate_extern_crates<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    for library_name in &env.config.external_libraries {
        try!(writeln!(w, "extern crate {0}_sys as {0};", crate_name(library_name)));
    }

    Ok(())
}

fn prepare<T: Ord>(ns: &library::Namespace) -> Vec<&T>
where library::Type: MaybeRef<T> {
    let mut vec: Vec<&T> = Vec::with_capacity(ns.types.len());
    for typ in ns.types.iter().filter_map(|t| t.as_ref()) {
        if let Some(ref x) = typ.maybe_ref() {
            vec.push(x);
        }
    }
    vec.sort();
    vec
}

fn generate_aliases<W: Write>(w: &mut W, env: &Env, items: &[&library::Alias])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        let (comment, c_type) = match ffi_type(env, item.typ, &item.target_c_type) {
            Ok(x) => ("", x),
            Err(x) => ("//", x),
        };
        try!(writeln!(w, "{}pub type {} = {};", comment, item.c_identifier, c_type));
    }

    Ok(())
}

fn generate_bitfields<W: Write>(w: &mut W, items: &[&library::Bitfield])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        try!(writeln!(w, "bitflags! {{\n{}#[repr(C)]\n{0}flags {}: c_uint {{",
                      tabs(1), item.c_type));
        for member in &item.members {
            let val: i64 = member.value.parse().unwrap();
            try!(writeln!(w, "{}const {} = {},", tabs(2), member.c_identifier, val as u32));
        }
        try!(writeln!(w, "{}}}\n}}", tabs(1)));
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_constants<W: Write>(w: &mut W, env: &Env, constants: &[library::Constant]) -> Result<()> {
    try!(writeln!(w, ""));
    for constant in constants {
        let (mut comment, mut type_) = match parameter_rust_type(env, constant.typ, library::ParameterDirection::In) {
            Ok(x) => ("", x),
            Err(x) => ("//", x),
        };
        if env.type_status_sys(&format!("{}.{}", env.config.library_name,
            constant.name)).ignored() {
            comment = "//";
        }
        let mut value = constant.value.clone();
        if type_ == "&str" {
            type_ = "&'static str".into();
            value = format!("r##\"{}\"##", value);
        }
        try!(writeln!(w, "{}pub const {}: {} = {};", comment,
            constant.c_identifier, type_, value));
    }

    Ok(())
}

fn generate_enums<W: Write>(w: &mut W, items: &[&library::Enumeration])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        if item.members.len() == 1 {
            try!(writeln!(w, "pub type {} = c_int;", item.name));
            try!(writeln!(w, "pub const {}: {} = {};",
                          item.members[0].c_identifier, item.name, item.members[0].value));
            try!(writeln!(w, "pub type {} = {};", item.c_type, item.name));
            try!(writeln!(w, ""));
            continue;
        }

        let mut vals = HashMap::new();
        try!(writeln!(w, "#[derive(Clone, Copy, Debug, Eq, PartialEq)]\n#[repr(C)]"));
        try!(writeln!(w, "pub enum {} {{", item.c_type));
        for member in &item.members {
            if vals.get(&member.value).is_some() {
                continue;
            }
            try!(writeln!(w, "{}{} = {},",
                          tabs(1), &prepare_enum_member_name(&member.name), member.value));
            vals.insert(member.value.clone(), member.name.clone());
        }
        try!(writeln!(w, "}}"));
        for member in &item.members {
            try!(writeln!(w, "pub const {}: {} = {1}::{};", member.c_identifier, item.c_type,
                          &prepare_enum_member_name(vals.get(&member.value).unwrap())));
        }
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_unions<W: Write>(w: &mut W, items: &[&library::Union])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        if let Some(ref c_type) = item.c_type {
            try!(writeln!(w, "pub type {} = c_void; // union", c_type));
        }
    }
    try!(writeln!(w, ""));

    Ok(())
}

fn prepare_enum_member_name(name: &str) -> String {
    let cameled = name.to_camel();
    if name.chars().next().unwrap().is_digit(10) {
        format!("_{}", cameled)
    } else {
        cameled
    }
}

fn generate_classes_structs<W: Write>(w: &mut W, classes: &[&library::Class]) -> Result<()> {
    try!(writeln!(w, ""));
    for klass in classes {
        try!(writeln!(w, "#[repr(C)]\npub struct {}(c_void);", klass.c_type));
    }

    Ok(())
}

fn generate_interfaces_structs<W: Write>(w: &mut W, interfaces: &[&library::Interface]) -> Result<()> {
    try!(writeln!(w, ""));
    for interface in interfaces {
        try!(writeln!(w, "#[repr(C)]\npub struct {}(c_void);", interface.c_type));
    }

    Ok(())
}

fn generate_records<W: Write>(w: &mut W, env: &Env, records: &[&library::Record]) -> Result<()> {
    try!(writeln!(w, ""));
    for record in records {
        let mut lines = Vec::new();
        let mut commented = false;
        let mut truncated = false;
        for field in &record.fields {
            let is_union = env.library.type_(field.typ).maybe_ref_as::<library::Union>().is_some();
            let is_bits = field.bits.is_some();
            if !truncated && (is_union || is_bits) {
                warn!("Record `{}` field `{}` not expressible in Rust, truncated",
                      record.name, field.name);
                lines.push(format!("{}_truncated_record_marker: c_void,", tabs(1)));
                truncated = true;
            }
            if truncated {
                if is_union {
                    lines.push(format!("{}//union,", tabs(1)));
                }
                else {
                    let bits = field.bits.map(|n| format!(": {}", n)).unwrap_or("".into());
                    lines.push(
                        format!("{}//{}: {}{},", tabs(1), field.name,
                                field.c_type.as_ref().map(|s| &s[..]).unwrap_or("fn"), bits));
                };
                continue;
            }

            let vis = if field.private { "" } else { "pub " };

            if let Some(ref c_type) = field.c_type {
                let name = mangle_keywords(&*field.name);
                let c_type = ffi_type(env, field.typ, c_type);
                lines.push(format!("{}{}{}: {},", tabs(1), vis, name, c_type.as_str()));
                if c_type.is_err() {
                    commented = true;
                }
            }
            else {
                let name = mangle_keywords(&*field.name);
                if let Some(ref func) =
                        env.library.type_(field.typ).maybe_ref_as::<library::Function>() {
                    let (com, sig) = functions::function_signature(env, func, true);
                    lines.push(format!("{}{}{}: Option<unsafe extern \"C\" fn{}>,", tabs(1), vis, name, sig));
                    commented |= com;
                }
                else if let Some(c_type) = env.library.type_(field.typ).get_glib_name() {
                    warn!("Record `{}`, field `{}` missing c:type assumed `{}`",
                          record.name, field.name, c_type);
                    let c_type = ffi_type(env, field.typ, c_type);
                    lines.push(format!("{}{}{}: {},", tabs(1), vis, name, c_type.as_str()));
                    if c_type.is_err() {
                        commented = true;
                    }
                }
                else {
                    lines.push(format!("{}{}{}: [{:?} {}],", tabs(1),
                        vis, name, field.typ, field.typ.full_name(&env.library)));
                    commented = true;
                }
            }
        }
        let comment = if commented { "//" } else { "" };
        if lines.is_empty() {
            try!(writeln!(w, "{}#[repr(C)]\n{0}pub struct {}(c_void);\n", comment, record.c_type));
        }
        else {
            try!(writeln!(w, "{}#[repr(C)]\n{0}pub struct {} {{", comment, record.c_type));
            for line in lines {
                try!(writeln!(w, "{}{}", comment, line));
            }
            try!(writeln!(w, "{}}}\n", comment));
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>pub struct RoomGen;
<commit_msg>new branch<commit_after>use rand::os::OsRng;
use rand::XorShiftRng;
use rand::Rand;
use rand::Rng;

pub struct RoomGen {
    rand: XorShiftRng,
}
<|endoftext|>


<commit_before>//! Implementation of `Filter` for certain non-probabilistic data structures. This can be helpful
//! for debugging and performance comparisons.
use std::collections::HashSet;
use std::hash::Hash;

use void::Void;

use crate::filters::Filter;

impl<T> Filter<T> for HashSet<T>
where
    T: Clone + Eq + Hash,
{
    type InsertErr = Void;

    fn clear(&mut self) {
        self.clear();
    }

    fn insert(&mut self, obj: &T) -> Result<bool, Self::InsertErr> {
        Ok(self.insert(obj.clone()))
    }

    fn is_empty(&self) -> bool {
        self.is_empty()
    }

    fn len(&self) -> usize {
        self.len()
    }

    fn query(&self, obj: &T) -> bool {
        self.contains(obj)
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashSet;

    use void::Void;

    use crate::filters::Filter;

    #[test]
    fn hashset() {
        let set: &mut Filter<u64, InsertErr = Void> = &mut HashSet::new();
        assert!(set.is_empty());
        assert_eq!(set.len(), 0);
        assert!(!set.query(&42));

        assert!(set.insert(&42).unwrap());
        assert!(!set.insert(&42).unwrap());
        assert!(!set.is_empty());
        assert_eq!(set.len(), 1);
        assert!(set.query(&42));
        assert!(!set.query(&13));
    }
}
<commit_msg>filters: impl Filter for non-standard HashSets<commit_after>//! Implementation of `Filter` for certain non-probabilistic data structures. This can be helpful
//! for debugging and performance comparisons.
use std::collections::HashSet;
use std::hash::{BuildHasher, Hash};

use void::Void;

use crate::filters::Filter;

impl<T, S> Filter<T> for HashSet<T, S>
where
    T: Clone + Eq + Hash,
    S: BuildHasher,
{
    type InsertErr = Void;

    fn clear(&mut self) {
        self.clear();
    }

    fn insert(&mut self, obj: &T) -> Result<bool, Self::InsertErr> {
        Ok(self.insert(obj.clone()))
    }

    fn is_empty(&self) -> bool {
        self.is_empty()
    }

    fn len(&self) -> usize {
        self.len()
    }

    fn query(&self, obj: &T) -> bool {
        self.contains(obj)
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashSet;

    use void::Void;

    use crate::filters::Filter;

    #[test]
    fn hashset() {
        let set: &mut Filter<u64, InsertErr = Void> = &mut HashSet::new();
        assert!(set.is_empty());
        assert_eq!(set.len(), 0);
        assert!(!set.query(&42));

        assert!(set.insert(&42).unwrap());
        assert!(!set.insert(&42).unwrap());
        assert!(!set.is_empty());
        assert_eq!(set.len(), 1);
        assert!(set.query(&42));
        assert!(!set.query(&13));
    }
}
<|endoftext|>


<commit_before>mod Worksheet;
// Basic excel

struct Basic_Excel {
    pub file_: Compound_File,                  // Compound file handler.
    pub workbook_: Workbook,                   // Raw Workbook.
    pub worksheets_: Vec<Worksheet::Worksheet>,// Raw Worksheets.
    pub yesheets_: Vec<Basic_Excel_Worksheet>, // Parsed Worksheets.
}

impl Basic_Excel {

    // File functions
    pub fn new(sheets: i32) {

    }

    pub fn load<T>(filename: T) -> bool {

    }

    pub fn save() -> bool {

    }

    pub fn save_as<T>(filename: T) -> bool {

    }

    pub fn close() {

    }

    // Worksheet functions
    pub fn get_total_worksheets() -> i32 {

    }

    pub fn get_worksheet<T>(sheet_index: T) -> Basic_Excel_Worksheet {

    }

    pub fn add_worksheet<T>(sheet_index: T) -> Basic_Excel_Worksheet {

    }

    pub fn delete_worksheet<T>(sheet_index: T) -> bool {

    }

    pub fn get_ansi_sheet_name(sheet_index: i32) {
        panic!("Rust operates completely in UTF-8 Unicode strings and as such there's no reason return an ANSI version.");
    }

    pub fn get_unicode_sheet_name(sheet_index: i32) -> String {

    }

    pub fn get_sheet_name(sheet_index: i32) -> (bool, String) {

    }

    pub fn rename_worksheet_from_index(sheet_index: i32, to: &str) -> bool {

    }

    pub fn rename_worksheet_from_str(from: &str, to: &str) -> bool {

    }

}

struct Basic_Excel_Worksheet {
    pub excel_: Basic_Excel,
    pub sheet_index: i32,
    pub max_rows_: i32,
    pub max_cols_: i32,
    pub cells_: Vec<Basic_Excel_Cell>,
    pub col_infos_: Worksheet::Col_Infos,
}

impl Basic_Excel_Worksheet {

}

struct Compound_File;

struct Workbook;

struct Basic_Excel_Cell;

<commit_msg>Functional (buildable) skeleton<commit_after>mod Worksheet;
// Basic excel

struct Basic_Excel {
    pub file_: Compound_File,                  // Compound file handler.
    pub workbook_: Workbook,                   // Raw Workbook.
    pub worksheets_: Vec<Worksheet::Worksheet>,// Raw Worksheets.
    pub yesheets_: Vec<Basic_Excel_Worksheet>, // Parsed Worksheets.
}

impl Basic_Excel {

    pub fn new() -> Basic_Excel {
        return Basic_Excel{file_: Compound_File, workbook_: Workbook, worksheets_: vec![Worksheet::Worksheet], yesheets_: vec![Basic_Excel_Worksheet::new()]};
    }

    // File functions
    pub fn new_with_sheets(sheets: i32) {

    }

    pub fn load<T>(filename: T) -> bool {
        let mut result = false;

        return result;
    }

    pub fn save() -> bool {
        let mut result = false;

        return result;
    }

    pub fn save_as<T>(filename: T) -> bool {
        let mut result = false;

        return result;
    }

    pub fn close() {

    }

    // Worksheet functions
    pub fn get_total_worksheets() -> i32 {
        let mut result = 0;

        return result;
    }

    pub fn get_worksheet<T>(sheet_index: T) -> Basic_Excel_Worksheet {
        let mut result = Basic_Excel_Worksheet::new();

        return result;
    }

    pub fn add_worksheet<T>(sheet_index: T) -> Basic_Excel_Worksheet {
        let mut result = Basic_Excel_Worksheet::new();

        return result;
    }

    pub fn delete_worksheet<T>(sheet_index: T) -> bool {
        let mut result = false;

        return result;
    }

    pub fn get_ansi_sheet_name(sheet_index: i32) {
        panic!("Rust operates completely in UTF-8 Unicode strings and as such there's no reason return an ANSI version.");
    }

    pub fn get_unicode_sheet_name(sheet_index: i32) -> String {
        let mut result = String::new();

        return result;
    }

    pub fn get_sheet_name(sheet_index: i32) -> (bool, String) {
        let mut result = false;
        let mut name = String::new();

        return (result, name);
    }

    pub fn rename_worksheet_from_index(sheet_index: i32, to: &str) -> bool {
        let mut result = false;

        return result;
    }

    pub fn rename_worksheet_from_str(from: &str, to: &str) -> bool {
        let mut result = false;

        return result;
    }

}

struct Basic_Excel_Worksheet {
    pub excel_: Basic_Excel,
    pub sheet_index_: i32,
    pub max_rows_: i32,
    pub max_cols_: i32,
    pub cells_: Vec<Basic_Excel_Cell>,
    pub col_infos_: Worksheet::Col_Infos,
}

impl Basic_Excel_Worksheet {
    pub fn new() -> Basic_Excel_Worksheet {
        return Basic_Excel_Worksheet{excel_: Basic_Excel::new(), sheet_index_: 0, max_rows_: 0, max_cols_: 0, cells_: vec![Basic_Excel_Cell], col_infos_: Worksheet::Col_Infos};
    }
}

struct Compound_File;

struct Workbook;

struct Basic_Excel_Cell;

<|endoftext|>


<commit_before>use std::borrow::Cow;

use rustc::mir::interpret::{
    read_target_uint, AllocId, AllocKind, Allocation, ConstValue, EvalResult, GlobalId, Scalar,
};
use rustc::ty::{Const, LazyConst};
use rustc_mir::interpret::{
    EvalContext, MPlaceTy, Machine, Memory, MemoryKind, OpTy, PlaceTy, Pointer, StackPopCleanup,
};

use cranelift_module::*;

use crate::prelude::*;

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        //println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        //println!("done {:?}", self.done);
        self.done.clear();
    }
}

pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
    ccx.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id, Linkage::Import);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        }))
        .unwrap();

    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

pub fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx LazyConst<'tcx>,
) -> Const<'tcx> {
    match *const_ {
        LazyConst::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        LazyConst::Evaluated(const_) => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        ty::Bool => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Uint(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Int(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        ty::FnDef(_def_id, _substs) => {
            CValue::ByRef(
                fx.bcx.ins().iconst(fx.pointer_type, 0),
                layout
            )
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: Const<'tcx>,
) -> CPlace<'tcx> {
    // Adapted from https://github.com/rust-lang/rust/pull/53671/files#diff-e0b58bb6712edaa8595ad7237542c958L551
    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
        let mut ecx = EvalContext::new(
            fx.tcx.at(DUMMY_SP),
            ty::ParamEnv::reveal_all(),
            TransPlaceInterpreter,
        );
        ecx.push_stack_frame(
            fx.instance,
            DUMMY_SP,
            fx.mir,
            None,
            StackPopCleanup::None { cleanup: false },
        )
        .unwrap();
        let op = ecx.eval_operand(
            &Operand::Constant(Box::new(Constant {
                span: DUMMY_SP,
                ty: const_.ty,
                user_ty: None,
                literal: fx.tcx.intern_lazy_const(LazyConst::Evaluated(const_)),
            })),
            None,
        )?;
        let ptr = ecx.allocate(op.layout, MemoryKind::Stack);
        ecx.copy_op(op, ptr.into())?;
        let alloc = ecx.memory().get(ptr.to_ptr()?.alloc_id)?;
        Ok(fx.tcx.intern_const_alloc(alloc.clone()))
    };
    let alloc = result().expect("unable to convert ConstValue to Allocation");

    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&format!("__alloc_{}", alloc_id.0), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    def_id: DefId,
    linkage: Linkage,
) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    let is_mutable = if let ::rustc::hir::Mutability::MutMutable = tcx.is_static(def_id).unwrap() {
        true
    } else {
        !tcx.type_of(def_id)
            .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
    };
    module
        .declare_data(&*symbol_name, linkage, is_mutable)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    assert!(!layout.is_unsized(), "unsized statics aren't supported");
    CPlace::Addr(global_ptr, None, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<TransPlaceInterpreter>::new(tcx.at(DUMMY_SP));

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                //println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                //println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(_alloc_id, alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id, Linkage::Export);
                (data_id, alloc)
            }
        };

        //("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(alloc.bytes.to_vec().into_boxed_slice());

        for &(offset, (_tag, reloc)) in alloc.relocations.iter() {
            let addend = {
                let endianness = tcx.data_layout.endian;
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocKind::Function(instance) => {
                    assert_eq!(addend, 0);
                    let func_id = crate::abi::import_function(tcx, module, instance);
                    let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
                    data_ctx.write_function_addr(offset.bytes() as u32, local_func_id);
                    continue;
                }
                AllocKind::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocKind::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id, Linkage::Import)
                }
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}

struct TransPlaceInterpreter;

impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for TransPlaceInterpreter {
    type MemoryKinds = !;
    type PointerTag = ();
    type AllocExtra = ();
    type MemoryExtra = ();
    type FrameExtra = ();
    type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation<()>)>;
    const STATIC_KIND: Option<!> = None;

    fn enforce_validity(_: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
        false
    }

    fn before_terminator(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_fn(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: Option<PlaceTy<'tcx>>,
        _: Option<BasicBlock>,
    ) -> EvalResult<'tcx, Option<&'mir Mir<'tcx>>> {
        panic!();
    }

    fn call_intrinsic(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_foreign_static(
        _: DefId,
        _: ::rustc::ty::query::TyCtxtAt<'a, 'tcx, 'tcx>,
        _: &(),
    ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> {
        panic!();
    }

    fn ptr_op(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: mir::BinOp,
        _: Scalar,
        _: TyLayout<'tcx>,
        _: Scalar,
        _: TyLayout<'tcx>,
    ) -> EvalResult<'tcx, (Scalar, bool)> {
        panic!();
    }

    fn box_alloc(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: PlaceTy<'tcx>) -> EvalResult<'tcx> {
        panic!();
    }

    fn tag_dereference(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: MPlaceTy<'tcx>,
        _: Option<::rustc::hir::Mutability>,
    ) -> EvalResult<'tcx, Scalar> {
        panic!();
    }

    fn adjust_static_allocation<'alloc>(
        alloc: &'alloc Allocation,
        _: &(),
    ) -> Cow<'alloc, Allocation> {
        Cow::Borrowed(alloc)
    }

    fn tag_new_allocation(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        ptr: Pointer,
        _: MemoryKind<!>,
    ) -> Pointer {
        ptr
    }

    fn stack_push(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>{
        Ok(())
    }

    fn stack_pop(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: ()) -> EvalResult<'tcx> {
        Ok(())
    }
}
<commit_msg>Rustup to rustc 1.34.0-nightly (0b7af2668 2019-02-10)<commit_after>use std::borrow::Cow;

use rustc::mir::interpret::{
    read_target_uint, AllocId, AllocKind, Allocation, ConstValue, EvalResult, GlobalId, Scalar,
};
use rustc::ty::{Const, LazyConst};
use rustc_mir::interpret::{
    EvalContext, MPlaceTy, Machine, Memory, MemoryKind, OpTy, PlaceTy, Pointer, StackPopCleanup,
};

use cranelift_module::*;

use crate::prelude::*;

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        //println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        //println!("done {:?}", self.done);
        self.done.clear();
    }
}

pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
    ccx.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id, Linkage::Import);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        }))
        .unwrap();

    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

pub fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx LazyConst<'tcx>,
) -> Const<'tcx> {
    match *const_ {
        LazyConst::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        LazyConst::Evaluated(const_) => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        ty::Bool => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Uint(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Int(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        ty::FnDef(_def_id, _substs) => {
            CValue::ByRef(
                fx.bcx.ins().iconst(fx.pointer_type, 0),
                layout
            )
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: Const<'tcx>,
) -> CPlace<'tcx> {
    // Adapted from https://github.com/rust-lang/rust/pull/53671/files#diff-e0b58bb6712edaa8595ad7237542c958L551
    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
        let mut ecx = EvalContext::new(
            fx.tcx.at(DUMMY_SP),
            ty::ParamEnv::reveal_all(),
            TransPlaceInterpreter,
        );
        ecx.push_stack_frame(
            fx.instance,
            DUMMY_SP,
            fx.mir,
            None,
            StackPopCleanup::None { cleanup: false },
        )
        .unwrap();
        let op = ecx.eval_operand(
            &Operand::Constant(Box::new(Constant {
                span: DUMMY_SP,
                ty: const_.ty,
                user_ty: None,
                literal: fx.tcx.mk_lazy_const(LazyConst::Evaluated(const_)),
            })),
            None,
        )?;
        let ptr = ecx.allocate(op.layout, MemoryKind::Stack);
        ecx.copy_op(op, ptr.into())?;
        let alloc = ecx.memory().get(ptr.to_ptr()?.alloc_id)?;
        Ok(fx.tcx.intern_const_alloc(alloc.clone()))
    };
    let alloc = result().expect("unable to convert ConstValue to Allocation");

    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&format!("__alloc_{}", alloc_id.0), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    def_id: DefId,
    linkage: Linkage,
) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    let is_mutable = if let ::rustc::hir::Mutability::MutMutable = tcx.is_static(def_id).unwrap() {
        true
    } else {
        !tcx.type_of(def_id)
            .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
    };
    module
        .declare_data(&*symbol_name, linkage, is_mutable)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    assert!(!layout.is_unsized(), "unsized statics aren't supported");
    CPlace::Addr(global_ptr, None, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<TransPlaceInterpreter>::new(tcx.at(DUMMY_SP));

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                //println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                //println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(_alloc_id, alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id, Linkage::Export);
                (data_id, alloc)
            }
        };

        //("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(alloc.bytes.to_vec().into_boxed_slice());

        for &(offset, (_tag, reloc)) in alloc.relocations.iter() {
            let addend = {
                let endianness = tcx.data_layout.endian;
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocKind::Function(instance) => {
                    assert_eq!(addend, 0);
                    let func_id = crate::abi::import_function(tcx, module, instance);
                    let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
                    data_ctx.write_function_addr(offset.bytes() as u32, local_func_id);
                    continue;
                }
                AllocKind::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocKind::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id, Linkage::Import)
                }
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}

struct TransPlaceInterpreter;

impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for TransPlaceInterpreter {
    type MemoryKinds = !;
    type PointerTag = ();
    type AllocExtra = ();
    type MemoryExtra = ();
    type FrameExtra = ();
    type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation<()>)>;
    const STATIC_KIND: Option<!> = None;

    fn enforce_validity(_: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
        false
    }

    fn before_terminator(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_fn(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: Option<PlaceTy<'tcx>>,
        _: Option<BasicBlock>,
    ) -> EvalResult<'tcx, Option<&'mir Mir<'tcx>>> {
        panic!();
    }

    fn call_intrinsic(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_foreign_static(
        _: DefId,
        _: ::rustc::ty::query::TyCtxtAt<'a, 'tcx, 'tcx>,
        _: &(),
    ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> {
        panic!();
    }

    fn ptr_op(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: mir::BinOp,
        _: Scalar,
        _: TyLayout<'tcx>,
        _: Scalar,
        _: TyLayout<'tcx>,
    ) -> EvalResult<'tcx, (Scalar, bool)> {
        panic!();
    }

    fn box_alloc(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: PlaceTy<'tcx>) -> EvalResult<'tcx> {
        panic!();
    }

    fn tag_dereference(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: MPlaceTy<'tcx>,
        _: Option<::rustc::hir::Mutability>,
    ) -> EvalResult<'tcx, Scalar> {
        panic!();
    }

    fn adjust_static_allocation<'alloc>(
        alloc: &'alloc Allocation,
        _: &(),
    ) -> Cow<'alloc, Allocation> {
        Cow::Borrowed(alloc)
    }

    fn tag_new_allocation(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        ptr: Pointer,
        _: MemoryKind<!>,
    ) -> Pointer {
        ptr
    }

    fn stack_push(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>{
        Ok(())
    }

    fn stack_pop(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: ()) -> EvalResult<'tcx> {
        Ok(())
    }
}
<|endoftext|>


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

pub fn score(s: &str) -> u64 {
    let t = {
        let mut h = HashMap::new();
        for (x, i) in vec![("AEIOULNRST", 1),
                           ("DG", 2),
                           ("BCMP", 3),
                           ("FHVMY", 4),
                           ("K", 5),
                           ("JX", 8),
                           ("QZ", 10)] {
            for c in x.chars() {
                h.insert(c, i);
            }
        }
        h
    };
    s.to_uppercase().chars().map(|c| *t.get(&c).unwrap_or(&0)).sum()
}
<commit_msg>better solution<commit_after>pub fn score(s: &str) -> u64 {
    s.to_uppercase().chars().map(lookup).sum()
}

fn lookup(c: char) -> u64 {
    match c {
        'A' | 'E' | 'I' | 'O' | 'U' | 'L' | 'N' | 'R' | 'S' | 'T' => 1,
        'D' | 'G' => 2,
        'B' | 'C' | 'M' | 'P' => 3,
        'F' | 'H' | 'V' | 'W' | 'Y' => 4,
        'K' => 5,
        'J' | 'X' => 8,
        'Q' | 'Z' => 10,
        _ => 0,
    }
}
<|endoftext|>


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

#![allow(dead_code)]

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

use crate::gpio::epoll::{epoll_event, Epoll, EventFd, EPOLLERR, EPOLLET, EPOLLIN, EPOLLPRI};
use crate::gpio::ioctl;
use crate::gpio::pin::InputPin;
use crate::gpio::{Error, Level, Result, Trigger};

#[derive(Debug)]
struct Interrupt {
    pin: u8,
    trigger: Trigger,
    cdev_fd: i32,
    event_request: ioctl::EventRequest,
}

impl Interrupt {
    fn new(cdev_fd: i32, pin: u8, trigger: Trigger) -> Result<Interrupt> {
        Ok(Interrupt {
            pin,
            trigger,
            cdev_fd,
            event_request: ioctl::EventRequest::new(cdev_fd, pin, trigger)?,
        })
    }

    fn trigger(&self) -> Trigger {
        self.trigger
    }

    fn fd(&self) -> i32 {
        self.event_request.fd
    }

    fn pin(&self) -> u8 {
        self.pin
    }

    fn set_trigger(&mut self, trigger: Trigger) -> Result<()> {
        self.trigger = trigger;

        self.reset()
    }

    fn event(&mut self) -> Result<ioctl::Event> {
        // This might block if there are no events waiting
        ioctl::get_event(self.event_request.fd)
    }

    fn reset(&mut self) -> Result<()> {
        // Close the old event fd before opening a new one
        self.event_request.close();
        self.event_request = ioctl::EventRequest::new(self.cdev_fd, self.pin, self.trigger)?;

        Ok(())
    }
}

#[derive(Debug)]
struct TriggerStatus {
    interrupt: Option<Interrupt>,
    triggered: bool,
    level: Level,
}

pub struct EventLoop {
    poll: Epoll,
    events: Vec<epoll_event>,
    trigger_status: Vec<TriggerStatus>,
    cdev_fd: i32,
}

impl fmt::Debug for EventLoop {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("EventLoop")
            .field("poll", &self.poll)
            .field("events", &format_args!("{{ .. }}"))
            .field("trigger_status", &format_args!("{{ .. }}"))
            .field("cdev_fd", &self.cdev_fd)
            .finish()
    }
}

impl EventLoop {
    pub fn new(cdev_fd: i32, capacity: usize) -> Result<EventLoop> {
        let mut trigger_status = Vec::with_capacity(capacity);

        // Initialize trigger_status while circumventing the Copy/Clone requirement
        for _ in 0..trigger_status.capacity() {
            trigger_status.push(TriggerStatus {
                interrupt: None,
                triggered: false,
                level: Level::Low,
            });
        }

        Ok(EventLoop {
            poll: Epoll::new()?,
            events: vec![epoll_event { events: 0, u64: 0 }; capacity],
            trigger_status,
            cdev_fd,
        })
    }

    pub fn poll<'a>(
        &mut self,
        pins: &[&'a InputPin],
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<Option<(&'a InputPin, Level)>> {
        for pin in pins {
            let trigger_status = &mut self.trigger_status[pin.pin() as usize];

            // Did we cache any trigger events during the previous poll?
            if trigger_status.triggered {
                trigger_status.triggered = false;

                if !reset {
                    return Ok(Some((pin, trigger_status.level)));
                }
            }

            // Reset any pending trigger events
            if let Some(ref mut interrupt) = trigger_status.interrupt {
                if reset {
                    self.poll.delete(interrupt.fd())?;
                    interrupt.reset()?;
                    self.poll.add(
                        interrupt.fd(),
                        u64::from(interrupt.pin()),
                        EPOLLIN | EPOLLPRI,
                    )?;
                }
            }
        }

        // Loop until we get any of the events we're waiting for, or a timeout occurs
        let now = Instant::now();
        loop {
            let num_events = self.poll.wait(&mut self.events, timeout)?;

            // No events means a timeout occurred
            if num_events == 0 {
                return Ok(None);
            }

            for event in &self.events[0..num_events] {
                let pin = event.u64 as usize;

                let trigger_status = &mut self.trigger_status[pin];

                debug_assert!(
                    trigger_status.interrupt.is_some(),
                    format!("No interrupt set for pin {}", pin)
                );

                if let Some(ref mut interrupt) = trigger_status.interrupt {
                    trigger_status.level = match interrupt.event()?.trigger {
                        Trigger::RisingEdge => Level::High,
                        Trigger::FallingEdge => Level::Low,
                        _ => unsafe { std::hint::unreachable_unchecked() },
                    };

                    trigger_status.triggered = true;
                };
            }

            // Were any interrupts triggered? If so, return one. The rest
            // will be saved for the next poll.
            for pin in pins {
                let trigger_status = &mut self.trigger_status[pin.pin() as usize];

                if trigger_status.triggered {
                    trigger_status.triggered = false;
                    return Ok(Some((pin, trigger_status.level)));
                }
            }

            // It's possible a pin we're not waiting for continuously triggers
            // an interrupt, causing repeated loops with calls to poll() using a
            // reset timeout value. Make sure we haven't been looping longer than
            // the requested timeout.
            if let Some(t) = timeout {
                if now.elapsed() > t {
                    return Ok(None);
                }
            }
        }
    }

    pub fn set_interrupt(&mut self, pin: u8, trigger: Trigger) -> Result<()> {
        let trigger_status = &mut self.trigger_status[pin as usize];

        trigger_status.triggered = false;

        // Interrupt already exists. We just need to change the trigger.
        if let Some(ref mut interrupt) = trigger_status.interrupt {
            if interrupt.trigger != trigger {
                // This requires a new event request, so the fd might change
                self.poll.delete(interrupt.fd())?;
                interrupt.set_trigger(trigger)?;
                self.poll
                    .add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
            }

            return Ok(());
        }

        // Register a new interrupt
        let interrupt = Interrupt::new(self.cdev_fd, pin, trigger)?;
        self.poll
            .add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
        trigger_status.interrupt = Some(interrupt);

        Ok(())
    }

    pub fn clear_interrupt(&mut self, pin: u8) -> Result<()> {
        let trigger_status = &mut self.trigger_status[pin as usize];

        trigger_status.triggered = false;

        if let Some(interrupt) = trigger_status.interrupt.take() {
            self.poll.delete(interrupt.fd())?;
        }

        Ok(())
    }
}

#[derive(Debug)]
pub struct AsyncInterrupt {
    poll_thread: Option<thread::JoinHandle<Result<()>>>,
    tx: EventFd,
}

impl AsyncInterrupt {
    pub fn new<C>(fd: i32, pin: u8, trigger: Trigger, mut callback: C) -> Result<AsyncInterrupt>
    where
        C: FnMut(Level) + Send + 'static,
    {
        let tx = EventFd::new()?;
        let rx = tx.fd();

        let poll_thread = thread::spawn(move || -> Result<()> {
            let poll = Epoll::new()?;

            // rx becomes readable when the main thread calls notify()
            poll.add(rx, rx as u64, EPOLLERR | EPOLLET | EPOLLIN)?;

            let mut interrupt = Interrupt::new(fd, pin, trigger)?;
            poll.add(interrupt.fd(), interrupt.fd() as u64, EPOLLIN | EPOLLPRI)?;

            let mut events = [epoll_event { events: 0, u64: 0 }; 2];
            loop {
                let num_events = poll.wait(&mut events, None)?;
                if num_events > 0 {
                    for event in &events[0..num_events] {
                        let fd = event.u64 as i32;
                        if fd == rx {
                            return Ok(()); // The main thread asked us to stop
                        } else if fd == interrupt.fd() {
                            let level = match interrupt.event()?.trigger {
                                Trigger::RisingEdge => Level::High,
                                _ => Level::Low,
                            };

                            callback(level);
                        }
                    }
                }
            }
        });

        Ok(AsyncInterrupt {
            poll_thread: Some(poll_thread),
            tx,
        })
    }

    pub fn stop(&mut self) -> Result<()> {
        self.tx.notify()?;

        if let Some(poll_thread) = self.poll_thread.take() {
            match poll_thread.join() {
                Ok(r) => return r,
                Err(_) => return Err(Error::ThreadPanic),
            }
        }

        Ok(())
    }
}

impl Drop for AsyncInterrupt {
    fn drop(&mut self) {
        // Don't wait for the poll thread to exit if the main thread is panicking,
        // because we could potentially block indefinitely while unwinding if the
        // poll thread is executing a callback that doesn't return.
        if !thread::panicking() {
            let _ = self.stop();
        }
    }
}
<commit_msg>Change panic message to string literal<commit_after>// Copyright (c) 2017-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#![allow(dead_code)]

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

use crate::gpio::epoll::{epoll_event, Epoll, EventFd, EPOLLERR, EPOLLET, EPOLLIN, EPOLLPRI};
use crate::gpio::ioctl;
use crate::gpio::pin::InputPin;
use crate::gpio::{Error, Level, Result, Trigger};

#[derive(Debug)]
struct Interrupt {
    pin: u8,
    trigger: Trigger,
    cdev_fd: i32,
    event_request: ioctl::EventRequest,
}

impl Interrupt {
    fn new(cdev_fd: i32, pin: u8, trigger: Trigger) -> Result<Interrupt> {
        Ok(Interrupt {
            pin,
            trigger,
            cdev_fd,
            event_request: ioctl::EventRequest::new(cdev_fd, pin, trigger)?,
        })
    }

    fn trigger(&self) -> Trigger {
        self.trigger
    }

    fn fd(&self) -> i32 {
        self.event_request.fd
    }

    fn pin(&self) -> u8 {
        self.pin
    }

    fn set_trigger(&mut self, trigger: Trigger) -> Result<()> {
        self.trigger = trigger;

        self.reset()
    }

    fn event(&mut self) -> Result<ioctl::Event> {
        // This might block if there are no events waiting
        ioctl::get_event(self.event_request.fd)
    }

    fn reset(&mut self) -> Result<()> {
        // Close the old event fd before opening a new one
        self.event_request.close();
        self.event_request = ioctl::EventRequest::new(self.cdev_fd, self.pin, self.trigger)?;

        Ok(())
    }
}

#[derive(Debug)]
struct TriggerStatus {
    interrupt: Option<Interrupt>,
    triggered: bool,
    level: Level,
}

pub struct EventLoop {
    poll: Epoll,
    events: Vec<epoll_event>,
    trigger_status: Vec<TriggerStatus>,
    cdev_fd: i32,
}

impl fmt::Debug for EventLoop {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("EventLoop")
            .field("poll", &self.poll)
            .field("events", &format_args!("{{ .. }}"))
            .field("trigger_status", &format_args!("{{ .. }}"))
            .field("cdev_fd", &self.cdev_fd)
            .finish()
    }
}

impl EventLoop {
    pub fn new(cdev_fd: i32, capacity: usize) -> Result<EventLoop> {
        let mut trigger_status = Vec::with_capacity(capacity);

        // Initialize trigger_status while circumventing the Copy/Clone requirement
        for _ in 0..trigger_status.capacity() {
            trigger_status.push(TriggerStatus {
                interrupt: None,
                triggered: false,
                level: Level::Low,
            });
        }

        Ok(EventLoop {
            poll: Epoll::new()?,
            events: vec![epoll_event { events: 0, u64: 0 }; capacity],
            trigger_status,
            cdev_fd,
        })
    }

    pub fn poll<'a>(
        &mut self,
        pins: &[&'a InputPin],
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<Option<(&'a InputPin, Level)>> {
        for pin in pins {
            let trigger_status = &mut self.trigger_status[pin.pin() as usize];

            // Did we cache any trigger events during the previous poll?
            if trigger_status.triggered {
                trigger_status.triggered = false;

                if !reset {
                    return Ok(Some((pin, trigger_status.level)));
                }
            }

            // Reset any pending trigger events
            if let Some(ref mut interrupt) = trigger_status.interrupt {
                if reset {
                    self.poll.delete(interrupt.fd())?;
                    interrupt.reset()?;
                    self.poll.add(
                        interrupt.fd(),
                        u64::from(interrupt.pin()),
                        EPOLLIN | EPOLLPRI,
                    )?;
                }
            }
        }

        // Loop until we get any of the events we're waiting for, or a timeout occurs
        let now = Instant::now();
        loop {
            let num_events = self.poll.wait(&mut self.events, timeout)?;

            // No events means a timeout occurred
            if num_events == 0 {
                return Ok(None);
            }

            for event in &self.events[0..num_events] {
                let pin = event.u64 as usize;

                let trigger_status = &mut self.trigger_status[pin];

                debug_assert!(
                    trigger_status.interrupt.is_some(),
                    "No interrupt set for pin {}",
                    pin
                );

                if let Some(ref mut interrupt) = trigger_status.interrupt {
                    trigger_status.level = match interrupt.event()?.trigger {
                        Trigger::RisingEdge => Level::High,
                        Trigger::FallingEdge => Level::Low,
                        _ => unsafe { std::hint::unreachable_unchecked() },
                    };

                    trigger_status.triggered = true;
                };
            }

            // Were any interrupts triggered? If so, return one. The rest
            // will be saved for the next poll.
            for pin in pins {
                let trigger_status = &mut self.trigger_status[pin.pin() as usize];

                if trigger_status.triggered {
                    trigger_status.triggered = false;
                    return Ok(Some((pin, trigger_status.level)));
                }
            }

            // It's possible a pin we're not waiting for continuously triggers
            // an interrupt, causing repeated loops with calls to poll() using a
            // reset timeout value. Make sure we haven't been looping longer than
            // the requested timeout.
            if let Some(t) = timeout {
                if now.elapsed() > t {
                    return Ok(None);
                }
            }
        }
    }

    pub fn set_interrupt(&mut self, pin: u8, trigger: Trigger) -> Result<()> {
        let trigger_status = &mut self.trigger_status[pin as usize];

        trigger_status.triggered = false;

        // Interrupt already exists. We just need to change the trigger.
        if let Some(ref mut interrupt) = trigger_status.interrupt {
            if interrupt.trigger != trigger {
                // This requires a new event request, so the fd might change
                self.poll.delete(interrupt.fd())?;
                interrupt.set_trigger(trigger)?;
                self.poll
                    .add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
            }

            return Ok(());
        }

        // Register a new interrupt
        let interrupt = Interrupt::new(self.cdev_fd, pin, trigger)?;
        self.poll
            .add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
        trigger_status.interrupt = Some(interrupt);

        Ok(())
    }

    pub fn clear_interrupt(&mut self, pin: u8) -> Result<()> {
        let trigger_status = &mut self.trigger_status[pin as usize];

        trigger_status.triggered = false;

        if let Some(interrupt) = trigger_status.interrupt.take() {
            self.poll.delete(interrupt.fd())?;
        }

        Ok(())
    }
}

#[derive(Debug)]
pub struct AsyncInterrupt {
    poll_thread: Option<thread::JoinHandle<Result<()>>>,
    tx: EventFd,
}

impl AsyncInterrupt {
    pub fn new<C>(fd: i32, pin: u8, trigger: Trigger, mut callback: C) -> Result<AsyncInterrupt>
    where
        C: FnMut(Level) + Send + 'static,
    {
        let tx = EventFd::new()?;
        let rx = tx.fd();

        let poll_thread = thread::spawn(move || -> Result<()> {
            let poll = Epoll::new()?;

            // rx becomes readable when the main thread calls notify()
            poll.add(rx, rx as u64, EPOLLERR | EPOLLET | EPOLLIN)?;

            let mut interrupt = Interrupt::new(fd, pin, trigger)?;
            poll.add(interrupt.fd(), interrupt.fd() as u64, EPOLLIN | EPOLLPRI)?;

            let mut events = [epoll_event { events: 0, u64: 0 }; 2];
            loop {
                let num_events = poll.wait(&mut events, None)?;
                if num_events > 0 {
                    for event in &events[0..num_events] {
                        let fd = event.u64 as i32;
                        if fd == rx {
                            return Ok(()); // The main thread asked us to stop
                        } else if fd == interrupt.fd() {
                            let level = match interrupt.event()?.trigger {
                                Trigger::RisingEdge => Level::High,
                                _ => Level::Low,
                            };

                            callback(level);
                        }
                    }
                }
            }
        });

        Ok(AsyncInterrupt {
            poll_thread: Some(poll_thread),
            tx,
        })
    }

    pub fn stop(&mut self) -> Result<()> {
        self.tx.notify()?;

        if let Some(poll_thread) = self.poll_thread.take() {
            match poll_thread.join() {
                Ok(r) => return r,
                Err(_) => return Err(Error::ThreadPanic),
            }
        }

        Ok(())
    }
}

impl Drop for AsyncInterrupt {
    fn drop(&mut self) {
        // Don't wait for the poll thread to exit if the main thread is panicking,
        // because we could potentially block indefinitely while unwinding if the
        // poll thread is executing a callback that doesn't return.
        if !thread::panicking() {
            let _ = self.stop();
        }
    }
}
<|endoftext|>