<commit_before>use crate::syntax::atom::Atom::{self, *};
use crate::syntax::report::Errors;
use crate::syntax::set::OrderedSet as Set;
use crate::syntax::{Api, Derive, Enum, Struct, Type, TypeAlias};
use proc_macro2::Ident;
use quote::ToTokens;
use std::collections::{BTreeMap as Map, HashSet as UnorderedSet};

pub struct Types<'a> {
    pub all: Set<&'a Type>,
    pub structs: Map<&'a Ident, &'a Struct>,
    pub enums: Map<&'a Ident, &'a Enum>,
    pub cxx: Set<&'a Ident>,
    pub rust: Set<&'a Ident>,
    pub aliases: Map<&'a Ident, &'a TypeAlias>,
}

impl<'a> Types<'a> {
    pub fn collect(cx: &mut Errors, apis: &'a [Api]) -> Self {
        let mut all = Set::new();
        let mut structs = Map::new();
        let mut enums = Map::new();
        let mut cxx = Set::new();
        let mut rust = Set::new();
        let mut aliases = Map::new();

        fn visit<'a>(all: &mut Set<&'a Type>, ty: &'a Type) {
            all.insert(ty);
            match ty {
                Type::Ident(_) | Type::Str(_) | Type::Void(_) | Type::SliceRefU8(_) => {}
                Type::RustBox(ty)
                | Type::UniquePtr(ty)
                | Type::CxxVector(ty)
                | Type::RustVec(ty) => visit(all, &ty.inner),
                Type::Ref(r) => visit(all, &r.inner),
                Type::Slice(s) => visit(all, &s.inner),
                Type::Fn(f) => {
                    if let Some(ret) = &f.ret {
                        visit(all, ret);
                    }
                    for arg in &f.args {
                        visit(all, &arg.ty);
                    }
                }
            }
        }

        let mut type_names = UnorderedSet::new();
        let mut function_names = UnorderedSet::new();
        for api in apis {
            // The same identifier is permitted to be declared as both a shared
            // enum and extern C++ type, or shared struct and extern C++ type.
            // That indicates to not emit the C++ enum/struct definition because
            // it's defined by the included headers already.
            //
            // All other cases of duplicate identifiers are reported as an error.
            match api {
                Api::Include(_) => {}
                Api::Struct(strct) => {
                    let ident = &strct.ident;
                    if !type_names.insert(ident)
                        && (!cxx.contains(ident)
                            || structs.contains_key(ident)
                            || enums.contains_key(ident))
                    {
                        // If already declared as a struct or enum, or if
                        // colliding with something other than an extern C++
                        // type, then error.
                        duplicate_name(cx, strct, ident);
                    }
                    structs.insert(ident, strct);
                    for field in &strct.fields {
                        visit(&mut all, &field.ty);
                    }
                }
                Api::Enum(enm) => {
                    let ident = &enm.ident;
                    if !type_names.insert(ident)
                        && (!cxx.contains(ident)
                            || structs.contains_key(ident)
                            || enums.contains_key(ident))
                    {
                        // If already declared as a struct or enum, or if
                        // colliding with something other than an extern C++
                        // type, then error.
                        duplicate_name(cx, enm, ident);
                    }
                    enums.insert(ident, enm);
                }
                Api::CxxType(ety) => {
                    let ident = &ety.ident;
                    if !type_names.insert(ident)
                        && (cxx.contains(ident)
                            || !structs.contains_key(ident) && !enums.contains_key(ident))
                    {
                        // If already declared as an extern C++ type, or if
                        // colliding with something which is neither struct nor
                        // enum, then error.
                        duplicate_name(cx, ety, ident);
                    }
                    cxx.insert(ident);
                }
                Api::RustType(ety) => {
                    let ident = &ety.ident;
                    if !type_names.insert(ident) {
                        duplicate_name(cx, ety, ident);
                    }
                    rust.insert(ident);
                }
                Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                    let ident = &efn.ident;
                    if !function_names.insert((&efn.receiver, ident)) {
                        duplicate_name(cx, efn, ident);
                    }
                    for arg in &efn.args {
                        visit(&mut all, &arg.ty);
                    }
                    if let Some(ret) = &efn.ret {
                        visit(&mut all, ret);
                    }
                }
                Api::TypeAlias(alias) => {
                    let ident = &alias.ident;
                    if !type_names.insert(ident) {
                        duplicate_name(cx, alias, ident);
                    }
                    cxx.insert(ident);
                    aliases.insert(ident, alias);
                }
            }
        }

        Types {
            all,
            structs,
            enums,
            cxx,
            rust,
            aliases,
        }
    }

    pub fn needs_indirect_abi(&self, ty: &Type) -> bool {
        match ty {
            Type::Ident(ident) => {
                if let Some(strct) = self.structs.get(ident) {
                    !self.is_pod(strct)
                } else {
                    Atom::from(ident) == Some(RustString)
                }
            }
            Type::RustVec(_) => true,
            _ => false,
        }
    }

    pub fn is_pod(&self, strct: &Struct) -> bool {
        for derive in &strct.derives {
            if *derive == Derive::Copy {
                return true;
            }
        }
        false
    }
}

impl<'t, 'a> IntoIterator for &'t Types<'a> {
    type Item = &'a Type;
    type IntoIter = crate::syntax::set::Iter<'t, 'a, Type>;
    fn into_iter(self) -> Self::IntoIter {
        self.all.into_iter()
    }
}

fn duplicate_name(cx: &mut Errors, sp: impl ToTokens, ident: &Ident) {
    let msg = format!("the name `{}` is defined multiple times", ident);
    cx.error(sp, msg);
}
<commit_msg>Track set of trusted extern types<commit_after>use crate::syntax::atom::Atom::{self, *};
use crate::syntax::report::Errors;
use crate::syntax::set::OrderedSet as Set;
use crate::syntax::{Api, Derive, Enum, Struct, Type, TypeAlias};
use proc_macro2::Ident;
use quote::ToTokens;
use std::collections::{BTreeMap as Map, HashSet as UnorderedSet};

pub struct Types<'a> {
    pub all: Set<&'a Type>,
    pub structs: Map<&'a Ident, &'a Struct>,
    pub enums: Map<&'a Ident, &'a Enum>,
    pub cxx: Set<&'a Ident>,
    pub rust: Set<&'a Ident>,
    pub aliases: Map<&'a Ident, &'a TypeAlias>,
    pub trusted: Set<&'a Ident>,
}

impl<'a> Types<'a> {
    pub fn collect(cx: &mut Errors, apis: &'a [Api]) -> Self {
        let mut all = Set::new();
        let mut structs = Map::new();
        let mut enums = Map::new();
        let mut cxx = Set::new();
        let mut rust = Set::new();
        let mut aliases = Map::new();
        let mut trusted = Set::new();

        fn visit<'a>(all: &mut Set<&'a Type>, ty: &'a Type) {
            all.insert(ty);
            match ty {
                Type::Ident(_) | Type::Str(_) | Type::Void(_) | Type::SliceRefU8(_) => {}
                Type::RustBox(ty)
                | Type::UniquePtr(ty)
                | Type::CxxVector(ty)
                | Type::RustVec(ty) => visit(all, &ty.inner),
                Type::Ref(r) => visit(all, &r.inner),
                Type::Slice(s) => visit(all, &s.inner),
                Type::Fn(f) => {
                    if let Some(ret) = &f.ret {
                        visit(all, ret);
                    }
                    for arg in &f.args {
                        visit(all, &arg.ty);
                    }
                }
            }
        }

        let mut type_names = UnorderedSet::new();
        let mut function_names = UnorderedSet::new();
        for api in apis {
            // The same identifier is permitted to be declared as both a shared
            // enum and extern C++ type, or shared struct and extern C++ type.
            // That indicates to not emit the C++ enum/struct definition because
            // it's defined by the included headers already.
            //
            // All other cases of duplicate identifiers are reported as an error.
            match api {
                Api::Include(_) => {}
                Api::Struct(strct) => {
                    let ident = &strct.ident;
                    if !type_names.insert(ident)
                        && (!cxx.contains(ident)
                            || structs.contains_key(ident)
                            || enums.contains_key(ident))
                    {
                        // If already declared as a struct or enum, or if
                        // colliding with something other than an extern C++
                        // type, then error.
                        duplicate_name(cx, strct, ident);
                    }
                    structs.insert(ident, strct);
                    for field in &strct.fields {
                        visit(&mut all, &field.ty);
                    }
                }
                Api::Enum(enm) => {
                    let ident = &enm.ident;
                    if !type_names.insert(ident)
                        && (!cxx.contains(ident)
                            || structs.contains_key(ident)
                            || enums.contains_key(ident))
                    {
                        // If already declared as a struct or enum, or if
                        // colliding with something other than an extern C++
                        // type, then error.
                        duplicate_name(cx, enm, ident);
                    }
                    enums.insert(ident, enm);
                }
                Api::CxxType(ety) => {
                    let ident = &ety.ident;
                    if !type_names.insert(ident)
                        && (cxx.contains(ident)
                            || !structs.contains_key(ident) && !enums.contains_key(ident))
                    {
                        // If already declared as an extern C++ type, or if
                        // colliding with something which is neither struct nor
                        // enum, then error.
                        duplicate_name(cx, ety, ident);
                    }
                    cxx.insert(ident);
                    if ety.trusted {
                        trusted.insert(ident);
                    }
                }
                Api::RustType(ety) => {
                    let ident = &ety.ident;
                    if !type_names.insert(ident) {
                        duplicate_name(cx, ety, ident);
                    }
                    rust.insert(ident);
                }
                Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                    let ident = &efn.ident;
                    if !function_names.insert((&efn.receiver, ident)) {
                        duplicate_name(cx, efn, ident);
                    }
                    for arg in &efn.args {
                        visit(&mut all, &arg.ty);
                    }
                    if let Some(ret) = &efn.ret {
                        visit(&mut all, ret);
                    }
                }
                Api::TypeAlias(alias) => {
                    let ident = &alias.ident;
                    if !type_names.insert(ident) {
                        duplicate_name(cx, alias, ident);
                    }
                    cxx.insert(ident);
                    aliases.insert(ident, alias);
                }
            }
        }

        Types {
            all,
            structs,
            enums,
            cxx,
            rust,
            aliases,
            trusted,
        }
    }

    pub fn needs_indirect_abi(&self, ty: &Type) -> bool {
        match ty {
            Type::Ident(ident) => {
                if let Some(strct) = self.structs.get(ident) {
                    !self.is_pod(strct)
                } else {
                    Atom::from(ident) == Some(RustString)
                }
            }
            Type::RustVec(_) => true,
            _ => false,
        }
    }

    pub fn is_pod(&self, strct: &Struct) -> bool {
        for derive in &strct.derives {
            if *derive == Derive::Copy {
                return true;
            }
        }
        false
    }
}

