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

use analysis::ref_mode::RefMode;
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;
use traits::*;

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

    let path =  env.config.target_path.join(file_name_sys("lib"));

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

fn generate_lib(w: &mut Write, 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(MAIN_NAMESPACE);
    let records = prepare(ns);
    let classes = prepare(ns);
    let interfaces = prepare(ns);
    let bitfields = prepare(ns);
    let enums = prepare(ns);
    let unions = prepare(ns);

    try!(generate_aliases(w, env, &prepare(ns)));
    try!(generate_enums(w, &enums));
    try!(generate_constants(w, env, &ns.constants));
    try!(generate_bitfields(w, &bitfields));
    try!(generate_unions(w, &unions));
    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_enums_funcs(w, env, &enums));
    try!(functions::generate_bitfields_funcs(w, env, &bitfields));
    try!(functions::generate_unions_funcs(w, env, &unions));
    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: &mut Write, 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: &Namespace) -> Vec<&T>
where 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: &mut Write, env: &Env, items: &[&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),
            x @ Err(..) => ("//", x.into_string()),
        };
        try!(writeln!(w, "{}pub type {} = {};", comment, item.c_identifier, c_type));
    }

    Ok(())
}

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

    Ok(())
}

fn generate_constants(w: &mut Write, env: &Env, constants: &[Constant]) -> Result<()> {
    try!(writeln!(w, ""));
    for constant in constants {
        let direction = ParameterDirection::In;
        let ref_mode = RefMode::of(&env.library, constant.typ, direction);
        let (mut comment, mut type_) =
            match parameter_rust_type(env, constant.typ, direction,
                                      Nullable(false), ref_mode) {
                Ok(x) => ("", x),
                x @ Err(..) => ("//", x.into_string()),
            };
        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);
        } else if type_ == "Glyph" && env.config.library_name == "Pango"  {
            //Fix single constant alias
            type_ = "PangoGlyph".into();
        }
        try!(writeln!(w, "{}pub const {}: {} = {};", comment,
            constant.c_identifier, type_, value));
    }

    Ok(())
}

