<commit_before>// Copyright 2012 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.

use core::prelude::*;

use driver::session;
use metadata::cstore;
use metadata::filesearch;

use core::os;
use core::uint;
use core::util;
use core::vec;
use std::oldmap::HashMap;
use std::oldmap;

pure fn not_win32(os: session::os) -> bool {
  match os {
      session::os_win32 => false,
      _ => true
  }
}

pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
                    -> ~[~str] {
    let os = sess.targ_cfg.os;

    // No rpath on windows
    if os == session::os_win32 {
        return ~[];
    }

    debug!("preparing the RPATH!");

    let sysroot = sess.filesearch.sysroot();
    let output = out_filename;
    let libs = cstore::get_used_crate_files(sess.cstore);
    // We don't currently rpath extern libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = vec::append_one(libs, get_sysroot_absolute_rt_lib(sess));

    let target_triple = /*bad*/copy sess.opts.target_triple;
    let rpaths = get_rpaths(os, &sysroot, output, libs, target_triple);
    rpaths_to_flags(rpaths)
}

fn get_sysroot_absolute_rt_lib(sess: session::Session) -> Path {
    let r = filesearch::relative_target_lib_path(sess.opts.target_triple);
    sess.filesearch.sysroot().push_rel(&r).push(os::dll_filename("rustrt"))
}

pub fn rpaths_to_flags(rpaths: &[Path]) -> ~[~str] {
    vec::map(rpaths, |rpath| fmt!("-Wl,-rpath,%s",rpath.to_str()))
}

fn get_rpaths(os: session::os,
              sysroot: &Path,
              output: &Path,
              libs: &[Path],
              target_triple: &str) -> ~[Path] {
    debug!("sysroot: %s", sysroot.to_str());
    debug!("output: %s", output.to_str());
    debug!("libs:");
    for libs.each |libpath| {
        debug!("    %s", libpath.to_str());
    }
    debug!("target_triple: %s", target_triple);

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(os, output, libs);

    // Make backup absolute paths to the libraries. Binaries can
    // be moved as long as the crates they link against don't move.
    let abs_rpaths = get_absolute_rpaths(libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = ~[get_install_prefix_rpath(target_triple)];

    fn log_rpaths(desc: &str, rpaths: &[Path]) {
        debug!("%s rpaths:", desc);
        for rpaths.each |rpath| {
            debug!("    %s", rpath.to_str());
        }
    }

    log_rpaths(~"relative", rel_rpaths);
    log_rpaths(~"absolute", abs_rpaths);
    log_rpaths(~"fallback", fallback_rpaths);

    let mut rpaths = rel_rpaths;
    rpaths.push_all(abs_rpaths);
    rpaths.push_all(fallback_rpaths);

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths);
    return rpaths;
}

fn get_rpaths_relative_to_output(os: session::os,
                                 output: &Path,
                                 libs: &[Path]) -> ~[Path] {
    vec::map(libs, |a| {
        get_rpath_relative_to_output(os, output, a)
    })
}

pub fn get_rpath_relative_to_output(os: session::os,
                                    output: &Path,
                                    lib: &Path)
                                 -> Path {
    use core::os;

    assert not_win32(os);

    // Mac doesn't appear to support $ORIGIN
    let prefix = match os {
        session::os_android |session::os_linux | session::os_freebsd
                          => "$ORIGIN",
        session::os_macos => "@executable_path",
        session::os_win32 => util::unreachable()
    };

    Path(prefix).push_rel(&get_relative_to(&os::make_absolute(output),
                                           &os::make_absolute(lib)))
}

// Find the relative path from one file to another
pub fn get_relative_to(abs1: &Path, abs2: &Path) -> Path {
    assert abs1.is_absolute;
    assert abs2.is_absolute;
    let abs1 = abs1.normalize();
    let abs2 = abs2.normalize();
    debug!("finding relative path from %s to %s",
           abs1.to_str(), abs2.to_str());
    let split1 = /*bad*/copy abs1.components;
    let split2 = /*bad*/copy abs2.components;
    let len1 = vec::len(split1);
    let len2 = vec::len(split2);
    assert len1 > 0;
    assert len2 > 0;

    let max_common_path = uint::min(len1, len2) - 1;
    let mut start_idx = 0;
    while start_idx < max_common_path
        && split1[start_idx] == split2[start_idx] {
        start_idx += 1;
    }

    let mut path = ~[];
    for uint::range(start_idx, len1 - 1) |_i| { path.push(~".."); };

    path.push_all(vec::view(split2, start_idx, len2 - 1));

    if !path.is_empty() {
        return Path("").push_many(path);
    } else {
        return Path(".");
    }
}

fn get_absolute_rpaths(libs: &[Path]) -> ~[Path] {
    vec::map(libs, |a| get_absolute_rpath(a) )
}

pub fn get_absolute_rpath(lib: &Path) -> Path {
    os::make_absolute(lib).dir_path()
}

pub fn get_install_prefix_rpath(target_triple: &str) -> Path {
    let install_prefix = env!("CFG_PREFIX");

    if install_prefix == ~"" {
        die!(~"rustc compiled without CFG_PREFIX environment variable");
    }

    let tlib = filesearch::relative_target_lib_path(target_triple);
    os::make_absolute(&Path(install_prefix).push_rel(&tlib))
}

pub fn minimize_rpaths(rpaths: &[Path]) -> ~[Path] {
    let set = oldmap::HashMap();
    let mut minimized = ~[];
    for rpaths.each |rpath| {
        let s = rpath.to_str();
        if !set.contains_key(&s) {
            minimized.push(/*bad*/copy *rpath);
            set.insert(s, ());
        }
    }
    return minimized;
}

#[cfg(unix)]
mod test {
    use core::prelude::*;

    use back::rpath::{get_absolute_rpath, get_install_prefix_rpath};
    use back::rpath::{get_relative_to, get_rpath_relative_to_output};
    use back::rpath::{minimize_rpaths, rpaths_to_flags};
    use driver::session;

    use core::os;
    use core::str;

    #[test]
    pub fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags(~[Path("path1"),
                                      Path("path2")]);
        assert flags == ~[~"-Wl,-rpath,path1", ~"-Wl,-rpath,path2"];
    }

    #[test]
    pub fn test_prefix_rpath() {
        let res = get_install_prefix_rpath("triple");
        let d = Path(env!("CFG_PREFIX"))
            .push_rel(&Path("lib/rustc/triple/lib"));
        debug!("test_prefix_path: %s vs. %s",
               res.to_str(),
               d.to_str());
        assert str::ends_with(res.to_str(), d.to_str());
    }

    #[test]
    pub fn test_prefix_rpath_abs() {
        let res = get_install_prefix_rpath("triple");
        assert res.is_absolute;
    }

    #[test]
    pub fn test_minimize1() {
        let res = minimize_rpaths([Path("rpath1"),
                                   Path("rpath2"),
                                   Path("rpath1")]);
        assert res == ~[Path("rpath1"), Path("rpath2")];
    }

    #[test]
    pub fn test_minimize2() {
        let res = minimize_rpaths(~[Path("1a"), Path("2"), Path("2"),
                                    Path("1a"), Path("4a"),Path("1a"),
                                    Path("2"), Path("3"), Path("4a"),
                                    Path("3")]);
        assert res == ~[Path("1a"), Path("2"), Path("4a"), Path("3")];
    }

    #[test]
    pub fn test_relative_to1() {
        let p1 = Path("/usr/bin/rustc");
        let p2 = Path("/usr/lib/mylib");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("../lib");
    }

    #[test]
    pub fn test_relative_to2() {
        let p1 = Path("/usr/bin/rustc");
        let p2 = Path("/usr/bin/../lib/mylib");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("../lib");
    }

    #[test]
    pub fn test_relative_to3() {
        let p1 = Path("/usr/bin/whatever/rustc");
        let p2 = Path("/usr/lib/whatever/mylib");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("../../lib/whatever");
    }

    #[test]
    pub fn test_relative_to4() {
        let p1 = Path("/usr/bin/whatever/../rustc");
        let p2 = Path("/usr/lib/whatever/mylib");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("../lib/whatever");
    }

    #[test]
    pub fn test_relative_to5() {
        let p1 = Path("/usr/bin/whatever/../rustc");
        let p2 = Path("/usr/lib/whatever/../mylib");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("../lib");
    }

    #[test]
    pub fn test_relative_to6() {
        let p1 = Path("/1");
        let p2 = Path("/2/3");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("2");
    }

    #[test]
    pub fn test_relative_to7() {
        let p1 = Path("/1/2");
        let p2 = Path("/3");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("..");
    }

    #[test]
    pub fn test_relative_to8() {
        let p1 = Path("/home/brian/Dev/rust/build/").push_rel(
            &Path("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so"));
        let p2 = Path("/home/brian/Dev/rust/build/stage2/bin/..").push_rel(
            &Path("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so"));
        let res = get_relative_to(&p1, &p2);
        debug!("test_relative_tu8: %s vs. %s",
               res.to_str(),
               Path(".").to_str());
        assert res == Path(".");
    }

    #[test]
    #[cfg(target_os = "linux")]
    #[cfg(target_os = "andorid")]
    pub fn test_rpath_relative() {
      let o = session::os_linux;
      let res = get_rpath_relative_to_output(o,
            &Path("bin/rustc"), &Path("lib/libstd.so"));
      assert res.to_str() == ~"$ORIGIN/../lib";
    }

    #[test]
    #[cfg(target_os = "freebsd")]
    pub fn test_rpath_relative() {
        let o = session::os_freebsd;
        let res = get_rpath_relative_to_output(o,
            &Path("bin/rustc"), &Path("lib/libstd.so"));
        assert res.to_str() == ~"$ORIGIN/../lib";
    }

    #[test]
    #[cfg(target_os = "macos")]
    pub fn test_rpath_relative() {
        // this is why refinements would be nice
        let o = session::os_macos;
        let res = get_rpath_relative_to_output(o,
                                               &Path("bin/rustc"),
                                               &Path("lib/libstd.so"));
        assert res.to_str() == ~"@executable_path/../lib";
    }

    #[test]
    pub fn test_get_absolute_rpath() {
        let res = get_absolute_rpath(&Path("lib/libstd.so"));
        debug!("test_get_absolute_rpath: %s vs. %s",
               res.to_str(),
               os::make_absolute(&Path("lib")).to_str());

        assert res == os::make_absolute(&Path("lib"));
    }
}
<commit_msg>librustc/back/rpath.rs: oldmap -> LinearSet<commit_after>// Copyright 2012 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.