impl<'t, 'a> IntoIterator for &'t Types<'a> {
    type Item = &'a Type;
    type IntoIter = crate::syntax::set::Iter<'t, 'a, Type>;
    fn into_iter(self) -> Self::IntoIter {
        self.all.into_iter()
    }
}

fn duplicate_name(cx: &mut Errors, sp: impl ToTokens, ident: &Ident) {
    let msg = format!("the name `{}` is defined multiple times", ident);
    cx.error(sp, msg);
}
<|endoftext|>


<commit_before>#[cfg(feature = "binaries")]
mod binary {
  use assert_cmd::Command;
  use rand::distributions::Alphanumeric;
  use rand::{thread_rng, Rng};
  use std::env::temp_dir;
  use std::fs::File;
  use std::io::Read;
  use std::path::{Path, PathBuf};

  fn get_y4m_input() -> Vec<u8> {
    let mut input = File::open(&format!(
      "{}/tests/small_input.y4m",
      env!("CARGO_MANIFEST_DIR")
    ))
    .unwrap();
    let mut data = Vec::new();
    input.read_to_end(&mut data).unwrap();
    data
  }

  fn get_tempfile_path(extension: &str) -> PathBuf {
    let mut path = temp_dir();
    let filename = thread_rng()
      .sample_iter(Alphanumeric)
      .take(12)
      .map(char::from)
      .collect::<String>();
    path.push(format!("{}.{}", filename, extension));
    path
  }

  #[cfg(not(windows))]
  fn get_rav1e_command() -> Command {
    let mut cmd = Command::cargo_bin("rav1e").unwrap();
    cmd.env_clear();
    cmd
  }

  #[cfg(windows)]
  // `env_clear` doesn't work on Windows: https://github.com/rust-lang/rust/issues/31259
  fn get_rav1e_command() -> Command {
    Command::cargo_bin("rav1e").unwrap()
  }

  fn get_common_cmd(outfile: &Path) -> Command {
    let mut cmd = get_rav1e_command();
    cmd.args(&["--bitrate", "1000"]).arg("-o").arg(outfile).arg("-y");
    cmd
  }

  #[test]
  fn one_pass_qp_based() {
    let outfile = get_tempfile_path("ivf");

    get_rav1e_command()
      .args(&["--quantizer", "100"])
      .arg("-o")
      .arg(&outfile)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();
  }

  #[test]
  fn one_pass_bitrate_based() {
    let outfile = get_tempfile_path("ivf");

    get_common_cmd(&outfile)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();
  }

  #[test]
  fn two_pass_bitrate_based() {
    let outfile = get_tempfile_path("ivf");
    let passfile = get_tempfile_path("pass");

    get_common_cmd(&outfile)
      .arg("--first-pass")
      .arg(&passfile)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();

    get_common_cmd(&outfile)
      .arg("--second-pass")
      .arg(&passfile)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();
  }
  #[test]
  fn two_pass_bitrate_based_constrained() {
    let outfile = get_tempfile_path("ivf");
    let passfile = get_tempfile_path("pass");

    get_common_cmd(&outfile)
      .args(&["--reservoir-frame-delay", "14"])
      .arg("--first-pass")
      .arg(&passfile)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();

    get_common_cmd(&outfile)
      .args(&["--reservoir-frame-delay", "14"])
      .arg("--second-pass")
      .arg(&passfile)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();
  }
}
<commit_msg>tests: Add three-pass encode with target bitrate<commit_after>#[cfg(feature = "binaries")]
mod binary {
  use assert_cmd::Command;
  use rand::distributions::Alphanumeric;
  use rand::{thread_rng, Rng};
  use std::env::temp_dir;
  use std::fs::File;
  use std::io::Read;
  use std::path::{Path, PathBuf};

  fn get_y4m_input() -> Vec<u8> {
    let mut input = File::open(&format!(
      "{}/tests/small_input.y4m",
      env!("CARGO_MANIFEST_DIR")
    ))
    .unwrap();
    let mut data = Vec::new();
    input.read_to_end(&mut data).unwrap();
    data
  }

  fn get_tempfile_path(extension: &str) -> PathBuf {
    let mut path = temp_dir();
    let filename = thread_rng()
      .sample_iter(Alphanumeric)
      .take(12)
      .map(char::from)
      .collect::<String>();
    path.push(format!("{}.{}", filename, extension));
    path
  }

  #[cfg(not(windows))]
  fn get_rav1e_command() -> Command {
    let mut cmd = Command::cargo_bin("rav1e").unwrap();
    cmd.env_clear();
    cmd
  }

  #[cfg(windows)]
  // `env_clear` doesn't work on Windows: https://github.com/rust-lang/rust/issues/31259
  fn get_rav1e_command() -> Command {
    Command::cargo_bin("rav1e").unwrap()
  }

  fn get_common_cmd(outfile: &Path) -> Command {
    let mut cmd = get_rav1e_command();
    cmd.args(&["--bitrate", "1000"]).arg("-o").arg(outfile).arg("-y");
    cmd
  }

  #[test]
  fn one_pass_qp_based() {
    let outfile = get_tempfile_path("ivf");

    get_rav1e_command()
      .args(&["--quantizer", "100"])
      .arg("-o")
      .arg(&outfile)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();
  }

  #[test]
  fn one_pass_bitrate_based() {
    let outfile = get_tempfile_path("ivf");

    get_common_cmd(&outfile)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();
  }

  #[test]
  fn two_pass_bitrate_based() {
    let outfile = get_tempfile_path("ivf");
    let passfile = get_tempfile_path("pass");

    get_common_cmd(&outfile)
      .arg("--first-pass")
      .arg(&passfile)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();

    get_common_cmd(&outfile)
      .arg("--second-pass")
      .arg(&passfile)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();
  }
  #[test]
  fn two_pass_bitrate_based_constrained() {
    let outfile = get_tempfile_path("ivf");
    let passfile = get_tempfile_path("pass");

    get_common_cmd(&outfile)
      .args(&["--reservoir-frame-delay", "14"])
      .arg("--first-pass")
      .arg(&passfile)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();

    get_common_cmd(&outfile)
      .args(&["--reservoir-frame-delay", "14"])
      .arg("--second-pass")
      .arg(&passfile)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();
  }

  #[test]
  fn three_pass_bitrate_based() {
    let outfile = get_tempfile_path("ivf");
    let pass1file = get_tempfile_path("pass1");
    let pass2file = get_tempfile_path("pass2");

    get_common_cmd(&outfile)
      .arg("--first-pass")
      .arg(&pass1file)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();

    get_common_cmd(&outfile)
      .arg("--second-pass")
      .arg(&pass1file)
      .arg("--first-pass")
      .arg(&pass2file)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();

    get_common_cmd(&outfile)
      .arg("--second-pass")
      .arg(&pass2file)
      .arg("-")
      .write_stdin(get_y4m_input())
      .assert()
      .success();
  }
}
<|endoftext|>


<commit_before>#![feature(io, path)]

extern crate flate2;

use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::path::Path;
use flate2::read::GzDecoder;

// test extraction of a gzipped file
#[test]
fn test_extract_success() {
    let content = extract_file(Path::new("tests/good-file.gz")).unwrap();
    let mut expected = Vec::new();
    File::open("tests/good-file.txt").unwrap().read_to_end(&mut expected).unwrap();
    assert!(content == expected);
}

// test extraction fails on a corrupt file
#[test]
fn test_extract_failure() {
    let result = extract_file(Path::new("tests/corrupt-file.gz"));
    assert_eq!(result.err().unwrap().kind(), io::ErrorKind::InvalidInput);
}