fn generate_enums(w: &mut Write, items: &[&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, "\t{} = {},",
                          &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: &mut Write, items: &[&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: &mut Write, classes: &[&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: &mut Write, interfaces: &[&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: &mut Write, env: &Env, records: &[&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::<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!("\t_truncated_record_marker: c_void,"));
                truncated = true;
            }
            if truncated {
                if is_union {
                    lines.push(format!("\t//union,"));
                }
                else {
                    let bits = field.bits.map(|n| format!(": {}", n)).unwrap_or("".into());
                    lines.push(
                        format!("\t//{}: {}{},", 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);
                if c_type.is_err() {
                    commented = true;
                }
                lines.push(format!("\t{}{}: {},", vis, name, c_type.into_string()));
            }
            else {
                let name = mangle_keywords(&*field.name);
                if let Some(ref func) =
                        env.library.type_(field.typ).maybe_ref_as::<Function>() {
                    let (com, sig) = functions::function_signature(env, func, true);
                    lines.push(format!("\t{}{}: Option<unsafe extern \"C\" fn{}>,", 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);
                    if c_type.is_err() {
                        commented = true;
                    }
                    lines.push(format!("\t{}{}: {},", vis, name, c_type.into_string()));
                }
                else {
                    lines.push(format!("\t{}{}: [{:?} {}],",
                        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(())
}
<commit_msg>sys: Handle 'alias' and 'version' config settings for enums and bitfields<commit_after>use std::collections::HashMap;
use std::io::{Result, Write};
use case::CaseExt;

use analysis::ref_mode::RefMode;
use analysis::rust_type::parameter_rust_type;
use codegen::general::{self, version_condition};
use env::Env;
use file_saver::*;
use library::*;
use nameutil::*;
use super::ffi_type::ffi_type;
use super::functions;
use super::statics;
use traits::*;
use version::Version;

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

    let path =  env.config.target_path.join(file_name_sys("lib"));

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

fn generate_lib(w: &mut Write, 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(MAIN_NAMESPACE);
    let records = prepare(ns);
    let classes = prepare(ns);
    let interfaces = prepare(ns);
    let bitfields = prepare(ns);
    let enums = prepare(ns);
    let unions = prepare(ns);

    try!(generate_aliases(w, env, &prepare(ns)));
    try!(generate_enums(w, env, &enums));
    try!(generate_constants(w, env, &ns.constants));
    try!(generate_bitfields(w, env, &bitfields));
    try!(generate_unions(w, &unions));
    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_enums_funcs(w, env, &enums));
    try!(functions::generate_bitfields_funcs(w, env, &bitfields));
    try!(functions::generate_unions_funcs(w, env, &unions));
    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: &mut Write, 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: &Namespace) -> Vec<&T>
where 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: &mut Write, env: &Env, items: &[&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),
            x @ Err(..) => ("//", x.into_string()),
        };
        try!(writeln!(w, "{}pub type {} = {};", comment, item.c_identifier, c_type));
    }

    Ok(())
}

fn generate_bitfields(w: &mut Write, env: &Env, items: &[&Bitfield])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        let full_name = format!("{}.{}", env.namespaces.main().name, item.name);
        let config = env.config.objects.get(&full_name);

        try!(writeln!(w, "bitflags! {{\n\t#[repr(C)]\n\tflags {}: c_uint {{", item.c_type));
        for member in &item.members {
            let member_config = config.as_ref()
                .map(|c| c.members.matched(&member.name)).unwrap_or(vec![]);
            let version = member_config.iter().filter_map(|m| m.version).next();

            try!(version_condition(w, env.config.min_cfg_version, version, false, 2));
            let val: i64 = member.value.parse().unwrap();
            try!(writeln!(w, "\t\tconst {} = {},", member.c_identifier, val as u32));
        }
        try!(writeln!(w, "\t}}\n}}"));
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_constants(w: &mut Write, env: &Env, constants: &[Constant]) -> Result<()> {
    try!(writeln!(w, ""));
    for constant in constants {
        let direction = ParameterDirection::In;
        let ref_mode = RefMode::of(&env.library, constant.typ, direction);
        let (mut comment, mut type_) =
            match parameter_rust_type(env, constant.typ, direction,
                                      Nullable(false), ref_mode) {
                Ok(x) => ("", x),
                x @ Err(..) => ("//", x.into_string()),
            };
        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);
        } else if type_ == "Glyph" && env.config.library_name == "Pango"  {
            //Fix single constant alias
            type_ = "PangoGlyph".into();
        }
        try!(writeln!(w, "{}pub const {}: {} = {};", comment,
            constant.c_identifier, type_, value));
    }

    Ok(())
}

fn generate_enums(w: &mut Write, env: &Env, items: &[&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 full_name = format!("{}.{}", env.namespaces.main().name, item.name);
        let config = env.config.objects.get(&full_name);

        let mut vals: HashMap<String, (String, Option<Version>)> = 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 {
            let member_config = config.as_ref()
                .map(|c| c.members.matched(&member.name)).unwrap_or(vec![]);
            let is_alias = member_config.iter().any(|m| m.alias);
            let version = member_config.iter().filter_map(|m| m.version).next();

            if is_alias || vals.get(&member.value).is_some() {
                continue;
            }
            try!(version_condition(w, env.config.min_cfg_version, version, false, 1));
            try!(writeln!(w, "\t{} = {},",
                          &prepare_enum_member_name(&member.name), member.value));
            vals.insert(member.value.clone(), (member.name.clone(), version.clone()));
        }
        try!(writeln!(w, "}}"));
        for member in &item.members {
            if let Some(&(ref value, version)) = vals.get(&member.value) {
                try!(version_condition(w, env.config.min_cfg_version, version, false, 0));
                try!(writeln!(w, "pub const {}: {} = {1}::{};", member.c_identifier, item.c_type,
                          &prepare_enum_member_name(value)));
            }
        }
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_unions(w: &mut Write, items: &[&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: &mut Write, classes: &[&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: &mut Write, interfaces: &[&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: &mut Write, env: &Env, records: &[&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::<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!("\t_truncated_record_marker: c_void,"));
                truncated = true;
            }
            if truncated {
                if is_union {
                    lines.push(format!("\t//union,"));
                }
                else {
                    let bits = field.bits.map(|n| format!(": {}", n)).unwrap_or("".into());
                    lines.push(
                        format!("\t//{}: {}{},", 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);
                if c_type.is_err() {
                    commented = true;
                }
                lines.push(format!("\t{}{}: {},", vis, name, c_type.into_string()));
            }
            else {
                let name = mangle_keywords(&*field.name);
                if let Some(ref func) =
                        env.library.type_(field.typ).maybe_ref_as::<Function>() {
                    let (com, sig) = functions::function_signature(env, func, true);
                    lines.push(format!("\t{}{}: Option<unsafe extern \"C\" fn{}>,", 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);
                    if c_type.is_err() {
                        commented = true;
                    }
                    lines.push(format!("\t{}{}: {},", vis, name, c_type.into_string()));
                }
                else {
                    lines.push(format!("\t{}{}: [{:?} {}],",
                        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>use std::str;
use std::fmt;
use std::io::{Write,Cursor};
use super::{Serializer, Serialized};
use super::binary::Slice;
use gen::GenError;

pub trait StrSr {
  fn raw<'a>(&'a self) -> Slice<'a>;
}

impl<S: AsRef<str>> StrSr for S {
  #[inline(always)]
  fn raw<'a>(&'a self) -> Slice<'a> {
    Slice::new(self.as_ref().as_bytes())
  }
}

pub struct Print<'a, T> {
  value: &'a T,
}

impl<'a, T: fmt::Display> Serializer for Print<'a, T> {
  fn serialize<'b, 'c>(&'b mut self, output: &'c mut [u8]) -> Result<(usize, Serialized), GenError> {
    let mut c = Cursor::new(output);
    match write!(&mut c, "{}", self.value) {
      //FIXME: maybe return an error here instead of assuming the buffer is too small?
      Err(_) => Ok((0, Serialized::Continue)),
      Ok(_) => Ok((c.position() as usize, Serialized::Done))
    }
  }
}

pub trait PrintSr<'a>: Sized {
  fn print(&'a self) -> Print<'a, Self>;
}

impl<'a, T: fmt::Display> PrintSr<'a> for T {
  #[inline(always)]
  fn print(&'a self) -> Print<'a, T> {
    Print { value: self }
  }
}

pub struct PrintUpperHex<T> {
  value: T,
}

impl<T: fmt::Display + fmt::UpperHex> Serializer for PrintUpperHex<T> {
  fn serialize<'b, 'c>(&'b mut self, output: &'c mut [u8]) -> Result<(usize, Serialized), GenError> {
    let mut c = Cursor::new(output);
    match write!(&mut c, "{:X}", self.value) {
      //FIXME: maybe return an error here instead of assuming the buffer is too small?
      Err(_) => Ok((0, Serialized::Continue)),
      Ok(_) => Ok((c.position() as usize, Serialized::Done))
    }
  }
}

pub trait PrintUpperHexSr: Sized + Copy {
  fn hex(self) -> PrintUpperHex<Self>;
}

impl<T: fmt::Display + fmt::UpperHex + Copy> PrintUpperHexSr for T {
  #[inline(always)]
  fn hex(self) -> PrintUpperHex<T> {
    PrintUpperHex { value: self }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use super::super::{Serializer, Serialized};
  use std::str::from_utf8;

  #[test]
  fn str_serializer() {
    let s = String::from("hello world!");
    let mut sr = Slice::new(s.as_str().as_bytes());

    let mut mem: [u8; 6] = [0; 6];
    let s = &mut mem[..];

    assert_eq!(sr.serialize(s), Ok((6, Serialized::Continue)));
    assert_eq!(&s[..], b"hello ");

    assert_eq!(sr.serialize(s), Ok((6, Serialized::Done)));
    assert_eq!(&s[..], b"world!");
  }

  #[test]
  fn print_serializer() {
    let mut mem: [u8; 100] = [0; 100];
    let s = &mut mem[..];

    let string = "hello";
    assert_eq!(string.print().serialize(s), Ok((5, Serialized::Done)));
    assert_eq!(from_utf8(&s[..5]).unwrap(), "hello");

    let num = 1234;
    assert_eq!(num.print().serialize(s), Ok((4, Serialized::Done)));
    assert_eq!(from_utf8(&s[..4]).unwrap(), "1234");

    let f = -1.2e14f32;
    assert_eq!(f.print().serialize(s), Ok((16, Serialized::Done)));
    assert_eq!(from_utf8(&s[..16]).unwrap(), "-120000000000000");

    let f2 = 1234.56e-2f64;
    assert_eq!(f2.print().serialize(s), Ok((7, Serialized::Done)));
    assert_eq!(from_utf8(&s[..7]).unwrap(), "12.3456");
  }

  #[test]
  fn print_hex_serializer() {
    let mut mem: [u8; 100] = [0; 100];
    let s = &mut mem[..];

    let num = 257;
    assert_eq!(num.hex().serialize(s), Ok((3, Serialized::Done)));
    assert_eq!(from_utf8(&s[..3]).unwrap(), "101");
  }
}
<commit_msg>fix build on stable<commit_after>use std::str;
use std::fmt;
use std::io::{Write,Cursor};
use super::{Serializer, Serialized};
use super::binary::Slice;
use gen::GenError;

pub trait StrSr {
  fn raw<'a>(&'a self) -> Slice<'a>;
}

impl<S: AsRef<str>> StrSr for S {
  #[inline(always)]
  fn raw<'a>(&'a self) -> Slice<'a> {
    Slice::new(self.as_ref().as_bytes())
  }
}

pub struct Print<'a, T: 'a> {
  value: &'a T,
}

impl<'a, T: fmt::Display> Serializer for Print<'a, T> {
  fn serialize<'b, 'c>(&'b mut self, output: &'c mut [u8]) -> Result<(usize, Serialized), GenError> {
    let mut c = Cursor::new(output);
    match write!(&mut c, "{}", self.value) {
      //FIXME: maybe return an error here instead of assuming the buffer is too small?
      Err(_) => Ok((0, Serialized::Continue)),
      Ok(_) => Ok((c.position() as usize, Serialized::Done))
    }
  }
}

pub trait PrintSr<'a>: Sized {
  fn print(&'a self) -> Print<'a, Self>;
}

impl<'a, T: fmt::Display> PrintSr<'a> for T {
  #[inline(always)]
  fn print(&'a self) -> Print<'a, T> {
    Print { value: self }
  }
}

pub struct PrintUpperHex<T> {
  value: T,
}

impl<T: fmt::Display + fmt::UpperHex> Serializer for PrintUpperHex<T> {
  fn serialize<'b, 'c>(&'b mut self, output: &'c mut [u8]) -> Result<(usize, Serialized), GenError> {
    let mut c = Cursor::new(output);
    match write!(&mut c, "{:X}", self.value) {
      //FIXME: maybe return an error here instead of assuming the buffer is too small?
      Err(_) => Ok((0, Serialized::Continue)),
      Ok(_) => Ok((c.position() as usize, Serialized::Done))
    }
  }
}

pub trait PrintUpperHexSr: Sized + Copy {
  fn hex(self) -> PrintUpperHex<Self>;
}

impl<T: fmt::Display + fmt::UpperHex + Copy> PrintUpperHexSr for T {
  #[inline(always)]
  fn hex(self) -> PrintUpperHex<T> {
    PrintUpperHex { value: self }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use super::super::{Serializer, Serialized};
  use std::str::from_utf8;

  #[test]
  fn str_serializer() {
    let s = String::from("hello world!");
    let mut sr = Slice::new(s.as_str().as_bytes());

    let mut mem: [u8; 6] = [0; 6];
    let s = &mut mem[..];

    assert_eq!(sr.serialize(s), Ok((6, Serialized::Continue)));
    assert_eq!(&s[..], b"hello ");

    assert_eq!(sr.serialize(s), Ok((6, Serialized::Done)));
    assert_eq!(&s[..], b"world!");
  }

  #[test]
  fn print_serializer() {
    let mut mem: [u8; 100] = [0; 100];
    let s = &mut mem[..];

    let string = "hello";
    assert_eq!(string.print().serialize(s), Ok((5, Serialized::Done)));
    assert_eq!(from_utf8(&s[..5]).unwrap(), "hello");

    let num = 1234;
    assert_eq!(num.print().serialize(s), Ok((4, Serialized::Done)));
    assert_eq!(from_utf8(&s[..4]).unwrap(), "1234");

    let f = -1.2e14f32;
    assert_eq!(f.print().serialize(s), Ok((16, Serialized::Done)));
    assert_eq!(from_utf8(&s[..16]).unwrap(), "-120000000000000");

    let f2 = 1234.56e-2f64;
    assert_eq!(f2.print().serialize(s), Ok((7, Serialized::Done)));
    assert_eq!(from_utf8(&s[..7]).unwrap(), "12.3456");
  }

  #[test]
  fn print_hex_serializer() {
    let mut mem: [u8; 100] = [0; 100];
    let s = &mut mem[..];

    let num = 257;
    assert_eq!(num.hex().serialize(s), Ok((3, Serialized::Done)));
    assert_eq!(from_utf8(&s[..3]).unwrap(), "101");
  }
}
<|endoftext|>


<commit_before>pub mod tag_command;
pub mod autotag;
pub mod update_tags;

pub use self::tag_command::TagCommand;
pub use self::autotag::AutoTagCommand;
pub use self::update_tags::UpdateTagsCommand;

use LalafellBot;
use database::AutotagUser;

use error::*;

use discord;
use discord::model::{UserId, LiveServer, Role, RoleId};

use serde_json;

use std::sync::{Arc, Mutex};
use std::collections::HashSet;

lazy_static! {
  // Limbo roles are roles that may or may not be added to the Discord bot state.
  static ref LIMBO_ROLES: Mutex<Vec<Role>> = Mutex::default();
}

pub struct Tagger;

impl Tagger {
  pub fn search_tag(bot: Arc<LalafellBot>, who: UserId, on: &LiveServer, server: &str, character_name: &str, ignore_verified: bool) -> Result<Option<String>> {
    let params = &[
      ("one", "characters"),
      ("strict", "on"),
      ("server|et", server)
    ];

    let res = bot.xivdb.search(character_name, params).chain_err(|| "could not query XIVDB")?;

    let search_chars = res.characters.unwrap().results;
    if search_chars.is_empty() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    let char_id = match search_chars[0]["id"].as_u64() {
      Some(u) => u,
      None => return Err("character ID was not a u64".into())
    };

    let name = match search_chars[0]["name"].as_str() {
      Some(s) => s,
      None => return Err("character name was not a string".into())
    };

    if name.to_lowercase() != character_name.to_lowercase() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    Tagger::tag(bot, who, on, char_id, ignore_verified)
  }

  fn find_or_create_role(bot: &LalafellBot, server: &LiveServer, name: &str, add_roles: &mut Vec<Role>, created_roles: &mut Vec<Role>) -> Result<()> {
    let lower_name = name.to_lowercase();
    match server.roles.iter().find(|x| x.name.to_lowercase() == lower_name) {
      Some(r) => add_roles.push(r.clone()),
      None => {
        let role = bot.discord.create_role(server.id, Some(&lower_name), None, None, None, None).chain_err(|| "could not create role")?;
        created_roles.push(role);
      }
    }
    Ok(())
  }

  pub fn tag(bot: Arc<LalafellBot>, who: UserId, on: &LiveServer, char_id: u64, ignore_verified: bool) -> Result<Option<String>> {
    let is_verified = match bot.database.read().unwrap().autotags.users.iter().find(|u| u.user_id == who.0 && u.server_id == on.id.0) {
      Some(u) => {
        if u.verification.verified && !ignore_verified && char_id != u.character_id {
          return Ok(Some(format!("{} is verified as {} on {}, so they cannot switch to another account.", who.mention(), u.character, u.server)));
        }
        u.verification.verified
      },
      None => false
    };

    let member = match bot.discord.get_member(on.id, who) {
      Ok(m) => m,
      Err(discord::Error::Status(_, Some(discord_error))) => {
        let error: DiscordNotFoundError = serde_json::from_value(discord_error)
          .chain_err(|| "could not get member for tagging and could not parse error")?;
        if error.code == 10013 {
          let mut database = bot.database.write().unwrap();
          match database.autotags.users.iter().position(|u| u.user_id == who.0) {
            Some(id) => {
              database.autotags.users.remove(id);
              return Err(format!("could not find user {} on server {}: removing from database", who.0, on.id.0).into());
            },
            _ => return Err("could not find user {} on server {}, but was not in database".into())
          }
        } else {
          return Err("could not get member for tagging with unknown error code".into());
        }
      },
      Err(e) => return Err(e).chain_err(|| "could not get member for tagging")
    };

    let character = bot.xivdb.character(char_id).chain_err(|| "could not look up character")?;

    bot.database.write().unwrap().autotags.update_or_add(AutotagUser::new(
      who.0,
      on.id.0,
      character.lodestone_id,
      &character.name,
      &character.server
    ));

    // Get a copy of the roles on the server.
    let mut roles = on.roles.clone();
    // Check for existing limbo roles.
    {
      let limbo = &mut *LIMBO_ROLES.lock().unwrap();
      for role in &roles {
        // If the server has updated to contain the limbo role, remove it.
        if let Some(i) = limbo.iter().position(|x| x.id == role.id) {
          limbo.remove(i);
        }
      }
    }
    // Get a copy of the limbo roles.
    let limbo = LIMBO_ROLES.lock().unwrap().clone();
    // Extend the server roles with the limbo roles.
    roles.extend(limbo);

    // Find or create the necessary roles
    let mut created_roles = Vec::new();
    let mut add_roles = Vec::new();
    Tagger::find_or_create_role(&bot, on, &character.data.race, &mut add_roles, &mut created_roles)?;
    Tagger::find_or_create_role(&bot, on, &character.data.gender, &mut add_roles, &mut created_roles)?;
    Tagger::find_or_create_role(&bot, on, &character.server, &mut add_roles, &mut created_roles)?;

    if is_verified {
      Tagger::find_or_create_role(&bot, on, "verified", &mut add_roles, &mut created_roles)?;
    }

    // If we created any roles, the server may or may not update with them fast enough, so store a copy in the limbo
    // roles.
    {
      let mut limbo = &mut *LIMBO_ROLES.lock().unwrap();
      for created in &created_roles {
        limbo.push(created.clone());
      }
    }

    debug!("Created the following roles:\n:{:#?}", created_roles);

    debug!("Existing roles:\n{:#?}", add_roles);

    // Extend the roles to add with the roles we created.
    add_roles.extend(created_roles);
    // Get all the roles that are part of groups
    let all_group_roles: Vec<String> = bot.config.roles.groups.iter().flat_map(|x| x).map(|x| x.to_lowercase()).collect();
    // Filter all roles on the server to only the roles the member has
    let keep: Vec<&Role> = roles.iter().filter(|x| member.roles.contains(&x.id)).collect();
    // Filter all the roles the member has, keeping the ones not in a group. These roles will not be touched when
    // updating the tag.
    let keep: Vec<&Role> = keep.into_iter().filter(|x| !all_group_roles.contains(&x.name.to_lowercase())).collect();
    debug!("Roles to keep:\n{:#?}", keep);
    // Combine the two sets of roles and map them to IDs
    let mut role_set: Vec<RoleId> = add_roles.iter().map(|r| r.id).chain(keep.into_iter().map(|r| r.id)).collect();
    // Sort the IDs so we can dedup them
    role_set.sort();
    // Remove the duplicate roles, if any
    role_set.dedup();

    debug!("Final role set:\n{:#?}", role_set);

    // Only update the roles if they are different
    let different = {
      let member_roles: HashSet<u64> = member.roles.iter().map(|x| x.0).collect();
      let actual_role_set: HashSet<u64> = role_set.iter().map(|x| x.0).collect();
      member_roles != actual_role_set
    };
    if different {
      bot.discord.edit_member_roles(on.id, who, &role_set).chain_err(|| "could not add roles")?;
    }

    // cannot edit nickname of those with a higher role
    let nick = match member.nick {
      Some(n) => n,
      None => Default::default()
    };
    if nick != character.name {
      bot.discord.edit_member(on.id, who, |e| e.nickname(&character.name)).ok();
    }
    Ok(None)
  }
}

#[derive(Debug, Deserialize)]
struct DiscordNotFoundError {
  code: u64,
  message: Option<String>
}
<commit_msg>fix: be more descriptive with unknown error codes<commit_after>pub mod tag_command;
pub mod autotag;
pub mod update_tags;

pub use self::tag_command::TagCommand;
pub use self::autotag::AutoTagCommand;
pub use self::update_tags::UpdateTagsCommand;

use LalafellBot;
use database::AutotagUser;

use error::*;

use discord;
use discord::model::{UserId, LiveServer, Role, RoleId};

use serde_json;

use std::sync::{Arc, Mutex};
use std::collections::HashSet;

lazy_static! {
  // Limbo roles are roles that may or may not be added to the Discord bot state.
  static ref LIMBO_ROLES: Mutex<Vec<Role>> = Mutex::default();
}

pub struct Tagger;

impl Tagger {
  pub fn search_tag(bot: Arc<LalafellBot>, who: UserId, on: &LiveServer, server: &str, character_name: &str, ignore_verified: bool) -> Result<Option<String>> {
    let params = &[
      ("one", "characters"),
      ("strict", "on"),
      ("server|et", server)
    ];

    let res = bot.xivdb.search(character_name, params).chain_err(|| "could not query XIVDB")?;

    let search_chars = res.characters.unwrap().results;
    if search_chars.is_empty() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    let char_id = match search_chars[0]["id"].as_u64() {
      Some(u) => u,
      None => return Err("character ID was not a u64".into())
    };

    let name = match search_chars[0]["name"].as_str() {
      Some(s) => s,
      None => return Err("character name was not a string".into())
    };

    if name.to_lowercase() != character_name.to_lowercase() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    Tagger::tag(bot, who, on, char_id, ignore_verified)
  }

  fn find_or_create_role(bot: &LalafellBot, server: &LiveServer, name: &str, add_roles: &mut Vec<Role>, created_roles: &mut Vec<Role>) -> Result<()> {
    let lower_name = name.to_lowercase();
    match server.roles.iter().find(|x| x.name.to_lowercase() == lower_name) {
      Some(r) => add_roles.push(r.clone()),
      None => {
        let role = bot.discord.create_role(server.id, Some(&lower_name), None, None, None, None).chain_err(|| "could not create role")?;
        created_roles.push(role);
      }
    }
    Ok(())
  }

  pub fn tag(bot: Arc<LalafellBot>, who: UserId, on: &LiveServer, char_id: u64, ignore_verified: bool) -> Result<Option<String>> {
    let is_verified = match bot.database.read().unwrap().autotags.users.iter().find(|u| u.user_id == who.0 && u.server_id == on.id.0) {
      Some(u) => {
        if u.verification.verified && !ignore_verified && char_id != u.character_id {
          return Ok(Some(format!("{} is verified as {} on {}, so they cannot switch to another account.", who.mention(), u.character, u.server)));
        }
        u.verification.verified
      },
      None => false
    };

    let member = match bot.discord.get_member(on.id, who) {
      Ok(m) => m,
      Err(discord::Error::Status(_, Some(discord_error))) => {
        let error: DiscordNotFoundError = serde_json::from_value(discord_error)
          .chain_err(|| "could not get member for tagging and could not parse error")?;
        if error.code == 10013 {
          let mut database = bot.database.write().unwrap();
          match database.autotags.users.iter().position(|u| u.user_id == who.0) {
            Some(id) => {
              database.autotags.users.remove(id);
              return Err(format!("could not find user {} on server {}: removing from database", who.0, on.id.0).into());
            },
            _ => return Err("could not find user {} on server {}, but was not in database".into())
          }
        } else {
          let message = error.message.map(|x| format!(" ({})", x)).unwrap_or_default();
          return Err(format!("could not get member for tagging with unknown error code: {}{}", error.code, message).into());
        }
      },
      Err(e) => return Err(e).chain_err(|| "could not get member for tagging")
    };

    let character = bot.xivdb.character(char_id).chain_err(|| "could not look up character")?;

    bot.database.write().unwrap().autotags.update_or_add(AutotagUser::new(
      who.0,
      on.id.0,
      character.lodestone_id,
      &character.name,
      &character.server
    ));

    // Get a copy of the roles on the server.
    let mut roles = on.roles.clone();
    // Check for existing limbo roles.
    {
      let limbo = &mut *LIMBO_ROLES.lock().unwrap();
      for role in &roles {
        // If the server has updated to contain the limbo role, remove it.
        if let Some(i) = limbo.iter().position(|x| x.id == role.id) {
          limbo.remove(i);
        }
      }
    }
    // Get a copy of the limbo roles.
    let limbo = LIMBO_ROLES.lock().unwrap().clone();
    // Extend the server roles with the limbo roles.
    roles.extend(limbo);

    // Find or create the necessary roles
    let mut created_roles = Vec::new();
    let mut add_roles = Vec::new();
    Tagger::find_or_create_role(&bot, on, &character.data.race, &mut add_roles, &mut created_roles)?;
    Tagger::find_or_create_role(&bot, on, &character.data.gender, &mut add_roles, &mut created_roles)?;
    Tagger::find_or_create_role(&bot, on, &character.server, &mut add_roles, &mut created_roles)?;

    if is_verified {
      Tagger::find_or_create_role(&bot, on, "verified", &mut add_roles, &mut created_roles)?;
    }

    // If we created any roles, the server may or may not update with them fast enough, so store a copy in the limbo
    // roles.
    {
      let mut limbo = &mut *LIMBO_ROLES.lock().unwrap();
      for created in &created_roles {
        limbo.push(created.clone());
      }
    }

    debug!("Created the following roles:\n:{:#?}", created_roles);

    debug!("Existing roles:\n{:#?}", add_roles);

    // Extend the roles to add with the roles we created.
    add_roles.extend(created_roles);
    // Get all the roles that are part of groups
    let all_group_roles: Vec<String> = bot.config.roles.groups.iter().flat_map(|x| x).map(|x| x.to_lowercase()).collect();
    // Filter all roles on the server to only the roles the member has
    let keep: Vec<&Role> = roles.iter().filter(|x| member.roles.contains(&x.id)).collect();
    // Filter all the roles the member has, keeping the ones not in a group. These roles will not be touched when
    // updating the tag.
    let keep: Vec<&Role> = keep.into_iter().filter(|x| !all_group_roles.contains(&x.name.to_lowercase())).collect();
    debug!("Roles to keep:\n{:#?}", keep);
    // Combine the two sets of roles and map them to IDs
    let mut role_set: Vec<RoleId> = add_roles.iter().map(|r| r.id).chain(keep.into_iter().map(|r| r.id)).collect();
    // Sort the IDs so we can dedup them
    role_set.sort();
    // Remove the duplicate roles, if any
    role_set.dedup();

    debug!("Final role set:\n{:#?}", role_set);

    // Only update the roles if they are different
    let different = {
      let member_roles: HashSet<u64> = member.roles.iter().map(|x| x.0).collect();
      let actual_role_set: HashSet<u64> = role_set.iter().map(|x| x.0).collect();
      member_roles != actual_role_set
    };
    if different {
      bot.discord.edit_member_roles(on.id, who, &role_set).chain_err(|| "could not add roles")?;
    }

    // cannot edit nickname of those with a higher role
    let nick = match member.nick {
      Some(n) => n,
      None => Default::default()
    };
    if nick != character.name {
      bot.discord.edit_member(on.id, who, |e| e.nickname(&character.name)).ok();
    }
    Ok(None)
  }
}

#[derive(Debug, Deserialize)]
struct DiscordNotFoundError {
  code: u64,
  message: Option<String>
}
<|endoftext|>


<commit_before>// Copyright 2018 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::mem::{self, ManuallyDrop};
use std::thread;

/// Dummy type that panics when its destructor is invoked.
#[derive(Debug)]
struct DropBomb();

impl Drop for DropBomb {
    fn drop(&mut self) {
        let message = "Trying to drop an AliasedCell, which may still have aliases outstanding.";
        if thread::panicking() {
            eprintln!("{}", message);
        } else {
            panic!(message);
        }
    }
}

/// A wrapper for unsafely aliased memory locations.
///
/// `AliasedCell' makes sure that its inner value
/// is completely inaccessible from safe code.
/// Once an `AliasedCell` has been constructed from some value,
/// until the value is moved out again with the (unsafe) `into_inner()` method,
/// the only way to access the wrapped value
/// is through the unsafe `alias_mut()` method.
///
/// This is useful for FFI calls that take raw pointers as input,
/// and hold on to them even after returning control to the caller.
/// Since Rust's type system is not aware of such aliases,
/// it cannot provide the usual guarantees about validity of pointers
/// and exclusiveness of mutable pointers.
/// This means that any code that has access to the memory in question
/// is inherently unsafe as long as such untracked aliases exist.
/// Putting the value in an `AliasedCell` before the FFI call,
/// and only taking it out again
/// once the caller has ensured that all aliases have been dropped
/// (most likely through another FFI call),
/// makes certain that any such unsafe access to the aliased value
/// can only happen from code marked as `unsafe`.
///
/// An `AliasedCell` should never be simply dropped in normal use.
/// Rather, it should always be freed explicitly with `into_inner()`,
/// signalling that there are no outstanding aliases anymore.
/// When an `AliasedCell` is dropped unexpectedly,
/// we have to assume that it likely still has untracked aliases,
/// and thus freeing the memory would probably be unsound.
/// Therefore, the `drop()` implementation of `AliasedCell`
/// leaks the inner value instead of freeing it;
/// and throws a panic.
/// Leaking the memory, while undesirable in general,
/// keeps the memory accessible to any outstanding aliases.
/// This is the only way to retain soundness during unwinding,
/// or when the panic gets caught.
///
/// Note that making FFI access through untracked aliases
/// requires the value to have a stable memory location --
/// typically by living on the heap rather than on the stack.
/// If the value isn't already in a heap-allocated container
/// such as `Box<>`, `Vec<>`, or `String`,
/// it is the caller's responsibility to wrap it in a `Box<>` explicitly.
/// `AliasedCell` itself cannot ensure that the address remains stable
/// when the `AliasedCell` gets moved around.
#[derive(Debug)]
pub struct AliasedCell<T> {
    value: ManuallyDrop<T>,
    drop_bomb: DropBomb,
}

impl<T> AliasedCell<T> {
    /// Wrap the provided value in an `AliasedCell`, making it inaccessible from safe code.
    pub fn new(value: T) -> AliasedCell<T> {
        AliasedCell {
            value: ManuallyDrop::new(value),
            drop_bomb: DropBomb(),
        }
    }

    /// Get a pointer to the inner value.
    ///
    /// Note that this yields a regular reference.
    /// To actually get an untracked alias,
    /// it needs to be cast or coerced into a raw pointer.
    /// This usually happens implicitly though
    /// when calling an FFI function (or any other function)
    /// taking a raw pointer as argument.
    ///
    /// `alias_mut()` can be called any number of times:
    /// the wrapper doesn't keep track of the number of outstanding aliases --
    /// the caller is responsible for making sure that no aliases are left
    /// before invoking `into_inner()`.
    /// If you need to track the number of aliases,
    /// wrap the inner value in an `Rc<>` or `Arc` --
    /// this way, the reference count will also be inaccessible from safe code.
    pub unsafe fn alias_mut(&mut self) -> &mut T {
        &mut self.value
    }

    /// Get a shared (immutable) pointer to the inner value.
    ///
    /// With this method it's possible to get an alias
    /// while only holding a shared reference to the `AliasedCell`.
    ///
    /// Since all the unsafe aliases are untracked,
    /// it's up to the callers to make sure no shared aliases are used
    /// while the data might actually be mutated elsewhere
    /// through some outstanding mutable aliases.
    pub unsafe fn alias(&self) -> &T {
        &self.value // orig &self.inner
    }

    /// Move out the wrapped value, making it accessible from safe code again.
    pub unsafe fn into_inner(self) -> T {
        mem::forget(self.drop_bomb);
        ManuallyDrop::into_inner(self.value)
    }
}

/// Some basic tests.
///
/// Note: These mostly just check that various expected usage scenarios
/// can be compiled and basically work.
/// We can't verify though that the usage is actually sound;
/// nor do we check whether invalid usage is indeed prevented by the compiler...
///
/// (The latter could probably be remedied though
/// with some sort of compile-fail tests.)
#[cfg(test)]
mod tests {
    use super::AliasedCell;

    unsafe fn mutate_value(addr: *mut [i32; 4]) {
        let value = addr.as_mut().unwrap();
        value[1] += value[3];
    }

    struct Mutator {
        addr: *mut [i32; 4],
        ascended: bool,
    }

    impl Mutator {
        unsafe fn new(addr: *mut [i32; 4]) -> Mutator {
            Mutator {
                addr: addr,
                ascended: false,
            }
        }

        fn ascend(&mut self) {
            self.ascended = true;
        }

        unsafe fn mutate(&mut self) {
            let value = self.addr.as_mut().unwrap();
            if self.ascended {
                value[3] += value[2];
            } else {
                value[1] += value[3];
            }
        }
    }

    #[test]
    fn noop_roundtrip() {
        let value = [1, 3, 3, 7];
        let cell = AliasedCell::new(Box::new(value));
        let new_value = unsafe {
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 3, 3, 7]);
    }

    #[test]
    fn unused_alias() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        unsafe {
            cell.alias_mut().as_mut();
        }
        let new_value = unsafe {
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 3, 3, 7]);
    }

    #[test]
    fn mutate() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        unsafe {
            mutate_value(cell.alias_mut().as_mut());
        }
        let new_value = unsafe {
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 10, 3, 7]);
    }

    /// Verify that we can take multiple aliases.
    #[test]
    fn mutate_twice() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        unsafe {
            mutate_value(cell.alias_mut().as_mut());
        }
        unsafe {
            mutate_value(cell.alias_mut().as_mut());
        }
        let new_value = unsafe {
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 17, 3, 7]);
    }

    /// Verify that we can do basic safe manipulations between unsafe blocks.
    #[test]
    fn moves() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        unsafe {
            mutate_value(cell.alias_mut().as_mut());
        }
        let mut cell2 = cell;
        unsafe {
            mutate_value(cell2.alias_mut().as_mut());
        }
        let cell3 = cell2;
        let new_value = unsafe {
            *cell3.into_inner()
        };
        assert_eq!(new_value, [1, 17, 3, 7]);
    }

    /// Verify that alias can be used at a later point.
    #[test]
    fn mutate_deferred() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        let mut mutator = unsafe {
            Mutator::new(cell.alias_mut().as_mut())
        };
        unsafe {
            mutator.mutate();
        }
        let new_value = unsafe {
            drop(mutator);
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 10, 3, 7]);
    }

    #[test]
    fn mutate_deferred_twice() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        let mut mutator = unsafe {
            Mutator::new(cell.alias_mut().as_mut())
        };
        unsafe {
            mutator.mutate();
        }
        unsafe {
            mutator.mutate();
        }
        let new_value = unsafe {
            drop(mutator);
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 17, 3, 7]);
    }

    /// Further safe manipulations.
    #[test]
    fn deferred_moves() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        let mutator = unsafe {
            Mutator::new(cell.alias_mut().as_mut())
        };
        let cell2 = cell;
        let mut mutator2 = mutator;
        unsafe {
            mutator2.mutate();
        }
        let cell3 = cell2;
        let mutator3 = mutator2;
        let new_value = unsafe {
            drop(mutator3);
            *cell3.into_inner()
        };
        assert_eq!(new_value, [1, 10, 3, 7]);
    }

    /// Non-trivial safe manipulation.
    #[test]
    fn safe_frobbing() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        let mut mutator = unsafe {
            Mutator::new(cell.alias_mut().as_mut())
        };
        unsafe {
            mutator.mutate();
        }
        mutator.ascend();
        unsafe {
            mutator.mutate();
        }
        let new_value = unsafe {
            drop(mutator);
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 10, 3, 10]);
    }

    /// Verify that two aliases can exist simultaneously.
    #[test]
    fn two_mutators() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        let mut mutator1 = unsafe {
            Mutator::new(cell.alias_mut().as_mut())
        };
        unsafe {
            mutator1.mutate();
        }
        let mut mutator2 = unsafe {
            Mutator::new(cell.alias_mut().as_mut())
        };
        unsafe {
            mutator2.mutate();
        }
        let new_value = unsafe {
            drop(mutator1);
            drop(mutator2);
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 17, 3, 7]);
    }

    #[test]
    #[should_panic(expected = "Trying to drop an AliasedCell, which may still have aliases outstanding.")]
    fn invalid_drop() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        unsafe {
            let mut mutator = Mutator::new(cell.alias_mut().as_mut());
            mutator.mutate();
            drop(cell);
        }
    }

    /// Verify that we skip the panic-on-drop while unwinding from another panic.
    #[test]
    #[should_panic(expected = "bye!")]
    fn panic() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        unsafe {
            let mut mutator = Mutator::new(cell.alias_mut().as_mut());
            mutator.mutate();
            panic!("bye!");
        }
    }
}
<commit_msg>Auto merge of #294 - NZXTCorp:edition-2021-fixes, r=jdm<commit_after>// Copyright 2018 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::mem::{self, ManuallyDrop};
use std::thread;