use core::prelude::*;

use driver::session;
use metadata::cstore;
use metadata::filesearch;

use core::os;
use core::uint;
use core::util;
use core::vec;
use core::hashmap::linear::LinearSet;

pure fn not_win32(os: session::os) -> bool {
  match os {
      session::os_win32 => false,
      _ => true
  }
}

pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
                    -> ~[~str] {
    let os = sess.targ_cfg.os;

    // No rpath on windows
    if os == session::os_win32 {
        return ~[];
    }

    debug!("preparing the RPATH!");

    let sysroot = sess.filesearch.sysroot();
    let output = out_filename;
    let libs = cstore::get_used_crate_files(sess.cstore);
    // We don't currently rpath extern libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = vec::append_one(libs, get_sysroot_absolute_rt_lib(sess));

    let target_triple = /*bad*/copy sess.opts.target_triple;
    let rpaths = get_rpaths(os, &sysroot, output, libs, target_triple);
    rpaths_to_flags(rpaths)
}

fn get_sysroot_absolute_rt_lib(sess: session::Session) -> Path {
    let r = filesearch::relative_target_lib_path(sess.opts.target_triple);
    sess.filesearch.sysroot().push_rel(&r).push(os::dll_filename("rustrt"))
}

pub fn rpaths_to_flags(rpaths: &[Path]) -> ~[~str] {
    vec::map(rpaths, |rpath| fmt!("-Wl,-rpath,%s",rpath.to_str()))
}

fn get_rpaths(os: session::os,
              sysroot: &Path,
              output: &Path,
              libs: &[Path],
              target_triple: &str) -> ~[Path] {
    debug!("sysroot: %s", sysroot.to_str());
    debug!("output: %s", output.to_str());
    debug!("libs:");
    for libs.each |libpath| {
        debug!("    %s", libpath.to_str());
    }
    debug!("target_triple: %s", target_triple);

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(os, output, libs);

    // Make backup absolute paths to the libraries. Binaries can
    // be moved as long as the crates they link against don't move.
    let abs_rpaths = get_absolute_rpaths(libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = ~[get_install_prefix_rpath(target_triple)];

    fn log_rpaths(desc: &str, rpaths: &[Path]) {
        debug!("%s rpaths:", desc);
        for rpaths.each |rpath| {
            debug!("    %s", rpath.to_str());
        }
    }

    log_rpaths(~"relative", rel_rpaths);
    log_rpaths(~"absolute", abs_rpaths);
    log_rpaths(~"fallback", fallback_rpaths);

    let mut rpaths = rel_rpaths;
    rpaths.push_all(abs_rpaths);
    rpaths.push_all(fallback_rpaths);

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths);
    return rpaths;
}

fn get_rpaths_relative_to_output(os: session::os,
                                 output: &Path,
                                 libs: &[Path]) -> ~[Path] {
    vec::map(libs, |a| {
        get_rpath_relative_to_output(os, output, a)
    })
}

pub fn get_rpath_relative_to_output(os: session::os,
                                    output: &Path,
                                    lib: &Path)
                                 -> Path {
    use core::os;

    assert not_win32(os);

    // Mac doesn't appear to support $ORIGIN
    let prefix = match os {
        session::os_android |session::os_linux | session::os_freebsd
                          => "$ORIGIN",
        session::os_macos => "@executable_path",
        session::os_win32 => util::unreachable()
    };

    Path(prefix).push_rel(&get_relative_to(&os::make_absolute(output),
                                           &os::make_absolute(lib)))
}

// Find the relative path from one file to another
pub fn get_relative_to(abs1: &Path, abs2: &Path) -> Path {
    assert abs1.is_absolute;
    assert abs2.is_absolute;
    let abs1 = abs1.normalize();
    let abs2 = abs2.normalize();
    debug!("finding relative path from %s to %s",
           abs1.to_str(), abs2.to_str());
    let split1 = /*bad*/copy abs1.components;
    let split2 = /*bad*/copy abs2.components;
    let len1 = vec::len(split1);
    let len2 = vec::len(split2);
    assert len1 > 0;
    assert len2 > 0;

    let max_common_path = uint::min(len1, len2) - 1;
    let mut start_idx = 0;
    while start_idx < max_common_path
        && split1[start_idx] == split2[start_idx] {
        start_idx += 1;
    }

    let mut path = ~[];
    for uint::range(start_idx, len1 - 1) |_i| { path.push(~".."); };

    path.push_all(vec::view(split2, start_idx, len2 - 1));

    if !path.is_empty() {
        return Path("").push_many(path);
    } else {
        return Path(".");
    }
}

fn get_absolute_rpaths(libs: &[Path]) -> ~[Path] {
    vec::map(libs, |a| get_absolute_rpath(a) )
}

pub fn get_absolute_rpath(lib: &Path) -> Path {
    os::make_absolute(lib).dir_path()
}

pub fn get_install_prefix_rpath(target_triple: &str) -> Path {
    let install_prefix = env!("CFG_PREFIX");

    if install_prefix == ~"" {
        die!(~"rustc compiled without CFG_PREFIX environment variable");
    }

    let tlib = filesearch::relative_target_lib_path(target_triple);
    os::make_absolute(&Path(install_prefix).push_rel(&tlib))
}

pub fn minimize_rpaths(rpaths: &[Path]) -> ~[Path] {
    let mut set = LinearSet::new();
    let mut minimized = ~[];
    for rpaths.each |rpath| {
        if set.insert(rpath.to_str()) {
            minimized.push(copy *rpath);
        }
    }
    minimized
}

#[cfg(unix)]
mod test {
    use core::prelude::*;

    use back::rpath::{get_absolute_rpath, get_install_prefix_rpath};
    use back::rpath::{get_relative_to, get_rpath_relative_to_output};
    use back::rpath::{minimize_rpaths, rpaths_to_flags};
    use driver::session;

    use core::os;
    use core::str;

    #[test]
    pub fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags(~[Path("path1"),
                                      Path("path2")]);
        assert flags == ~[~"-Wl,-rpath,path1", ~"-Wl,-rpath,path2"];
    }

    #[test]
    pub fn test_prefix_rpath() {
        let res = get_install_prefix_rpath("triple");
        let d = Path(env!("CFG_PREFIX"))
            .push_rel(&Path("lib/rustc/triple/lib"));
        debug!("test_prefix_path: %s vs. %s",
               res.to_str(),
               d.to_str());
        assert str::ends_with(res.to_str(), d.to_str());
    }

    #[test]
    pub fn test_prefix_rpath_abs() {
        let res = get_install_prefix_rpath("triple");
        assert res.is_absolute;
    }

    #[test]
    pub fn test_minimize1() {
        let res = minimize_rpaths([Path("rpath1"),
                                   Path("rpath2"),
                                   Path("rpath1")]);
        assert res == ~[Path("rpath1"), Path("rpath2")];
    }

    #[test]
    pub fn test_minimize2() {
        let res = minimize_rpaths(~[Path("1a"), Path("2"), Path("2"),
                                    Path("1a"), Path("4a"),Path("1a"),
                                    Path("2"), Path("3"), Path("4a"),
                                    Path("3")]);
        assert res == ~[Path("1a"), Path("2"), Path("4a"), Path("3")];
    }

    #[test]
    pub fn test_relative_to1() {
        let p1 = Path("/usr/bin/rustc");
        let p2 = Path("/usr/lib/mylib");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("../lib");
    }

    #[test]
    pub fn test_relative_to2() {
        let p1 = Path("/usr/bin/rustc");
        let p2 = Path("/usr/bin/../lib/mylib");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("../lib");
    }

    #[test]
    pub fn test_relative_to3() {
        let p1 = Path("/usr/bin/whatever/rustc");
        let p2 = Path("/usr/lib/whatever/mylib");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("../../lib/whatever");
    }

    #[test]
    pub fn test_relative_to4() {
        let p1 = Path("/usr/bin/whatever/../rustc");
        let p2 = Path("/usr/lib/whatever/mylib");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("../lib/whatever");
    }

    #[test]
    pub fn test_relative_to5() {
        let p1 = Path("/usr/bin/whatever/../rustc");
        let p2 = Path("/usr/lib/whatever/../mylib");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("../lib");
    }

    #[test]
    pub fn test_relative_to6() {
        let p1 = Path("/1");
        let p2 = Path("/2/3");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("2");
    }

    #[test]
    pub fn test_relative_to7() {
        let p1 = Path("/1/2");
        let p2 = Path("/3");
        let res = get_relative_to(&p1, &p2);
        assert res == Path("..");
    }

    #[test]
    pub fn test_relative_to8() {
        let p1 = Path("/home/brian/Dev/rust/build/").push_rel(
            &Path("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so"));
        let p2 = Path("/home/brian/Dev/rust/build/stage2/bin/..").push_rel(
            &Path("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so"));
        let res = get_relative_to(&p1, &p2);
        debug!("test_relative_tu8: %s vs. %s",
               res.to_str(),
               Path(".").to_str());
        assert res == Path(".");
    }

    #[test]
    #[cfg(target_os = "linux")]
    #[cfg(target_os = "andorid")]
    pub fn test_rpath_relative() {
      let o = session::os_linux;
      let res = get_rpath_relative_to_output(o,
            &Path("bin/rustc"), &Path("lib/libstd.so"));
      assert res.to_str() == ~"$ORIGIN/../lib";
    }

    #[test]
    #[cfg(target_os = "freebsd")]
    pub fn test_rpath_relative() {
        let o = session::os_freebsd;
        let res = get_rpath_relative_to_output(o,
            &Path("bin/rustc"), &Path("lib/libstd.so"));
        assert res.to_str() == ~"$ORIGIN/../lib";
    }

    #[test]
    #[cfg(target_os = "macos")]
    pub fn test_rpath_relative() {
        // this is why refinements would be nice
        let o = session::os_macos;
        let res = get_rpath_relative_to_output(o,
                                               &Path("bin/rustc"),
                                               &Path("lib/libstd.so"));
        assert res.to_str() == ~"@executable_path/../lib";
    }

    #[test]
    pub fn test_get_absolute_rpath() {
        let res = get_absolute_rpath(&Path("lib/libstd.so"));
        debug!("test_get_absolute_rpath: %s vs. %s",
               res.to_str(),
               os::make_absolute(&Path("lib")).to_str());

        assert res == os::make_absolute(&Path("lib"));
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use parking_lot::RwLock;
use elements::{GlobalType, ValueType, TableElementType};
use interpreter::Error;
use interpreter::value::RuntimeValue;

/// Variable type.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum VariableType {
	/// Any func value.
	AnyFunc,
	/// i32 value.
	I32,
	/// i64 value.
	I64,
	/// f32 value.
	F32,
	/// f64 value.
	F64,
}