// Tries to extract path into memory (assuming a .gz file).
fn extract_file(path_compressed: &Path) -> io::Result<Vec<u8>>{
    let mut v = Vec::new();
    let f = try!(File::open(path_compressed));
    try!(try!(GzDecoder::new(f)).read_to_end(&mut v));
    Ok(v)
}
<commit_msg>Update to rust master<commit_after>extern crate flate2;

use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::path::Path;
use flate2::read::GzDecoder;

// test extraction of a gzipped file
#[test]
fn test_extract_success() {
    let content = extract_file(Path::new("tests/good-file.gz")).unwrap();
    let mut expected = Vec::new();
    File::open("tests/good-file.txt").unwrap().read_to_end(&mut expected).unwrap();
    assert!(content == expected);
}

// test extraction fails on a corrupt file
#[test]
fn test_extract_failure() {
    let result = extract_file(Path::new("tests/corrupt-file.gz"));
    assert_eq!(result.err().unwrap().kind(), io::ErrorKind::InvalidInput);
}

// Tries to extract path into memory (assuming a .gz file).
fn extract_file(path_compressed: &Path) -> io::Result<Vec<u8>>{
    let mut v = Vec::new();
    let f = try!(File::open(path_compressed));
    try!(try!(GzDecoder::new(f)).read_to_end(&mut v));
    Ok(v)
}
<|endoftext|>


<commit_before>mod arg {
    #[test]
    fn name_explicit() {
        let arg = clap::arg!(foo: --bar <NUM>);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_long(), Some("bar"));
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(arg.is_required_set());
    }

    #[test]
    fn name_from_long() {
        let arg = clap::arg!(--bar <NUM>);
        assert_eq!(arg.get_id(), "bar");
        assert_eq!(arg.get_long(), Some("bar"));
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(arg.is_required_set());
    }

    #[test]
    fn name_from_value() {
        let arg = clap::arg!(<NUM>);
        assert_eq!(arg.get_id(), "NUM");
        assert_eq!(arg.get_long(), None);
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(arg.is_required_set());
    }

    #[test]
    #[should_panic]
    fn name_none_fails() {
        clap::arg!("Help");
    }

    #[test]
    #[should_panic]
    fn short_only_fails() {
        clap::arg!(-b);
    }

    #[test]
    fn short() {
        let arg = clap::arg!(foo: -b);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::SetTrue));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -'b');
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::SetTrue));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -b ...);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::Count));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -b "How to use it");
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::SetTrue));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), Some("How to use it"));
    }

    #[test]
    fn short_and_long() {
        let arg = clap::arg!(foo: -b --hello);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_long(), Some("hello"));
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::SetTrue));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -'b' --hello);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_long(), Some("hello"));
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::SetTrue));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -b --hello ...);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_long(), Some("hello"));
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::Count));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -b --hello "How to use it");
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_long(), Some("hello"));
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::SetTrue));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), Some("How to use it"));
    }

    #[test]
    fn short_with_value() {
        let arg = clap::arg!(foo: -b <NUM>);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -'b' <NUM>);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -b  <NUM> ...);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::Append));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -b  <NUM> "How to use it");
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), Some("How to use it"));
    }

    #[test]
    fn positional() {
        let arg = clap::arg!(<NUM>);
        assert_eq!(arg.get_id(), "NUM");
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!([NUM]);
        assert_eq!(arg.get_id(), "NUM");
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(<NUM>);
        assert_eq!(arg.get_id(), "NUM");
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: <NUM>);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(<NUM> ...);
        assert_eq!(arg.get_id(), "NUM");
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(matches!(arg.get_action(), clap::ArgAction::Append));
        assert!(arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(<NUM> "How to use it");
        assert_eq!(arg.get_id(), "NUM");
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), Some("How to use it"));
    }
}

mod arg_impl {
    #[test]
    fn string_ident() {
        let expected = "one";
        let actual = clap::arg_impl! { @string one };
        assert_eq!(actual, expected);
    }

    #[test]
    fn string_literal() {
        let expected = "one";
        let actual = clap::arg_impl! { @string "one" };
        assert_eq!(actual, expected);
    }

    #[test]
    fn char_ident() {
        let expected = 'o';
        let actual = clap::arg_impl! { @char o };
        assert_eq!(actual, expected);
    }

    #[test]
    fn char_literal() {
        let expected = 'o';
        let actual = clap::arg_impl! { @char 'o' };
        assert_eq!(actual, expected);
    }

    #[test]
    // allow double quoted dashed arg name in square brackets (e.g ["some-arg"])
    fn arg_name_dashed() {
        let arg = clap::arg!(["some-arg"] "some arg");
        assert_eq!(arg, clap::Arg::new("some-arg").help("some arg"));

        let m = clap::Command::new("flag")
            .arg(arg)
            .try_get_matches_from(vec!["", "some-val"])
            .unwrap();
        #[allow(deprecated)]
        {
            assert!(m.is_present("some-arg"));
        }
        assert_eq!(m.get_one::<String>("some-arg").unwrap(), "some-val");
    }

    #[test]
    // allow double quoted dashed arg value in triangle brackets (e.g <"some-val">)
    // test in combination with short argument name (e.g. -v)
    fn arg_value_dashed_with_short_arg() {
        let arg = clap::arg!(-a <"some-val"> "some arg");
        assert_eq!(
            arg,
            clap::Arg::new("some-val")
                .short('a')
                .long("arg")
                .value_name("some-val")
        );

        let m = clap::Command::new("cmd")
            .arg(arg)
            .try_get_matches_from(vec!["", "-a", "val"])
            .unwrap();
        #[allow(deprecated)]
        {
            assert!(m.is_present("some-val"));
        }
        assert_eq!(m.get_one::<String>("some-val").unwrap(), "val");
    }

    #[test]
    // allow double quoted dashed arg value in triangle brackets (e.g <"some-val">)
    // test in combination with long argument name (e.g. --value)
    fn arg_value_dashed_with_long_arg() {
        let arg = clap::arg!(-a --arg <"some-val"> "some arg");
        assert_eq!(
            arg,
            clap::Arg::new("arg")
                .short('a')
                .long("arg")
                .value_name("some-val")
        );

        let m = clap::Command::new("cmd")
            .arg(arg)
            .try_get_matches_from(vec!["", "--arg", "some-val"])
            .unwrap();
        #[allow(deprecated)]
        {
            assert!(m.is_present("arg"));
        }
        assert_eq!(m.get_one::<String>("arg").unwrap(), "some-val");
    }
}
<commit_msg>test(macros): Port optional-value test from derive to arg<commit_after>mod arg {
    #[test]
    fn name_explicit() {
        let arg = clap::arg!(foo: --bar <NUM>);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_long(), Some("bar"));
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(arg.is_required_set());
    }

    #[test]
    fn name_from_long() {
        let arg = clap::arg!(--bar <NUM>);
        assert_eq!(arg.get_id(), "bar");
        assert_eq!(arg.get_long(), Some("bar"));
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(arg.is_required_set());
    }

    #[test]
    fn name_from_value() {
        let arg = clap::arg!(<NUM>);
        assert_eq!(arg.get_id(), "NUM");
        assert_eq!(arg.get_long(), None);
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(arg.is_required_set());
    }

    #[test]
    #[should_panic]
    fn name_none_fails() {
        clap::arg!("Help");
    }

    #[test]
    #[should_panic]
    fn short_only_fails() {
        clap::arg!(-b);
    }

    #[test]
    fn short() {
        let arg = clap::arg!(foo: -b);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::SetTrue));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -'b');
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::SetTrue));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -b ...);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::Count));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -b "How to use it");
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::SetTrue));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), Some("How to use it"));
    }

    #[test]
    fn short_and_long() {
        let arg = clap::arg!(foo: -b --hello);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_long(), Some("hello"));
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::SetTrue));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -'b' --hello);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_long(), Some("hello"));
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::SetTrue));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -b --hello ...);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_long(), Some("hello"));
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::Count));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -b --hello "How to use it");
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_long(), Some("hello"));
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::SetTrue));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), Some("How to use it"));
    }

    #[test]
    fn short_with_value() {
        let arg = clap::arg!(foo: -b <NUM>);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -'b' <NUM>);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -b  <NUM> ...);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::Append));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: -b  <NUM> "How to use it");
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_short(), Some('b'));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), Some("How to use it"));
    }

    #[test]
    fn positional() {
        let arg = clap::arg!(<NUM>);
        assert_eq!(arg.get_id(), "NUM");
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!([NUM]);
        assert_eq!(arg.get_id(), "NUM");
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(!arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(<NUM>);
        assert_eq!(arg.get_id(), "NUM");
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(foo: <NUM>);
        assert_eq!(arg.get_id(), "foo");
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(<NUM> ...);
        assert_eq!(arg.get_id(), "NUM");
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(matches!(arg.get_action(), clap::ArgAction::Append));
        assert!(arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), None);

        let arg = clap::arg!(<NUM> "How to use it");
        assert_eq!(arg.get_id(), "NUM");
        assert_eq!(arg.get_value_names(), Some(vec!["NUM"].as_slice()));
        assert!(matches!(arg.get_action(), clap::ArgAction::Set));
        assert!(!arg.is_multiple_values_set());
        assert!(arg.is_required_set());
        assert_eq!(arg.get_help(), Some("How to use it"));
    }

    #[test]
    fn optional_value() {
        let mut cmd = clap::Command::new("test").arg(clap::arg!(port: -p [NUM]));

        let r = cmd.try_get_matches_from_mut(["test", "-p42"]);
        assert!(r.is_ok(), "{}", r.unwrap_err());
        let m = r.unwrap();
        assert!(m.contains_id("port"));
        assert_eq!(m.get_one::<String>("port").unwrap(), "42");

        let r = cmd.try_get_matches_from_mut(["test", "-p"]);
        assert!(r.is_ok(), "{}", r.unwrap_err());
        let m = r.unwrap();
        assert!(m.contains_id("port"));
        assert!(m.get_one::<String>("port").is_none());

        let r = cmd.try_get_matches_from_mut(["test", "-p", "24", "-p", "42"]);
        assert!(r.is_ok(), "{}", r.unwrap_err());
        let m = r.unwrap();
        assert!(m.contains_id("port"));
        assert_eq!(m.get_one::<String>("port").unwrap(), "42");

        let mut help = Vec::new();
        cmd.write_help(&mut help).unwrap();
        const HELP: &str = "\
test

USAGE:
    test [OPTIONS]

OPTIONS:
    -p [<NUM>...]
    -h, --help           Print help information
";
        snapbox::assert_eq(HELP, help);
    }
}