/// Dummy type that panics when its destructor is invoked.
#[derive(Debug)]
struct DropBomb();

impl Drop for DropBomb {
    fn drop(&mut self) {
        let message = "Trying to drop an AliasedCell, which may still have aliases outstanding.";
        if thread::panicking() {
            eprintln!("{}", message);
        } else {
            panic!("{}", message);
        }
    }
}

/// A wrapper for unsafely aliased memory locations.
///
/// `AliasedCell' makes sure that its inner value
/// is completely inaccessible from safe code.
/// Once an `AliasedCell` has been constructed from some value,
/// until the value is moved out again with the (unsafe) `into_inner()` method,
/// the only way to access the wrapped value
/// is through the unsafe `alias_mut()` method.
///
/// This is useful for FFI calls that take raw pointers as input,
/// and hold on to them even after returning control to the caller.
/// Since Rust's type system is not aware of such aliases,
/// it cannot provide the usual guarantees about validity of pointers
/// and exclusiveness of mutable pointers.
/// This means that any code that has access to the memory in question
/// is inherently unsafe as long as such untracked aliases exist.
/// Putting the value in an `AliasedCell` before the FFI call,
/// and only taking it out again
/// once the caller has ensured that all aliases have been dropped
/// (most likely through another FFI call),
/// makes certain that any such unsafe access to the aliased value
/// can only happen from code marked as `unsafe`.
///
/// An `AliasedCell` should never be simply dropped in normal use.
/// Rather, it should always be freed explicitly with `into_inner()`,
/// signalling that there are no outstanding aliases anymore.
/// When an `AliasedCell` is dropped unexpectedly,
/// we have to assume that it likely still has untracked aliases,
/// and thus freeing the memory would probably be unsound.
/// Therefore, the `drop()` implementation of `AliasedCell`
/// leaks the inner value instead of freeing it;
/// and throws a panic.
/// Leaking the memory, while undesirable in general,
/// keeps the memory accessible to any outstanding aliases.
/// This is the only way to retain soundness during unwinding,
/// or when the panic gets caught.
///
/// Note that making FFI access through untracked aliases
/// requires the value to have a stable memory location --
/// typically by living on the heap rather than on the stack.
/// If the value isn't already in a heap-allocated container
/// such as `Box<>`, `Vec<>`, or `String`,
/// it is the caller's responsibility to wrap it in a `Box<>` explicitly.
/// `AliasedCell` itself cannot ensure that the address remains stable
/// when the `AliasedCell` gets moved around.
#[derive(Debug)]
pub struct AliasedCell<T> {
    value: ManuallyDrop<T>,
    drop_bomb: DropBomb,
}