/// Externally stored variable value.
pub trait ExternalVariableValue {
	/// Get variable value.
	fn get(&self) -> RuntimeValue;
	/// Set variable value.
	fn set(&mut self, value: RuntimeValue) -> Result<(), Error>;
}

/// Variable instance.
#[derive(Debug)]
pub struct VariableInstance {
	/// Is mutable?
	is_mutable: bool,
	/// Variable type.
	variable_type: VariableType,
	/// Global value.
	value: RwLock<VariableValue>,
}

/// Enum variable value.
enum VariableValue {
	/// Internal value.
	Internal(RuntimeValue),
	/// External value.
	External(Box<ExternalVariableValue>),
}

impl VariableInstance {
	/// New variable instance
	pub fn new(is_mutable: bool, variable_type: VariableType, value: RuntimeValue) -> Result<Self, Error> {
		// TODO: there is nothing about null value in specification + there is nothing about initializing missing table elements? => runtime check for nulls
		if !value.is_null() && value.variable_type() != Some(variable_type) {
			return Err(Error::Variable(format!("trying to initialize variable of type {:?} with value of type {:?}", variable_type, value.variable_type())));
		}

		Ok(VariableInstance {
			is_mutable: is_mutable,
			variable_type: variable_type,
			value: RwLock::new(VariableValue::Internal(value)),
		})
	}

	/// New global variable
	pub fn new_global(global_type: &GlobalType, value: RuntimeValue) -> Result<Self, Error> {
		Self::new(global_type.is_mutable(), global_type.content_type().into(), value)
	}

	/// New global with externally stored value.
	pub fn new_external_global(is_mutable: bool, variable_type: VariableType, value: Box<ExternalVariableValue>) -> Result<Self, Error> {
		// TODO: there is nothing about null value in specification + there is nothing about initializing missing table elements? => runtime check for nulls
		let current_value = value.get();
		if !current_value.is_null() && current_value.variable_type() != Some(variable_type) {
			return Err(Error::Variable(format!("trying to initialize variable of type {:?} with value of type {:?}", variable_type, current_value.variable_type())));
		}

		Ok(VariableInstance {
			is_mutable: is_mutable,
			variable_type: variable_type,
			value: RwLock::new(VariableValue::External(value)),
		})
	}

	/// Is mutable
	pub fn is_mutable(&self) -> bool {
		self.is_mutable
	}

	/// Get variable type.
	pub fn variable_type(&self) -> VariableType {
		self.variable_type
	}

	/// Get the value of the variable instance
	pub fn get(&self) -> RuntimeValue {
		self.value.read().get()
	}

	/// Set the value of the variable instance
	pub fn set(&self, value: RuntimeValue) -> Result<(), Error> {
		if !self.is_mutable {
			return Err(Error::Variable("trying to update immutable variable".into()));
		}
		if value.variable_type() != Some(self.variable_type) {
			return Err(Error::Variable(format!("trying to update variable of type {:?} with value of type {:?}", self.variable_type, value.variable_type())));
		}

		self.value.write().set(value)
	}
}

impl VariableValue {
	fn get(&self) -> RuntimeValue {
		match *self {
			VariableValue::Internal(ref value) => value.clone(),
			VariableValue::External(ref value) => value.get(),
		}
	}

	fn set(&mut self, new_value: RuntimeValue) -> Result<(), Error> {
		match *self {
			VariableValue::Internal(ref mut value) => {
				*value = new_value;
				Ok(())
			},
			VariableValue::External(ref mut value) => value.set(new_value),
		}
	}
}

impl From<ValueType> for VariableType {
	fn from(vt: ValueType) -> VariableType {
		match vt {
			ValueType::I32 => VariableType::I32,
			ValueType::I64 => VariableType::I64,
			ValueType::F32 => VariableType::F32,
			ValueType::F64 => VariableType::F64,
		}
	}
}

impl From<TableElementType> for VariableType {
	fn from(tt: TableElementType) -> VariableType {
		match tt {
			TableElementType::AnyFunc => VariableType::AnyFunc,
		}
	}
}

impl fmt::Debug for VariableValue {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			VariableValue::Internal(ref value) => write!(f, "Variable.Internal({:?})", value),
			VariableValue::External(ref value) => write!(f, "Variable.External({:?})", value.get()),
		}
	}
}
<commit_msg>Update documentation for ExternalVariableValue.<commit_after>use std::fmt;
use parking_lot::RwLock;
use elements::{GlobalType, ValueType, TableElementType};
use interpreter::Error;
use interpreter::value::RuntimeValue;

/// Variable type.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum VariableType {
	/// Any func value.
	AnyFunc,
	/// i32 value.
	I32,
	/// i64 value.
	I64,
	/// f32 value.
	F32,
	/// f64 value.
	F64,
}

/// Externally stored variable value.
pub trait ExternalVariableValue {
	/// Get variable value.
	fn get(&self) -> RuntimeValue;

	/// Set variable value.
	///
	/// WebAssembly specificaiton [requires][0] that if global variable is immutable, then
	/// it should remain unchanged.
	///
	/// [0]: https://webassembly.github.io/spec/appendix/properties.html#global-instance
	fn set(&mut self, value: RuntimeValue) -> Result<(), Error>;
}

/// Variable instance.
#[derive(Debug)]
pub struct VariableInstance {
	/// Is mutable?
	is_mutable: bool,
	/// Variable type.
	variable_type: VariableType,
	/// Global value.
	value: RwLock<VariableValue>,
}

/// Enum variable value.
enum VariableValue {
	/// Internal value.
	Internal(RuntimeValue),
	/// External value.
	External(Box<ExternalVariableValue>),
}

impl VariableInstance {
	/// New variable instance
	pub fn new(is_mutable: bool, variable_type: VariableType, value: RuntimeValue) -> Result<Self, Error> {
		// TODO: there is nothing about null value in specification + there is nothing about initializing missing table elements? => runtime check for nulls
		if !value.is_null() && value.variable_type() != Some(variable_type) {
			return Err(Error::Variable(format!("trying to initialize variable of type {:?} with value of type {:?}", variable_type, value.variable_type())));
		}

		Ok(VariableInstance {
			is_mutable: is_mutable,
			variable_type: variable_type,
			value: RwLock::new(VariableValue::Internal(value)),
		})
	}

	/// New global variable
	pub fn new_global(global_type: &GlobalType, value: RuntimeValue) -> Result<Self, Error> {
		Self::new(global_type.is_mutable(), global_type.content_type().into(), value)
	}

	/// New global with externally stored value.
	pub fn new_external_global(is_mutable: bool, variable_type: VariableType, value: Box<ExternalVariableValue>) -> Result<Self, Error> {
		// TODO: there is nothing about null value in specification + there is nothing about initializing missing table elements? => runtime check for nulls
		let current_value = value.get();
		if !current_value.is_null() && current_value.variable_type() != Some(variable_type) {
			return Err(Error::Variable(format!("trying to initialize variable of type {:?} with value of type {:?}", variable_type, current_value.variable_type())));
		}

		Ok(VariableInstance {
			is_mutable: is_mutable,
			variable_type: variable_type,
			value: RwLock::new(VariableValue::External(value)),
		})
	}

	/// Is mutable
	pub fn is_mutable(&self) -> bool {
		self.is_mutable
	}

	/// Get variable type.
	pub fn variable_type(&self) -> VariableType {
		self.variable_type
	}

	/// Get the value of the variable instance
	pub fn get(&self) -> RuntimeValue {
		self.value.read().get()
	}

	/// Set the value of the variable instance
	pub fn set(&self, value: RuntimeValue) -> Result<(), Error> {
		if !self.is_mutable {
			return Err(Error::Variable("trying to update immutable variable".into()));
		}
		if value.variable_type() != Some(self.variable_type) {
			return Err(Error::Variable(format!("trying to update variable of type {:?} with value of type {:?}", self.variable_type, value.variable_type())));
		}

		self.value.write().set(value)
	}
}

impl VariableValue {
	fn get(&self) -> RuntimeValue {
		match *self {
			VariableValue::Internal(ref value) => value.clone(),
			VariableValue::External(ref value) => value.get(),
		}
	}

	fn set(&mut self, new_value: RuntimeValue) -> Result<(), Error> {
		match *self {
			VariableValue::Internal(ref mut value) => {
				*value = new_value;
				Ok(())
			},
			VariableValue::External(ref mut value) => value.set(new_value),
		}
	}
}