mod arg_impl {
    #[test]
    fn string_ident() {
        let expected = "one";
        let actual = clap::arg_impl! { @string one };
        assert_eq!(actual, expected);
    }

    #[test]
    fn string_literal() {
        let expected = "one";
        let actual = clap::arg_impl! { @string "one" };
        assert_eq!(actual, expected);
    }

    #[test]
    fn char_ident() {
        let expected = 'o';
        let actual = clap::arg_impl! { @char o };
        assert_eq!(actual, expected);
    }

    #[test]
    fn char_literal() {
        let expected = 'o';
        let actual = clap::arg_impl! { @char 'o' };
        assert_eq!(actual, expected);
    }

    #[test]
    // allow double quoted dashed arg name in square brackets (e.g ["some-arg"])
    fn arg_name_dashed() {
        let arg = clap::arg!(["some-arg"] "some arg");
        assert_eq!(arg, clap::Arg::new("some-arg").help("some arg"));

        let m = clap::Command::new("flag")
            .arg(arg)
            .try_get_matches_from(vec!["", "some-val"])
            .unwrap();
        #[allow(deprecated)]
        {
            assert!(m.is_present("some-arg"));
        }
        assert_eq!(m.get_one::<String>("some-arg").unwrap(), "some-val");
    }

    #[test]
    // allow double quoted dashed arg value in triangle brackets (e.g <"some-val">)
    // test in combination with short argument name (e.g. -v)
    fn arg_value_dashed_with_short_arg() {
        let arg = clap::arg!(-a <"some-val"> "some arg");
        assert_eq!(
            arg,
            clap::Arg::new("some-val")
                .short('a')
                .long("arg")
                .value_name("some-val")
        );

        let m = clap::Command::new("cmd")
            .arg(arg)
            .try_get_matches_from(vec!["", "-a", "val"])
            .unwrap();
        #[allow(deprecated)]
        {
            assert!(m.is_present("some-val"));
        }
        assert_eq!(m.get_one::<String>("some-val").unwrap(), "val");
    }

    #[test]
    // allow double quoted dashed arg value in triangle brackets (e.g <"some-val">)
    // test in combination with long argument name (e.g. --value)
    fn arg_value_dashed_with_long_arg() {
        let arg = clap::arg!(-a --arg <"some-val"> "some arg");
        assert_eq!(
            arg,
            clap::Arg::new("arg")
                .short('a')
                .long("arg")
                .value_name("some-val")
        );

        let m = clap::Command::new("cmd")
            .arg(arg)
            .try_get_matches_from(vec!["", "--arg", "some-val"])
            .unwrap();
        #[allow(deprecated)]
        {
            assert!(m.is_present("arg"));
        }
        assert_eq!(m.get_one::<String>("arg").unwrap(), "some-val");
    }
}
<|endoftext|>


<commit_before>extern crate thunderdome;

#[cfg(test)]
mod parser_tests {
    use thunderdome::parser::*;
    use thunderdome::steps::*;

    fn validate(q: &str) -> Option<ParsedGraphQuery> {
        let result = pre_parse(q);
        assert!(result.is_ok());
        result.ok()
    }

    #[test]
    fn global_graph_query() {
        validate("g.V");
    }

    #[test]
    fn vertex_query() {
        validate("g.v(1)");
        validate("g.v(1,2)");
        validate("g.v(1, 2)");
    }

    #[test]
    fn simple_step_test() {
        validate("g.v(1).outV()");
        let result = validate("g.v(1).outV().inE()").unwrap();
        assert_eq!(result.steps.len(), 2);
        assert_eq!(result.steps.get(0).unwrap().name, "outV".to_string());
        assert_eq!(result.steps.get(1).unwrap().name, "inE".to_string());
    }

    #[test]
    fn test_args() {
        validate("g.v(1).outV('edge').has('age', 30)");
    }
    #[test]
    fn test_args_numbers() {
        // maybe a weird offset command?
        validate("g.V.limit(10, 20)");
        validate("g.V.limit(10.0)");
    }
}
<commit_msg>fixed formatting<commit_after>extern crate thunderdome;

#[cfg(test)]
mod parser_tests {
    use thunderdome::parser::*;
    use thunderdome::steps::*;

    fn validate(q: &str) -> Option<ParsedGraphQuery> {
        let result = pre_parse(q);
        assert!(result.is_ok());
        result.ok()
    }

    #[test]
    fn global_graph_query() {
        validate("g.V");
    }

    #[test]
    fn vertex_query() {
        validate("g.v(1)");
        validate("g.v(1,2)");
        validate("g.v(1, 2)");
    }

    #[test]
    fn simple_step_test() {
        validate("g.v(1).outV()");
        let result = validate("g.v(1).outV().inE()").unwrap();
        assert_eq!(result.steps.len(), 2);
        assert_eq!(result.steps.get(0).unwrap().name,
                    "outV".to_string());
        assert_eq!(result.steps.get(1).unwrap().name,
                    "inE".to_string());
    }

    #[test]
    fn test_args() {
        validate("g.v(1).outV('edge').has('age', 30)");
    }
    #[test]
    fn test_args_numbers() {
        // maybe a weird offset command?
        validate("g.V.limit(10, 20)");
        validate("g.V.limit(10.0)");
    }
}
<|endoftext|>


<commit_before>//! A semaphore implementation based on the rust Mutex<T> type

use alloc::boxed::Box;

use core::sync::atomic::{AtomicIsize, Ordering};
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};

use super::super::interrupts::{on,off};
use super::super::process::{ready_queue, proc_yield, ProcessQueue};

/// `Semaphore` is a much more Rustic semaphore. It returns an RAII
/// `SemaphoreGuard`, which automatically calls "up" when it goes out of
/// scope. This semaphore takes ownership of the data it is guarding, so that
/// Rust ownership and lifetime semantics can be used to guarantee safety of
/// the resource.
///
/// ```
///  // wrap resource in a semaphore with initial count 3
///  let s = Semaphore::new(resource, 3);
///
///  {
///      // acquire
///      let guard = s.clone();
///  }
///  // guard dies => release
/// ```
pub struct Semaphore<T> {
    // box the inner semaphore so it has a constant address
    // and can be safely moved
    inner: Box<StaticSemaphore>,
    data: UnsafeCell<T>,
}

/// `StaticSemaphore` is a semaphore implementation that can be used in
/// statics. It has a const constructor.
pub struct StaticSemaphore {
    // Use UnsafeCells so that it the semaphore can be used immutably
    count: UnsafeCell<AtomicIsize>,
    queue: UnsafeCell<ProcessQueue>,
}

/// RAII SemaphoreGuard
pub struct SemaphoreGuard<'semaphore, T: 'semaphore> {
    semaphore: &'semaphore mut StaticSemaphore,
    data: &'semaphore UnsafeCell<T>,
}

unsafe impl<T: Send> Send for Semaphore<T> {}
unsafe impl<T: Send> Sync for Semaphore<T> {}

impl<T> Semaphore<T> {
    /// Create a new semaphore with the the given count guarding the given value
    pub fn new(val: T, i: isize) -> Semaphore<T> {
        Semaphore {
            inner: box StaticSemaphore::new(i),
            data: UnsafeCell::new(val),
        }
    }

    /// Acquire.
    /// returns an RAII guard, so no need for up()
    pub fn down<'semaphore>(&'semaphore mut self) -> SemaphoreGuard<'semaphore, T> {
        // acquire semaphore
        self.inner.down();
        SemaphoreGuard::new(&mut *self.inner, &self.data)
    }
}

impl<T> Drop for Semaphore<T> {
    /// When the semaphore goes out of scope, it destroys the contents
    fn drop(&mut self) {
        self.inner.destroy();
    }
}