impl<T> AliasedCell<T> {
    /// Wrap the provided value in an `AliasedCell`, making it inaccessible from safe code.
    pub fn new(value: T) -> AliasedCell<T> {
        AliasedCell {
            value: ManuallyDrop::new(value),
            drop_bomb: DropBomb(),
        }
    }

    /// Get a pointer to the inner value.
    ///
    /// Note that this yields a regular reference.
    /// To actually get an untracked alias,
    /// it needs to be cast or coerced into a raw pointer.
    /// This usually happens implicitly though
    /// when calling an FFI function (or any other function)
    /// taking a raw pointer as argument.
    ///
    /// `alias_mut()` can be called any number of times:
    /// the wrapper doesn't keep track of the number of outstanding aliases --
    /// the caller is responsible for making sure that no aliases are left
    /// before invoking `into_inner()`.
    /// If you need to track the number of aliases,
    /// wrap the inner value in an `Rc<>` or `Arc` --
    /// this way, the reference count will also be inaccessible from safe code.
    pub unsafe fn alias_mut(&mut self) -> &mut T {
        &mut self.value
    }

    /// Get a shared (immutable) pointer to the inner value.
    ///
    /// With this method it's possible to get an alias
    /// while only holding a shared reference to the `AliasedCell`.
    ///
    /// Since all the unsafe aliases are untracked,
    /// it's up to the callers to make sure no shared aliases are used
    /// while the data might actually be mutated elsewhere
    /// through some outstanding mutable aliases.
    pub unsafe fn alias(&self) -> &T {
        &self.value // orig &self.inner
    }