impl From<ValueType> for VariableType {
	fn from(vt: ValueType) -> VariableType {
		match vt {
			ValueType::I32 => VariableType::I32,
			ValueType::I64 => VariableType::I64,
			ValueType::F32 => VariableType::F32,
			ValueType::F64 => VariableType::F64,
		}
	}
}

impl From<TableElementType> for VariableType {
	fn from(tt: TableElementType) -> VariableType {
		match tt {
			TableElementType::AnyFunc => VariableType::AnyFunc,
		}
	}
}

impl fmt::Debug for VariableValue {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			VariableValue::Internal(ref value) => write!(f, "Variable.Internal({:?})", value),
			VariableValue::External(ref value) => write!(f, "Variable.External({:?})", value.get()),
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

#![unstable(feature = "collections_range",
            reason = "waiting for dust to settle on inclusive ranges",
            issue = "30877")]

//! Range syntax.

use core::option::Option::{self, None, Some};
use core::ops::{RangeFull, Range, RangeTo, RangeFrom};

/// **RangeArgument** is implemented by Rust's built-in range types, produced
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
pub trait RangeArgument<T> {
    /// Start index (inclusive)
    ///
    /// Return start value if present, else `None`.
    fn start(&self) -> Option<&T> {
        None
    }

    /// End index (exclusive)
    ///
    /// Return end value if present, else `None`.
    fn end(&self) -> Option<&T> {
        None
    }
}

// FIXME add inclusive ranges to RangeArgument

impl<T> RangeArgument<T> for RangeFull {}

impl<T> RangeArgument<T> for RangeFrom<T> {
    fn start(&self) -> Option<&T> {
        Some(&self.start)
    }
}

impl<T> RangeArgument<T> for RangeTo<T> {
    fn end(&self) -> Option<&T> {
        Some(&self.end)
    }
}

impl<T> RangeArgument<T> for Range<T> {
    fn start(&self) -> Option<&T> {
        Some(&self.start)
    }
    fn end(&self) -> Option<&T> {
        Some(&self.end)
    }
}
<commit_msg>Add doc examples for `range::RangeArgument::{start,end}`.<commit_after>// Copyright 2015 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.

#![unstable(feature = "collections_range",
            reason = "waiting for dust to settle on inclusive ranges",
            issue = "30877")]

//! Range syntax.

use core::option::Option::{self, None, Some};
use core::ops::{RangeFull, Range, RangeTo, RangeFrom};

/// **RangeArgument** is implemented by Rust's built-in range types, produced
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
pub trait RangeArgument<T> {
    /// Start index (inclusive)
    ///
    /// Return start value if present, else `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(collections)]
    /// #![feature(collections_range)]
    ///
    /// extern crate collections;
    ///
    /// # fn main() {
    /// use collections::range::RangeArgument;
    ///
    /// assert_eq!((..10).start(), None);
    /// assert_eq!((3..10).start(), Some(&3));
    /// # }
    /// ```
    fn start(&self) -> Option<&T> {
        None
    }

    /// End index (exclusive)
    ///
    /// Return end value if present, else `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(collections)]
    /// #![feature(collections_range)]
    ///
    /// extern crate collections;
    ///
    /// # fn main() {
    /// use collections::range::RangeArgument;
    ///
    /// assert_eq!((3..).end(), None);
    /// assert_eq!((3..10).end(), Some(&10));
    /// # }
    /// ```
    fn end(&self) -> Option<&T> {
        None
    }
}

// FIXME add inclusive ranges to RangeArgument

impl<T> RangeArgument<T> for RangeFull {}

impl<T> RangeArgument<T> for RangeFrom<T> {
    fn start(&self) -> Option<&T> {
        Some(&self.start)
    }
}

impl<T> RangeArgument<T> for RangeTo<T> {
    fn end(&self) -> Option<&T> {
        Some(&self.end)
    }
}

impl<T> RangeArgument<T> for Range<T> {
    fn start(&self) -> Option<&T> {
        Some(&self.start)
    }
    fn end(&self) -> Option<&T> {
        Some(&self.end)
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 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.
//
// Original implementation taken from rust-memchr
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch

use cmp;
use mem;

const LO_U64: u64 = 0x0101010101010101;
const HI_U64: u64 = 0x8080808080808080;

// use truncation
const LO_USIZE: usize = LO_U64 as usize;
const HI_USIZE: usize = HI_U64 as usize;

/// Return `true` if `x` contains any zero byte.
///
/// From *Matters Computational*, J. Arndt
///
/// "The idea is to subtract one from each of the bytes and then look for
/// bytes where the borrow propagated all the way to the most significant
/// bit."
#[inline]
fn contains_zero_byte(x: usize) -> bool {
    x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
}

#[cfg(target_pointer_width = "16")]
#[inline]
fn repeat_byte(b: u8) -> usize {
    (b as usize) << 8 | b as usize
}

#[cfg(target_pointer_width = "32")]
#[inline]
fn repeat_byte(b: u8) -> usize {
    let mut rep = (b as usize) << 8 | b as usize;
    rep = rep << 16 | rep;
    rep
}

#[cfg(target_pointer_width = "64")]
#[inline]
fn repeat_byte(b: u8) -> usize {
    let mut rep = (b as usize) << 8 | b as usize;
    rep = rep << 16 | rep;
    rep = rep << 32 | rep;
    rep
}

/// Return the first index matching the byte `x` in `text`.
pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
    // Scan for a single byte value by reading two `usize` words at a time.
    //
    // Split `text` in three parts
    // - unaligned initial part, before the first word aligned address in text
    // - body, scan by 2 words at a time
    // - the last remaining part, < 2 word size
    let len = text.len();
    let ptr = text.as_ptr();
    let usize_bytes = mem::size_of::<usize>();

    // search up to an aligned boundary
    let mut offset = ptr.align_offset(usize_bytes);
    if offset > 0 {
        offset = cmp::min(offset, len);
        if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
            return Some(index);
        }
    }

    // search the body of the text
    let repeated_x = repeat_byte(x);

    if len >= 2 * usize_bytes {
        while offset <= len - 2 * usize_bytes {
            unsafe {
                let u = *(ptr.offset(offset as isize) as *const usize);
                let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);

                // break if there is a matching byte
                let zu = contains_zero_byte(u ^ repeated_x);
                let zv = contains_zero_byte(v ^ repeated_x);
                if zu || zv {
                    break;
                }
            }
            offset += usize_bytes * 2;
        }
    }

    // find the byte after the point the body loop stopped
    text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
}

/// Return the last index matching the byte `x` in `text`.
pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
    // Scan for a single byte value by reading two `usize` words at a time.
    //
    // Split `text` in three parts
    // - unaligned tail, after the last word aligned address in text
    // - body, scan by 2 words at a time
    // - the first remaining bytes, < 2 word size
    let len = text.len();
    let ptr = text.as_ptr();
    let usize_bytes = mem::size_of::<usize>();

    // search to an aligned boundary
    let end_align = (ptr as usize + len) & (usize_bytes - 1);
    let mut offset;
    if end_align > 0 {
        offset = if end_align >= len { 0 } else { len - end_align };
        if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
            return Some(offset + index);
        }
    } else {
        offset = len;
    }

    // search the body of the text
    let repeated_x = repeat_byte(x);

    while offset >= 2 * usize_bytes {
        unsafe {
            let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
            let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);

            // break if there is a matching byte
            let zu = contains_zero_byte(u ^ repeated_x);
            let zv = contains_zero_byte(v ^ repeated_x);
            if zu || zv {
                break;
            }
        }
        offset -= 2 * usize_bytes;
    }

    // find the byte before the point the body loop stopped
    text[..offset].iter().rposition(|elt| *elt == x)
}

// test fallback implementations on all platforms
#[test]
fn matches_one() {
    assert_eq!(Some(0), memchr(b'a', b"a"));
}

#[test]
fn matches_begin() {
    assert_eq!(Some(0), memchr(b'a', b"aaaa"));
}

#[test]
fn matches_end() {
    assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
}

#[test]
fn matches_nul() {
    assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
}

#[test]
fn matches_past_nul() {
    assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
}

#[test]
fn no_match_empty() {
    assert_eq!(None, memchr(b'a', b""));
}

#[test]
fn no_match() {
    assert_eq!(None, memchr(b'a', b"xyz"));
}

#[test]
fn matches_one_reversed() {
    assert_eq!(Some(0), memrchr(b'a', b"a"));
}

#[test]
fn matches_begin_reversed() {
    assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
}

#[test]
fn matches_end_reversed() {
    assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
}

#[test]
fn matches_nul_reversed() {
    assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
}

#[test]
fn matches_past_nul_reversed() {
    assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
}

#[test]
fn no_match_empty_reversed() {
    assert_eq!(None, memrchr(b'a', b""));
}

#[test]
fn no_match_reversed() {
    assert_eq!(None, memrchr(b'a', b"xyz"));
}

#[test]
fn each_alignment_reversed() {
    let mut data = [1u8; 64];
    let needle = 2;
    let pos = 40;
    data[pos] = needle;
    for start in 0..16 {
        assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
    }
}
<commit_msg>Auto merge of #50398 - llogiq:memchr-nano-opt, r=nagisa<commit_after>// Copyright 2015 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.
//
// Original implementation taken from rust-memchr
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch

use cmp;
use mem;

const LO_U64: u64 = 0x0101010101010101;
const HI_U64: u64 = 0x8080808080808080;

// use truncation
const LO_USIZE: usize = LO_U64 as usize;
const HI_USIZE: usize = HI_U64 as usize;

/// Return `true` if `x` contains any zero byte.
///
/// From *Matters Computational*, J. Arndt
///
/// "The idea is to subtract one from each of the bytes and then look for
/// bytes where the borrow propagated all the way to the most significant
/// bit."
#[inline]
fn contains_zero_byte(x: usize) -> bool {
    x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
}