impl StaticSemaphore {
    /// Create a new `StaticSemaphore` with the given count
    pub const fn new(i: isize) -> StaticSemaphore {
        StaticSemaphore {
            count: UnsafeCell::new(AtomicIsize::new(i)),
            queue: UnsafeCell::new(ProcessQueue::new()),
        }
    }

    /// Acquire
    pub fn down(&self) {
        off();
        unsafe {
            if (*self.count.get()).fetch_sub(1, Ordering::AcqRel) <= 0 {
                (*self.count.get()).fetch_add(1, Ordering::AcqRel);
                // block
                proc_yield(Some(&mut *self.queue.get()));
            }
        }
        on();
    }

    /// Release
    pub fn up(&self) {
        off();
        unsafe {
            if let Some(next) = (*self.queue.get()).pop_front() {
                ready_queue::make_ready(next);
            } else {
                (*self.count.get()).fetch_add(1,Ordering::AcqRel);
            }
        }
        on();
    }

    /// Clean up.
    /// Cannot implement Drop here because we want to be able
    /// to create a static semaphore.
    pub fn destroy(&self) {
        unsafe {
            if (*self.queue.get()).len() > 0 {
                // TODO: intead, just kill the processes or do zombie detection
                panic!("Semaphore destroyed with processes waiting!");
            }
        }
    }
}

impl<'semaphore, T> SemaphoreGuard<'semaphore, T> {
    /// Create a guard referring to the given semaphore and data
    fn new(semaphore: &'semaphore mut StaticSemaphore,
               data: &'semaphore UnsafeCell<T>) -> SemaphoreGuard<'semaphore, T>{
        SemaphoreGuard {
            semaphore: semaphore,
            data: data,
        }
    }

    pub fn up(&mut self) {
        self.semaphore.up();
    }
}

impl<'semaphore, T> Drop for SemaphoreGuard<'semaphore, T> {
    /// `SemaphoreGuard` is RAII, so dropping the guard calls up
    fn drop(&mut self) {
        self.semaphore.up();
    }
}

/// Implement Deref and DerefMut to get deref coersions
impl<'semaphore, T> Deref for SemaphoreGuard<'semaphore, T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.data.get() }
    }
}

/// Implement Deref and DerefMut to get deref coersions
impl<'semaphore, T> DerefMut for SemaphoreGuard<'semaphore, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.data.get() }
    }
}

<commit_msg>Minor improvements to semaphore<commit_after>//! A semaphore implementation based on the rust Mutex<T> type

use alloc::boxed::Box;

use core::sync::atomic::{AtomicIsize, Ordering};
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};

use super::super::interrupts::{on,off};
use super::super::process::{ready_queue, proc_yield, ProcessQueue};

/// `Semaphore` is a much more Rustic semaphore. It returns an RAII
/// `SemaphoreGuard`, which automatically calls "up" when it goes out of
/// scope. This semaphore takes ownership of the data it is guarding, so that
/// Rust ownership and lifetime semantics can be used to guarantee safety of
/// the resource.
///
/// ```
///  // wrap resource in a semaphore with initial count 3
///  let s = Semaphore::new(resource, 3);
///
///  {
///      // acquire
///      let guard = s.clone();
///  }
///  // guard dies => release
/// ```
pub struct Semaphore<T> {
    // box the inner semaphore so it has a constant address
    // and can be safely moved
    inner: Box<StaticSemaphore>,
    data: UnsafeCell<T>,
}

/// `StaticSemaphore` is a semaphore implementation that can be used in
/// statics. It has a const constructor.
pub struct StaticSemaphore {
    // Use UnsafeCells so that it the semaphore can be used immutably
    count: UnsafeCell<AtomicIsize>,
    queue: UnsafeCell<ProcessQueue>,
}

/// RAII SemaphoreGuard
pub struct SemaphoreGuard<'semaphore, T: 'semaphore> {
    semaphore: &'semaphore StaticSemaphore,
    data: &'semaphore UnsafeCell<T>,
}

unsafe impl<T: Send> Send for Semaphore<T> {}
unsafe impl<T: Send> Sync for Semaphore<T> {}

impl<T> Semaphore<T> {
    /// Create a new semaphore with the the given count guarding the given value
    pub fn new(val: T, i: isize) -> Semaphore<T> {
        Semaphore {
            inner: box StaticSemaphore::new(i),
            data: UnsafeCell::new(val),
        }
    }

    /// Acquire.
    /// returns an RAII guard, so no need for up()
    pub fn down<'semaphore>(&'semaphore self) -> SemaphoreGuard<'semaphore, T> {
        // acquire semaphore
        self.inner.down();
        SemaphoreGuard::new(&*self.inner, &self.data)
    }
}

impl<T> Drop for Semaphore<T> {
    /// When the semaphore goes out of scope, it destroys the contents
    fn drop(&mut self) {
        self.inner.destroy();
    }
}

impl StaticSemaphore {
    /// Create a new `StaticSemaphore` with the given count
    pub const fn new(i: isize) -> StaticSemaphore {
        StaticSemaphore {
            count: UnsafeCell::new(AtomicIsize::new(i)),
            queue: UnsafeCell::new(ProcessQueue::new()),
        }
    }

    /// Acquire
    pub fn down(&self) {
        off();
        unsafe {
            if (*self.count.get()).fetch_sub(1, Ordering::AcqRel) <= 0 {
                (*self.count.get()).fetch_add(1, Ordering::AcqRel);
                // block
                proc_yield(Some(&mut *self.queue.get()));
            }
        }
        on();
    }

    /// Release
    pub fn up(&self) {
        off();
        unsafe {
            if let Some(next) = (*self.queue.get()).pop_front() {
                ready_queue::make_ready(next);
            } else {
                (*self.count.get()).fetch_add(1,Ordering::AcqRel);
            }
        }
        on();
    }

    /// Clean up.
    /// Cannot implement Drop here because we want to be able
    /// to create a static semaphore.
    pub fn destroy(&self) {
        unsafe {
            if (*self.queue.get()).len() > 0 {
                // TODO: intead, just kill the processes or do zombie detection
                panic!("Semaphore destroyed with processes waiting!");
            }
        }
    }
}

impl<'semaphore, T> SemaphoreGuard<'semaphore, T> {
    /// Create a guard referring to the given semaphore and data
    fn new(semaphore: &'semaphore StaticSemaphore,
               data: &'semaphore UnsafeCell<T>) -> SemaphoreGuard<'semaphore, T>{
        SemaphoreGuard {
            semaphore: semaphore,
            data: data,
        }
    }

    pub fn up(&self) {
        self.semaphore.up();
    }
}

impl<'semaphore, T> Drop for SemaphoreGuard<'semaphore, T> {
    /// `SemaphoreGuard` is RAII, so dropping the guard calls up
    fn drop(&mut self) {
        self.semaphore.up();
    }
}

/// Implement Deref and DerefMut to get deref coersions
impl<'semaphore, T> Deref for SemaphoreGuard<'semaphore, T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.data.get() }
    }
}

/// Implement Deref and DerefMut to get deref coersions
impl<'semaphore, T> DerefMut for SemaphoreGuard<'semaphore, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.data.get() }
    }
}

<|endoftext|>


<commit_before>use std::borrow::ToOwned;
use std::collections::HashSet;
use std::fs;
use std::io::{Read,Write};
use std::io;
use std::path;
use std::process;
use std::convert::AsRef;

use atomicwrites::{AtomicFile,DisallowOverwrite};
use email::rfc5322::Rfc5322Parser;
use uuid::Uuid;
use vobject::{Component,Property,parse_component,write_component};

use cli::Configuration;

pub trait CustomPathExt {
    fn metadata(&self) -> io::Result<fs::Metadata>;
    fn exists(&self) -> bool;
    fn is_file(&self) -> bool;
    fn is_dir(&self) -> bool;
    fn str_extension(&self) -> Option<&str>;
}

impl CustomPathExt for path::Path {
    fn metadata(&self) -> io::Result<fs::Metadata> { fs::metadata(self) }

    fn exists(&self) -> bool { fs::metadata(self).is_ok() }

    fn is_file(&self) -> bool {
        fs::metadata(self).map(|s| s.is_file()).unwrap_or(false)
    }
    fn is_dir(&self) -> bool {
        fs::metadata(self).map(|s| s.is_dir()).unwrap_or(false)
    }

    fn str_extension(&self) -> Option<&str> {
        self.extension().and_then(|x| x.to_str())
    }
}

pub fn handle_process(process: &mut process::Child) -> io::Result<()> {
    let exitcode = try!(process.wait());
    if !exitcode.success() {
        return Err(io::Error::new(
            io::ErrorKind::Other,
            format!("{}", exitcode)
        ));
    };
    Ok(())
}

pub struct IndexIterator {
    linebuffer: Vec<String>
}

impl IndexIterator {
    fn new(output: &String) -> IndexIterator {
        let rv = output.split('\n').map(|x| x.to_string()).collect();
        IndexIterator {
            linebuffer: rv
        }
    }
}

impl Iterator for IndexIterator {
    type Item = IndexItem;

    fn next(&mut self) -> Option<IndexItem> {
        match self.linebuffer.pop() {
            Some(x) => Some(IndexItem::new(x)),
            None => None
        }
    }
}