    /// Move out the wrapped value, making it accessible from safe code again.
    pub unsafe fn into_inner(self) -> T {
        mem::forget(self.drop_bomb);
        ManuallyDrop::into_inner(self.value)
    }
}

/// Some basic tests.
///
/// Note: These mostly just check that various expected usage scenarios
/// can be compiled and basically work.
/// We can't verify though that the usage is actually sound;
/// nor do we check whether invalid usage is indeed prevented by the compiler...
///
/// (The latter could probably be remedied though
/// with some sort of compile-fail tests.)
#[cfg(test)]
mod tests {
    use super::AliasedCell;

    unsafe fn mutate_value(addr: *mut [i32; 4]) {
        let value = addr.as_mut().unwrap();
        value[1] += value[3];
    }

    struct Mutator {
        addr: *mut [i32; 4],
        ascended: bool,
    }

    impl Mutator {
        unsafe fn new(addr: *mut [i32; 4]) -> Mutator {
            Mutator {
                addr: addr,
                ascended: false,
            }
        }

        fn ascend(&mut self) {
            self.ascended = true;
        }

        unsafe fn mutate(&mut self) {
            let value = self.addr.as_mut().unwrap();
            if self.ascended {
                value[3] += value[2];
            } else {
                value[1] += value[3];
            }
        }
    }