#[cfg(target_pointer_width = "16")]
#[inline]
fn repeat_byte(b: u8) -> usize {
    (b as usize) << 8 | b as usize
}

#[cfg(not(target_pointer_width = "16"))]
#[inline]
fn repeat_byte(b: u8) -> usize {
    (b as usize) * (::usize::MAX / 255)
}

/// Return the first index matching the byte `x` in `text`.
pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
    // Scan for a single byte value by reading two `usize` words at a time.
    //
    // Split `text` in three parts
    // - unaligned initial part, before the first word aligned address in text
    // - body, scan by 2 words at a time
    // - the last remaining part, < 2 word size
    let len = text.len();
    let ptr = text.as_ptr();
    let usize_bytes = mem::size_of::<usize>();

    // search up to an aligned boundary
    let mut offset = ptr.align_offset(usize_bytes);
    if offset > 0 {
        offset = cmp::min(offset, len);
        if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
            return Some(index);
        }
    }

    // search the body of the text
    let repeated_x = repeat_byte(x);

    if len >= 2 * usize_bytes {
        while offset <= len - 2 * usize_bytes {
            unsafe {
                let u = *(ptr.offset(offset as isize) as *const usize);
                let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);

                // break if there is a matching byte
                let zu = contains_zero_byte(u ^ repeated_x);
                let zv = contains_zero_byte(v ^ repeated_x);
                if zu || zv {
                    break;
                }
            }
            offset += usize_bytes * 2;
        }
    }

    // find the byte after the point the body loop stopped
    text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
}

/// Return the last index matching the byte `x` in `text`.
pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
    // Scan for a single byte value by reading two `usize` words at a time.
    //
    // Split `text` in three parts
    // - unaligned tail, after the last word aligned address in text
    // - body, scan by 2 words at a time
    // - the first remaining bytes, < 2 word size
    let len = text.len();
    let ptr = text.as_ptr();
    let usize_bytes = mem::size_of::<usize>();

    // search to an aligned boundary
    let end_align = (ptr as usize + len) & (usize_bytes - 1);
    let mut offset;
    if end_align > 0 {
        offset = if end_align >= len { 0 } else { len - end_align };
        if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
            return Some(offset + index);
        }
    } else {
        offset = len;
    }

    // search the body of the text
    let repeated_x = repeat_byte(x);

    while offset >= 2 * usize_bytes {
        unsafe {
            let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
            let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);

            // break if there is a matching byte
            let zu = contains_zero_byte(u ^ repeated_x);
            let zv = contains_zero_byte(v ^ repeated_x);
            if zu || zv {
                break;
            }
        }
        offset -= 2 * usize_bytes;
    }

    // find the byte before the point the body loop stopped
    text[..offset].iter().rposition(|elt| *elt == x)
}

// test fallback implementations on all platforms
#[test]
fn matches_one() {
    assert_eq!(Some(0), memchr(b'a', b"a"));
}

#[test]
fn matches_begin() {
    assert_eq!(Some(0), memchr(b'a', b"aaaa"));
}

#[test]
fn matches_end() {
    assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
}

#[test]
fn matches_nul() {
    assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
}

#[test]
fn matches_past_nul() {
    assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
}

#[test]
fn no_match_empty() {
    assert_eq!(None, memchr(b'a', b""));
}

#[test]
fn no_match() {
    assert_eq!(None, memchr(b'a', b"xyz"));
}

#[test]
fn matches_one_reversed() {
    assert_eq!(Some(0), memrchr(b'a', b"a"));
}

#[test]
fn matches_begin_reversed() {
    assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
}

#[test]
fn matches_end_reversed() {
    assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
}

#[test]
fn matches_nul_reversed() {
    assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
}

#[test]
fn matches_past_nul_reversed() {
    assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
}

#[test]
fn no_match_empty_reversed() {
    assert_eq!(None, memrchr(b'a', b""));
}

#[test]
fn no_match_reversed() {
    assert_eq!(None, memrchr(b'a', b"xyz"));
}

#[test]
fn each_alignment_reversed() {
    let mut data = [1u8; 64];
    let needle = 2;
    let pos = 40;
    data[pos] = needle;
    for start in 0..16 {
        assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
    }
}
<|endoftext|>


<commit_before>extern crate rayon;

use std::collections::HashMap;

use super::common::Value;
use super::network::Network;

#[derive(RustcDecodable)]
pub struct Conf {
    pub group_size: usize,
    pub threshold: Value,
}

pub trait Apply {
    fn apply<'r>(&'r self, conf: &'r Conf) -> Application<'r>;
}

impl<'network> Apply for Network<'network> {
    fn apply<'r>(&'r self, conf: &'r Conf) -> Application<'r> {
        Application::new(self, conf)
    }
}

struct ValuesGroup {
    pub sum: Value,
    pub node: usize,
}

pub struct Application<'r> {
    conf: &'r Conf,
    network: &'r Network<'r>,
}

impl<'r> Application<'r> {
    pub fn new(network: &'r Network<'r>, conf: &'r Conf) -> Self {
        Application {network: network, conf: conf}
    }

    pub fn perform(&self, values: &[Value]) -> Vec<Value> {
        use std::ops::{AddAssign, Deref, DerefMut};
        use std::sync::{Arc, Mutex};
        use self::rayon::prelude::*;
        assert!(values.len() >= self.network.inputs.len());
        let group_size = self.conf.group_size as Value;
        let result = Arc::new(Mutex::new(self.network.outputs.iter()
            .map(|&x| (x, 0.0)).collect::<HashMap<usize, Value>>()));
        self.network.inputs.par_iter().zip(values)
            .map(|(&node, value)| {
                self.perform_one(ValuesGroup {sum: value * group_size, node: node})
            })
            .for_each(|groups| {
                for group in groups {
                    let mut guarded = result.lock().unwrap();
                    guarded.deref_mut().get_mut(&group.node).unwrap().add_assign(group.sum);
                }
            });
        let guarded = result.lock().unwrap();
        let mut values = guarded.deref().into_iter().collect::<Vec<_>>();
        values.sort_by_key(|&(group, _)| group);
        values.into_iter()
            .map(|(_, value)| value / group_size as Value)
            .collect::<Vec<Value>>()
    }

    fn perform_one(&self, group: ValuesGroup) -> Vec<ValuesGroup> {
        if self.network.outputs.contains(&group.node) {
            vec![group]
        } else if group.sum > self.conf.threshold {
            let row = self.network.weights.row(group.node);
            let nodes = row.iter()
                .enumerate()
                .filter(|&(_, &w)| w.abs() > 0.0)
                .map(|(n, &w)| (n, w))
                .collect::<Vec<(usize, Value)>>();
            let new_sum = group.sum / nodes.len() as Value;
            nodes.iter()
                .map(|&(node, weight)| {
                    self.perform_one(ValuesGroup {sum: new_sum * weight, node: node})
                })
                .flat_map(|x| x.into_iter())
                .collect::<Vec<_>>()
        } else {
            vec![]
        }
    }
}

#[test]
fn test_apply_network_contains_one_arc_with_positive_weight_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let weight = 0.4;
    let weights_values = [
        0.0, weight,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..], &[input * weight]);
}

#[test]
fn test_apply_network_contains_one_arc_with_negative_weight_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let weight = -0.4;
    let weights_values = [
        0.0, weight,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..], &[input * weight]);
}

#[test]
fn test_apply_network_with_two_arcs_and_two_inputs_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w13 = 0.4;
    let w23 = 0.2;
    let weights_values = [
        0.0, 0.0, w13,
        0.0, 0.0, w23,
        0.0, 0.0, 0.0,
    ];
    let inputs = [0, 1].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [2].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(3, &weights_values);
    let nodes = (0..3).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let i1 = 0.6;
    let i2 = 0.7;
    assert_eq!(&network.apply(&conf).perform(&[i1, i2])[..], &[i1 * w13 + i2 * w23]);
}

#[test]
fn test_apply_network_with_two_arcs_and_two_outputs_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w12 = 0.4;
    let w13 = 0.2;
    let weights_values = [
        0.0, w12, w13,
        0.0, 0.0, 0.0,
        0.0, 0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1, 2].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(3, &weights_values);
    let nodes = (0..3).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..],
               &[input * w12 / 2.0, input * w13 / 2.0]);
}

#[test]
fn test_apply_network_with_two_arcs_and_one_middle_node_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w12 = 0.4;
    let w23 = 0.2;
    let weights_values = [
        0.0, w12, 0.0,
        0.0, 0.0, w23,
        0.0, 0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [2].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(3, &weights_values);
    let nodes = (0..3).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..], &[input * w12 * w23]);
}

#[test]
fn test_apply_network_with_two_arcs_and_self_add_arced_input_node_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w11 = 0.2;
    let w12 = 0.4;
    let weights_values = [
        w11, w12,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1000, threshold: 1e-8};
    let input = 0.6;
    let actual = network.apply(&conf).perform(&[input]);
    let expected = [input * w12 * (1.0 + w11 / (2.0 - w11)) / 2.0];
    assert_eq!(actual.len(), expected.len());
    assert!((actual[0] - expected[0]).abs() <= 1e-8);
}

#[test]
fn test_apply_network_without_arcs_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let weights_values = [
        0.0, 0.0,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1000, threshold: 1e-8};
    assert_eq!(&network.apply(&conf).perform(&[1.0]), &[0.0]);
}
<commit_msg>Revert "Use parallel map in apply"<commit_after>use std::collections::BTreeMap;

use super::common::Value;
use super::network::Network;

#[derive(RustcDecodable)]
pub struct Conf {
    pub group_size: usize,
    pub threshold: Value,
}

pub trait Apply {
    fn apply<'r>(&'r self, conf: &'r Conf) -> Application<'r>;
}

impl<'network> Apply for Network<'network> {
    fn apply<'r>(&'r self, conf: &'r Conf) -> Application<'r> {
        Application::new(self, conf)
    }
}