pub struct IndexItem {
    pub email: String,
    pub name: String,
    pub filepath: Option<path::PathBuf>
}

impl IndexItem {
    fn new(line: String) -> IndexItem {
        let mut parts = line.split('\t');

        IndexItem {
            email: parts.next().unwrap_or("").to_string(),
            name: parts.next().unwrap_or("").to_string(),
            filepath: match parts.next() {
                Some(x) => Some(path::PathBuf::from(x)),
                None => None
            }
        }
    }
}

pub struct Contact {
    pub component: Component,
    pub path: path::PathBuf
}

impl Contact {
    pub fn from_file<P: AsRef<path::Path>>(path: P) -> io::Result<Contact> {
        let mut contact_file = try!(fs::File::open(&path));
        let contact_string = {
            let mut x = String::new();
            try!(contact_file.read_to_string(&mut x));
            x
        };

        let item = match parse_component(&contact_string[..]) {
            Ok(x) => x,
            Err(e) => return Err(io::Error::new(
                io::ErrorKind::Other,
                format!("Error while parsing contact: {}", e)
            ))
        };

        Ok(Contact { component: item, path: path.as_ref().to_owned() })
    }

    pub fn generate(fullname: Option<&str>, email: Option<&str>, dir: &path::Path) -> Contact {
        let (uid, contact_path) = {
            let mut uid;
            let mut contact_path;
            loop {
                uid = Uuid::new_v4().hyphenated().to_string();
                contact_path = dir.join(&format!("{}.vcf", uid));
                if !(*contact_path).exists() {
                    break
                }
            };
            (uid, contact_path)
        };
        Contact { path: contact_path, component: generate_component(uid.into(), fullname, email) }
    }

    pub fn write_create(&self) -> io::Result<()> {
        let string = write_component(&self.component);
        let af = AtomicFile::new(&self.path, DisallowOverwrite);

        af.write(|f| {
            f.write_all(string.as_bytes())
        })
    }
}

fn generate_component(uid: String, fullname: Option<&str>, email: Option<&str>) -> Component {
    let mut comp = Component::new("VCARD");

    comp.all_props_mut("VERSION").push(Property::new("VERSION", "3.0"));

    match fullname {
        Some(x) => comp.all_props_mut("FN").push(Property::new("FN", x)),
        None => ()
    };

    match email {
        Some(x) => comp.all_props_mut("EMAIL").push(Property::new("EMAIL", x)),
        None => ()
    };
    comp.all_props_mut("UID").push(Property::new("UID", &uid[..]));
    comp
}

pub fn index_query<'a>(config: &Configuration, query: &str) -> io::Result<IndexIterator> {
    let mut process = try!(
        command_from_config(&config.grep_cmd[..])
        .arg(&query[..])
        .arg(&config.index_path)
        .stdin(process::Stdio::piped())
        .stdout(process::Stdio::piped())
        .stderr(process::Stdio::inherit())
        .spawn());

    try!(handle_process(&mut process));

    let stream = match process.stdout.as_mut() {
        Some(x) => x,
        None => return Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to get stdout from grep process.",
        ))
    };

    let mut output = String::new();
    try!(stream.read_to_string(&mut output));
    Ok(IndexIterator::new(&output))
}

/// Better than index_query if you're only interested in the filepath, as duplicate entries will be
/// removed.
pub fn file_query(config: &Configuration, query: &str) -> io::Result<HashSet<path::PathBuf>> {
    let mut rv: HashSet<path::PathBuf> = HashSet::new();
    rv.extend(
        try!(index_query(config, query)).filter_map(|x| x.filepath)
    );
    Ok(rv)
}

pub fn index_item_from_contact(contact: &Contact) -> io::Result<String> {
    let name = match contact.component.single_prop("FN") {
        Some(name) => name.value_as_string(),
        None => return Err(io::Error::new(
            io::ErrorKind::Other,
            "No name found.",
        ))
    };

    let emails = contact.component.all_props("EMAIL");
    let mut rv = String::new();
    for email in emails.iter() {
        rv.push_str(&format!("{}\t{}\t{}\n", email.value_as_string(), name, contact.path.display())[..]);
    };
    Ok(rv)
}

/// Return a tuple (fullname, email)
pub fn parse_from_header<'a>(s: &'a String) -> (Option<&'a str>, Option<&'a str>) {
    let mut split = s.rsplitn(1, ' ');
    let email = match split.next() {
        Some(x) => Some(x.trim_left_matches('<').trim_right_matches('>')),
        None => Some(&s[..])
    };
    let name = split.next();
    (name, email)
}

/// Given an email, return value of From header.
pub fn read_sender_from_email(email: &str) -> Option<String> {
    let mut parser = Rfc5322Parser::new(email);
    while !parser.eof() {
        match parser.consume_header() {
            Some(header) => {
                if header.name == "From" {
                    return header.get_value().ok()
                };
            },
            None => return None
        };
    };
    None
}

/// Write sender from given email as .vcf file to given directory.
pub fn add_contact_from_email(contact_dir: &path::Path, email_input: &str) -> io::Result<Contact> {
    let from_header = match read_sender_from_email(email_input) {
        Some(x) => x,
        None => return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "Couldn't find From-header in email.",
        ))
    };
    let (fullname, email) = parse_from_header(&from_header);
    let contact = Contact::generate(fullname, email, contact_dir);
    try!(contact.write_create());
    Ok(contact)
}

fn command_from_config(config_val: &str) -> process::Command {
    let mut parts = config_val.split(' ');
    let main = parts.next().unwrap();
    let rest: Vec<_> = parts.map(|x| x.to_string()).collect();
    let mut rv = process::Command::new(main);
    rv.args(&rest[..]);
    rv
}
<commit_msg>Fix bug in email splitting<commit_after>use std::borrow::ToOwned;
use std::collections::HashSet;
use std::fs;
use std::io::{Read,Write};
use std::io;
use std::path;
use std::process;
use std::convert::AsRef;

use atomicwrites::{AtomicFile,DisallowOverwrite};
use email::rfc5322::Rfc5322Parser;
use uuid::Uuid;
use vobject::{Component,Property,parse_component,write_component};

use cli::Configuration;

pub trait CustomPathExt {
    fn metadata(&self) -> io::Result<fs::Metadata>;
    fn exists(&self) -> bool;
    fn is_file(&self) -> bool;
    fn is_dir(&self) -> bool;
    fn str_extension(&self) -> Option<&str>;
}

impl CustomPathExt for path::Path {
    fn metadata(&self) -> io::Result<fs::Metadata> { fs::metadata(self) }

    fn exists(&self) -> bool { fs::metadata(self).is_ok() }

    fn is_file(&self) -> bool {
        fs::metadata(self).map(|s| s.is_file()).unwrap_or(false)
    }
    fn is_dir(&self) -> bool {
        fs::metadata(self).map(|s| s.is_dir()).unwrap_or(false)
    }

    fn str_extension(&self) -> Option<&str> {
        self.extension().and_then(|x| x.to_str())
    }
}

pub fn handle_process(process: &mut process::Child) -> io::Result<()> {
    let exitcode = try!(process.wait());
    if !exitcode.success() {
        return Err(io::Error::new(
            io::ErrorKind::Other,
            format!("{}", exitcode)
        ));
    };
    Ok(())
}

pub struct IndexIterator {
    linebuffer: Vec<String>
}

impl IndexIterator {
    fn new(output: &String) -> IndexIterator {
        let rv = output.split('\n').map(|x| x.to_string()).collect();
        IndexIterator {
            linebuffer: rv
        }
    }
}

impl Iterator for IndexIterator {
    type Item = IndexItem;

    fn next(&mut self) -> Option<IndexItem> {
        match self.linebuffer.pop() {
            Some(x) => Some(IndexItem::new(x)),
            None => None
        }
    }
}

pub struct IndexItem {
    pub email: String,
    pub name: String,
    pub filepath: Option<path::PathBuf>
}

impl IndexItem {
    fn new(line: String) -> IndexItem {
        let mut parts = line.split('\t');

        IndexItem {
            email: parts.next().unwrap_or("").to_string(),
            name: parts.next().unwrap_or("").to_string(),
            filepath: match parts.next() {
                Some(x) => Some(path::PathBuf::from(x)),
                None => None
            }
        }
    }
}

pub struct Contact {
    pub component: Component,
    pub path: path::PathBuf
}

impl Contact {
    pub fn from_file<P: AsRef<path::Path>>(path: P) -> io::Result<Contact> {
        let mut contact_file = try!(fs::File::open(&path));
        let contact_string = {
            let mut x = String::new();
            try!(contact_file.read_to_string(&mut x));
            x
        };

        let item = match parse_component(&contact_string[..]) {
            Ok(x) => x,
            Err(e) => return Err(io::Error::new(
                io::ErrorKind::Other,
                format!("Error while parsing contact: {}", e)
            ))
        };

        Ok(Contact { component: item, path: path.as_ref().to_owned() })
    }