    #[test]
    fn noop_roundtrip() {
        let value = [1, 3, 3, 7];
        let cell = AliasedCell::new(Box::new(value));
        let new_value = unsafe {
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 3, 3, 7]);
    }

    #[test]
    fn unused_alias() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        unsafe {
            cell.alias_mut().as_mut();
        }
        let new_value = unsafe {
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 3, 3, 7]);
    }

    #[test]
    fn mutate() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        unsafe {
            mutate_value(cell.alias_mut().as_mut());
        }
        let new_value = unsafe {
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 10, 3, 7]);
    }

    /// Verify that we can take multiple aliases.
    #[test]
    fn mutate_twice() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        unsafe {
            mutate_value(cell.alias_mut().as_mut());
        }
        unsafe {
            mutate_value(cell.alias_mut().as_mut());
        }
        let new_value = unsafe {
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 17, 3, 7]);
    }

    /// Verify that we can do basic safe manipulations between unsafe blocks.
    #[test]
    fn moves() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        unsafe {
            mutate_value(cell.alias_mut().as_mut());
        }
        let mut cell2 = cell;
        unsafe {
            mutate_value(cell2.alias_mut().as_mut());
        }
        let cell3 = cell2;
        let new_value = unsafe {
            *cell3.into_inner()
        };
        assert_eq!(new_value, [1, 17, 3, 7]);
    }

    /// Verify that alias can be used at a later point.
    #[test]
    fn mutate_deferred() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        let mut mutator = unsafe {
            Mutator::new(cell.alias_mut().as_mut())
        };
        unsafe {
            mutator.mutate();
        }
        let new_value = unsafe {
            drop(mutator);
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 10, 3, 7]);
    }

    #[test]
    fn mutate_deferred_twice() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        let mut mutator = unsafe {
            Mutator::new(cell.alias_mut().as_mut())
        };
        unsafe {
            mutator.mutate();
        }
        unsafe {
            mutator.mutate();
        }
        let new_value = unsafe {
            drop(mutator);
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 17, 3, 7]);
    }

    /// Further safe manipulations.
    #[test]
    fn deferred_moves() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        let mutator = unsafe {
            Mutator::new(cell.alias_mut().as_mut())
        };
        let cell2 = cell;
        let mut mutator2 = mutator;
        unsafe {
            mutator2.mutate();
        }
        let cell3 = cell2;
        let mutator3 = mutator2;
        let new_value = unsafe {
            drop(mutator3);
            *cell3.into_inner()
        };
        assert_eq!(new_value, [1, 10, 3, 7]);
    }

    /// Non-trivial safe manipulation.
    #[test]
    fn safe_frobbing() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        let mut mutator = unsafe {
            Mutator::new(cell.alias_mut().as_mut())
        };
        unsafe {
            mutator.mutate();
        }
        mutator.ascend();
        unsafe {
            mutator.mutate();
        }
        let new_value = unsafe {
            drop(mutator);
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 10, 3, 10]);
    }

    /// Verify that two aliases can exist simultaneously.
    #[test]
    fn two_mutators() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        let mut mutator1 = unsafe {
            Mutator::new(cell.alias_mut().as_mut())
        };
        unsafe {
            mutator1.mutate();
        }
        let mut mutator2 = unsafe {
            Mutator::new(cell.alias_mut().as_mut())
        };
        unsafe {
            mutator2.mutate();
        }
        let new_value = unsafe {
            drop(mutator1);
            drop(mutator2);
            *cell.into_inner()
        };
        assert_eq!(new_value, [1, 17, 3, 7]);
    }

    #[test]
    #[should_panic(expected = "Trying to drop an AliasedCell, which may still have aliases outstanding.")]
    fn invalid_drop() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        unsafe {
            let mut mutator = Mutator::new(cell.alias_mut().as_mut());
            mutator.mutate();
            drop(cell);
        }
    }

    /// Verify that we skip the panic-on-drop while unwinding from another panic.
    #[test]
    #[should_panic(expected = "bye!")]
    fn panic() {
        let value = [1, 3, 3, 7];
        let mut cell = AliasedCell::new(Box::new(value));
        unsafe {
            let mut mutator = Mutator::new(cell.alias_mut().as_mut());
            mutator.mutate();
            panic!("bye!");
        }
    }
}
<|endoftext|>


<commit_before>/// Trait of dispatcher.
///
/// A (collision) dispatcher typically takes two bodies in parameter and return the corresponding
/// narrow phase algorithm.
pub trait Dispatcher<G1, G2, NF> {
    /// Deduce the narrow phase from two bodies.
    fn dispatch(&self, &G1, &G2) -> Option<NF>;
    /// Tells whether a collision between two bodies can occur.
    fn is_valid(&self, &G1, &G2) -> bool;
}

/// Dispatcher which disallows dispatches between identical pointers.
///
/// It has no result.
pub struct NoIdDispatcher<B>;

impl<B> Dispatcher<B, B, ()> for NoIdDispatcher<B> {
    #[inline]
    fn dispatch(&self, _: &B, _: &B) -> Option<()> {
        Some(())
    }

    #[inline]
    fn is_valid(&self, a: &B, b: &B) -> bool {
        a as *const B != b as *const B
    }
}
<commit_msg>Add a `::new()` constructor for `NoIdDispatcher`.<commit_after>/// Trait of dispatcher.
///
/// A (collision) dispatcher typically takes two bodies in parameter and return the corresponding
/// narrow phase algorithm.
pub trait Dispatcher<G1, G2, NF> {
    /// Deduce the narrow phase from two bodies.
    fn dispatch(&self, &G1, &G2) -> Option<NF>;
    /// Tells whether a collision between two bodies can occur.
    fn is_valid(&self, &G1, &G2) -> bool;
}

/// Dispatcher which disallows dispatches between identical pointers.
///
/// It has no result.
pub struct NoIdDispatcher<B>;

impl<B> NoIdDispatcher<B> {
    /// Creates a new `NoIdDispatcher`.
    pub fn new() -> NoIdDispatcher<B> {
        NoIdDispatcher
    }
}

impl<B> Dispatcher<B, B, ()> for NoIdDispatcher<B> {
    #[inline]
    fn dispatch(&self, _: &B, _: &B) -> Option<()> {
        Some(())
    }

    #[inline]
    fn is_valid(&self, a: &B, b: &B) -> bool {
        a as *const B != b as *const B
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Regression test for issue #3645

fn main() {
    let n = 1;
    let a = [0, ..n]; //~ ERROR expected constant integer for repeat count but found variable
    let b = [0, ..()]; //~ ERROR expected positive integer for repeat count but found ()
    //~^ ERROR: expected `uint` but found `()`
    let c = [0, ..true]; //~ ERROR expected positive integer for repeat count but found boolean
    //~^ ERROR: expected `uint` but found `bool`
    let d = [0, ..0.5]; //~ ERROR expected positive integer for repeat count but found float
    //~^ ERROR: expected `uint` but found `<generic float #0>`
    let e = [0, .."foo"]; //~ ERROR expected positive integer for repeat count but found string
    //~^ ERROR: expected `uint` but found `&'static str`
    let f = [0, ..-4];
    //~^ ERROR expected positive integer for repeat count but found negative integer
}
<commit_msg>auto merge of #16350 : hirschenberger/rust/issue-15917, r=alexcrichton<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Regression test for issue #3645

fn main() {
    let n = 1;
    let a = [0, ..n]; //~ ERROR expected constant integer for repeat count but found variable
    let b = [0, ..()]; //~ ERROR expected positive integer for repeat count but found ()
    //~^ ERROR: expected `uint` but found `()`
    let c = [0, ..true]; //~ ERROR expected positive integer for repeat count but found boolean
    //~^ ERROR: expected `uint` but found `bool`
    let d = [0, ..0.5]; //~ ERROR expected positive integer for repeat count but found float
    //~^ ERROR: expected `uint` but found `<generic float #0>`
    let e = [0, .."foo"]; //~ ERROR expected positive integer for repeat count but found string
    //~^ ERROR: expected `uint` but found `&'static str`
    let f = [0, ..-4];
    //~^ ERROR expected positive integer for repeat count but found negative integer
    let f = [0u, ..-1];
    //~^ ERROR expected positive integer for repeat count but found negative integer
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! This library defines a BitVec struct that represents a bit vector.

use serde::{de::Error, Deserialize, Deserializer, Serialize};
use std::ops::BitAnd;

#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;

// Every u8 is used as a bucket of 8 bits. Total max buckets = 256 / 8 = 32.
const BUCKET_SIZE: usize = 8;
const MAX_BUCKETS: usize = 32;

/// BitVec represents a bit vector that supports 4 operations:
/// 1. Marking a position as set.
/// 2. Checking if a position is set.
/// 3. Count set bits.
/// 4. Get the index of the last set bit.
/// Internally, it stores a vector of u8's (as Vec<u8>).
/// * The first 8 positions of the bit vector are encoded in the first element of the vector, the
///   next 8 are encoded in the second element, and so on.
/// * Bits are read from left to right. For instance, in the following bitvec
///   [0b0001_0000, 0b0000_0000, 0b0000_0000, 0b0000_0001], the 3rd and 31st positions are set.
/// * Each bit of a u8 is set to 1 if the position is set and to 0 if it's not.
/// * We only allow setting positions upto u8::MAX. As a result, the size of the inner vector is
///   limited to 32 (= 256 / 8).
/// * Once a bit has been set, it cannot be unset. As a result, the inner vector cannot shrink.
/// * The positions can be set in any order.
/// * A position can set more than once -- it remains set after the first time.
///
/// # Examples:
/// let mut bv = BitVec::default();
/// bv.set(2);
/// bv.set(5);
/// assert!(bv.is_set(2));
/// assert!(bv.is_set(5));
/// assert_eq!(false, bv.is_set(0));
/// assert_eq!(bv.count_ones(), 2);
/// assert_eq!(bv.last_set_bit(), 5);
///
/// // A bitwise AND of BitVec can be performed by using the `&` operator.
/// let mut bv1 = BitVec::default();
/// bv1.set(2);
/// bv1.set(3);
/// let mut bv2 = BitVec::default();
/// bv2.set(2);
/// let intersection = bv1 & bv2;
/// assert!(intersection.is_set(2));
/// assert_eq!(false, intersection.is_set(3));
/// ```
#[derive(Clone, Default, Debug, PartialEq, Serialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct BitVec {
    #[serde(with = "serde_bytes")]
    inner: Vec<u8>,
}

impl BitVec {
    // TODO(abhayb): Remove after migration to new wire format.
    #[allow(dead_code)]
    /// Sets the bit at position @pos.
    pub fn set(&mut self, pos: u8) {
        // This is optimised to: let bucket = pos >> 3;
        let bucket: usize = pos as usize / BUCKET_SIZE;
        if self.inner.len() <= bucket {
            self.inner.resize(bucket + 1, 0);
        }
        // This is optimized to: let bucket_pos = pos | 0x07;
        let bucket_pos = pos as usize - (bucket * BUCKET_SIZE);
        self.inner[bucket] |= 0b1000_0000 >> bucket_pos as u8;
    }

    // TODO(abhayb): Remove after migration to new wire format.
    #[allow(dead_code)]
    /// Checks if the bit at position @pos is set.
    pub fn is_set(&self, pos: u8) -> bool {
        // This is optimised to: let bucket = pos >> 3;
        let bucket: usize = pos as usize / BUCKET_SIZE;
        if self.inner.len() <= bucket {
            return false;
        }
        // This is optimized to: let bucket_pos = pos | 0x07;
        let bucket_pos = pos as usize - (bucket * BUCKET_SIZE);
        (self.inner[bucket] & (0b1000_0000 >> bucket_pos as u8)) != 0
    }

    // TODO(kostas): Remove after applying it to multi-sig.
    #[allow(dead_code)]
    /// Returns the number of set bits.
    pub fn count_ones(&self) -> u32 {
        self.inner.iter().map(|a| a.count_ones()).sum()
    }

    // TODO(kostas): Remove after applying it to multi-sig.
    #[allow(dead_code)]
    /// Returns the index of the last set bit.
    pub fn last_set_bit(&self) -> Option<u8> {
        self.inner
            .iter()
            .rev()
            .enumerate()
            .find(|(_, byte)| byte != &&0u8)
            .map(|(i, byte)| {
                (8 * (self.inner.len() - i) - byte.trailing_zeros() as usize - 1) as u8
            })
    }
}

impl BitAnd for BitVec {
    type Output = BitVec;

    /// Returns a new BitVec that is a bitwise AND of two BitVecs.
    fn bitand(self, other: Self) -> Self {
        let len = std::cmp::min(self.inner.len(), other.inner.len());
        let mut ret = BitVec {
            inner: Vec::with_capacity(len),
        };
        for i in 0..len {
            ret.inner.push(self.inner[i] & other.inner[i]);
        }
        ret
    }
}

// We impl custom deserialization to ensure that the length of inner vector does not exceed
// 32 (= 256 / 8).
impl<'de> Deserialize<'de> for BitVec {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let v = serde_bytes::ByteBuf::deserialize(deserializer)?.into_vec();
        if v.len() > MAX_BUCKETS {
            return Err(D::Error::custom(format!("BitVec too long: {}", v.len())));
        }
        Ok(BitVec { inner: v })
    }
}

#[cfg(test)]
mod test {

