<commit_before>// Copyright 2012-2013 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 driver::session::Session;
use metadata::cstore;
use metadata::filesearch;

use collections::HashSet;
use std::{os, slice};
use syntax::abi;

fn not_win32(os: abi::Os) -> bool {
  os != abi::OsWin32
}

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

    // No rpath on windows
    if os == abi::OsWin32 {
        return Vec::new();
    }

    let mut flags = Vec::new();

    if sess.targ_cfg.os == abi::OsFreebsd {
        flags.push_all([~"-Wl,-rpath,/usr/local/lib/gcc46",
                        ~"-Wl,-rpath,/usr/local/lib/gcc44",
                        ~"-Wl,-z,origin"]);
    }

    debug!("preparing the RPATH!");

    let sysroot = sess.filesearch().sysroot;
    let output = out_filename;
    let libs = sess.cstore.get_used_crates(cstore::RequireDynamic);
    let libs = libs.move_iter().filter_map(|(_, l)| l.map(|p| p.clone())).collect();
    // We don't currently rpath extern libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = slice::append_one(libs, get_sysroot_absolute_rt_lib(sess));

    let rpaths = get_rpaths(os, sysroot, output, libs,
                            sess.opts.target_triple);
    flags.push_all(rpaths_to_flags(rpaths.as_slice()).as_slice());
    flags
}

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

pub fn rpaths_to_flags(rpaths: &[~str]) -> Vec<~str> {
    let mut ret = Vec::new();
    for rpath in rpaths.iter() {
        ret.push("-Wl,-rpath," + *rpath);
    }
    return ret;
}