    pub fn generate(fullname: Option<&str>, email: Option<&str>, dir: &path::Path) -> Contact {
        let (uid, contact_path) = {
            let mut uid;
            let mut contact_path;
            loop {
                uid = Uuid::new_v4().hyphenated().to_string();
                contact_path = dir.join(&format!("{}.vcf", uid));
                if !(*contact_path).exists() {
                    break
                }
            };
            (uid, contact_path)
        };
        Contact { path: contact_path, component: generate_component(uid.into(), fullname, email) }
    }

    pub fn write_create(&self) -> io::Result<()> {
        let string = write_component(&self.component);
        let af = AtomicFile::new(&self.path, DisallowOverwrite);

        af.write(|f| {
            f.write_all(string.as_bytes())
        })
    }
}

fn generate_component(uid: String, fullname: Option<&str>, email: Option<&str>) -> Component {
    let mut comp = Component::new("VCARD");

    comp.all_props_mut("VERSION").push(Property::new("VERSION", "3.0"));

    match fullname {
        Some(x) => comp.all_props_mut("FN").push(Property::new("FN", x)),
        None => ()
    };

    match email {
        Some(x) => comp.all_props_mut("EMAIL").push(Property::new("EMAIL", x)),
        None => ()
    };
    comp.all_props_mut("UID").push(Property::new("UID", &uid[..]));
    comp
}

pub fn index_query<'a>(config: &Configuration, query: &str) -> io::Result<IndexIterator> {
    let mut process = try!(
        command_from_config(&config.grep_cmd[..])
        .arg(&query[..])
        .arg(&config.index_path)
        .stdin(process::Stdio::piped())
        .stdout(process::Stdio::piped())
        .stderr(process::Stdio::inherit())
        .spawn());

    try!(handle_process(&mut process));

    let stream = match process.stdout.as_mut() {
        Some(x) => x,
        None => return Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to get stdout from grep process.",
        ))
    };

    let mut output = String::new();
    try!(stream.read_to_string(&mut output));
    Ok(IndexIterator::new(&output))
}

/// Better than index_query if you're only interested in the filepath, as duplicate entries will be
/// removed.
pub fn file_query(config: &Configuration, query: &str) -> io::Result<HashSet<path::PathBuf>> {
    let mut rv: HashSet<path::PathBuf> = HashSet::new();
    rv.extend(
        try!(index_query(config, query)).filter_map(|x| x.filepath)
    );
    Ok(rv)
}

pub fn index_item_from_contact(contact: &Contact) -> io::Result<String> {
    let name = match contact.component.single_prop("FN") {
        Some(name) => name.value_as_string(),
        None => return Err(io::Error::new(
            io::ErrorKind::Other,
            "No name found.",
        ))
    };

    let emails = contact.component.all_props("EMAIL");
    let mut rv = String::new();
    for email in emails.iter() {
        rv.push_str(&format!("{}\t{}\t{}\n", email.value_as_string(), name, contact.path.display())[..]);
    };
    Ok(rv)
}

/// Return a tuple (fullname, email)
pub fn parse_from_header<'a>(s: &'a String) -> (Option<&'a str>, Option<&'a str>) {
    let mut split = s.rsplitn(2, '<');
    let email = match split.next() {
        Some(x) => Some(x.trim_right_matches('>')),
        None => Some(&s[..])
    };
    let name = split.next();
    (name, email)
}

/// Given an email, return value of From header.
pub fn read_sender_from_email(email: &str) -> Option<String> {
    let mut parser = Rfc5322Parser::new(email);
    while !parser.eof() {
        match parser.consume_header() {
            Some(header) => {
                if header.name == "From" {
                    return header.get_value().ok()
                };
            },
            None => return None
        };
    };
    None
}

/// Write sender from given email as .vcf file to given directory.
pub fn add_contact_from_email(contact_dir: &path::Path, email_input: &str) -> io::Result<Contact> {
    let from_header = match read_sender_from_email(email_input) {
        Some(x) => x,
        None => return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "Couldn't find From-header in email.",
        ))
    };
    let (fullname, email) = parse_from_header(&from_header);
    let contact = Contact::generate(fullname, email, contact_dir);
    try!(contact.write_create());
    Ok(contact)
}

fn command_from_config(config_val: &str) -> process::Command {
    let mut parts = config_val.split(' ');
    let main = parts.next().unwrap();
    let rest: Vec<_> = parts.map(|x| x.to_string()).collect();
    let mut rv = process::Command::new(main);
    rv.args(&rest[..]);
    rv
}
<|endoftext|>


<commit_before>//! Exposes types related to memdb files
use std::str::from_utf8;

use uuid::Uuid;

use super::super::sdk::SdkInfo;

/// The stored memdb file header
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct MemDbHeader {
    pub version: u32,
    pub sdk_info: PackedSdkInfo,
    pub variants_start: u32,
    pub variants_count: u32,
    pub uuids_start: u32,
    pub uuids_count: u32,
    pub tagged_object_names_start: u32,
    pub tagged_object_names_end: u32,
    pub object_names_start: u32,
    pub object_names_count: u32,
    pub symbols_start: u32,
    pub symbols_count: u32,
}

/// Packed SDK information
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct PackedSdkInfo {
    pub name: [u8; 8],
    pub version_major: u16,
    pub version_minor: u16,
    pub version_patchlevel: u16,
    pub build: [u8; 10],
}

/// A stored slice that points to a memory region in the memdb file
#[repr(C, packed)]
pub struct StoredSlice {
    pub offset: u32,
    pub len: u32,
}

/// For the UUID index this points to a variant by index
#[repr(C, packed)]
pub struct IndexedUuid {
    pub uuid: Uuid,
    pub idx: u16,
}

/// A symbol in the index
#[repr(C, packed)]
#[derive(Debug)]
pub struct IndexItem {
    addr_low: u32,
    addr_high: u16,
    src_id: u16,
    sym_id: u32,
}

fn copy_str_to_slice(slice: &mut [u8], s: &str) {
    let bytes = s.as_bytes();
    (&mut slice[..bytes.len()]).copy_from_slice(bytes);
}

fn str_from_zero_slice(slice: &[u8]) -> &str {
    from_utf8(slice).unwrap().trim_right_matches('\x00')
}

impl PackedSdkInfo {

    pub fn set_from_sdk_info(&mut self, info: &SdkInfo) {
        self.version_major = info.version_major() as u16;
        self.version_minor = info.version_minor() as u16;
        self.version_patchlevel = info.version_patchlevel() as u16;
        copy_str_to_slice(&mut self.name[..], info.name());
        if let Some(build) = info.build() {
            copy_str_to_slice(&mut self.build[..], build);
        }
    }

    pub fn to_sdk_info(&self) -> SdkInfo {
        let build = str_from_zero_slice(&self.build[..]);
        SdkInfo::new(
            str_from_zero_slice(&self.name[..]),
            self.version_major as u32,
            self.version_minor as u32,
            self.version_patchlevel as u32,
            if build.is_empty() { None } else { Some(build) },
        )
    }
}

impl IndexedUuid {

    pub fn new(uuid: &Uuid, idx: usize) -> IndexedUuid {
        IndexedUuid {
            uuid: *uuid,
            idx: idx as u16,
        }
    }

    pub fn uuid(&self) -> &Uuid {
        &self.uuid
    }

    pub fn idx(&self) -> usize {
        self.idx as usize
    }
}

impl StoredSlice {

    /// Creates a new stored slice
    pub fn new(offset: usize, mut len: usize, is_compressed: bool) -> StoredSlice {
        if is_compressed {
            len |= 0x80000000;
        }
        StoredSlice {
            offset: offset as u32,
            len: len as u32,
        }
    }

    /// Returns the offset of the stored slice as bytes
    pub fn offset(&self) -> usize {
        self.offset as usize
    }

    /// Returns the length of the stored slice
    pub fn len(&self) -> usize {
        (self.len as usize) & 0x7fffffff
    }

    /// Indicates that the string is compressed (currently not used)
    pub fn is_compressed(&self) -> bool {
        self.len >> 31 != 0
    }
}

impl IndexItem {
    /// Creates a new indexed symbol in the index
    pub fn new(addr: u64, src_id: usize, sym_id: usize) -> IndexItem {
        IndexItem {
            addr_low: (addr & 0xffffffff) as u32,
            addr_high: ((addr >> 32) &0xffff) as u16,
            src_id: src_id as u16,
            sym_id: sym_id as u32,
        }
    }

    /// The address of the symbol
    pub fn addr(&self) -> u64 {
        ((self.addr_high as u64) << 32) | (self.addr_low as u64)
    }

    /// The ID of the source variant
    pub fn src_id(&self) -> usize {
        self.src_id as usize
    }

    /// The ID of the symbol
    pub fn sym_id(&self) -> usize {
        self.sym_id as usize
    }
}
<commit_msg>Leave more space for build<commit_after>//! Exposes types related to memdb files
use std::str::from_utf8;

use uuid::Uuid;

use super::super::sdk::SdkInfo;

/// The stored memdb file header
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct MemDbHeader {
    pub version: u32,
    pub sdk_info: PackedSdkInfo,
    pub variants_start: u32,
    pub variants_count: u32,
    pub uuids_start: u32,
    pub uuids_count: u32,
    pub tagged_object_names_start: u32,
    pub tagged_object_names_end: u32,
    pub object_names_start: u32,
    pub object_names_count: u32,
    pub symbols_start: u32,
    pub symbols_count: u32,
}