    use super::*;
    use proptest::{arbitrary::any, collection::vec, prelude::*};

    #[test]
    fn test_count_ones() {
        let p0 = BitVec::default();
        assert_eq!(p0.count_ones(), 0);
        // 7 = b'0000111' and 240 = b'00001111'
        let p1 = BitVec {
            inner: vec![7u8, 15u8],
        };
        assert_eq!(p1.count_ones(), 7);

        let p2 = BitVec {
            inner: vec![7u8; MAX_BUCKETS],
        };
        assert_eq!(p2.count_ones(), 3 * MAX_BUCKETS as u32);

        // 255 = b'11111111'
        let p3 = BitVec {
            inner: vec![255u8; MAX_BUCKETS],
        };
        assert_eq!(p3.count_ones(), 8 * MAX_BUCKETS as u32);

        // 0 = b'00000000'
        let p4 = BitVec {
            inner: vec![0u8; MAX_BUCKETS],
        };
        assert_eq!(p4.count_ones(), 0);
    }

    #[test]
    fn test_last_set_bit() {
        let p0 = BitVec::default();
        assert_eq!(p0.last_set_bit(), None);
        // 224 = b'11100000'
        let p1 = BitVec { inner: vec![224u8] };
        assert_eq!(p1.inner.len(), 1);
        assert_eq!(p1.last_set_bit(), Some(2));

        // 128 = 0b1000_0000
        let p2 = BitVec {
            inner: vec![7u8, 128u8],
        };
        assert_eq!(p2.inner.len(), 2);
        assert_eq!(p2.last_set_bit(), Some(8));

        let p3 = BitVec {
            inner: vec![255u8; MAX_BUCKETS],
        };
        assert_eq!(p3.inner.len(), MAX_BUCKETS);
        assert_eq!(p3.last_set_bit(), Some(255));

        let p4 = BitVec {
            inner: vec![0u8; MAX_BUCKETS],
        };
        assert_eq!(p4.last_set_bit(), None);

        // An extra test to ensure left to right encoding.
        let mut p5 = BitVec {
            inner: vec![0b0000_0001, 0b0100_0000],
        };
        assert_eq!(p5.last_set_bit(), Some(9));
        assert!(p5.is_set(7));
        assert!(p5.is_set(9));
        assert!(!p5.is_set(0));

        p5.set(10);
        assert!(p5.is_set(10));
        assert_eq!(p5.last_set_bit(), Some(10));
        assert_eq!(p5.inner, vec![0b0000_0001, 0b0110_0000])
    }

    #[test]
    fn test_empty() {
        let p = BitVec::default();
        for i in 0..=std::u8::MAX {
            assert_eq!(false, p.is_set(i));
        }
    }

    #[test]
    fn test_extremes() {
        let mut p = BitVec::default();
        p.set(std::u8::MAX);
        p.set(0);
        assert!(p.is_set(std::u8::MAX));
        assert!(p.is_set(0));
        for i in 1..std::u8::MAX {
            assert_eq!(false, p.is_set(i));
        }
    }

    #[test]
    fn test_deserialization() {
        // When the length is smaller than 128, it is encoded in the first byte.
        // (see comments in BCS crate)
        let mut bytes = [0u8; 47];
        bytes[0] = 46;
        assert!(bcs::from_bytes::<Vec<u8>>(&bytes).is_ok());
        // However, 46 > MAX_BUCKET:
        assert!(bcs::from_bytes::<BitVec>(&bytes).is_err());
        let mut bytes = [0u8; 33];
        bytes[0] = 32;
        let bv = BitVec {
            inner: Vec::from([0u8; 32].as_ref()),
        };
        assert_eq!(Ok(bv), bcs::from_bytes::<BitVec>(&bytes));
    }

    // Constructs a bit vector by setting the positions specified in the argument vector. The
    // vector can have duplicates and need not be sorted.
    fn construct_bitvec(posns: &[u8]) -> BitVec {
        let mut bv = BitVec::default();
        posns.iter().for_each(|x| bv.set(*x));
        bv
    }

    // Proptest for ensuring is_set returns true iff corresponding position was set.
    proptest! {
        #[test]
        fn test_arbitrary(mut v in vec(any::<u8>(), 0..256)) {
            let bv = construct_bitvec(&v);
            // Sort and dedup the vector so we can iterate over its elements from smallest to largest.
            v.sort_unstable();
            v.dedup();
            let mut viter = v.into_iter().peekable();
            // Positions in bv should be set iff they are in v.
            for i in 0..std::u8::MAX {
                if viter.peek() == Some(&i) {
                    prop_assert!(bv.is_set(i));
                    viter.next();
                } else {
                    prop_assert_eq!(false, bv.is_set(i));
                }
            }

        }
    }

    // Test for bitwise AND operation on 2 bitvecs.
    proptest! {
        #[test]
        fn test_and(v1 in vec(any::<u8>(), 0..256), v2 in vec(any::<u8>(), 0..256)) {
            let bv1 = construct_bitvec(&v1);
            let bv2 = construct_bitvec(&v2);
            let intersection = bv1.clone() & bv2.clone();
            for i in 0..std::u8::MAX {
                if bv1.is_set(i) && bv2.is_set(i) {
                    prop_assert!(intersection.is_set(i));
                } else {
                    prop_assert_eq!(false, intersection.is_set(i));
                }
            }

        }
    }
}
<commit_msg>fix bitvec test<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! This library defines a BitVec struct that represents a bit vector.

use serde::{de::Error, Deserialize, Deserializer, Serialize};
use std::ops::BitAnd;

#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;

// Every u8 is used as a bucket of 8 bits. Total max buckets = 256 / 8 = 32.
const BUCKET_SIZE: usize = 8;
const MAX_BUCKETS: usize = 32;

/// BitVec represents a bit vector that supports 4 operations:
/// 1. Marking a position as set.
/// 2. Checking if a position is set.
/// 3. Count set bits.
/// 4. Get the index of the last set bit.
/// Internally, it stores a vector of u8's (as Vec<u8>).
/// * The first 8 positions of the bit vector are encoded in the first element of the vector, the
///   next 8 are encoded in the second element, and so on.
/// * Bits are read from left to right. For instance, in the following bitvec
///   [0b0001_0000, 0b0000_0000, 0b0000_0000, 0b0000_0001], the 3rd and 31st positions are set.
/// * Each bit of a u8 is set to 1 if the position is set and to 0 if it's not.
/// * We only allow setting positions upto u8::MAX. As a result, the size of the inner vector is
///   limited to 32 (= 256 / 8).
/// * Once a bit has been set, it cannot be unset. As a result, the inner vector cannot shrink.
/// * The positions can be set in any order.
/// * A position can set more than once -- it remains set after the first time.
///
/// # Examples:
/// let mut bv = BitVec::default();
/// bv.set(2);
/// bv.set(5);
/// assert!(bv.is_set(2));
/// assert!(bv.is_set(5));
/// assert_eq!(false, bv.is_set(0));
/// assert_eq!(bv.count_ones(), 2);
/// assert_eq!(bv.last_set_bit(), 5);
///
/// // A bitwise AND of BitVec can be performed by using the `&` operator.
/// let mut bv1 = BitVec::default();
/// bv1.set(2);
/// bv1.set(3);
/// let mut bv2 = BitVec::default();
/// bv2.set(2);
/// let intersection = bv1 & bv2;
/// assert!(intersection.is_set(2));
/// assert_eq!(false, intersection.is_set(3));
/// ```
#[derive(Clone, Default, Debug, PartialEq, Serialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct BitVec {
    #[serde(with = "serde_bytes")]
    inner: Vec<u8>,
}