struct ValuesGroup {
    pub sum: Value,
    pub node: usize,
}

pub struct Application<'r> {
    conf: &'r Conf,
    network: &'r Network<'r>,
}

impl<'r> Application<'r> {
    pub fn new(network: &'r Network<'r>, conf: &'r Conf) -> Self {
        Application {network: network, conf: conf}
    }

    pub fn perform(&self, values: &[Value]) -> Vec<Value> {
        assert!(values.len() >= self.network.inputs.len());
        let group_size = self.conf.group_size as Value;
        let mut result: BTreeMap<usize, Value> = self.network.outputs.iter()
            .map(|&x| (x, 0.0)).collect::<_>();
        {
            let groups = self.network.inputs.iter().zip(values)
                .map(|(&node, value)| {
                    self.perform_one(ValuesGroup {sum: value * group_size, node: node})
                })
                .flat_map(|x| x.into_iter());
            for group in groups {
                *result.get_mut(&group.node).unwrap() += group.sum;
            }
        }
        result.values()
            .map(|x| x / group_size as Value)
            .collect::<Vec<Value>>()
    }

    fn perform_one(&self, group: ValuesGroup) -> Box<Iterator<Item=ValuesGroup>> {
        if self.network.outputs.contains(&group.node) {
            Box::new(vec![group].into_iter())
        } else if group.sum > self.conf.threshold {
            let row = self.network.weights.row(group.node);
            let nodes = row.iter()
                .enumerate()
                .filter(|&(_, &w)| w.abs() > 0.0)
                .map(|(n, &w)| (n, w))
                .collect::<Vec<(usize, Value)>>();
            let new_sum = group.sum / nodes.len() as Value;
            Box::new(nodes.iter()
                .map(|&(node, weight)| {
                    self.perform_one(ValuesGroup {sum: new_sum * weight, node: node})
                })
                .flat_map(|x| x.into_iter())
                .collect::<Vec<_>>()
                .into_iter())
        } else {
            Box::new(vec![].into_iter())
        }
    }
}

#[test]
fn test_apply_network_contains_one_arc_with_positive_weight_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let weight = 0.4;
    let weights_values = [
        0.0, weight,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..], &[input * weight]);
}

#[test]
fn test_apply_network_contains_one_arc_with_negative_weight_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let weight = -0.4;
    let weights_values = [
        0.0, weight,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..], &[input * weight]);
}

#[test]
fn test_apply_network_with_two_arcs_and_two_inputs_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w13 = 0.4;
    let w23 = 0.2;
    let weights_values = [
        0.0, 0.0, w13,
        0.0, 0.0, w23,
        0.0, 0.0, 0.0,
    ];
    let inputs = [0, 1].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [2].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(3, &weights_values);
    let nodes = (0..3).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let i1 = 0.6;
    let i2 = 0.7;
    assert_eq!(&network.apply(&conf).perform(&[i1, i2])[..], &[i1 * w13 + i2 * w23]);
}

#[test]
fn test_apply_network_with_two_arcs_and_two_outputs_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w12 = 0.4;
    let w13 = 0.2;
    let weights_values = [
        0.0, w12, w13,
        0.0, 0.0, 0.0,
        0.0, 0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1, 2].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(3, &weights_values);
    let nodes = (0..3).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..],
               &[input * w12 / 2.0, input * w13 / 2.0]);
}

#[test]
fn test_apply_network_with_two_arcs_and_one_middle_node_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w12 = 0.4;
    let w23 = 0.2;
    let weights_values = [
        0.0, w12, 0.0,
        0.0, 0.0, w23,
        0.0, 0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [2].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(3, &weights_values);
    let nodes = (0..3).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..], &[input * w12 * w23]);
}

#[test]
fn test_apply_network_with_two_arcs_and_self_add_arced_input_node_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w11 = 0.2;
    let w12 = 0.4;
    let weights_values = [
        w11, w12,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1000, threshold: 1e-8};
    let input = 0.6;
    let actual = network.apply(&conf).perform(&[input]);
    let expected = [input * w12 * (1.0 + w11 / (2.0 - w11)) / 2.0];
    assert_eq!(actual.len(), expected.len());
    assert!((actual[0] - expected[0]).abs() <= 1e-8);
}

#[test]
fn test_apply_network_without_arcs_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let weights_values = [
        0.0, 0.0,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1000, threshold: 1e-8};
    assert_eq!(&network.apply(&conf).perform(&[1.0]), &[0.0]);
}
<|endoftext|>


<commit_before>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! This module implements a lightweight and safe decoder interface over `libavcodec`. It is
//! designed to concentrate all calls to unsafe methods in one place, while providing the same
//! low-level access as the libavcodec functions do.

use std::{ffi::CStr, fmt::Display, marker::PhantomData, ops::Deref};

use base::MappedRegion;
use libc::{c_char, c_int};
use thiserror::Error as ThisError;

use super::*;

/// An error returned by a low-level libavcodec function.
#[derive(Debug, ThisError)]
pub struct AvError(pub libc::c_int);

impl Display for AvError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut buffer = [0u8; 255];
        // Safe because we are passing valid bounds for the buffer.
        let ret = unsafe {
            ffi::av_strerror(
                self.0,
                buffer.as_mut_ptr() as *mut c_char,
                buffer.len() as ffi::size_t,
            )
        };
        match ret {
            ret if ret >= 0 => {
                let end_of_string = buffer.iter().position(|i| *i == 0).unwrap_or(buffer.len());
                let error_string = std::string::String::from_utf8_lossy(&buffer[..end_of_string]);
                f.write_str(&error_string)
            }
            _ => f.write_fmt(format_args!("Unknown avcodec error {}", self.0)),
        }
    }
}

/// Lightweight abstraction over libavcodec's `AVCodec` struct, allowing the query the capabilities
/// of supported codecs and opening a session to work with them.
///
/// `AVCodec` instances in libavcodec are all static, hence we can safely use a static reference
/// lifetime here.
pub struct AvCodec(&'static ffi::AVCodec);

#[derive(Debug, ThisError)]
pub enum AvCodecOpenError {
    #[error("failed to allocate AVContext object")]
    ContextAllocation,
    #[error("failed to open AVContext object")]
    ContextOpen,
}

impl AvCodec {
    /// Returns whether the codec is a decoder codec.
    pub fn is_decoder(&self) -> bool {
        // Safe because `av_codec_is_decoder` is called on a valid static `AVCodec` reference.
        (unsafe { ffi::av_codec_is_decoder(self.0) } != 0)
    }

    /// Returns the name of the codec.
    pub fn name(&self) -> &'static str {
        const INVALID_CODEC_STR: &str = "invalid codec";

        // Safe because `CStr::from_ptr` is called on a valid zero-terminated C string.
        unsafe { CStr::from_ptr(self.0.name).to_str() }.unwrap_or(INVALID_CODEC_STR)
    }

    /// Returns the capabilities of the codec, as a mask of AV_CODEC_CAP_* bits.
    pub fn capabilities(&self) -> u32 {
        self.0.capabilities as u32
    }

    /// Returns an iterator over the profiles supported by this codec.
    pub fn profile_iter(&self) -> AvProfileIterator {
        AvProfileIterator(self.0.profiles)
    }

    /// Obtain a context that can be used to decode using this codec.
    ///
    /// `get_buffer`'s first element is an optional function that decides which buffer is used to
    /// render a frame (see libavcodec's documentation for `get_buffer2` for more details). If
    /// provided, this function must be thread-safe. If none is provided, avcodec's default function
    /// is used. The second element is a pointer that will be passed as first argument to the
    /// function when it is called.
    pub fn open(
        &self,
        get_buffer: Option<(
            unsafe extern "C" fn(*mut ffi::AVCodecContext, *mut ffi::AVFrame, i32) -> i32,
            *mut libc::c_void,
        )>,
    ) -> Result<AvCodecContext, AvCodecOpenError> {
        // Safe because `self.0` is a valid static AVCodec reference.
        let mut context = unsafe { ffi::avcodec_alloc_context3(self.0).as_mut() }
            .ok_or(AvCodecOpenError::ContextAllocation)?;

        if let Some((get_buffer2, opaque)) = get_buffer {
            context.get_buffer2 = Some(get_buffer2);
            context.opaque = opaque;
            context.thread_safe_callbacks = 1;
        }

        // Safe because `self.0` is a valid static AVCodec reference, and `context` has been
        // successfully allocated above.
        if unsafe { ffi::avcodec_open2(context, self.0, std::ptr::null_mut()) } < 0 {
            return Err(AvCodecOpenError::ContextOpen);
        }

        Ok(AvCodecContext(context))
    }
}

/// Lightweight abstraction over libavcodec's `av_codec_iterate` function that can be used to
/// enumerate all the supported codecs.
pub struct AvCodecIterator(*mut libc::c_void);

impl AvCodecIterator {
    pub fn new() -> Self {
        Self(std::ptr::null_mut())
    }
}

impl Iterator for AvCodecIterator {
    type Item = AvCodec;

    fn next(&mut self) -> Option<Self::Item> {
        // Safe because our pointer was initialized to `NULL` and we only use it with
        // `av_codec_iterate`, which will update it to a valid value.
        unsafe { ffi::av_codec_iterate(&mut self.0 as *mut *mut libc::c_void).as_ref() }
            .map(AvCodec)
    }
}

/// Lightweight abstraction over the array of supported profiles for a given codec.
pub struct AvProfileIterator(*const ffi::AVProfile);

impl Iterator for AvProfileIterator {
    type Item = &'static ffi::AVProfile;

    fn next(&mut self) -> Option<Self::Item> {
        // Safe because the contract of `new` stipulates we have received a valid `AVCodec`
        // reference, thus the `profiles` pointer must either be NULL or point to a valid array
        // or `VAProfile`s.
        match unsafe { self.0.as_ref() } {
            None => None,
            Some(profile) => {
                match profile.profile {
                    ffi::FF_PROFILE_UNKNOWN => None,
                    _ => {
                        // Safe because we have been initialized to a static, valid profiles array
                        // which is terminated by FF_PROFILE_UNKNOWN.
                        self.0 = unsafe { self.0.offset(1) };
                        Some(profile)
                    }
                }
            }
        }
    }
}