fn get_rpaths(os: abi::Os,
              sysroot: &Path,
              output: &Path,
              libs: &[Path],
              target_triple: &str) -> Vec<~str> {
    debug!("sysroot: {}", sysroot.display());
    debug!("output: {}", output.display());
    debug!("libs:");
    for libpath in libs.iter() {
        debug!("    {}", libpath.display());
    }
    debug!("target_triple: {}", 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 = vec!(get_install_prefix_rpath(sysroot, target_triple));

    fn log_rpaths(desc: &str, rpaths: &[~str]) {
        debug!("{} rpaths:", desc);
        for rpath in rpaths.iter() {
            debug!("    {}", *rpath);
        }
    }

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

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

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

fn get_rpaths_relative_to_output(os: abi::Os,
                                 output: &Path,
                                 libs: &[Path]) -> Vec<~str> {
    libs.iter().map(|a| get_rpath_relative_to_output(os, output, a)).collect()
}

pub fn get_rpath_relative_to_output(os: abi::Os,
                                    output: &Path,
                                    lib: &Path)
                                 -> ~str {
    use std::os;

    assert!(not_win32(os));

    // Mac doesn't appear to support $ORIGIN
    let prefix = match os {
        abi::OsAndroid | abi::OsLinux | abi::OsFreebsd
                          => "$ORIGIN",
        abi::OsMacos => "@loader_path",
        abi::OsWin32 => unreachable!()
    };

    let mut lib = os::make_absolute(lib);
    lib.pop();
    let mut output = os::make_absolute(output);
    output.pop();
    let relative = lib.path_relative_from(&output);
    let relative = relative.expect("could not create rpath relative to output");
    // FIXME (#9639): This needs to handle non-utf8 paths
    prefix+"/"+relative.as_str().expect("non-utf8 component in path")
}

fn get_absolute_rpaths(libs: &[Path]) -> Vec<~str> {
    libs.iter().map(|a| get_absolute_rpath(a)).collect()
}

pub fn get_absolute_rpath(lib: &Path) -> ~str {
    let mut p = os::make_absolute(lib);
    p.pop();
    // FIXME (#9639): This needs to handle non-utf8 paths
    p.as_str().expect("non-utf8 component in rpath").to_owned()
}

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

    let tlib = filesearch::relative_target_lib_path(sysroot, target_triple);
    let mut path = Path::new(install_prefix);
    path.push(&tlib);
    let path = os::make_absolute(&path);
    // FIXME (#9639): This needs to handle non-utf8 paths
    path.as_str().expect("non-utf8 component in rpath").to_owned()
}

pub fn minimize_rpaths(rpaths: &[~str]) -> Vec<~str> {
    let mut set = HashSet::new();
    let mut minimized = Vec::new();
    for rpath in rpaths.iter() {
        if set.insert(rpath.as_slice()) {
            minimized.push(rpath.clone());
        }
    }
    minimized
}

#[cfg(unix, test)]
mod test {
    use std::os;

    use back::rpath::{get_absolute_rpath, get_install_prefix_rpath};
    use back::rpath::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
    use syntax::abi;
    use metadata::filesearch;

    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags([~"path1", ~"path2"]);
        assert_eq!(flags, vec!(~"-Wl,-rpath,path1", ~"-Wl,-rpath,path2"));
    }

    #[test]
    fn test_prefix_rpath() {
        let sysroot = filesearch::get_or_default_sysroot();
        let res = get_install_prefix_rpath(sysroot, "triple");
        let mut d = Path::new(env!("CFG_PREFIX"));
        d.push("lib");
        d.push(filesearch::rustlibdir());
        d.push("triple/lib");
        debug!("test_prefix_path: {} vs. {}",
               res,
               d.display());
        assert!(res.as_bytes().ends_with(d.as_vec()));
    }

    #[test]
    fn test_prefix_rpath_abs() {
        let sysroot = filesearch::get_or_default_sysroot();
        let res = get_install_prefix_rpath(sysroot, "triple");
        assert!(Path::new(res).is_absolute());
    }

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

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

    #[test]
    #[cfg(target_os = "linux")]
    #[cfg(target_os = "android")]
    fn test_rpath_relative() {
      let o = abi::OsLinux;
      let res = get_rpath_relative_to_output(o,
            &Path::new("bin/rustc"), &Path::new("lib/libstd.so"));
      assert_eq!(res.as_slice(), "$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "freebsd")]
    fn test_rpath_relative() {
        let o = abi::OsFreebsd;
        let res = get_rpath_relative_to_output(o,
            &Path::new("bin/rustc"), &Path::new("lib/libstd.so"));
        assert_eq!(res.as_slice(), "$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn test_rpath_relative() {
        let o = abi::OsMacos;
        let res = get_rpath_relative_to_output(o,
                                               &Path::new("bin/rustc"),
                                               &Path::new("lib/libstd.so"));
        assert_eq!(res.as_slice(), "@loader_path/../lib");
    }

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

        // FIXME (#9639): This needs to handle non-utf8 paths
        assert_eq!(res.as_slice(), lib.as_str().expect("non-utf8 component in path"));
    }
}
<commit_msg>rustc: Fix tests for sysroot changes<commit_after>// Copyright 2012-2013 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 driver::session::Session;
use metadata::cstore;
use metadata::filesearch;

use collections::HashSet;
use std::{os, slice};
use syntax::abi;

fn not_win32(os: abi::Os) -> bool {
  os != abi::OsWin32
}

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

    // No rpath on windows
    if os == abi::OsWin32 {
        return Vec::new();
    }

    let mut flags = Vec::new();

    if sess.targ_cfg.os == abi::OsFreebsd {
        flags.push_all([~"-Wl,-rpath,/usr/local/lib/gcc46",
                        ~"-Wl,-rpath,/usr/local/lib/gcc44",
                        ~"-Wl,-z,origin"]);
    }

    debug!("preparing the RPATH!");

    let sysroot = sess.filesearch().sysroot;
    let output = out_filename;
    let libs = sess.cstore.get_used_crates(cstore::RequireDynamic);
    let libs = libs.move_iter().filter_map(|(_, l)| l.map(|p| p.clone())).collect();
    // We don't currently rpath extern libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = slice::append_one(libs, get_sysroot_absolute_rt_lib(sess));

    let rpaths = get_rpaths(os, sysroot, output, libs,
                            sess.opts.target_triple);
    flags.push_all(rpaths_to_flags(rpaths.as_slice()).as_slice());
    flags
}

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

pub fn rpaths_to_flags(rpaths: &[~str]) -> Vec<~str> {
    let mut ret = Vec::new();
    for rpath in rpaths.iter() {
        ret.push("-Wl,-rpath," + *rpath);
    }
    return ret;
}

fn get_rpaths(os: abi::Os,
              sysroot: &Path,
              output: &Path,
              libs: &[Path],
              target_triple: &str) -> Vec<~str> {
    debug!("sysroot: {}", sysroot.display());
    debug!("output: {}", output.display());
    debug!("libs:");
    for libpath in libs.iter() {
        debug!("    {}", libpath.display());
    }
    debug!("target_triple: {}", 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 = vec!(get_install_prefix_rpath(sysroot, target_triple));

    fn log_rpaths(desc: &str, rpaths: &[~str]) {
        debug!("{} rpaths:", desc);
        for rpath in rpaths.iter() {
            debug!("    {}", *rpath);
        }
    }

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

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

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

fn get_rpaths_relative_to_output(os: abi::Os,
                                 output: &Path,
                                 libs: &[Path]) -> Vec<~str> {
    libs.iter().map(|a| get_rpath_relative_to_output(os, output, a)).collect()
}

pub fn get_rpath_relative_to_output(os: abi::Os,
                                    output: &Path,
                                    lib: &Path)
                                 -> ~str {
    use std::os;

    assert!(not_win32(os));

    // Mac doesn't appear to support $ORIGIN
    let prefix = match os {
        abi::OsAndroid | abi::OsLinux | abi::OsFreebsd
                          => "$ORIGIN",
        abi::OsMacos => "@loader_path",
        abi::OsWin32 => unreachable!()
    };

    let mut lib = os::make_absolute(lib);
    lib.pop();
    let mut output = os::make_absolute(output);
    output.pop();
    let relative = lib.path_relative_from(&output);
    let relative = relative.expect("could not create rpath relative to output");
    // FIXME (#9639): This needs to handle non-utf8 paths
    prefix+"/"+relative.as_str().expect("non-utf8 component in path")
}

fn get_absolute_rpaths(libs: &[Path]) -> Vec<~str> {
    libs.iter().map(|a| get_absolute_rpath(a)).collect()
}

pub fn get_absolute_rpath(lib: &Path) -> ~str {
    let mut p = os::make_absolute(lib);
    p.pop();
    // FIXME (#9639): This needs to handle non-utf8 paths
    p.as_str().expect("non-utf8 component in rpath").to_owned()
}

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

    let tlib = filesearch::relative_target_lib_path(sysroot, target_triple);
    let mut path = Path::new(install_prefix);
    path.push(&tlib);
    let path = os::make_absolute(&path);
    // FIXME (#9639): This needs to handle non-utf8 paths
    path.as_str().expect("non-utf8 component in rpath").to_owned()
}

pub fn minimize_rpaths(rpaths: &[~str]) -> Vec<~str> {
    let mut set = HashSet::new();
    let mut minimized = Vec::new();
    for rpath in rpaths.iter() {
        if set.insert(rpath.as_slice()) {
            minimized.push(rpath.clone());
        }
    }
    minimized
}

#[cfg(unix, test)]
mod test {
    use std::os;

    use back::rpath::{get_absolute_rpath, get_install_prefix_rpath};
    use back::rpath::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
    use syntax::abi;
    use metadata::filesearch;

    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags([~"path1", ~"path2"]);
        assert_eq!(flags, vec!(~"-Wl,-rpath,path1", ~"-Wl,-rpath,path2"));
    }

    #[test]
    fn test_prefix_rpath() {
        let sysroot = filesearch::get_or_default_sysroot();
        let res = get_install_prefix_rpath(&sysroot, "triple");
        let mut d = Path::new(env!("CFG_PREFIX"));
        d.push("lib");
        d.push(filesearch::rustlibdir());
        d.push("triple/lib");
        debug!("test_prefix_path: {} vs. {}",
               res,
               d.display());
        assert!(res.as_bytes().ends_with(d.as_vec()));
    }

    #[test]
    fn test_prefix_rpath_abs() {
        let sysroot = filesearch::get_or_default_sysroot();
        let res = get_install_prefix_rpath(&sysroot, "triple");
        assert!(Path::new(res).is_absolute());
    }

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

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

    #[test]
    #[cfg(target_os = "linux")]
    #[cfg(target_os = "android")]
    fn test_rpath_relative() {
      let o = abi::OsLinux;
      let res = get_rpath_relative_to_output(o,
            &Path::new("bin/rustc"), &Path::new("lib/libstd.so"));
      assert_eq!(res.as_slice(), "$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "freebsd")]
    fn test_rpath_relative() {
        let o = abi::OsFreebsd;
        let res = get_rpath_relative_to_output(o,
            &Path::new("bin/rustc"), &Path::new("lib/libstd.so"));
        assert_eq!(res.as_slice(), "$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn test_rpath_relative() {
        let o = abi::OsMacos;
        let res = get_rpath_relative_to_output(o,
                                               &Path::new("bin/rustc"),
                                               &Path::new("lib/libstd.so"));
        assert_eq!(res.as_slice(), "@loader_path/../lib");
    }

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

        // FIXME (#9639): This needs to handle non-utf8 paths
        assert_eq!(res.as_slice(), lib.as_str().expect("non-utf8 component in path"));
    }
}
<|endoftext|>


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

#[doc(keyword = "as")]
//
/// The type coercion keyword.
///
/// `as` is most commonly used to turn primitive types into other primitive types, but it has other
/// uses that include turning pointers into addresses, addresses into pointers, and pointers into
/// other pointers.
///
/// ```rust
/// let thing1: u8 = 89.0 as u8;
/// assert_eq!('B' as u32, 66);
/// assert_eq!(thing1 as char, 'Y');
/// let thing2: f32 = thing1 as f32 + 10.5;
/// assert_eq!(true as u8 + thing2 as u8, 100);
/// ```
///
/// In general, any coercion that can be performed via writing out type hints can also be done
/// using `as`, so instead of writing `let x: u32 = 123`, you can write `let x = 123 as u32` (Note:
/// `let x = 123u32` would be best in that situation). The same is not true in the other direction,
/// however, explicitly using `as` allows a few more coercions that aren't allowed implicitly, such
/// as changing the type of a raw pointer or turning closures into raw pointers.
///
/// For more information on what `as` is capable of, see the [Reference]
///
/// [Reference]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions
mod as_keyword { }

#[doc(keyword = "const")]
//
/// The keyword for defining constants.
///
/// Sometimes a certain value is used many times throughout a program, and it can become
/// inconvenient to copy it over and over. What's more, it's not always possible or desirable to
/// make it a variable that gets carried around to each function that needs it. In these cases, the
/// `const` keyword provides a convenient alternative to code duplication.
///
/// ```rust
/// const THING: u32 = 0xABAD1DEA;
///
/// let foo = 123 + THING;
/// ```
///
/// Constants must be explicitly typed, unlike with `let` you can't ignore its type and let the
/// compiler figure it out. Any constant value can be defined in a const, which in practice happens
/// to be most things that would be reasonable to have a constant. For example, you can't have a
/// File as a const.
///
/// The only lifetime allowed in a constant is 'static, which is the lifetime that encompasses all
/// others in a Rust program. For example, if you wanted to define a constant string, it would look
/// like this:
///
/// ```rust
/// const WORDS: &'static str = "hello rust!";
/// ```
///
/// Thanks to static lifetime elision, you usually don't have to explicitly use 'static:
///
/// ```rust
/// const WORDS: &str = "hello convenience!";
/// ```
///
/// `const` items looks remarkably similar to [`static`] items, which introduces some confusion as
/// to which one should be used at which times. To put it simply, constants are inlined wherever
/// they're used, making using them identical to simply replacing the name of the const with its
/// value. Static variables on the other hand point to a single location in memory, which all
/// accesses share. This means that, unlike with constants, they can't have destructors, but it
/// also means that (via unsafe code) they can be mutable, which is useful for the rare situations
/// in which you can't avoid using global state.
///
/// Constants, as with statics, should always be in SCREAMING_SNAKE_CASE.
///
/// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const
/// T` and `*mut T`. More about that can be read at the [pointer] primitive part of the Rust docs.
///
/// For more detail on `const`, see the [Rust Book] or the [Reference]
///
/// [`static`]: keyword.static.html
/// [pointer]: primitive.pointer.html
/// [Rust Book]: https://doc.rust-lang.org/stable/book/2018-edition/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
/// [Reference]: https://doc.rust-lang.org/reference/items/constant-items.html
mod const_keyword { }

#[doc(keyword = "fn")]
//
/// The `fn` keyword.
///
/// The `fn` keyword is used to declare a function.
///
/// Example:
///
/// ```rust
/// fn some_function() {
///     // code goes in here
/// }
/// ```
///
/// For more information about functions, take a look at the [Rust Book][book].
///
/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html
mod fn_keyword { }

#[doc(keyword = "let")]
//
/// The `let` keyword.
///
/// The `let` keyword is used to declare a variable.
///
/// Example:
///
/// ```rust
/// # #![allow(unused_assignments)]
/// let x = 3; // We create a variable named `x` with the value `3`.
/// ```
///
/// By default, all variables are **not** mutable. If you want a mutable variable,
/// you'll have to use the `mut` keyword.
///
/// Example:
///
/// ```rust
/// # #![allow(unused_assignments)]
/// let mut x = 3; // We create a mutable variable named `x` with the value `3`.
///
/// x += 4; // `x` is now equal to `7`.
/// ```
///
/// For more information about the `let` keyword, take a look at the [Rust Book][book].
///
/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html
mod let_keyword { }

#[doc(keyword = "struct")]
//
/// The keyword used to define structs.
///
/// Structs in Rust come in three flavours: Regular structs, tuple structs,
/// and empty structs.
///
/// ```rust
/// struct Regular {
///     field1: f32,
///     field2: String,
///     pub field3: bool
/// }
///
/// struct Tuple(u32, String);
///
/// struct Empty;
/// ```
///
/// Regular structs are the most commonly used. Each field defined within them has a name and a
/// type, and once defined can be accessed using `example_struct.field` syntax. The fields of a
/// struct share its mutability, so `foo.bar = 2;` would only be valid if `foo` was mutable. Adding
/// `pub` to a field makes it visible to code in other modules, as well as allowing it to be
/// directly accessed and modified.
///
/// Tuple structs are similar to regular structs, but its fields have no names. They are used like
/// tuples, with deconstruction possible via `let TupleStruct(x, y) = foo;` syntax.  For accessing
/// individual variables, the same syntax is used as with regular tuples, namely `foo.0`, `foo.1`,
/// etc, starting at zero.
///
/// Empty structs, or unit-like structs, are most commonly used as markers, for example
/// [`PhantomData`]. Empty structs have a size of zero bytes, but unlike empty enums they can be
/// instantiated, making them similar to the unit type `()`. Unit-like structs are useful when you
/// need to implement a trait on something, but don't need to store any data inside it.
///
/// # Instantiation
///
/// Structs can be instantiated in a manner of different ways, each of which can be mixed and
/// matched as needed. The most common way to make a new struct is via a constructor method such as
/// `new()`, but when that isn't available (or you're writing the constructor itself), struct
/// literal syntax is used:
///
/// ```rust
/// # struct Foo { field1: f32, field2: String, etc: bool }
/// let example = Foo {
///     field1: 42.0,
///     field2: "blah".to_string(),
///     etc: true,
/// };
/// ```
///
/// It's only possible to directly instantiate a struct using struct literal syntax when all of its
/// fields are visible to you.
///
/// There are a handful of shortcuts provided to make writing constructors more convenient, most
/// common of which is the Field Init shorthand. When there is a variable and a field of the same
/// name, the assignment can be simplified from `field: field` into simply `field`. The following
/// example of a hypothetical constructor demonstrates this:
///
/// ```rust
/// struct User {
///     name: String,
///     admin: bool,
/// }
///
/// impl User {
///     pub fn new(name: String) -> Self {
///         Self {
///             name,
///             admin: false,
///         }
///     }
/// }
/// ```
///
/// Another shortcut for struct instantiation is available when you need to make a new struct that
/// shares most of a previous struct's values called struct update syntax:
///
/// ```rust
/// # struct Foo { field1: String, field2: () }
/// # let thing = Foo { field1: "".to_string(), field2: () };
/// let updated_thing = Foo {
///     field1: "a new value".to_string(),
///     ..thing
/// };
/// ```
///
/// Tuple structs are instantiated in the same way as tuples themselves, except with the struct's
/// name as a prefix: `Foo(123, false, 0.1)`.
///
/// Empty structs are instantiated with just their name and nothing else. `let thing =
/// EmptyStruct;`
///
///
/// # Style conventions
///
/// Structs are always written in CamelCase, with few exceptions. While the trailing comma on a
/// struct's list of fields can be omitted, it's usually kept for convenience in adding and
/// removing fields down the line.
///
/// For more information on structs, take a look at the [Rust Book][book] or the
/// [Reference][reference].
///
/// [`PhantomData`]: marker/struct.PhantomData.html
/// [book]: https://doc.rust-lang.org/book/second-edition/ch05-01-defining-structs.html
/// [reference]: https://doc.rust-lang.org/reference/items/structs.html

mod struct_keyword { }
<commit_msg>Fix a few small things, re-word others<commit_after>// Copyright 2018 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.

#[doc(keyword = "as")]
//
/// The type coercion keyword.
///
/// `as` is most commonly used to turn primitive types into other primitive types, but it has other
/// uses that include turning pointers into addresses, addresses into pointers, and pointers into
/// other pointers.
///
/// ```rust
/// let thing1: u8 = 89.0 as u8;
/// assert_eq!('B' as u32, 66);
/// assert_eq!(thing1 as char, 'Y');
/// let thing2: f32 = thing1 as f32 + 10.5;
/// assert_eq!(true as u8 + thing2 as u8, 100);
/// ```
///
/// In general, any coercion that can be performed via writing out type hints can also be done
/// using `as`, so instead of writing `let x: u32 = 123`, you can write `let x = 123 as u32` (Note:
/// `let x = 123u32` would be best in that situation). The same is not true in the other direction,
/// however, explicitly using `as` allows a few more coercions that aren't allowed implicitly, such
/// as changing the type of a raw pointer or turning closures into raw pointers.
///
/// For more information on what `as` is capable of, see the [Reference]
///
/// [Reference]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions
mod as_keyword { }

#[doc(keyword = "const")]
//
/// The keyword for defining constants.
///
/// Sometimes a certain value is used many times throughout a program, and it can become
/// inconvenient to copy it over and over. What's more, it's not always possible or desirable to
/// make it a variable that gets carried around to each function that needs it. In these cases, the
/// `const` keyword provides a convenient alternative to code duplication.
///
/// ```rust
/// const THING: u32 = 0xABAD1DEA;
///
/// let foo = 123 + THING;
/// ```
///
/// Constants must be explicitly typed, unlike with `let` you can't ignore its type and let the
/// compiler figure it out. Any constant value can be defined in a const, which in practice happens
/// to be most things that would be reasonable to have a constant. For example, you can't have a
/// File as a `const`.
///
/// The only lifetime allowed in a constant is 'static, which is the lifetime that encompasses all
/// others in a Rust program. For example, if you wanted to define a constant string, it would look
/// like this:
///
/// ```rust
/// const WORDS: &'static str = "hello rust!";
/// ```
///
/// Thanks to static lifetime elision, you usually don't have to explicitly use 'static:
///
/// ```rust
/// const WORDS: &str = "hello convenience!";
/// ```
///
/// `const` items looks remarkably similar to [`static`] items, which introduces some confusion as
/// to which one should be used at which times. To put it simply, constants are inlined wherever
/// they're used, making using them identical to simply replacing the name of the const with its
/// value. Static variables on the other hand point to a single location in memory, which all
/// accesses share. This means that, unlike with constants, they can't have destructors, but it
/// also means that (via unsafe code) they can be mutable, which is useful for the rare situations
/// in which you can't avoid using global state.
///
/// Constants, as with statics, should always be in SCREAMING_SNAKE_CASE.
///
/// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const
/// T` and `*mut T`. More about that can be read at the [pointer] primitive part of the Rust docs.
///
/// For more detail on `const`, see the [Rust Book] or the [Reference]
///
/// [`static`]: keyword.static.html
/// [pointer]: primitive.pointer.html
/// [Rust Book]: https://doc.rust-lang.org/stable/book/2018-edition/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
/// [Reference]: https://doc.rust-lang.org/reference/items/constant-items.html
mod const_keyword { }

#[doc(keyword = "fn")]
//
/// The `fn` keyword.
///
/// The `fn` keyword is used to declare a function.
///
/// Example:
///
/// ```rust
/// fn some_function() {
///     // code goes in here
/// }
/// ```
///
/// For more information about functions, take a look at the [Rust Book][book].
///
/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html
mod fn_keyword { }

#[doc(keyword = "let")]
//
/// The `let` keyword.
///
/// The `let` keyword is used to declare a variable.
///
/// Example:
///
/// ```rust
/// # #![allow(unused_assignments)]
/// let x = 3; // We create a variable named `x` with the value `3`.
/// ```
///
/// By default, all variables are **not** mutable. If you want a mutable variable,
/// you'll have to use the `mut` keyword.
///
/// Example:
///
/// ```rust
/// # #![allow(unused_assignments)]
/// let mut x = 3; // We create a mutable variable named `x` with the value `3`.
///
/// x += 4; // `x` is now equal to `7`.
/// ```
///
/// For more information about the `let` keyword, take a look at the [Rust Book][book].
///
/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html
mod let_keyword { }

#[doc(keyword = "struct")]
//
/// The keyword used to define structs.
///
/// Structs in Rust come in three flavours: Regular structs, tuple structs,
/// and empty structs.
///
/// ```rust
/// struct Regular {
///     field1: f32,
///     field2: String,
///     pub field3: bool
/// }
///
/// struct Tuple(u32, String);
///
/// struct Empty;
/// ```
///
/// Regular structs are the most commonly used. Each field defined within them has a name and a
/// type, and once defined can be accessed using `example_struct.field` syntax. The fields of a
/// struct share its mutability, so `foo.bar = 2;` would only be valid if `foo` was mutable. Adding
/// `pub` to a field makes it visible to code in other modules, as well as allowing it to be
/// directly accessed and modified.
///
/// Tuple structs are similar to regular structs, but its fields have no names. They are used like
/// tuples, with deconstruction possible via `let TupleStruct(x, y) = foo;` syntax.  For accessing
/// individual variables, the same syntax is used as with regular tuples, namely `foo.0`, `foo.1`,
/// etc, starting at zero.
///
/// Empty structs, or unit-like structs, are most commonly used as markers, for example
/// [`PhantomData`]. Empty structs have a size of zero bytes, but unlike empty enums they can be
/// instantiated, making them similar to the unit type `()`. Unit-like structs are useful when you
/// need to implement a trait on something, but don't need to store any data inside it.
///
/// # Instantiation
///
/// Structs can be instantiated in a manner of different ways, each of which can be mixed and
/// matched as needed. The most common way to make a new struct is via a constructor method such as
/// `new()`, but when that isn't available (or you're writing the constructor itself), struct
/// literal syntax is used:
///
/// ```rust
/// # struct Foo { field1: f32, field2: String, etc: bool }
/// let example = Foo {
///     field1: 42.0,
///     field2: "blah".to_string(),
///     etc: true,
/// };
/// ```
///
/// It's only possible to directly instantiate a struct using struct literal syntax when all of its
/// fields are visible to you.
///
/// There are a handful of shortcuts provided to make writing constructors more convenient, most
/// common of which is the Field Init shorthand. When there is a variable and a field of the same
/// name, the assignment can be simplified from `field: field` into simply `field`. The following
/// example of a hypothetical constructor demonstrates this:
///
/// ```rust
/// struct User {
///     name: String,
///     admin: bool,
/// }
///
/// impl User {
///     pub fn new(name: String) -> Self {
///         Self {
///             name,
///             admin: false,
///         }
///     }
/// }
/// ```
///
/// Another shortcut for struct instantiation is available, used when you need to make a new
/// struct that has the same values as most of a previous struct of the same type, called struct
/// update syntax:
///
/// ```rust
/// # struct Foo { field1: String, field2: () }
/// # let thing = Foo { field1: "".to_string(), field2: () };
/// let updated_thing = Foo {
///     field1: "a new value".to_string(),
///     ..thing
/// };
/// ```
///
/// Tuple structs are instantiated in the same way as tuples themselves, except with the struct's
/// name as a prefix: `Foo(123, false, 0.1)`.
///
/// Empty structs are instantiated with just their name, and don't need anything else. `let thing =
/// EmptyStruct;`
///
/// # Style conventions
///
/// Structs are always written in CamelCase, with few exceptions. While the trailing comma on a
/// struct's list of fields can be omitted, it's usually kept for convenience in adding and
/// removing fields down the line.
///
/// For more information on structs, take a look at the [Rust Book][book] or the
/// [Reference][reference].
///
/// [`PhantomData`]: marker/struct.PhantomData.html
/// [book]: https://doc.rust-lang.org/book/second-edition/ch05-01-defining-structs.html
/// [reference]: https://doc.rust-lang.org/reference/items/structs.html
mod struct_keyword { }
<|endoftext|>


<commit_before>mod command;

use std::io::{stdin, stdout};
use std::io::prelude::*;
use std::borrow::Cow;

use cpu::cpu::Cpu;
use cpu::cpu::GFX_HEIGHT;
use cpu::cpu::GFX_WIDTH;
use self::command::Command;

pub struct Debugger {
    cpu: Cpu,
    last_commad: Option<Command>,
}

impl Debugger {
    pub fn new(cpu: Cpu) -> Debugger {
        Debugger {
            cpu: cpu,
            last_commad: None,
        }
    }

    pub fn run(&mut self) {
        loop {
            print!("chip8> ");
            stdout().flush().unwrap();

            let command = match (read_stdin().parse(), self.last_commad) {
                (Ok(Command::Repeat), Some(c)) => Ok(c),
                (Ok(Command::Repeat), None) => Err("No last command".into()),
                (Ok(c), _) => Ok(c),
                (Err(e), _) => Err(e),
            };

            match command {
                Ok(Command::Step(count)) => self.step(count),
                Ok(Command::Exit) => break,
                Ok(Command::Repeat) => unreachable!(),
                Err(ref e) => println!("{}", e),
            }

            self.last_commad = command.ok();
        }
    }

    pub fn step(&mut self, count: usize) {
        for _ in 0..count {
            let curr_pc = self.cpu.curr_pc();
            let curr_index = self.cpu.curr_index();
            let curr_opcode = self.cpu.curr_opcode();
            let curr_regs = self.cpu.curr_regs();
            let curr_stack = self.cpu.curr_stack();
            let curr_sp = self.cpu.curr_sp();
            let curr_gfx = self.cpu.curr_gfx();

            print!("pc:{:04X},", curr_pc);
            print!("index:{:04X},", curr_index);
            println!("opcode:{:04X}", curr_opcode);
            println!("=============================================");

            println!("stack:");
            print_stack(curr_stack, curr_sp);
            println!("=============================================");
            println!("registers:");
            print_regs(curr_regs);
            println!("=============================================");
            println!("screen:");
            print_gfx(curr_gfx);
            println!("=============================================");

            self.cpu.emulate_cycle();
        }
    }
}

fn print_gfx(gfx: Vec<u8>) {
    for i in 0..GFX_HEIGHT {
        for j in 0..GFX_WIDTH {
            print!("{}", gfx[(i * GFX_WIDTH + j) as usize]);
        }
        println!();
    }
}

fn print_regs(regs: Vec<u8>) {
    println!("| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9| A| B| C| D| E| F|");
    for i in 0..regs.len() {
        print!("|{:02X}", regs[i as usize]);
    }
    println!("|");
}

fn print_stack(stack: Vec<usize>, sp: usize) {
    for i in 0..stack.len() {
        print!("|");
        if i == sp {
            print!("[");
        }
        print!("{:04X}", stack[i as usize]);
        if i == sp {
            print!("]");
        }
    }
    println!("|");
}

fn read_stdin() -> String {
    let mut input = String::new();
    stdin().read_line(&mut input).unwrap();
    input.trim().into()
}
<commit_msg>Add count to debugger<commit_after>mod command;

use std::io::{stdin, stdout};
use std::io::prelude::*;
use std::borrow::Cow;

use cpu::cpu::Cpu;
use cpu::cpu::GFX_HEIGHT;
use cpu::cpu::GFX_WIDTH;
use self::command::Command;

pub struct Debugger {
    cpu: Cpu,
    last_commad: Option<Command>,
}

impl Debugger {
    pub fn new(cpu: Cpu) -> Debugger {
        Debugger {
            cpu: cpu,
            last_commad: None,
        }
    }

    pub fn run(&mut self) {
        let mut cnt = 1;
        loop {
            print!("chip8:{}> ", cnt);
            stdout().flush().unwrap();

            let command = match (read_stdin().parse(), self.last_commad) {
                (Ok(Command::Repeat), Some(c)) => Ok(c),
                (Ok(Command::Repeat), None) => Err("No last command".into()),
                (Ok(c), _) => Ok(c),
                (Err(e), _) => Err(e),
            };

            match command {
                Ok(Command::Step(count)) => self.step(count),
                Ok(Command::Exit) => break,
                Ok(Command::Repeat) => unreachable!(),
                Err(ref e) => println!("{}", e),
            }

            self.last_commad = command.ok();
            cnt += 1;
        }
    }

    pub fn step(&mut self, count: usize) {
        for _ in 0..count {
            let curr_pc = self.cpu.curr_pc();
            let curr_index = self.cpu.curr_index();
            let curr_opcode = self.cpu.curr_opcode();
            let curr_regs = self.cpu.curr_regs();
            let curr_stack = self.cpu.curr_stack();
            let curr_sp = self.cpu.curr_sp();
            let curr_gfx = self.cpu.curr_gfx();

            print!("pc:{:04X},", curr_pc);
            print!("index:{:04X},", curr_index);
            println!("opcode:{:04X}", curr_opcode);
            println!("=============================================");

            println!("stack:");
            print_stack(curr_stack, curr_sp);
            println!("=============================================");
            println!("registers:");
            print_regs(curr_regs);
            println!("=============================================");
            println!("screen:");
            print_gfx(curr_gfx);
            println!("=============================================");

            self.cpu.emulate_cycle();
        }
    }
}

fn print_gfx(gfx: Vec<u8>) {
    for i in 0..GFX_HEIGHT {
        for j in 0..GFX_WIDTH {
            print!("{}", gfx[(i * GFX_WIDTH + j) as usize]);
        }
        println!();
    }
}

fn print_regs(regs: Vec<u8>) {
    println!("| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9| A| B| C| D| E| F|");
    for i in 0..regs.len() {
        print!("|{:02X}", regs[i as usize]);
    }
    println!("|");
}

fn print_stack(stack: Vec<usize>, sp: usize) {
    for i in 0..stack.len() {
        print!("|");
        if i == sp {
            print!("[");
        }
        print!("{:04X}", stack[i as usize]);
        if i == sp {
            print!("]");
        }
    }
    println!("|");
}

fn read_stdin() -> String {
    let mut input = String::new();
    stdin().read_line(&mut input).unwrap();
    input.trim().into()
}
<|endoftext|>


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

use url::Url;
use hyper::method::Method;
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use hyper::header::{Headers, ContentType, IfModifiedSince, IfNoneMatch, Accept};
use hyper::header::{IfUnmodifiedSince, IfMatch, IfRange, Location, HeaderView};
use hyper::header::{AcceptLanguage, ContentLanguage};
use hyper::status::StatusCode;
use fetch::cors_cache::{CORSCache, CacheRequestDetails};
use fetch::response::{Response, ResponseType};
use std::ascii::AsciiExt;

/// A [request context](https://fetch.spec.whatwg.org/#concept-request-context)
#[derive(Copy, Clone, PartialEq)]
pub enum Context {
    Audio, Beacon, CSPreport, Download, Embed, Eventsource,
    Favicon, Fetch, Font, Form, Frame, Hyperlink, IFrame, Image,
    ImageSet, Import, Internal, Location, Manifest, Object, Ping,
    Plugin, Prefetch, Script, ServiceWorker, SharedWorker, Subresource,
    Style, Track, Video, Worker, XMLHttpRequest, XSLT
}

/// A [request context frame type](https://fetch.spec.whatwg.org/#concept-request-context-frame-type)
#[derive(Copy, Clone, PartialEq)]
pub enum ContextFrameType {
    Auxiliary,
    TopLevel,
    Nested,
    ContextNone
}

/// A [referer](https://fetch.spec.whatwg.org/#concept-request-referrer)
pub enum Referer {
    RefererNone,
    Client,
    RefererUrl(Url)
}

/// A [request mode](https://fetch.spec.whatwg.org/#concept-request-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum RequestMode {
    SameOrigin,
    NoCORS,
    CORSMode,
    ForcedPreflightMode
}

/// Request [credentials mode](https://fetch.spec.whatwg.org/#concept-request-credentials-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum CredentialsMode {
    Omit,
    CredentialsSameOrigin,
    Include
}

/// [Cache mode](https://fetch.spec.whatwg.org/#concept-request-cache-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum CacheMode {
    Default,
    NoStore,
    Reload,
    NoCache,
    ForceCache,
    OnlyIfCached
}