impl BitVec {
    // TODO(abhayb): Remove after migration to new wire format.
    #[allow(dead_code)]
    /// Sets the bit at position @pos.
    pub fn set(&mut self, pos: u8) {
        // This is optimised to: let bucket = pos >> 3;
        let bucket: usize = pos as usize / BUCKET_SIZE;
        if self.inner.len() <= bucket {
            self.inner.resize(bucket + 1, 0);
        }
        // This is optimized to: let bucket_pos = pos | 0x07;
        let bucket_pos = pos as usize - (bucket * BUCKET_SIZE);
        self.inner[bucket] |= 0b1000_0000 >> bucket_pos as u8;
    }

    // TODO(abhayb): Remove after migration to new wire format.
    #[allow(dead_code)]
    /// Checks if the bit at position @pos is set.
    pub fn is_set(&self, pos: u8) -> bool {
        // This is optimised to: let bucket = pos >> 3;
        let bucket: usize = pos as usize / BUCKET_SIZE;
        if self.inner.len() <= bucket {
            return false;
        }
        // This is optimized to: let bucket_pos = pos | 0x07;
        let bucket_pos = pos as usize - (bucket * BUCKET_SIZE);
        (self.inner[bucket] & (0b1000_0000 >> bucket_pos as u8)) != 0
    }

    // TODO(kostas): Remove after applying it to multi-sig.
    #[allow(dead_code)]
    /// Returns the number of set bits.
    pub fn count_ones(&self) -> u32 {
        self.inner.iter().map(|a| a.count_ones()).sum()
    }

    // TODO(kostas): Remove after applying it to multi-sig.
    #[allow(dead_code)]
    /// Returns the index of the last set bit.
    pub fn last_set_bit(&self) -> Option<u8> {
        self.inner
            .iter()
            .rev()
            .enumerate()
            .find(|(_, byte)| byte != &&0u8)
            .map(|(i, byte)| {
                (8 * (self.inner.len() - i) - byte.trailing_zeros() as usize - 1) as u8
            })
    }
}

impl BitAnd for BitVec {
    type Output = BitVec;

    /// Returns a new BitVec that is a bitwise AND of two BitVecs.
    fn bitand(self, other: Self) -> Self {
        let len = std::cmp::min(self.inner.len(), other.inner.len());
        let mut ret = BitVec {
            inner: Vec::with_capacity(len),
        };
        for i in 0..len {
            ret.inner.push(self.inner[i] & other.inner[i]);
        }
        ret
    }
}

// We impl custom deserialization to ensure that the length of inner vector does not exceed
// 32 (= 256 / 8).
impl<'de> Deserialize<'de> for BitVec {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let v = serde_bytes::ByteBuf::deserialize(deserializer)?.into_vec();
        if v.len() > MAX_BUCKETS {
            return Err(D::Error::custom(format!("BitVec too long: {}", v.len())));
        }
        Ok(BitVec { inner: v })
    }
}

#[cfg(test)]
mod test {

    use super::*;
    use proptest::{arbitrary::any, collection::vec, prelude::*};

    #[test]
    fn test_count_ones() {
        let p0 = BitVec::default();
        assert_eq!(p0.count_ones(), 0);
        // 7 = b'0000111' and 240 = b'00001111'
        let p1 = BitVec {
            inner: vec![7u8, 15u8],
        };
        assert_eq!(p1.count_ones(), 7);

        let p2 = BitVec {
            inner: vec![7u8; MAX_BUCKETS],
        };
        assert_eq!(p2.count_ones(), 3 * MAX_BUCKETS as u32);

        // 255 = b'11111111'
        let p3 = BitVec {
            inner: vec![255u8; MAX_BUCKETS],
        };
        assert_eq!(p3.count_ones(), 8 * MAX_BUCKETS as u32);

        // 0 = b'00000000'
        let p4 = BitVec {
            inner: vec![0u8; MAX_BUCKETS],
        };
        assert_eq!(p4.count_ones(), 0);
    }

    #[test]
    fn test_last_set_bit() {
        let p0 = BitVec::default();
        assert_eq!(p0.last_set_bit(), None);
        // 224 = b'11100000'
        let p1 = BitVec { inner: vec![224u8] };
        assert_eq!(p1.inner.len(), 1);
        assert_eq!(p1.last_set_bit(), Some(2));

        // 128 = 0b1000_0000
        let p2 = BitVec {
            inner: vec![7u8, 128u8],
        };
        assert_eq!(p2.inner.len(), 2);
        assert_eq!(p2.last_set_bit(), Some(8));

        let p3 = BitVec {
            inner: vec![255u8; MAX_BUCKETS],
        };
        assert_eq!(p3.inner.len(), MAX_BUCKETS);
        assert_eq!(p3.last_set_bit(), Some(255));

        let p4 = BitVec {
            inner: vec![0u8; MAX_BUCKETS],
        };
        assert_eq!(p4.last_set_bit(), None);

        // An extra test to ensure left to right encoding.
        let mut p5 = BitVec {
            inner: vec![0b0000_0001, 0b0100_0000],
        };
        assert_eq!(p5.last_set_bit(), Some(9));
        assert!(p5.is_set(7));
        assert!(p5.is_set(9));
        assert!(!p5.is_set(0));

        p5.set(10);
        assert!(p5.is_set(10));
        assert_eq!(p5.last_set_bit(), Some(10));
        assert_eq!(p5.inner, vec![0b0000_0001, 0b0110_0000]);

        let p6 = BitVec { inner: vec![128u8] };
        assert_eq!(p6.inner.len(), 1);
        assert_eq!(p6.last_set_bit(), Some(0));
    }

    #[test]
    fn test_empty() {
        let p = BitVec::default();
        for i in 0..=std::u8::MAX {
            assert_eq!(false, p.is_set(i));
        }
    }

    #[test]
    fn test_extremes() {
        let mut p = BitVec::default();
        p.set(std::u8::MAX);
        p.set(0);
        assert!(p.is_set(std::u8::MAX));
        assert!(p.is_set(0));
        for i in 1..std::u8::MAX {
            assert_eq!(false, p.is_set(i));
        }
    }

    #[test]
    fn test_deserialization() {
        // When the length is smaller than 128, it is encoded in the first byte.
        // (see comments in BCS crate)
        let mut bytes = [0u8; 47];
        bytes[0] = 46;
        assert!(bcs::from_bytes::<Vec<u8>>(&bytes).is_ok());
        // However, 46 > MAX_BUCKET:
        assert!(bcs::from_bytes::<BitVec>(&bytes).is_err());
        let mut bytes = [0u8; 33];
        bytes[0] = 32;
        let bv = BitVec {
            inner: Vec::from([0u8; 32].as_ref()),
        };
        assert_eq!(Ok(bv), bcs::from_bytes::<BitVec>(&bytes));
    }

    // Constructs a bit vector by setting the positions specified in the argument vector. The
    // vector can have duplicates and need not be sorted.
    fn construct_bitvec(posns: &[u8]) -> BitVec {
        let mut bv = BitVec::default();
        posns.iter().for_each(|x| bv.set(*x));
        bv
    }

    // Proptest for ensuring is_set returns true iff corresponding position was set.
    proptest! {
        #[test]
        fn test_arbitrary(mut v in vec(any::<u8>(), 0..256)) {
            let bv = construct_bitvec(&v);
            // Sort and dedup the vector so we can iterate over its elements from smallest to largest.
            v.sort_unstable();
            v.dedup();
            let mut viter = v.into_iter().peekable();
            // Positions in bv should be set iff they are in v.
            for i in 0..std::u8::MAX {
                if viter.peek() == Some(&i) {
                    prop_assert!(bv.is_set(i));
                    viter.next();
                } else {
                    prop_assert_eq!(false, bv.is_set(i));
                }
            }

        }
    }

    // Test for bitwise AND operation on 2 bitvecs.
    proptest! {
        #[test]
        fn test_and(v1 in vec(any::<u8>(), 0..256), v2 in vec(any::<u8>(), 0..256)) {
            let bv1 = construct_bitvec(&v1);
            let bv2 = construct_bitvec(&v2);
            let intersection = bv1.clone() & bv2.clone();
            for i in 0..std::u8::MAX {
                if bv1.is_set(i) && bv2.is_set(i) {
                    prop_assert!(intersection.is_set(i));
                } else {
                    prop_assert_eq!(false, intersection.is_set(i));
                }
            }

        }
    }
}
<|endoftext|>