/// Packed SDK information
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct PackedSdkInfo {
    pub name: [u8; 8],
    pub version_major: u16,
    pub version_minor: u16,
    pub version_patchlevel: u16,
    pub build: [u8; 40],
}

/// A stored slice that points to a memory region in the memdb file
#[repr(C, packed)]
pub struct StoredSlice {
    pub offset: u32,
    pub len: u32,
}

/// For the UUID index this points to a variant by index
#[repr(C, packed)]
pub struct IndexedUuid {
    pub uuid: Uuid,
    pub idx: u16,
}

/// A symbol in the index
#[repr(C, packed)]
#[derive(Debug)]
pub struct IndexItem {
    addr_low: u32,
    addr_high: u16,
    src_id: u16,
    sym_id: u32,
}

fn copy_str_to_slice(slice: &mut [u8], s: &str) {
    let bytes = s.as_bytes();
    (&mut slice[..bytes.len()]).copy_from_slice(bytes);
}

fn str_from_zero_slice(slice: &[u8]) -> &str {
    from_utf8(slice).unwrap().trim_right_matches('\x00')
}

impl PackedSdkInfo {

    pub fn set_from_sdk_info(&mut self, info: &SdkInfo) {
        self.version_major = info.version_major() as u16;
        self.version_minor = info.version_minor() as u16;
        self.version_patchlevel = info.version_patchlevel() as u16;
        copy_str_to_slice(&mut self.name[..], info.name());
        if let Some(build) = info.build() {
            copy_str_to_slice(&mut self.build[..], build);
        }
    }

    pub fn to_sdk_info(&self) -> SdkInfo {
        let build = str_from_zero_slice(&self.build[..]);
        SdkInfo::new(
            str_from_zero_slice(&self.name[..]),
            self.version_major as u32,
            self.version_minor as u32,
            self.version_patchlevel as u32,
            if build.is_empty() { None } else { Some(build) },
        )
    }
}

impl IndexedUuid {

    pub fn new(uuid: &Uuid, idx: usize) -> IndexedUuid {
        IndexedUuid {
            uuid: *uuid,
            idx: idx as u16,
        }
    }

    pub fn uuid(&self) -> &Uuid {
        &self.uuid
    }

    pub fn idx(&self) -> usize {
        self.idx as usize
    }
}

impl StoredSlice {

    /// Creates a new stored slice
    pub fn new(offset: usize, mut len: usize, is_compressed: bool) -> StoredSlice {
        if is_compressed {
            len |= 0x80000000;
        }
        StoredSlice {
            offset: offset as u32,
            len: len as u32,
        }
    }

    /// Returns the offset of the stored slice as bytes
    pub fn offset(&self) -> usize {
        self.offset as usize
    }

    /// Returns the length of the stored slice
    pub fn len(&self) -> usize {
        (self.len as usize) & 0x7fffffff
    }

    /// Indicates that the string is compressed (currently not used)
    pub fn is_compressed(&self) -> bool {
        self.len >> 31 != 0
    }
}

impl IndexItem {
    /// Creates a new indexed symbol in the index
    pub fn new(addr: u64, src_id: usize, sym_id: usize) -> IndexItem {
        IndexItem {
            addr_low: (addr & 0xffffffff) as u32,
            addr_high: ((addr >> 32) &0xffff) as u16,
            src_id: src_id as u16,
            sym_id: sym_id as u32,
        }
    }

    /// The address of the symbol
    pub fn addr(&self) -> u64 {
        ((self.addr_high as u64) << 32) | (self.addr_low as u64)
    }

    /// The ID of the source variant
    pub fn src_id(&self) -> usize {
        self.src_id as usize
    }

    /// The ID of the symbol
    pub fn sym_id(&self) -> usize {
        self.sym_id as usize
    }
}
<|endoftext|>


<commit_before>use std;
import std::map::*;

enum cat_type { tuxedo, tabby, tortoiseshell }

// Very silly -- this just returns the value of the name field
// for any int value that's less than the meows field

// ok: T should be in scope when resolving the iface ref for map
class cat<T: copy> : map<int, T> {
  priv {
    // Yes, you can have negative meows
    let mut meows : int;
    fn meow() {
      self.meows += 1;
      #error("Meow %d", self.meows);
      if self.meows % 5 == 0 {
          self.how_hungry += 1;
      }
    }
  }

  let mut how_hungry : int;
  let name : T;

  new(in_x : int, in_y : int, in_name: T)
    { self.meows = in_x; self.how_hungry = in_y; self.name = in_name; }

  fn speak() { self.meow(); }

  fn eat() -> bool {
    if self.how_hungry > 0 {
        #error("OM NOM NOM");
        self.how_hungry -= 2;
        ret true;
    }
    else {
        #error("Not hungry!");
        ret false;
    }
  }

  fn size() -> uint { self.meows as uint }
  fn insert(+k: int, +_v: T) -> bool {
    self.meows += k;
    true
  }
  fn contains_key(&&k: int) -> bool { k <= self.meows }

  fn get(&&k:int) -> T { alt self.find(k) {
      some(v) { v }
      none    { fail "epic fail"; }
    }
  }
  fn [](&&k:int) -> T { get(k) }
  fn find(&&k:int) -> option<T> { if k <= self.meows {
        some(self.name)
     }
     else { none }
  }

  fn remove(&&k:int) -> option<T> {
    alt self.find(k) {
      some(x) {
        self.meows -= k; some(x)
      }
      none { none }
    }
  }

  fn each(f: fn(&&int, &&T) -> bool) {
    let mut n = int::abs(self.meows);
    while n > 0 {
        if !f(n, self.name) { break; }
        n -= 1;
    }
  }

  fn each_key(&&f: fn(&&int) -> bool) {
    for self.each {|k, _v| if !f(k) { break; } cont;};
  }
  fn each_value(&&f: fn(&&T) -> bool) {
    for self.each {|_k, v| if !f(v) { break; } cont;};
  }
}

fn main() {
  let nyan : cat<str> = cat(0, 2, "nyan");
  for uint::range(1u, 5u) {|_i| nyan.speak(); }
  assert(nyan.find(1) == some("nyan"));
  assert(nyan.find(10) == none);
  let spotty : cat<cat_type> = cat(2, 57, tuxedo);
  for uint::range(0u, 6u) {|_i| spotty.speak(); }
  assert(spotty.size() == 8u);
  assert(spotty.contains_key(2));
  assert(spotty.get(3) == tuxedo);
}
<commit_msg>Oops. Actually fix that problem.<commit_after>use std;
import std::map::*;

enum cat_type { tuxedo, tabby, tortoiseshell }

// Very silly -- this just returns the value of the name field
// for any int value that's less than the meows field

// ok: T should be in scope when resolving the iface ref for map
class cat<T: copy> : map<int, T> {
  priv {
    // Yes, you can have negative meows
    let mut meows : int;
    fn meow() {
      self.meows += 1;
      #error("Meow %d", self.meows);
      if self.meows % 5 == 0 {
          self.how_hungry += 1;
      }
    }
  }

  let mut how_hungry : int;
  let name : T;

  new(in_x : int, in_y : int, in_name: T)
    { self.meows = in_x; self.how_hungry = in_y; self.name = in_name; }

  fn speak() { self.meow(); }

  fn eat() -> bool {
    if self.how_hungry > 0 {
        #error("OM NOM NOM");
        self.how_hungry -= 2;
        ret true;
    }
    else {
        #error("Not hungry!");
        ret false;
    }
  }

  fn size() -> uint { self.meows as uint }
  fn insert(+k: int, +_v: T) -> bool {
    self.meows += k;
    true
  }
  fn contains_key(&&k: int) -> bool { k <= self.meows }

  fn get(&&k:int) -> T { alt self.find(k) {
      some(v) { v }
      none    { fail "epic fail"; }
    }
  }
  fn [](&&k:int) -> T { self.get(k) }
  fn find(&&k:int) -> option<T> { if k <= self.meows {
        some(self.name)
     }
     else { none }
  }

  fn remove(&&k:int) -> option<T> {
    alt self.find(k) {
      some(x) {
        self.meows -= k; some(x)
      }
      none { none }
    }
  }

  fn each(f: fn(&&int, &&T) -> bool) {
    let mut n = int::abs(self.meows);
    while n > 0 {
        if !f(n, self.name) { break; }
        n -= 1;
    }
  }

  fn each_key(&&f: fn(&&int) -> bool) {
    for self.each {|k, _v| if !f(k) { break; } cont;};
  }
  fn each_value(&&f: fn(&&T) -> bool) {
    for self.each {|_k, v| if !f(v) { break; } cont;};
  }
}

fn main() {
  let nyan : cat<str> = cat(0, 2, "nyan");
  for uint::range(1u, 5u) {|_i| nyan.speak(); }
  assert(nyan.find(1) == some("nyan"));
  assert(nyan.find(10) == none);
  let spotty : cat<cat_type> = cat(2, 57, tuxedo);
  for uint::range(0u, 6u) {|_i| spotty.speak(); }
  assert(spotty.size() == 8u);
  assert(spotty.contains_key(2));
  assert(spotty.get(3) == tuxedo);
}
<|endoftext|>