/// A codec context from which decoding can be performed.
pub struct AvCodecContext(*mut ffi::AVCodecContext);

impl Drop for AvCodecContext {
    fn drop(&mut self) {
        // Safe because our context member is properly initialized, fully owned by us, and has not
        // leaked in any form.
        unsafe { ffi::avcodec_free_context(&mut self.0) };
    }
}

impl AsRef<ffi::AVCodecContext> for AvCodecContext {
    fn as_ref(&self) -> &ffi::AVCodecContext {
        // Safe because our context member is properly initialized and fully owned by us.
        unsafe { &*self.0 }
    }
}

pub enum TryReceiveFrameResult {
    Received,
    TryAgain,
    FlushCompleted,
}

impl AvCodecContext {
    /// Send a packet to be decoded to the codec.
    ///
    /// Returns `true` if the packet has been accepted and will be decoded, `false` if the codec can
    /// not accept frames at the moment - in this case `try_receive_frame` must be called before
    /// the packet can be submitted again.
    ///
    /// Error codes are the same as those returned by `avcodec_send_packet` with the exception of
    /// EAGAIN which is converted into `Ok(false)` as it is not actually an error.
    pub fn try_send_packet<'a, T: MappedRegion>(
        &mut self,
        packet: &AvPacket<'a, T>,
    ) -> Result<bool, AvError> {
        // Safe because the context is valid through the life of this object, and `packet`'s
        // lifetime properties ensures its memory area is readable.
        match unsafe { ffi::avcodec_send_packet(self.0, &packet.packet) } {
            AVERROR_EAGAIN => Ok(false),
            ret if ret >= 0 => Ok(true),
            err => Err(AvError(err)),
        }
    }

    /// Attempt to write a decoded frame in `frame` if the codec has enough data to do so.
    ///
    /// Returned `Received` if `frame` has been filled with the next decoded frame, `TryAgain` if
    /// no frame could be returned at that time (in which case `try_send_packet` should be called to
    /// submit more input to decode), or `FlushCompleted` to signal that a previous flush triggered
    /// by calling the `flush` method has completed.
    ///
    /// Error codes are the same as those returned by `avcodec_receive_frame`.
    pub fn try_receive_frame(
        &mut self,
        frame: &mut AvFrame,
    ) -> Result<TryReceiveFrameResult, AvError> {
        // Safe because the context is valid through the life of this object, and `avframe` is
        // guaranteed to contain a properly initialized frame.
        match unsafe { ffi::avcodec_receive_frame(self.0, frame.as_mut()) } {
            AVERROR_EAGAIN => Ok(TryReceiveFrameResult::TryAgain),
            AVERROR_EOF => Ok(TryReceiveFrameResult::FlushCompleted),
            ret if ret >= 0 => Ok(TryReceiveFrameResult::Received),
            err => Err(AvError(err)),
        }
    }

    /// Reset the internal codec state/flush internal buffers.
    /// Should be called e.g. when seeking or switching to a different stream.
    pub fn reset(&mut self) {
        // Safe because the context is valid through the life of this object.
        unsafe { ffi::avcodec_flush_buffers(self.0) }
    }

    /// Ask the context to start flushing, i.e. to process all pending input packets and produce
    /// frames for them.
    ///
    /// The flush process is complete when `try_receive_frame` returns `FlushCompleted`,
    pub fn flush(&mut self) -> Result<(), AvError> {
        // Safe because the context is valid through the life of this object.
        match unsafe { ffi::avcodec_send_packet(self.0, std::ptr::null()) } {
            ret if ret >= 0 => Ok(()),
            err => Err(AvError(err)),
        }
    }
}

/// An encoded input packet that can be submitted to `AvCodecContext::try_send_packet`.
pub struct AvPacket<'a, T: MappedRegion> {
    packet: ffi::AVPacket,
    _phantom: PhantomData<&'a T>,
}

impl<'a, T: MappedRegion> AvPacket<'a, T> {
    /// Create a new AvPacket.
    ///
    /// `input_data` is the encoded data we want to send to the codec for decoding. The data is not
    /// copied by the AvPacket itself, however a copy may happen when the packet is submitted.
    pub fn new(pts: i64, input_data: &'a T) -> Self {
        Self {
            packet: ffi::AVPacket {
                buf: std::ptr::null_mut(),
                pts,
                dts: AV_NOPTS_VALUE as i64,
                data: input_data.as_ptr(),
                size: input_data.size() as c_int,
                side_data: std::ptr::null_mut(),
                pos: -1,
                // Safe because all the other elements of this struct can be zeroed.
                ..unsafe { std::mem::zeroed() }
            },
            _phantom: PhantomData,
        }
    }
}

/// An owned AVFrame, i.e. one decoded frame from libavcodec that can be converted into a
/// destination buffer.
pub struct AvFrame(*mut ffi::AVFrame);

#[derive(Debug, ThisError)]
pub enum AvFrameError {
    #[error("failed to allocate AVFrame object")]
    FrameAllocationFailed,
}

impl AvFrame {
    /// Create a new AvFrame. The frame's parameters and backing memory will be assigned when it is
    /// decoded into.
    pub fn new() -> Result<Self, AvFrameError> {
        Ok(Self(
            // Safe because `av_frame_alloc` does not take any input.
            unsafe { ffi::av_frame_alloc().as_mut() }.ok_or(AvFrameError::FrameAllocationFailed)?,
        ))
    }
}

impl AsRef<ffi::AVFrame> for AvFrame {
    fn as_ref(&self) -> &ffi::AVFrame {
        // Safe because the AVFrame has been properly initialized during construction.
        unsafe { &*self.0 }
    }
}

impl AsMut<ffi::AVFrame> for AvFrame {
    fn as_mut(&mut self) -> &mut ffi::AVFrame {
        // Safe because the AVFrame has been properly initialized during construction.
        unsafe { &mut *self.0 }
    }
}

impl Deref for AvFrame {
    type Target = ffi::AVFrame;

    fn deref(&self) -> &Self::Target {
        // Safe because the AVFrame has been properly initialized during construction.
        unsafe { self.0.as_ref().unwrap() }
    }
}

impl Drop for AvFrame {
    fn drop(&mut self) {
        // Safe because the AVFrame is valid through the life of this object and fully owned by us.
        unsafe { ffi::av_frame_free(&mut self.0) };
    }
}

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

    #[test]
    fn test_averror() {
        // Just test that the error is wrapper properly. The bindings test module already checks
        // that the error bindings correspond to the right ffmpeg errors.
        let averror = AvError(AVERROR_EOF);
        let msg = format!("{}", averror);
        assert_eq!(msg, "End of file");

        let averror = AvError(0);
        let msg = format!("{}", averror);
        assert_eq!(msg, "Success");

        let averror = AvError(10);
        let msg = format!("{}", averror);
        assert_eq!(msg, "Unknown avcodec error 10");
    }
}
<commit_msg>media: ffmpeg: remove generic type from AvPacket<commit_after>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! This module implements a lightweight and safe decoder interface over `libavcodec`. It is
//! designed to concentrate all calls to unsafe methods in one place, while providing the same
//! low-level access as the libavcodec functions do.

use std::{ffi::CStr, fmt::Display, marker::PhantomData, ops::Deref};

use base::MappedRegion;
use libc::{c_char, c_int};
use thiserror::Error as ThisError;

use super::*;

/// An error returned by a low-level libavcodec function.
#[derive(Debug, ThisError)]
pub struct AvError(pub libc::c_int);

impl Display for AvError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut buffer = [0u8; 255];
        // Safe because we are passing valid bounds for the buffer.
        let ret = unsafe {
            ffi::av_strerror(
                self.0,
                buffer.as_mut_ptr() as *mut c_char,
                buffer.len() as ffi::size_t,
            )
        };
        match ret {
            ret if ret >= 0 => {
                let end_of_string = buffer.iter().position(|i| *i == 0).unwrap_or(buffer.len());
                let error_string = std::string::String::from_utf8_lossy(&buffer[..end_of_string]);
                f.write_str(&error_string)
            }
            _ => f.write_fmt(format_args!("Unknown avcodec error {}", self.0)),
        }
    }
}