/// [Redirect mode](https://fetch.spec.whatwg.org/#concept-request-redirect-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum RedirectMode {
    Follow,
    Error,
    Manual
}

/// [Response tainting](https://fetch.spec.whatwg.org/#concept-request-response-tainting)
#[derive(Copy, Clone, PartialEq)]
pub enum ResponseTainting {
    Basic,
    CORSTainting,
    Opaque
}

/// A [Request](https://fetch.spec.whatwg.org/#requests) as defined by the Fetch spec
pub struct Request {
    pub method: Method,
    pub url: Url,
    pub headers: Headers,
    pub unsafe_request: bool,
    pub body: Option<Vec<u8>>,
    pub preserve_content_codings: bool,
    // pub client: GlobalRef, // XXXManishearth copy over only the relevant fields of the global scope,
                              // not the entire scope to avoid the libscript dependency
    pub is_service_worker_global_scope: bool,
    pub skip_service_worker: bool,
    pub context: Context,
    pub context_frame_type: ContextFrameType,
    pub origin: Option<Url>,
    pub force_origin_header: bool,
    pub same_origin_data: bool,
    pub referer: Referer,
    pub authentication: bool,
    pub sync: bool,
    pub mode: RequestMode,
    pub credentials_mode: CredentialsMode,
    pub use_url_credentials: bool,
    pub cache_mode: CacheMode,
    pub redirect_mode: RedirectMode,
    pub redirect_count: usize,
    pub response_tainting: ResponseTainting,
    pub cache: Option<Box<CORSCache+'static>>
}

impl Request {
    pub fn new(url: Url, context: Context, isServiceWorkerGlobalScope: bool) -> Request {
         Request {
            method: Method::Get,
            url: url,
            headers: Headers::new(),
            unsafe_request: false,
            body: None,
            preserve_content_codings: false,
            is_service_worker_global_scope: isServiceWorkerGlobalScope,
            skip_service_worker: false,
            context: context,
            context_frame_type: ContextFrameType::ContextNone,
            origin: None,
            force_origin_header: false,
            same_origin_data: false,
            referer: Referer::Client,
            authentication: false,
            sync: false,
            mode: RequestMode::NoCORS,
            credentials_mode: CredentialsMode::Omit,
            use_url_credentials: false,
            cache_mode: CacheMode::Default,
            redirect_mode: RedirectMode::Follow,
            redirect_count: 0,
            response_tainting: ResponseTainting::Basic,
            cache: None
        }
    }

    // [Fetch](https://fetch.spec.whatwg.org#concept-fetch)
    pub fn fetch(&mut self, _cors_flag: bool) -> Response {
        // TODO: Implement fetch spec
        Response::network_error()
    }

    /// [Basic fetch](https://fetch.spec.whatwg.org#basic-fetch)
    pub fn basic_fetch(&mut self) -> Response {
        match &*self.url.scheme {
            "about" => match self.url.non_relative_scheme_data() {
                Some(s) if &*s == "blank" => {
                    let mut response = Response::new();
                    response.headers.set(ContentType(Mime(
                        TopLevel::Text, SubLevel::Html,
                        vec![(Attr::Charset, Value::Utf8)])));
                    response
                },
                _ => Response::network_error()
            },
            "http" | "https" => {
                self.http_fetch(false, false, false)
            },
            "blob" | "data" | "file" | "ftp" => {
                // XXXManishearth handle these
                panic!("Unimplemented scheme for Fetch")
            },

            _ => Response::network_error()
        }
    }