/// Lightweight abstraction over libavcodec's `AVCodec` struct, allowing the query the capabilities
/// of supported codecs and opening a session to work with them.
///
/// `AVCodec` instances in libavcodec are all static, hence we can safely use a static reference
/// lifetime here.
pub struct AvCodec(&'static ffi::AVCodec);

#[derive(Debug, ThisError)]
pub enum AvCodecOpenError {
    #[error("failed to allocate AVContext object")]
    ContextAllocation,
    #[error("failed to open AVContext object")]
    ContextOpen,
}

impl AvCodec {
    /// Returns whether the codec is a decoder codec.
    pub fn is_decoder(&self) -> bool {
        // Safe because `av_codec_is_decoder` is called on a valid static `AVCodec` reference.
        (unsafe { ffi::av_codec_is_decoder(self.0) } != 0)
    }

    /// Returns the name of the codec.
    pub fn name(&self) -> &'static str {
        const INVALID_CODEC_STR: &str = "invalid codec";

        // Safe because `CStr::from_ptr` is called on a valid zero-terminated C string.
        unsafe { CStr::from_ptr(self.0.name).to_str() }.unwrap_or(INVALID_CODEC_STR)
    }

    /// Returns the capabilities of the codec, as a mask of AV_CODEC_CAP_* bits.
    pub fn capabilities(&self) -> u32 {
        self.0.capabilities as u32
    }

    /// Returns an iterator over the profiles supported by this codec.
    pub fn profile_iter(&self) -> AvProfileIterator {
        AvProfileIterator(self.0.profiles)
    }

    /// Obtain a context that can be used to decode using this codec.
    ///
    /// `get_buffer`'s first element is an optional function that decides which buffer is used to
    /// render a frame (see libavcodec's documentation for `get_buffer2` for more details). If
    /// provided, this function must be thread-safe. If none is provided, avcodec's default function
    /// is used. The second element is a pointer that will be passed as first argument to the
    /// function when it is called.
    pub fn open(
        &self,
        get_buffer: Option<(
            unsafe extern "C" fn(*mut ffi::AVCodecContext, *mut ffi::AVFrame, i32) -> i32,
            *mut libc::c_void,
        )>,
    ) -> Result<AvCodecContext, AvCodecOpenError> {
        // Safe because `self.0` is a valid static AVCodec reference.
        let mut context = unsafe { ffi::avcodec_alloc_context3(self.0).as_mut() }
            .ok_or(AvCodecOpenError::ContextAllocation)?;

        if let Some((get_buffer2, opaque)) = get_buffer {
            context.get_buffer2 = Some(get_buffer2);
            context.opaque = opaque;
            context.thread_safe_callbacks = 1;
        }

        // Safe because `self.0` is a valid static AVCodec reference, and `context` has been
        // successfully allocated above.
        if unsafe { ffi::avcodec_open2(context, self.0, std::ptr::null_mut()) } < 0 {
            return Err(AvCodecOpenError::ContextOpen);
        }

        Ok(AvCodecContext(context))
    }
}

/// Lightweight abstraction over libavcodec's `av_codec_iterate` function that can be used to
/// enumerate all the supported codecs.
pub struct AvCodecIterator(*mut libc::c_void);

impl AvCodecIterator {
    pub fn new() -> Self {
        Self(std::ptr::null_mut())
    }
}

impl Iterator for AvCodecIterator {
    type Item = AvCodec;

    fn next(&mut self) -> Option<Self::Item> {
        // Safe because our pointer was initialized to `NULL` and we only use it with
        // `av_codec_iterate`, which will update it to a valid value.
        unsafe { ffi::av_codec_iterate(&mut self.0 as *mut *mut libc::c_void).as_ref() }
            .map(AvCodec)
    }
}

/// Lightweight abstraction over the array of supported profiles for a given codec.
pub struct AvProfileIterator(*const ffi::AVProfile);

impl Iterator for AvProfileIterator {
    type Item = &'static ffi::AVProfile;

    fn next(&mut self) -> Option<Self::Item> {
        // Safe because the contract of `new` stipulates we have received a valid `AVCodec`
        // reference, thus the `profiles` pointer must either be NULL or point to a valid array
        // or `VAProfile`s.
        match unsafe { self.0.as_ref() } {
            None => None,
            Some(profile) => {
                match profile.profile {
                    ffi::FF_PROFILE_UNKNOWN => None,
                    _ => {
                        // Safe because we have been initialized to a static, valid profiles array
                        // which is terminated by FF_PROFILE_UNKNOWN.
                        self.0 = unsafe { self.0.offset(1) };
                        Some(profile)
                    }
                }
            }
        }
    }
}

/// A codec context from which decoding can be performed.
pub struct AvCodecContext(*mut ffi::AVCodecContext);

impl Drop for AvCodecContext {
    fn drop(&mut self) {
        // Safe because our context member is properly initialized, fully owned by us, and has not
        // leaked in any form.
        unsafe { ffi::avcodec_free_context(&mut self.0) };
    }
}

impl AsRef<ffi::AVCodecContext> for AvCodecContext {
    fn as_ref(&self) -> &ffi::AVCodecContext {
        // Safe because our context member is properly initialized and fully owned by us.
        unsafe { &*self.0 }
    }
}

pub enum TryReceiveFrameResult {
    Received,
    TryAgain,
    FlushCompleted,
}

impl AvCodecContext {
    /// Send a packet to be decoded to the codec.
    ///
    /// Returns `true` if the packet has been accepted and will be decoded, `false` if the codec can
    /// not accept frames at the moment - in this case `try_receive_frame` must be called before
    /// the packet can be submitted again.
    ///
    /// Error codes are the same as those returned by `avcodec_send_packet` with the exception of
    /// EAGAIN which is converted into `Ok(false)` as it is not actually an error.
    pub fn try_send_packet<'a>(&mut self, packet: &AvPacket<'a>) -> Result<bool, AvError> {
        // Safe because the context is valid through the life of this object, and `packet`'s
        // lifetime properties ensures its memory area is readable.
        match unsafe { ffi::avcodec_send_packet(self.0, &packet.packet) } {
            AVERROR_EAGAIN => Ok(false),
            ret if ret >= 0 => Ok(true),
            err => Err(AvError(err)),
        }
    }

    /// Attempt to write a decoded frame in `frame` if the codec has enough data to do so.
    ///
    /// Returned `Received` if `frame` has been filled with the next decoded frame, `TryAgain` if
    /// no frame could be returned at that time (in which case `try_send_packet` should be called to
    /// submit more input to decode), or `FlushCompleted` to signal that a previous flush triggered
    /// by calling the `flush` method has completed.
    ///
    /// Error codes are the same as those returned by `avcodec_receive_frame`.
    pub fn try_receive_frame(
        &mut self,
        frame: &mut AvFrame,
    ) -> Result<TryReceiveFrameResult, AvError> {
        // Safe because the context is valid through the life of this object, and `avframe` is
        // guaranteed to contain a properly initialized frame.
        match unsafe { ffi::avcodec_receive_frame(self.0, frame.as_mut()) } {
            AVERROR_EAGAIN => Ok(TryReceiveFrameResult::TryAgain),
            AVERROR_EOF => Ok(TryReceiveFrameResult::FlushCompleted),
            ret if ret >= 0 => Ok(TryReceiveFrameResult::Received),
            err => Err(AvError(err)),
        }
    }

    /// Reset the internal codec state/flush internal buffers.
    /// Should be called e.g. when seeking or switching to a different stream.
    pub fn reset(&mut self) {
        // Safe because the context is valid through the life of this object.
        unsafe { ffi::avcodec_flush_buffers(self.0) }
    }

    /// Ask the context to start flushing, i.e. to process all pending input packets and produce
    /// frames for them.
    ///
    /// The flush process is complete when `try_receive_frame` returns `FlushCompleted`,
    pub fn flush(&mut self) -> Result<(), AvError> {
        // Safe because the context is valid through the life of this object.
        match unsafe { ffi::avcodec_send_packet(self.0, std::ptr::null()) } {
            ret if ret >= 0 => Ok(()),
            err => Err(AvError(err)),
        }
    }
}

/// An encoded input packet that can be submitted to `AvCodecContext::try_send_packet`.
pub struct AvPacket<'a> {
    packet: ffi::AVPacket,
    _phantom: PhantomData<&'a ()>,
}

impl<'a> AvPacket<'a> {
    /// Create a new AvPacket.
    ///
    /// `input_data` is the encoded data we want to send to the codec for decoding. The data is not
    /// copied by the AvPacket itself, however a copy may happen when the packet is submitted.
    pub fn new<T: MappedRegion>(pts: i64, input_data: &'a T) -> Self {
        Self {
            packet: ffi::AVPacket {
                buf: std::ptr::null_mut(),
                pts,
                dts: AV_NOPTS_VALUE as i64,
                data: input_data.as_ptr(),
                size: input_data.size() as c_int,
                side_data: std::ptr::null_mut(),
                pos: -1,
                // Safe because all the other elements of this struct can be zeroed.
                ..unsafe { std::mem::zeroed() }
            },
            _phantom: PhantomData,
        }
    }
}

/// An owned AVFrame, i.e. one decoded frame from libavcodec that can be converted into a
/// destination buffer.
pub struct AvFrame(*mut ffi::AVFrame);

#[derive(Debug, ThisError)]
pub enum AvFrameError {
    #[error("failed to allocate AVFrame object")]
    FrameAllocationFailed,
}

impl AvFrame {
    /// Create a new AvFrame. The frame's parameters and backing memory will be assigned when it is
    /// decoded into.
    pub fn new() -> Result<Self, AvFrameError> {
        Ok(Self(
            // Safe because `av_frame_alloc` does not take any input.
            unsafe { ffi::av_frame_alloc().as_mut() }.ok_or(AvFrameError::FrameAllocationFailed)?,
        ))
    }
}

impl AsRef<ffi::AVFrame> for AvFrame {
    fn as_ref(&self) -> &ffi::AVFrame {
        // Safe because the AVFrame has been properly initialized during construction.
        unsafe { &*self.0 }
    }
}

impl AsMut<ffi::AVFrame> for AvFrame {
    fn as_mut(&mut self) -> &mut ffi::AVFrame {
        // Safe because the AVFrame has been properly initialized during construction.
        unsafe { &mut *self.0 }
    }
}

impl Deref for AvFrame {
    type Target = ffi::AVFrame;

    fn deref(&self) -> &Self::Target {
        // Safe because the AVFrame has been properly initialized during construction.
        unsafe { self.0.as_ref().unwrap() }
    }
}

impl Drop for AvFrame {
    fn drop(&mut self) {
        // Safe because the AVFrame is valid through the life of this object and fully owned by us.
        unsafe { ffi::av_frame_free(&mut self.0) };
    }
}

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

    #[test]
    fn test_averror() {
        // Just test that the error is wrapper properly. The bindings test module already checks
        // that the error bindings correspond to the right ffmpeg errors.
        let averror = AvError(AVERROR_EOF);
        let msg = format!("{}", averror);
        assert_eq!(msg, "End of file");

        let averror = AvError(0);
        let msg = format!("{}", averror);
        assert_eq!(msg, "Success");

        let averror = AvError(10);
        let msg = format!("{}", averror);
        assert_eq!(msg, "Unknown avcodec error 10");
    }
}
<|endoftext|>