    // [HTTP fetch](https://fetch.spec.whatwg.org#http-fetch)
    pub fn http_fetch(&mut self, cors_flag: bool, cors_preflight_flag: bool, authentication_fetch_flag: bool) -> Response {
        // Step 1
        let mut response: Option<Response> = None;
        // Step 2
        if !self.skip_service_worker && !self.is_service_worker_global_scope {
            // TODO: Substep 1 (handle fetch unimplemented)
            // Substep 2
            if let Some(ref res) = response {
                if (res.response_type == ResponseType::Opaque && self.mode != RequestMode::NoCORS) ||
                   res.response_type == ResponseType::Error {
                    return Response::network_error();
                }
            }
        }
        // Step 3
        if response.is_none() {
            // Substep 1
            if cors_preflight_flag {
                let mut method_mismatch = false;
                let mut header_mismatch = false;
                if let Some(ref mut cache) = self.cache {
                    let origin = self.origin.clone().unwrap_or(Url::parse("").unwrap());
                    let url = self.url.clone();
                    let credentials = self.credentials_mode == CredentialsMode::Include;
                    let method_cache_match = cache.match_method(CacheRequestDetails {
                        origin: origin.clone(),
                        destination: url.clone(),
                        credentials: credentials
                    }, self.method.clone());
                    method_mismatch = !method_cache_match && (!is_simple_method(&self.method) ||
                        self.mode == RequestMode::ForcedPreflightMode);
                    header_mismatch = self.headers.iter().any(|view|
                        !cache.match_header(CacheRequestDetails {
                            origin: origin.clone(),
                            destination: url.clone(),
                            credentials: credentials
                        }, view.name()) && !is_simple_header(&view)
                        );
                }
                if method_mismatch || header_mismatch {
                    let preflight_result = self.preflight_fetch();
                    if preflight_result.response_type == ResponseType::Error {
                        return Response::network_error();
                    }
                    response = Some(preflight_result);
                }
            }
            // Substep 2
            self.skip_service_worker = true;
            // Substep 3
            let credentials = match self.credentials_mode {
                CredentialsMode::Include => true,
                CredentialsMode::CredentialsSameOrigin if !cors_flag => true,
                _ => false
            };
            // Substep 4
            if self.cache_mode == CacheMode::Default && is_no_store_cache(&self.headers) {
                self.cache_mode = CacheMode::NoStore;
            }
            // Substep 5
            let fetch_result = self.http_network_or_cache_fetch(credentials, authentication_fetch_flag);
            // Substep 6
            if cors_flag && self.cors_check(&fetch_result).is_err() {
                return Response::network_error();
            }
            response = Some(fetch_result);
        }
        // Step 4
        let mut response = response.unwrap();
        match response.status.unwrap() {
            // Code 304
            StatusCode::NotModified => match self.cache_mode {
                CacheMode::Default | CacheMode::NoCache => {
                    // TODO: Check HTTP cache for request and response entry
                }
                _ => { }
            },
            // Code 301, 302, 303, 307, 308
            StatusCode::MovedPermanently | StatusCode::Found | StatusCode::SeeOther |
            StatusCode::TemporaryRedirect | StatusCode::PermanentRedirect => {
                // Step 1
                if self.redirect_mode == RedirectMode::Error {
                    return Response::network_error();
                }
                // Step 2-4
                if !response.headers.has::<Location>() {
                    return response;
                }
                let location = response.headers.get::<Location>();
                if location.is_none() {
                    return Response::network_error();
                }
                // Step 5
                let locationUrl = Url::parse(location.unwrap());
                // Step 6
                let locationUrl = match locationUrl {
                    Ok(url) => url,
                    Err(_) => return Response::network_error()
                };
                // Step 7
                if self.redirect_count == 20 {
                    return Response::network_error();
                }
                // Step 8
                self.redirect_count += 1;
                // Step 9
                self.same_origin_data = false;
                // Step 10
                if self.redirect_mode == RedirectMode::Follow {
                    // FIXME: Origin method of the Url crate hasn't been implemented (https://github.com/servo/rust-url/issues/54)
                    // Substep 1
                    // if cors_flag && locationUrl.origin() != self.url.origin() { self.origin = None; }
                    // Substep 2
                    if cors_flag && (!locationUrl.username().unwrap_or("").is_empty() ||
                                      locationUrl.password().is_some()) {
                        return Response::network_error();
                    }
                    // Substep 3
                    if response.status.unwrap() == StatusCode::MovedPermanently ||
                       response.status.unwrap() == StatusCode::SeeOther ||
                       (response.status.unwrap() == StatusCode::Found && self.method == Method::Post) {
                        self.method = Method::Get;
                    }
                    // Substep 4
                    self.url = locationUrl;
                    // Substep 5
                    return self.fetch(cors_flag);
                }
            }
            // Code 401
            StatusCode::Unauthorized => {
                // Step 1
                if !self.authentication || cors_flag {
                    return response;
                }
                // Step 2
                // TODO: Spec says requires testing
                // Step 3
                if !self.use_url_credentials || authentication_fetch_flag {
                    // TODO: Prompt the user for username and password
                }
                return self.http_fetch(cors_flag, cors_preflight_flag, true);
            }
            // Code 407
            StatusCode::ProxyAuthenticationRequired => {
                // Step 1
                // TODO: Spec says requires testing
                // Step 2
                // TODO: Prompt the user for proxy authentication credentials
                // Step 3
                return self.http_fetch(cors_flag, cors_preflight_flag, authentication_fetch_flag);
            }
            _ => { }
        }
        // Step 5
        if authentication_fetch_flag {
            // TODO: Create authentication entry for this request
        }
        // Step 6
        response
    }

    // [HTTP network or cache fetch](https://fetch.spec.whatwg.org#http-network-or-cache-fetch)
    pub fn http_network_or_cache_fetch(&mut self, _credentials_flag: bool, _authentication_fetch_flag: bool) -> Response {
        // TODO: Implement HTTP network or cache fetch spec
        Response::network_error()
    }

    // [CORS preflight fetch](https://fetch.spec.whatwg.org#cors-preflight-fetch)
    pub fn preflight_fetch(&mut self) -> Response {
        // TODO: Implement preflight fetch spec
        Response::network_error()
    }

    // [CORS check](https://fetch.spec.whatwg.org#concept-cors-check)
    pub fn cors_check(&mut self, response: &Response) -> Result<(), ()> {
        // TODO: Implement CORS check spec
        Err(())
    }
}

fn is_no_store_cache(headers: &Headers) -> bool {
    headers.has::<IfModifiedSince>() | headers.has::<IfNoneMatch>() |
    headers.has::<IfUnmodifiedSince>() | headers.has::<IfMatch>() |
    headers.has::<IfRange>()
}

fn is_simple_header(h: &HeaderView) -> bool {
    if h.is::<ContentType>() {
        match h.value() {
            Some(&ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) |
            Some(&ContentType(Mime(TopLevel::Application, SubLevel::WwwFormUrlEncoded, _))) |
            Some(&ContentType(Mime(TopLevel::Multipart, SubLevel::FormData, _))) => true,
            _ => false

        }
    } else {
        h.is::<Accept>() || h.is::<AcceptLanguage>() || h.is::<ContentLanguage>()
    }
}

fn is_simple_method(m: &Method) -> bool {
    match *m {
        Method::Get | Method::Head | Method::Post => true,
        _ => false
    }
}
<commit_msg>Implement fetch (partial #4576)<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use url::Url;
use hyper::method::Method;
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use hyper::header::{Header, Headers, ContentType, IfModifiedSince, IfNoneMatch};
use hyper::header::{Accept, IfUnmodifiedSince, IfMatch, IfRange, Location};
use hyper::header::{HeaderView, AcceptLanguage, ContentLanguage, Language};
use hyper::header::{QualityItem, qitem, q};
use hyper::status::StatusCode;
use fetch::cors_cache::{CORSCache, CacheRequestDetails};
use fetch::response::{Response, ResponseType};
use std::ascii::AsciiExt;
use std::str::FromStr;

/// A [request context](https://fetch.spec.whatwg.org/#concept-request-context)
#[derive(Copy, Clone, PartialEq)]
pub enum Context {
    Audio, Beacon, CSPreport, Download, Embed, Eventsource,
    Favicon, Fetch, Font, Form, Frame, Hyperlink, IFrame, Image,
    ImageSet, Import, Internal, Location, Manifest, MetaRefresh, Object,
    Ping, Plugin, Prefetch, PreRender, Script, ServiceWorker, SharedWorker,
    Subresource, Style, Track, Video, Worker, XMLHttpRequest, XSLT
}

/// A [request context frame type](https://fetch.spec.whatwg.org/#concept-request-context-frame-type)
#[derive(Copy, Clone, PartialEq)]
pub enum ContextFrameType {
    Auxiliary,
    TopLevel,
    Nested,
    ContextNone
}

/// A [referer](https://fetch.spec.whatwg.org/#concept-request-referrer)
pub enum Referer {
    RefererNone,
    Client,
    RefererUrl(Url)
}

/// A [request mode](https://fetch.spec.whatwg.org/#concept-request-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum RequestMode {
    SameOrigin,
    NoCORS,
    CORSMode,
    ForcedPreflightMode
}

/// Request [credentials mode](https://fetch.spec.whatwg.org/#concept-request-credentials-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum CredentialsMode {
    Omit,
    CredentialsSameOrigin,
    Include
}

/// [Cache mode](https://fetch.spec.whatwg.org/#concept-request-cache-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum CacheMode {
    Default,
    NoStore,
    Reload,
    NoCache,
    ForceCache,
    OnlyIfCached
}

/// [Redirect mode](https://fetch.spec.whatwg.org/#concept-request-redirect-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum RedirectMode {
    Follow,
    Error,
    Manual
}

/// [Response tainting](https://fetch.spec.whatwg.org/#concept-request-response-tainting)
#[derive(Copy, Clone, PartialEq)]
pub enum ResponseTainting {
    Basic,
    CORSTainting,
    Opaque
}

/// A [Request](https://fetch.spec.whatwg.org/#requests) as defined by the Fetch spec
pub struct Request {
    pub method: Method,
    pub url: Url,
    pub headers: Headers,
    pub unsafe_request: bool,
    pub body: Option<Vec<u8>>,
    pub preserve_content_codings: bool,
    // pub client: GlobalRef, // XXXManishearth copy over only the relevant fields of the global scope,
                              // not the entire scope to avoid the libscript dependency
    pub is_service_worker_global_scope: bool,
    pub skip_service_worker: bool,
    pub context: Context,
    pub context_frame_type: ContextFrameType,
    pub origin: Option<Url>,
    pub force_origin_header: bool,
    pub same_origin_data: bool,
    pub referer: Referer,
    pub authentication: bool,
    pub sync: bool,
    pub mode: RequestMode,
    pub credentials_mode: CredentialsMode,
    pub use_url_credentials: bool,
    pub cache_mode: CacheMode,
    pub redirect_mode: RedirectMode,
    pub redirect_count: usize,
    pub response_tainting: ResponseTainting,
    pub cache: Option<Box<CORSCache+'static>>
}

impl Request {
    pub fn new(url: Url, context: Context, isServiceWorkerGlobalScope: bool) -> Request {
         Request {
            method: Method::Get,
            url: url,
            headers: Headers::new(),
            unsafe_request: false,
            body: None,
            preserve_content_codings: false,
            is_service_worker_global_scope: isServiceWorkerGlobalScope,
            skip_service_worker: false,
            context: context,
            context_frame_type: ContextFrameType::ContextNone,
            origin: None,
            force_origin_header: false,
            same_origin_data: false,
            referer: Referer::Client,
            authentication: false,
            sync: false,
            mode: RequestMode::NoCORS,
            credentials_mode: CredentialsMode::Omit,
            use_url_credentials: false,
            cache_mode: CacheMode::Default,
            redirect_mode: RedirectMode::Follow,
            redirect_count: 0,
            response_tainting: ResponseTainting::Basic,
            cache: None
        }
    }

    /// [Fetch](https://fetch.spec.whatwg.org#concept-fetch)
    pub fn fetch(&mut self, cors_flag: bool) -> Response {
        // Step 1
        if self.context != Context::Fetch && !self.headers.has::<Accept>() {
            // Substep 1
            let value = match self.context {
                Context::Favicon | Context::Image | Context::ImageSet
                    => vec![qitem(Mime(TopLevel::Image, SubLevel::Png, vec![])),
                        // FIXME: This should properly generate a MimeType that has a
                        // SubLevel of svg+xml (https://github.com/hyperium/mime.rs/issues/22)
                        qitem(Mime(TopLevel::Image, SubLevel::Ext("svg+xml".to_string()), vec![])),
                        QualityItem::new(Mime(TopLevel::Image, SubLevel::Star, vec![]), q(0.8)),
                        QualityItem::new(Mime(TopLevel::Star, SubLevel::Star, vec![]), q(0.5))],
                Context::Form | Context::Frame | Context::Hyperlink |
                Context::IFrame | Context::Location | Context::MetaRefresh |
                Context::PreRender
                    => vec![qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
                        // FIXME: This should properly generate a MimeType that has a
                        // SubLevel of xhtml+xml (https://github.com/hyperium/mime.rs/issues/22)
                        qitem(Mime(TopLevel::Application, SubLevel::Ext("xhtml+xml".to_string()), vec![])),
                        QualityItem::new(Mime(TopLevel::Application, SubLevel::Xml, vec![]), q(0.9)),
                        QualityItem::new(Mime(TopLevel::Star, SubLevel::Star, vec![]), q(0.8))],
                Context::Internal if self.context_frame_type != ContextFrameType::ContextNone
                    => vec![qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
                        // FIXME: This should properly generate a MimeType that has a
                        // SubLevel of xhtml+xml (https://github.com/hyperium/mime.rs/issues/22)
                        qitem(Mime(TopLevel::Application, SubLevel::Ext("xhtml+xml".to_string()), vec![])),
                        QualityItem::new(Mime(TopLevel::Application, SubLevel::Xml, vec![]), q(0.9)),
                        QualityItem::new(Mime(TopLevel::Star, SubLevel::Star, vec![]), q(0.8))],
                Context::Style
                    => vec![qitem(Mime(TopLevel::Text, SubLevel::Css, vec![])),
                        QualityItem::new(Mime(TopLevel::Star, SubLevel::Star, vec![]), q(0.1))],
                _ => vec![qitem(Mime(TopLevel::Star, SubLevel::Star, vec![]))]
            };
            // Substep 2
            self.headers.set(Accept(value));
        }
        // Step 2
        if self.context != Context::Fetch && !self.headers.has::<AcceptLanguage>() {
            self.headers.set(AcceptLanguage(vec![qitem(Language::from_str("en-US").unwrap())]));
        }
        // TODO: Figure out what a Priority object is
        // Step 3
        // Step 4
        self.main_fetch(cors_flag)
    }

    /// [Main fetch](https://fetch.spec.whatwg.org/#concept-main-fetch)
    pub fn main_fetch(&mut self, _cors_flag: bool) -> Response {
        // TODO: Implement main fetch spec
        Response::network_error()
    }

    /// [Basic fetch](https://fetch.spec.whatwg.org#basic-fetch)
    pub fn basic_fetch(&mut self) -> Response {
        match &*self.url.scheme {
            "about" => match self.url.non_relative_scheme_data() {
                Some(s) if &*s == "blank" => {
                    let mut response = Response::new();
                    response.headers.set(ContentType(Mime(
                        TopLevel::Text, SubLevel::Html,
                        vec![(Attr::Charset, Value::Utf8)])));
                    response
                },
                _ => Response::network_error()
            },
            "http" | "https" => {
                self.http_fetch(false, false, false)
            },
            "blob" | "data" | "file" | "ftp" => {
                // XXXManishearth handle these
                panic!("Unimplemented scheme for Fetch")
            },

            _ => Response::network_error()
        }
    }

    /// [HTTP fetch](https://fetch.spec.whatwg.org#http-fetch)
    pub fn http_fetch(&mut self, cors_flag: bool, cors_preflight_flag: bool, authentication_fetch_flag: bool) -> Response {
        // Step 1
        let mut response: Option<Response> = None;
        // Step 2
        if !self.skip_service_worker && !self.is_service_worker_global_scope {
            // TODO: Substep 1 (handle fetch unimplemented)
            // Substep 2
            if let Some(ref res) = response {
                if (res.response_type == ResponseType::Opaque && self.mode != RequestMode::NoCORS) ||
                   res.response_type == ResponseType::Error {
                    return Response::network_error();
                }
            }
        }
        // Step 3
        if response.is_none() {
            // Substep 1
            if cors_preflight_flag {
                let mut method_mismatch = false;
                let mut header_mismatch = false;
                if let Some(ref mut cache) = self.cache {
                    let origin = self.origin.clone().unwrap_or(Url::parse("").unwrap());
                    let url = self.url.clone();
                    let credentials = self.credentials_mode == CredentialsMode::Include;
                    let method_cache_match = cache.match_method(CacheRequestDetails {
                        origin: origin.clone(),
                        destination: url.clone(),
                        credentials: credentials
                    }, self.method.clone());
                    method_mismatch = !method_cache_match && (!is_simple_method(&self.method) ||
                        self.mode == RequestMode::ForcedPreflightMode);
                    header_mismatch = self.headers.iter().any(|view|
                        !cache.match_header(CacheRequestDetails {
                            origin: origin.clone(),
                            destination: url.clone(),
                            credentials: credentials
                        }, view.name()) && !is_simple_header(&view)
                        );
                }
                if method_mismatch || header_mismatch {
                    let preflight_result = self.preflight_fetch();
                    if preflight_result.response_type == ResponseType::Error {
                        return Response::network_error();
                    }
                    response = Some(preflight_result);
                }
            }
            // Substep 2
            self.skip_service_worker = true;
            // Substep 3
            let credentials = match self.credentials_mode {
                CredentialsMode::Include => true,
                CredentialsMode::CredentialsSameOrigin if !cors_flag => true,
                _ => false
            };
            // Substep 4
            if self.cache_mode == CacheMode::Default && is_no_store_cache(&self.headers) {
                self.cache_mode = CacheMode::NoStore;
            }
            // Substep 5
            let fetch_result = self.http_network_or_cache_fetch(credentials, authentication_fetch_flag);
            // Substep 6
            if cors_flag && self.cors_check(&fetch_result).is_err() {
                return Response::network_error();
            }
            response = Some(fetch_result);
        }
        // Step 4
        let mut response = response.unwrap();
        match response.status.unwrap() {
            // Code 304
            StatusCode::NotModified => match self.cache_mode {
                CacheMode::Default | CacheMode::NoCache => {
                    // TODO: Check HTTP cache for request and response entry
                }
                _ => { }
            },
            // Code 301, 302, 303, 307, 308
            StatusCode::MovedPermanently | StatusCode::Found | StatusCode::SeeOther |
            StatusCode::TemporaryRedirect | StatusCode::PermanentRedirect => {
                // Step 1
                if self.redirect_mode == RedirectMode::Error {
                    return Response::network_error();
                }
                // Step 2-4
                if !response.headers.has::<Location>() {
                    return response;
                }
                let location = response.headers.get::<Location>();
                if location.is_none() {
                    return Response::network_error();
                }
                // Step 5
                let locationUrl = Url::parse(location.unwrap());
                // Step 6
                let locationUrl = match locationUrl {
                    Ok(url) => url,
                    Err(_) => return Response::network_error()
                };
                // Step 7
                if self.redirect_count == 20 {
                    return Response::network_error();
                }
                // Step 8
                self.redirect_count += 1;
                // Step 9
                self.same_origin_data = false;
                // Step 10
                if self.redirect_mode == RedirectMode::Follow {
                    // FIXME: Origin method of the Url crate hasn't been implemented (https://github.com/servo/rust-url/issues/54)
                    // Substep 1
                    // if cors_flag && locationUrl.origin() != self.url.origin() { self.origin = None; }
                    // Substep 2
                    if cors_flag && (!locationUrl.username().unwrap_or("").is_empty() ||
                                      locationUrl.password().is_some()) {
                        return Response::network_error();
                    }
                    // Substep 3
                    if response.status.unwrap() == StatusCode::MovedPermanently ||
                       response.status.unwrap() == StatusCode::SeeOther ||
                       (response.status.unwrap() == StatusCode::Found && self.method == Method::Post) {
                        self.method = Method::Get;
                    }
                    // Substep 4
                    self.url = locationUrl;
                    // Substep 5
                    return self.fetch(cors_flag);
                }
            }
            // Code 401
            StatusCode::Unauthorized => {
                // Step 1
                if !self.authentication || cors_flag {
                    return response;
                }
                // Step 2
                // TODO: Spec says requires testing
                // Step 3
                if !self.use_url_credentials || authentication_fetch_flag {
                    // TODO: Prompt the user for username and password
                }
                return self.http_fetch(cors_flag, cors_preflight_flag, true);
            }
            // Code 407
            StatusCode::ProxyAuthenticationRequired => {
                // Step 1
                // TODO: Spec says requires testing
                // Step 2
                // TODO: Prompt the user for proxy authentication credentials
                // Step 3
                return self.http_fetch(cors_flag, cors_preflight_flag, authentication_fetch_flag);
            }
            _ => { }
        }
        // Step 5
        if authentication_fetch_flag {
            // TODO: Create authentication entry for this request
        }
        // Step 6
        response
    }

    /// [HTTP network or cache fetch](https://fetch.spec.whatwg.org#http-network-or-cache-fetch)
    pub fn http_network_or_cache_fetch(&mut self, _credentials_flag: bool, _authentication_fetch_flag: bool) -> Response {
        // TODO: Implement HTTP network or cache fetch spec
        Response::network_error()
    }

    /// [CORS preflight fetch](https://fetch.spec.whatwg.org#cors-preflight-fetch)
    pub fn preflight_fetch(&mut self) -> Response {
        // TODO: Implement preflight fetch spec
        Response::network_error()
    }

    /// [CORS check](https://fetch.spec.whatwg.org#concept-cors-check)
    pub fn cors_check(&mut self, response: &Response) -> Result<(), ()> {
        // TODO: Implement CORS check spec
        Err(())
    }
}

fn is_no_store_cache(headers: &Headers) -> bool {
    headers.has::<IfModifiedSince>() | headers.has::<IfNoneMatch>() |
    headers.has::<IfUnmodifiedSince>() | headers.has::<IfMatch>() |
    headers.has::<IfRange>()
}

fn is_simple_header(h: &HeaderView) -> bool {
    if h.is::<ContentType>() {
        match h.value() {
            Some(&ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) |
            Some(&ContentType(Mime(TopLevel::Application, SubLevel::WwwFormUrlEncoded, _))) |
            Some(&ContentType(Mime(TopLevel::Multipart, SubLevel::FormData, _))) => true,
            _ => false

        }
    } else {
        h.is::<Accept>() || h.is::<AcceptLanguage>() || h.is::<ContentLanguage>()
    }
}

fn is_simple_method(m: &Method) -> bool {
    match *m {
        Method::Get | Method::Head | Method::Post => true,
        _ => false
    }
}
<|endoftext|>


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

use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods};
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::utils::create_typed_array;
use crate::dom::globalscope::GlobalScope;
use crate::dom::xrrigidtransform::XRRigidTransform;
use crate::dom::xrsession::{cast_transform, ApiViewerPose, XRSession};
use crate::script_runtime::JSContext;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
use std::ptr::NonNull;
use webxr_api::View;

#[dom_struct]
pub struct XRView {
    reflector_: Reflector,
    session: Dom<XRSession>,
    eye: XREye,
    #[ignore_malloc_size_of = "mozjs"]
    proj: Heap<*mut JSObject>,
    #[ignore_malloc_size_of = "mozjs"]
    view: Heap<*mut JSObject>,
    transform: Dom<XRRigidTransform>,
}

impl XRView {
    fn new_inherited(session: &XRSession, transform: &XRRigidTransform, eye: XREye) -> XRView {
        XRView {
            reflector_: Reflector::new(),
            session: Dom::from_ref(session),
            eye,
            proj: Heap::default(),
            view: Heap::default(),
            transform: Dom::from_ref(transform),
        }
    }

    pub fn new<V: Copy>(
        global: &GlobalScope,
        session: &XRSession,
        view: &View<V>,
        eye: XREye,
        pose: &ApiViewerPose,
    ) -> DomRoot<XRView> {
        // XXXManishearth compute and cache projection matrices on the Display

        // this transform is the pose of the viewer in the eye space, i.e. it is the transform
        // from the viewer space to the eye space. We invert it to get the pose of the eye in the viewer space.
        let offset = view.transform.inverse();

        let transform = pose.pre_transform(&offset);
        let transform = XRRigidTransform::new(global, cast_transform(transform));

        let ret = reflect_dom_object(
            Box::new(XRView::new_inherited(session, &transform, eye)),
            global,
        );

        // row_major since euclid uses row vectors
        let proj = view.projection.to_row_major_array();
        let cx = global.get_cx();
        create_typed_array(cx, &proj, &ret.proj);
        ret
    }

    pub fn session(&self) -> &XRSession {
        &self.session
    }
}

impl XRViewMethods for XRView {
    /// https://immersive-web.github.io/webxr/#dom-xrview-eye
    fn Eye(&self) -> XREye {
        self.eye
    }

    /// https://immersive-web.github.io/webxr/#dom-xrview-projectionmatrix
    fn ProjectionMatrix(&self, _cx: JSContext) -> NonNull<JSObject> {
        NonNull::new(self.proj.get()).unwrap()
    }

    /// https://immersive-web.github.io/webxr/#dom-xrview-transform
    fn Transform(&self) -> DomRoot<XRRigidTransform> {
        DomRoot::from_ref(&self.transform)
    }
}
<commit_msg>handle detached array in XRView<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods};
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::utils::create_typed_array;
use crate::dom::globalscope::GlobalScope;
use crate::dom::xrrigidtransform::XRRigidTransform;
use crate::dom::xrsession::{cast_transform, ApiViewerPose, XRSession};
use crate::script_runtime::JSContext;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
use std::ptr::NonNull;
use webxr_api::View;

#[dom_struct]
pub struct XRView {
    reflector_: Reflector,
    session: Dom<XRSession>,
    eye: XREye,
    #[ignore_malloc_size_of = "mozjs"]
    proj: Heap<*mut JSObject>,
    #[ignore_malloc_size_of = "mozjs"]
    view: Heap<*mut JSObject>,
    proj_array: Vec<f32>,
    transform: Dom<XRRigidTransform>,
}

impl XRView {
    fn new_inherited(
        session: &XRSession,
        transform: &XRRigidTransform,
        eye: XREye,
        proj_array: Vec<f32>,
    ) -> XRView {
        XRView {
            reflector_: Reflector::new(),
            session: Dom::from_ref(session),
            eye,
            proj: Heap::default(),
            view: Heap::default(),
            proj_array,
            transform: Dom::from_ref(transform),
        }
    }

    pub fn new<V: Copy>(
        global: &GlobalScope,
        session: &XRSession,
        view: &View<V>,
        eye: XREye,
        pose: &ApiViewerPose,
    ) -> DomRoot<XRView> {
        // XXXManishearth compute and cache projection matrices on the Display

        // this transform is the pose of the viewer in the eye space, i.e. it is the transform
        // from the viewer space to the eye space. We invert it to get the pose of the eye in the viewer space.
        let offset = view.transform.inverse();

        let transform = pose.pre_transform(&offset);
        let transform = XRRigidTransform::new(global, cast_transform(transform));

        // row_major since euclid uses row vectors
        let proj = view.projection.to_row_major_array();
        let ret = reflect_dom_object(
            Box::new(XRView::new_inherited(
                session,
                &transform,
                eye,
                (&proj).to_vec(),
            )),
            global,
        );

        let cx = global.get_cx();
        create_typed_array(cx, &proj, &ret.proj);
        ret
    }

    pub fn session(&self) -> &XRSession {
        &self.session
    }
}

impl XRViewMethods for XRView {
    /// https://immersive-web.github.io/webxr/#dom-xrview-eye
    fn Eye(&self) -> XREye {
        self.eye
    }

    /// https://immersive-web.github.io/webxr/#dom-xrview-projectionmatrix
    fn ProjectionMatrix(&self, _cx: JSContext) -> NonNull<JSObject> {
        if self.proj.get().is_null() {
            let cx = self.global().get_cx();
            create_typed_array(cx, &self.proj_array, &self.proj);
        }
        NonNull::new(self.proj.get()).unwrap()
    }

    /// https://immersive-web.github.io/webxr/#dom-xrview-transform
    fn Transform(&self) -> DomRoot<XRRigidTransform> {
        DomRoot::from_ref(&self.transform)
    }
}
<|endoftext|>


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

use crate::{BlockingClient, Error, Result, WaitForTransactionError};
use diem_types::transaction::{authenticator::AuthenticationKey, SignedTransaction};

pub struct FaucetClient {
    url: String,
    json_rpc_client: BlockingClient,
}

impl FaucetClient {
    pub fn new(url: String, json_rpc_url: String) -> Self {
        Self {
            url,
            json_rpc_client: BlockingClient::new(json_rpc_url),
        }
    }

    pub fn fund(
        &self,
        currency_code: &str,
        auth_key: AuthenticationKey,
        amount: u64,
    ) -> Result<()> {
        let client = reqwest::blocking::Client::new();

        let url = format!(
            "{}?amount={}&auth_key={}&currency_code={}&return_txns=true",
            self.url, amount, auth_key, currency_code,
        );

        //TODO Fix faucet
        // The current implementation of Faucet is racy, in that 2 independent requests can come in
        // and result in faucet sending 2 txns to the network with the same sequence number and
        // they race to complete. One request will complete while the other will get a HashMismatch
        // Error.
        //
        // Faucet returns a list of txns that need to be waited on before returning. 1) a txn for
        // creating the account (if it doesn't already exist) and 2) to issue funds to said
        // account.
        'faucet: loop {
            let response = client.post(&url).send().map_err(Error::request)?;
            let status_code = response.status();
            let body = response.text().map_err(Error::decode)?;
            if !status_code.is_success() {
                return Err(Error::status(status_code.as_u16()));
            }
            let bytes = hex::decode(body).map_err(Error::decode)?;
            let txns: Vec<SignedTransaction> = bcs::from_bytes(&bytes).unwrap();

            for txn in txns {
                match self
                    .json_rpc_client
                    .wait_for_signed_transaction(&txn, None, None)
                {
                    Ok(_) => {}
                    Err(WaitForTransactionError::TransactionHashMismatchError(_))
                    | Err(WaitForTransactionError::TransactionExpired) => continue 'faucet,
                    Err(e) => return Err(Error::unknown(e)),
                }
            }

            break;
        }

        Ok(())
    }
}
<commit_msg>client: remove faucet retry logic<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{BlockingClient, Error, Result};
use diem_types::transaction::{authenticator::AuthenticationKey, SignedTransaction};

pub struct FaucetClient {
    url: String,
    json_rpc_client: BlockingClient,
}

impl FaucetClient {
    pub fn new(url: String, json_rpc_url: String) -> Self {
        Self {
            url,
            json_rpc_client: BlockingClient::new(json_rpc_url),
        }
    }

    pub fn fund(
        &self,
        currency_code: &str,
        auth_key: AuthenticationKey,
        amount: u64,
    ) -> Result<()> {
        let client = reqwest::blocking::Client::new();

        let url = format!(
            "{}?amount={}&auth_key={}&currency_code={}&return_txns=true",
            self.url, amount, auth_key, currency_code,
        );

        // Faucet returns a list of txns that need to be waited on before returning. 1) a txn for
        // creating the account (if it doesn't already exist) and 2) to issue funds to said
        // account.
        let response = client.post(&url).send().map_err(Error::request)?;
        let status_code = response.status();
        let body = response.text().map_err(Error::decode)?;
        if !status_code.is_success() {
            return Err(Error::status(status_code.as_u16()));
        }
        let bytes = hex::decode(body).map_err(Error::decode)?;
        let txns: Vec<SignedTransaction> = bcs::from_bytes(&bytes).map_err(Error::decode)?;

        for txn in txns {
            self.json_rpc_client
                .wait_for_signed_transaction(&txn, None, None)
                .map_err(Error::unknown)?;
        }

        Ok(())
    }
}
<|endoftext|>