<commit_before>use rustc_ast::{token, Attribute, Mod};
use rustc_errors::{struct_span_err, PResult};
use rustc_parse::new_parser_from_file;
use rustc_session::parse::ParseSess;
use rustc_session::Session;
use rustc_span::source_map::{FileName, Span};
use rustc_span::symbol::{sym, Ident};

use std::path::{self, Path, PathBuf};

#[derive(Clone)]
pub struct Directory {
    pub path: PathBuf,
    pub ownership: DirectoryOwnership,
}

#[derive(Copy, Clone)]
pub enum DirectoryOwnership {
    Owned {
        // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`.
        relative: Option<Ident>,
    },
    UnownedViaBlock,
    UnownedViaMod,
}

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath<'a> {
    name: String,
    path_exists: bool,
    pub result: PResult<'a, ModulePathSuccess>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub path: PathBuf,
    pub ownership: DirectoryOwnership,
}

crate fn parse_external_mod(
    sess: &Session,
    id: Ident,
    span: Span, // The span to blame on errors.
    Directory { mut ownership, path }: Directory,
    attrs: &mut Vec<Attribute>,
    pop_mod_stack: &mut bool,
) -> (Mod, Directory) {
    // We bail on the first error, but that error does not cause a fatal error... (1)
    let result: PResult<'_, _> = try {
        // Extract the file path and the new ownership.
        let mp = submod_path(sess, id, span, &attrs, ownership, &path)?;
        ownership = mp.ownership;

        // Ensure file paths are acyclic.
        let mut included_mod_stack = sess.parse_sess.included_mod_stack.borrow_mut();
        error_on_circular_module(&sess.parse_sess, span, &mp.path, &included_mod_stack)?;
        included_mod_stack.push(mp.path.clone());
        *pop_mod_stack = true; // We have pushed, so notify caller.
        drop(included_mod_stack);

        // Actually parse the external file as a module.
        let mut module =
            new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)).parse_mod(&token::Eof)?;
        module.0.inline = false;
        module
    };
    // (1) ...instead, we return a dummy module.
    let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_default();
    attrs.append(&mut new_attrs);

    // Extract the directory path for submodules of `module`.
    let path = sess.source_map().span_to_unmapped_path(module.inner);
    let mut path = match path {
        FileName::Real(name) => name.into_local_path(),
        other => PathBuf::from(other.to_string()),
    };
    path.pop();

    (module, Directory { ownership, path })
}

fn error_on_circular_module<'a>(
    sess: &'a ParseSess,
    span: Span,
    path: &Path,
    included_mod_stack: &[PathBuf],
) -> PResult<'a, ()> {
    if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
        let mut err = String::from("circular modules: ");
        for p in &included_mod_stack[i..] {
            err.push_str(&p.to_string_lossy());
            err.push_str(" -> ");
        }
        err.push_str(&path.to_string_lossy());
        return Err(sess.span_diagnostic.struct_span_err(span, &err[..]));
    }
    Ok(())
}

crate fn push_directory(
    sess: &Session,
    id: Ident,
    attrs: &[Attribute],
    Directory { mut ownership, mut path }: Directory,
) -> Directory {
    if let Some(filename) = sess.first_attr_value_str_by_name(attrs, sym::path) {
        path.push(&*filename.as_str());
        ownership = DirectoryOwnership::Owned { relative: None };
    } else {
        // We have to push on the current module name in the case of relative
        // paths in order to ensure that any additional module paths from inline
        // `mod x { ... }` come after the relative extension.
        //
        // For example, a `mod z { ... }` inside `x/y.rs` should set the current
        // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
        if let DirectoryOwnership::Owned { relative } = &mut ownership {
            if let Some(ident) = relative.take() {
                // Remove the relative offset.
                path.push(&*ident.as_str());
            }
        }
        path.push(&*id.as_str());
    }
    Directory { ownership, path }
}

fn submod_path<'a>(
    sess: &'a Session,
    id: Ident,
    span: Span,
    attrs: &[Attribute],
    ownership: DirectoryOwnership,
    dir_path: &Path,
) -> PResult<'a, ModulePathSuccess> {
    if let Some(path) = submod_path_from_attr(sess, attrs, dir_path) {
        let ownership = match path.file_name().and_then(|s| s.to_str()) {
            // All `#[path]` files are treated as though they are a `mod.rs` file.
            // This means that `mod foo;` declarations inside `#[path]`-included
            // files are siblings,
            //
            // Note that this will produce weirdness when a file named `foo.rs` is
            // `#[path]` included and contains a `mod foo;` declaration.
            // If you encounter this, it's your own darn fault :P
            Some(_) => DirectoryOwnership::Owned { relative: None },
            _ => DirectoryOwnership::UnownedViaMod,
        };
        return Ok(ModulePathSuccess { ownership, path });
    }

    let relative = match ownership {
        DirectoryOwnership::Owned { relative } => relative,
        DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
    };
    let ModulePath { path_exists, name, result } =
        default_submod_path(&sess.parse_sess, id, span, relative, dir_path);
    match ownership {
        DirectoryOwnership::Owned { .. } => Ok(result?),
        DirectoryOwnership::UnownedViaBlock => {
            let _ = result.map_err(|mut err| err.cancel());
            error_decl_mod_in_block(&sess.parse_sess, span, path_exists, &name)
        }
        DirectoryOwnership::UnownedViaMod => {
            let _ = result.map_err(|mut err| err.cancel());
            error_cannot_declare_mod_here(&sess.parse_sess, span, path_exists, &name)
        }
    }
}

fn error_decl_mod_in_block<'a, T>(
    sess: &'a ParseSess,
    span: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute";
    let mut err = sess.span_diagnostic.struct_span_err(span, msg);
    if path_exists {
        let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name);
        err.span_note(span, &msg);
    }
    Err(err)
}

fn error_cannot_declare_mod_here<'a, T>(
    sess: &'a ParseSess,
    span: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let mut err =
        sess.span_diagnostic.struct_span_err(span, "cannot declare a new module at this location");
    if !span.is_dummy() {
        if let FileName::Real(src_name) = sess.source_map().span_to_filename(span) {
            let src_path = src_name.into_local_path();
            if let Some(stem) = src_path.file_stem() {
                let mut dest_path = src_path.clone();
                dest_path.set_file_name(stem);
                dest_path.push("mod.rs");
                err.span_note(
                    span,
                    &format!(
                        "maybe move this module `{}` to its own directory via `{}`",
                        src_path.display(),
                        dest_path.display()
                    ),
                );
            }
        }
    }
    if path_exists {
        err.span_note(
            span,
            &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name),
        );
    }
    Err(err)
}

/// Derive a submodule path from the first found `#[path = "path_string"]`.
/// The provided `dir_path` is joined with the `path_string`.
// Public for rustfmt usage.
pub fn submod_path_from_attr(
    sess: &Session,
    attrs: &[Attribute],
    dir_path: &Path,
) -> Option<PathBuf> {
    // Extract path string from first `#[path = "path_string"]` attribute.
    let path_string = sess.first_attr_value_str_by_name(attrs, sym::path)?;
    let path_string = path_string.as_str();

    // On windows, the base path might have the form
    // `\\?\foo\bar` in which case it does not tolerate
    // mixed `/` and `\` separators, so canonicalize
    // `/` to `\`.
    #[cfg(windows)]
    let path_string = path_string.replace("/", "\\");

    Some(dir_path.join(&*path_string))
}

/// Returns a path to a module.
// Public for rustfmt usage.
pub fn default_submod_path<'a>(
    sess: &'a ParseSess,
    id: Ident,
    span: Span,
    relative: Option<Ident>,
    dir_path: &Path,
) -> ModulePath<'a> {
    // If we're in a foo.rs file instead of a mod.rs file,
    // we need to look for submodules in
    // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
    // `./<id>.rs` and `./<id>/mod.rs`.
    let relative_prefix_string;
    let relative_prefix = if let Some(ident) = relative {
        relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
        &relative_prefix_string
    } else {
        ""
    };

    let mod_name = id.name.to_string();
    let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
    let secondary_path_str =
        format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
    let default_path = dir_path.join(&default_path_str);
    let secondary_path = dir_path.join(&secondary_path_str);
    let default_exists = sess.source_map().file_exists(&default_path);
    let secondary_exists = sess.source_map().file_exists(&secondary_path);

    let result = match (default_exists, secondary_exists) {
        (true, false) => Ok(ModulePathSuccess {
            path: default_path,
            ownership: DirectoryOwnership::Owned { relative: Some(id) },
        }),
        (false, true) => Ok(ModulePathSuccess {
            path: secondary_path,
            ownership: DirectoryOwnership::Owned { relative: None },
        }),
        (false, false) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                span,
                E0583,
                "file not found for module `{}`",
                mod_name,
            );
            err.help(&format!(
                "to create the module `{}`, create file \"{}\"",
                mod_name,
                default_path.display(),
            ));
            Err(err)
        }
        (true, true) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                span,
                E0761,
                "file for module `{}` found at both {} and {}",
                mod_name,
                default_path_str,
                secondary_path_str,
            );
            err.help("delete or rename one of them to remove the ambiguity");
            Err(err)
        }
    };

    ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
}
<commit_msg>rustc_expand: remove pub visibility for rustfmt<commit_after>use rustc_ast::{token, Attribute, Mod};
use rustc_errors::{struct_span_err, PResult};
use rustc_parse::new_parser_from_file;
use rustc_session::parse::ParseSess;
use rustc_session::Session;
use rustc_span::source_map::{FileName, Span};
use rustc_span::symbol::{sym, Ident};

use std::path::{self, Path, PathBuf};

#[derive(Clone)]
pub struct Directory {
    pub path: PathBuf,
    pub ownership: DirectoryOwnership,
}

#[derive(Copy, Clone)]
pub enum DirectoryOwnership {
    Owned {
        // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`.
        relative: Option<Ident>,
    },
    UnownedViaBlock,
    UnownedViaMod,
}

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath<'a> {
    name: String,
    path_exists: bool,
    pub result: PResult<'a, ModulePathSuccess>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub path: PathBuf,
    pub ownership: DirectoryOwnership,
}

crate fn parse_external_mod(
    sess: &Session,
    id: Ident,
    span: Span, // The span to blame on errors.
    Directory { mut ownership, path }: Directory,
    attrs: &mut Vec<Attribute>,
    pop_mod_stack: &mut bool,
) -> (Mod, Directory) {
    // We bail on the first error, but that error does not cause a fatal error... (1)
    let result: PResult<'_, _> = try {
        // Extract the file path and the new ownership.
        let mp = submod_path(sess, id, span, &attrs, ownership, &path)?;
        ownership = mp.ownership;

        // Ensure file paths are acyclic.
        let mut included_mod_stack = sess.parse_sess.included_mod_stack.borrow_mut();
        error_on_circular_module(&sess.parse_sess, span, &mp.path, &included_mod_stack)?;
        included_mod_stack.push(mp.path.clone());
        *pop_mod_stack = true; // We have pushed, so notify caller.
        drop(included_mod_stack);

        // Actually parse the external file as a module.
        let mut module =
            new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)).parse_mod(&token::Eof)?;
        module.0.inline = false;
        module
    };
    // (1) ...instead, we return a dummy module.
    let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_default();
    attrs.append(&mut new_attrs);

    // Extract the directory path for submodules of `module`.
    let path = sess.source_map().span_to_unmapped_path(module.inner);
    let mut path = match path {
        FileName::Real(name) => name.into_local_path(),
        other => PathBuf::from(other.to_string()),
    };
    path.pop();

    (module, Directory { ownership, path })
}

fn error_on_circular_module<'a>(
    sess: &'a ParseSess,
    span: Span,
    path: &Path,
    included_mod_stack: &[PathBuf],
) -> PResult<'a, ()> {
    if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
        let mut err = String::from("circular modules: ");
        for p in &included_mod_stack[i..] {
            err.push_str(&p.to_string_lossy());
            err.push_str(" -> ");
        }
        err.push_str(&path.to_string_lossy());
        return Err(sess.span_diagnostic.struct_span_err(span, &err[..]));
    }
    Ok(())
}

crate fn push_directory(
    sess: &Session,
    id: Ident,
    attrs: &[Attribute],
    Directory { mut ownership, mut path }: Directory,
) -> Directory {
    if let Some(filename) = sess.first_attr_value_str_by_name(attrs, sym::path) {
        path.push(&*filename.as_str());
        ownership = DirectoryOwnership::Owned { relative: None };
    } else {
        // We have to push on the current module name in the case of relative
        // paths in order to ensure that any additional module paths from inline
        // `mod x { ... }` come after the relative extension.
        //
        // For example, a `mod z { ... }` inside `x/y.rs` should set the current
        // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
        if let DirectoryOwnership::Owned { relative } = &mut ownership {
            if let Some(ident) = relative.take() {
                // Remove the relative offset.
                path.push(&*ident.as_str());
            }
        }
        path.push(&*id.as_str());
    }
    Directory { ownership, path }
}

fn submod_path<'a>(
    sess: &'a Session,
    id: Ident,
    span: Span,
    attrs: &[Attribute],
    ownership: DirectoryOwnership,
    dir_path: &Path,
) -> PResult<'a, ModulePathSuccess> {
    if let Some(path) = submod_path_from_attr(sess, attrs, dir_path) {
        let ownership = match path.file_name().and_then(|s| s.to_str()) {
            // All `#[path]` files are treated as though they are a `mod.rs` file.
            // This means that `mod foo;` declarations inside `#[path]`-included
            // files are siblings,
            //
            // Note that this will produce weirdness when a file named `foo.rs` is
            // `#[path]` included and contains a `mod foo;` declaration.
            // If you encounter this, it's your own darn fault :P
            Some(_) => DirectoryOwnership::Owned { relative: None },
            _ => DirectoryOwnership::UnownedViaMod,
        };
        return Ok(ModulePathSuccess { ownership, path });
    }

    let relative = match ownership {
        DirectoryOwnership::Owned { relative } => relative,
        DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
    };
    let ModulePath { path_exists, name, result } =
        default_submod_path(&sess.parse_sess, id, span, relative, dir_path);
    match ownership {
        DirectoryOwnership::Owned { .. } => Ok(result?),
        DirectoryOwnership::UnownedViaBlock => {
            let _ = result.map_err(|mut err| err.cancel());
            error_decl_mod_in_block(&sess.parse_sess, span, path_exists, &name)
        }
        DirectoryOwnership::UnownedViaMod => {
            let _ = result.map_err(|mut err| err.cancel());
            error_cannot_declare_mod_here(&sess.parse_sess, span, path_exists, &name)
        }
    }
}

fn error_decl_mod_in_block<'a, T>(
    sess: &'a ParseSess,
    span: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute";
    let mut err = sess.span_diagnostic.struct_span_err(span, msg);
    if path_exists {
        let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name);
        err.span_note(span, &msg);
    }
    Err(err)
}

fn error_cannot_declare_mod_here<'a, T>(
    sess: &'a ParseSess,
    span: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let mut err =
        sess.span_diagnostic.struct_span_err(span, "cannot declare a new module at this location");
    if !span.is_dummy() {
        if let FileName::Real(src_name) = sess.source_map().span_to_filename(span) {
            let src_path = src_name.into_local_path();
            if let Some(stem) = src_path.file_stem() {
                let mut dest_path = src_path.clone();
                dest_path.set_file_name(stem);
                dest_path.push("mod.rs");
                err.span_note(
                    span,
                    &format!(
                        "maybe move this module `{}` to its own directory via `{}`",
                        src_path.display(),
                        dest_path.display()
                    ),
                );
            }
        }
    }
    if path_exists {
        err.span_note(
            span,
            &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name),
        );
    }
    Err(err)
}

/// Derive a submodule path from the first found `#[path = "path_string"]`.
/// The provided `dir_path` is joined with the `path_string`.
pub(super) fn submod_path_from_attr(
    sess: &Session,
    attrs: &[Attribute],
    dir_path: &Path,
) -> Option<PathBuf> {
    // Extract path string from first `#[path = "path_string"]` attribute.
    let path_string = sess.first_attr_value_str_by_name(attrs, sym::path)?;
    let path_string = path_string.as_str();

    // On windows, the base path might have the form
    // `\\?\foo\bar` in which case it does not tolerate
    // mixed `/` and `\` separators, so canonicalize
    // `/` to `\`.
    #[cfg(windows)]
    let path_string = path_string.replace("/", "\\");

    Some(dir_path.join(&*path_string))
}

/// Returns a path to a module.
// Public for rustfmt usage.
pub fn default_submod_path<'a>(
    sess: &'a ParseSess,
    id: Ident,
    span: Span,
    relative: Option<Ident>,
    dir_path: &Path,
) -> ModulePath<'a> {
    // If we're in a foo.rs file instead of a mod.rs file,
    // we need to look for submodules in
    // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
    // `./<id>.rs` and `./<id>/mod.rs`.
    let relative_prefix_string;
    let relative_prefix = if let Some(ident) = relative {
        relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
        &relative_prefix_string
    } else {
        ""
    };

    let mod_name = id.name.to_string();
    let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
    let secondary_path_str =
        format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
    let default_path = dir_path.join(&default_path_str);
    let secondary_path = dir_path.join(&secondary_path_str);
    let default_exists = sess.source_map().file_exists(&default_path);
    let secondary_exists = sess.source_map().file_exists(&secondary_path);

    let result = match (default_exists, secondary_exists) {
        (true, false) => Ok(ModulePathSuccess {
            path: default_path,
            ownership: DirectoryOwnership::Owned { relative: Some(id) },
        }),
        (false, true) => Ok(ModulePathSuccess {
            path: secondary_path,
            ownership: DirectoryOwnership::Owned { relative: None },
        }),
        (false, false) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                span,
                E0583,
                "file not found for module `{}`",
                mod_name,
            );
            err.help(&format!(
                "to create the module `{}`, create file \"{}\"",
                mod_name,
                default_path.display(),
            ));
            Err(err)
        }
        (true, true) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                span,
                E0761,
                "file for module `{}` found at both {} and {}",
                mod_name,
                default_path_str,
                secondary_path_str,
            );
            err.help("delete or rename one of them to remove the ambiguity");
            Err(err)
        }
    };

    ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
}
<|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/. */

#[cfg(feature = "energy-profiling")]
pub fn read_energy_uj() -> u64 {
    energymon::read_energy_uj()
}

#[cfg(not(feature = "energy-profiling"))]
pub fn read_energy_uj() -> u64 {
    0
}

#[cfg(feature = "energy-profiling")]
pub fn energy_interval_ms() -> u32 {
    energymon::get_min_interval_ms()
}

#[cfg(not(feature = "energy-profiling"))]
pub fn energy_interval_ms() -> u32 {
    1000
}

#[cfg(feature = "energy-profiling")]
mod energymon {
    extern crate energy_monitor;
    extern crate energymon;

    use self::energy_monitor::EnergyMonitor;
    use self::energymon::EnergyMon;
    use std::mem;
    use std::sync::{Once, ONCE_INIT};

    static mut EM: Option<*mut EnergyMon> = None;

    fn init() {
        // can't use lazy_static macro for EM (no Sync trait for EnergyMon)
        static ONCE: Once = ONCE_INIT;
        ONCE.call_once(|| {
            if let Ok(em) = EnergyMon::new() {
                println!("Started energy monitoring from: {}", em.source());
                unsafe {
                    EM = Some(mem::transmute(Box::new(em)));
                }
            }
        });
    }

    /// Read energy from the energy monitor, otherwise return 0.
    pub fn read_energy_uj() -> u64 {
        init();
        unsafe {
            // EnergyMon implementations of EnergyMonitor always return a value
            EM.map_or(0, |em| (*em).read_uj().unwrap())
        }
    }

    pub fn get_min_interval_ms() -> u32 {
        init();
        unsafe { EM.map_or(0, |em| ((*em).interval_us() as f64 / 1000.0).ceil() as u32) }
    }
}
<commit_msg>Auto merge of #26641 - dylni:fix-undefined-behavior, r=SimonSapin<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/. */

#[cfg(feature = "energy-profiling")]
pub fn read_energy_uj() -> u64 {
    energymon::read_energy_uj()
}

#[cfg(not(feature = "energy-profiling"))]
pub fn read_energy_uj() -> u64 {
    0
}

#[cfg(feature = "energy-profiling")]
pub fn energy_interval_ms() -> u32 {
    energymon::get_min_interval_ms()
}

#[cfg(not(feature = "energy-profiling"))]
pub fn energy_interval_ms() -> u32 {
    1000
}

#[cfg(feature = "energy-profiling")]
mod energymon {
    extern crate energy_monitor;
    extern crate energymon;

    use self::energy_monitor::EnergyMonitor;
    use self::energymon::EnergyMon;
    use std::sync::{Once, ONCE_INIT};

    static mut EM: Option<*mut EnergyMon> = None;

    fn init() {
        // can't use lazy_static macro for EM (no Sync trait for EnergyMon)
        static ONCE: Once = ONCE_INIT;
        ONCE.call_once(|| {
            if let Ok(em) = EnergyMon::new() {
                println!("Started energy monitoring from: {}", em.source());
                unsafe {
                    EM = Some(Box::into_raw(Box::new(em)));
                }
            }
        });
    }

    /// Read energy from the energy monitor, otherwise return 0.
    pub fn read_energy_uj() -> u64 {
        init();
        unsafe {
            // EnergyMon implementations of EnergyMonitor always return a value
            EM.map_or(0, |em| (*em).read_uj().unwrap())
        }
    }

    pub fn get_min_interval_ms() -> u32 {
        init();
        unsafe { EM.map_or(0, |em| ((*em).interval_us() as f64 / 1000.0).ceil() as u32) }
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Read};
use std::fmt;
use std::fs::File;
use std::path::Path;

const ROM_TYPE_OFFSET: usize = 0x0147;

enum Mbc {
    NONE,
    MBC1,
}

impl From<u8> for Mbc {
    fn from(val: u8) -> Self {
        match val {
            0x00 | 0x08 | 0x09 => Mbc::NONE,
            0x01 | 0x02 | 0x03 => Mbc::MBC1,
            _ => panic!("Unknown cartridge type {:02x}", val),
        }
    }
}

impl fmt::Display for Mbc {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Mbc::NONE => "None",
                   Mbc::MBC1 => "MBC1",
               })
    }
}

pub struct Cartridge {
    rom: Box<[u8]>,
    ram: Box<[u8]>,
    boot_rom: Box<[u8]>,

    boot_rom_active: bool,

    mbc: Mbc,
    rom_bank_lower: usize,
    bank_upper: usize,
    ram_banking: bool,

    rom_offsets: (usize, usize),
    ram_bank_offset: usize,
    ram_enabled: bool,
}

impl Cartridge {
    pub fn load<P: AsRef<Path>>(file_name: P) -> io::Result<Cartridge> {
        let mut file = File::open(file_name)?;
        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer)?;

        let cart = Cartridge::from_bytes(&buffer);

        println!("Loaded {:0x} bytes of cart", buffer.len());
        println!("{}", cart.name());
        println!("Cart type: {}", cart.type_name());
        println!("MBC: {}", cart.mbc);
        println!("Rom Size: {}", cart.rom_size());

        Ok(cart)
    }

    pub fn load_boot_rom<P: AsRef<Path>>(&mut self, file_name: P) -> io::Result<()> {
        let mut file = File::open(file_name)?;
        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer)?;

        self.boot_rom = buffer.into_boxed_slice();
        self.boot_rom_active = true;

        Ok(())
    }

    pub fn from_bytes(bytes: &[u8]) -> Cartridge {
        let bytes_copy = bytes.to_vec();

        let rom_type = bytes[ROM_TYPE_OFFSET];
        let mbc: Mbc = rom_type.into();

        Cartridge {
            rom: bytes_copy.into_boxed_slice(),
            ram: vec![0; 0x10000].into_boxed_slice(),
            boot_rom: Box::default(),

            boot_rom_active: false,
            mbc: mbc,

            rom_bank_lower: 1,
            bank_upper: 0,
            ram_banking: false,

            rom_offsets: (0x0000, 0x4000),
            ram_bank_offset: 0,
            ram_enabled: false,
        }
    }

    pub fn read_byte(&self, addr: u16) -> u8 {
        let addr = addr as usize;
        let (lower, upper) = self.rom_offsets;

        match addr {
            0...0x00ff if self.boot_rom_active => self.boot_rom[addr],
            0...0x3fff => self.rom[lower + addr],
            0x4000...0x7fff => self.rom[upper + (addr - 0x4000)],
            0xa000...0xbfff => {
                self.ram[self.ram_bank_offset + (addr - 0xa000)]
            }
            _ => panic!("Unrecognized read address in cartridge {:04x}", addr),
        }
    }

    pub fn write(&mut self, addr: u16, val: u8) {
        let addr = addr as usize;
        match addr {
            0x0000...0x1fff => self.ram_enabled = (val & 0x0a) != 0,
            0x2000...0x3fff => {
                let val = (val as usize) & 0x1f;
                self.rom_bank_lower = if val == 0x00 { 0x01 } else { val };
                self.update_rom_offset();
            }
            0x4000...0x5fff => {
                self.bank_upper = (val as usize) & 0x3;
                self.update_rom_offset();
                self.update_ram_offset();
            }
            0x6000...0x7fff => {
                self.ram_banking = val != 0;
                self.update_rom_offset();
                self.update_ram_offset();
            }
            0xa000...0xbfff => {
                self.ram[self.ram_bank_offset + (addr - 0xa000)] = val;
            }
            _ => {
                panic!("Unrecognized write address in cartridge {:04x}={:02x}",
                       addr,
                       val)
            }
        }
    }

    pub fn disable_boot_rom(&mut self) {
        self.boot_rom_active = false;
    }

    fn update_rom_offset(&mut self) {
        let bank_upper = self.bank_upper << 5;
        let lower = if self.ram_banking { bank_upper } else { 0x00 };
        let upper = bank_upper | self.rom_bank_lower;

        let lower_bank = (lower * 0x4000) & (self.rom.len() - 1);
        let upper_bank = (upper * 0x4000) & (self.rom.len() - 1);

        self.rom_offsets = (lower_bank, upper_bank);
    }

    fn update_ram_offset(&mut self) {
        self.ram_bank_offset = if self.ram_banking {
            self.bank_upper * 0x2000
        } else {
            0
        };
    }

    fn name(&self) -> String {
        let mut ret = "".to_string();

        for i in 0..16 {
            let c = self.rom[0x0134 + i];
            if c == 0 {
                break;
            }
            ret.push(c as char);
        }

        ret
    }

    fn rom_type(&self) -> u8 {
        self.rom[0x0147]
    }

    fn type_name(&self) -> &'static str {
        match self.rom_type() {
            0x00 => "ROM ONLY",
            0x01 => "ROM+MBC1",
            0x02 => "ROM+MBC1+RAM",
            0x03 => "ROM+MBC1+RAM+BATT",
            0x05 => "ROM+MBC2",
            0x06 => "ROM+MBC2+BATTERY",
            0x08 => "ROM+RAM",
            0x09 => "ROM+RAM+BATTERY",
            0x0B => "ROM+MMM01",
            0x0C => "ROM+MMM01+SRAM",
            0x0D => "ROM+MMM01+SRAM+BATT",
            0x0F => "ROM+MBC3+TIMER+BATT",
            0x10 => "ROM+MBC3+TIMER+RAM+BATT",
            0x11 => "ROM+MBC3",
            0x12 => "ROM+MBC3+RAM",
            0x13 => "ROM+MBC3+RAM+BATT",
            0x15 => "MBC4",
            0x16 => "MBC4+RAM",
            0x17 => "MBC4+RAM+BATTERY",
            0x19 => "ROM+MBC5",
            0x1A => "ROM+MBC5+RAM",
            0x1B => "ROM+MBC5+RAM+BATT",
            0x1C => "ROM+MBC5+RUMBLE",
            0x1D => "ROM+MBC5+RUMBLE+SRAM",
            0x1E => "ROM+MBC5+RUMBLE+SRAM+BATT",
            0x1F => "Pocket Camera",
            0x20 => "MBC6",
            0x22 => "MBC7+SENSOR+RUMBLE+RAM+BATTERY",
            0xFC => "POCKET CAMERA",
            0xFD => "Bandai TAMA5",
            0xFE => "Hudson HuC-3",
            0xFF => "Hudson HuC-1",
            _ => "UNRECOGNISED CART TYPE",
        }
    }

    fn rom_size(&self) -> &'static str {
        match self.rom[0x0148] {
            0x00 => "32KByte (no ROM banking)",
            0x01 => "64KByte (4 banks)",
            0x02 => "128KByte (8 banks)",
            0x03 => "256KByte (16 banks)",
            0x04 => "512KByte (32 banks)",
            0x05 => "1MByte (64 banks)  - only 63 banks used by MBC1",
            0x06 => "2MByte (128 banks) - only 125 banks used by MBC1",
            0x07 => "4MByte (256 banks)",
            0x08 => "8MByte (512 banks)",
            0x52 => "1.1MByte (72 banks)",
            0x53 => "1.2MByte (80 banks)",
            0x54 => "1.5MByte (96 banks)",
            _ => "UNRECOGNISED CART ROM SIZE",
        }
    }
}
<commit_msg>Pass the mooneye ram tests<commit_after>use std::io::{self, Read};
use std::fmt;
use std::fs::File;
use std::path::Path;

const ROM_TYPE_OFFSET: usize = 0x0147;
const RAM_SIZE_OFFSET: usize = 0x0149;

enum Mbc {
    NONE,
    MBC1,
}

impl From<u8> for Mbc {
    fn from(val: u8) -> Self {
        match val {
            0x00 | 0x08 | 0x09 => Mbc::NONE,
            0x01 | 0x02 | 0x03 => Mbc::MBC1,
            _ => panic!("Unknown cartridge type {:02x}", val),
        }
    }
}

impl fmt::Display for Mbc {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Mbc::NONE => "None",
                   Mbc::MBC1 => "MBC1",
               })
    }
}

pub struct Cartridge {
    rom: Box<[u8]>,
    ram: Box<[u8]>,
    boot_rom: Box<[u8]>,

    boot_rom_active: bool,

    mbc: Mbc,
    rom_bank_lower: usize,
    bank_upper: usize,
    ram_banking: bool,

    rom_offsets: (usize, usize),
    ram_bank_offset: usize,
    ram_enabled: bool,
}

impl Cartridge {
    pub fn load<P: AsRef<Path>>(file_name: P) -> io::Result<Cartridge> {
        let mut file = File::open(file_name)?;
        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer)?;

        let cart = Cartridge::from_bytes(&buffer);

        println!("Loaded {:0x} bytes of cart", buffer.len());
        println!("{}", cart.name());
        println!("Cart type: {}", cart.type_name());
        println!("MBC: {}", cart.mbc);
        println!("Rom Size: {}", cart.rom_size());
        println!("Ram Size: {} KByte", cart.ram.len() / 1024);

        Ok(cart)
    }

    pub fn load_boot_rom<P: AsRef<Path>>(&mut self, file_name: P) -> io::Result<()> {
        let mut file = File::open(file_name)?;
        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer)?;

        self.boot_rom = buffer.into_boxed_slice();
        self.boot_rom_active = true;

        Ok(())
    }

    pub fn from_bytes(bytes: &[u8]) -> Cartridge {
        let bytes_copy = bytes.to_vec();

        let rom_type = bytes[ROM_TYPE_OFFSET];
        let mbc: Mbc = rom_type.into();
        let ram_size = match bytes[RAM_SIZE_OFFSET] {
            0x00 => 0,
            0x01 => 2 * 1024,
            0x02 => 8 * 1024,
            0x03 => 32 * 1024,
            0x04 => 128 * 1024,
            0x05 => 64 * 1024,
            _ => unreachable!(),
        };

        Cartridge {
            rom: bytes_copy.into_boxed_slice(),
            ram: vec![0; ram_size].into_boxed_slice(),
            boot_rom: Box::default(),

            boot_rom_active: false,
            mbc: mbc,

            rom_bank_lower: 1,
            bank_upper: 0,
            ram_banking: false,

            rom_offsets: (0x0000, 0x4000),
            ram_bank_offset: 0,
            ram_enabled: false,
        }
    }

    pub fn read_byte(&self, addr: u16) -> u8 {
        let addr = addr as usize;
        let (lower, upper) = self.rom_offsets;

        match addr {
            0...0x00ff if self.boot_rom_active => self.boot_rom[addr],
            0...0x3fff => self.rom[lower + addr],
            0x4000...0x7fff => self.rom[upper + (addr - 0x4000)],
            0xa000...0xbfff => {
                if self.ram_enabled {
                    self.ram[self.ram_bank_offset + (addr - 0xa000)]
                } else {
                    0xff
                }
            }
            _ => panic!("Unrecognized read address in cartridge {:04x}", addr),
        }
    }

    pub fn write(&mut self, addr: u16, val: u8) {
        let addr = addr as usize;
        match addr {
            0x0000...0x1fff => self.ram_enabled = (val & 0x0a) != 0,
            0x2000...0x3fff => {
                let val = (val as usize) & 0x1f;
                self.rom_bank_lower = if val == 0x00 { 0x01 } else { val };
                self.update_rom_offset();
            }
            0x4000...0x5fff => {
                self.bank_upper = (val as usize) & 0x3;
                self.update_rom_offset();
                self.update_ram_offset();
            }
            0x6000...0x7fff => {
                self.ram_banking = val != 0;
                self.update_rom_offset();
                self.update_ram_offset();
            }
            0xa000...0xbfff => {
                if self.ram_enabled {
                    self.ram[self.ram_bank_offset + (addr - 0xa000)] = val;
                }
            }
            _ => {
                panic!("Unrecognized write address in cartridge {:04x}={:02x}",
                       addr,
                       val)
            }
        }
    }

    pub fn disable_boot_rom(&mut self) {
        self.boot_rom_active = false;
    }

    fn update_rom_offset(&mut self) {
        let bank_upper = self.bank_upper << 5;
        let lower = if self.ram_banking { bank_upper } else { 0x00 };
        let upper = bank_upper | self.rom_bank_lower;

        let lower_bank = (lower * 0x4000) & (self.rom.len() - 1);
        let upper_bank = (upper * 0x4000) & (self.rom.len() - 1);

        self.rom_offsets = (lower_bank, upper_bank);
    }

    fn update_ram_offset(&mut self) {
        self.ram_bank_offset = if self.ram_banking {
            (self.bank_upper * 0x2000) & (self.ram.len() - 1)
        } else {
            0
        };
    }

    fn name(&self) -> String {
        let mut ret = "".to_string();

        for i in 0..16 {
            let c = self.rom[0x0134 + i];
            if c == 0 {
                break;
            }
            ret.push(c as char);
        }

        ret
    }

    fn rom_type(&self) -> u8 {
        self.rom[0x0147]
    }

    fn type_name(&self) -> &'static str {
        match self.rom_type() {
            0x00 => "ROM ONLY",
            0x01 => "ROM+MBC1",
            0x02 => "ROM+MBC1+RAM",
            0x03 => "ROM+MBC1+RAM+BATT",
            0x05 => "ROM+MBC2",
            0x06 => "ROM+MBC2+BATTERY",
            0x08 => "ROM+RAM",
            0x09 => "ROM+RAM+BATTERY",
            0x0B => "ROM+MMM01",
            0x0C => "ROM+MMM01+SRAM",
            0x0D => "ROM+MMM01+SRAM+BATT",
            0x0F => "ROM+MBC3+TIMER+BATT",
            0x10 => "ROM+MBC3+TIMER+RAM+BATT",
            0x11 => "ROM+MBC3",
            0x12 => "ROM+MBC3+RAM",
            0x13 => "ROM+MBC3+RAM+BATT",
            0x15 => "MBC4",
            0x16 => "MBC4+RAM",
            0x17 => "MBC4+RAM+BATTERY",
            0x19 => "ROM+MBC5",
            0x1A => "ROM+MBC5+RAM",
            0x1B => "ROM+MBC5+RAM+BATT",
            0x1C => "ROM+MBC5+RUMBLE",
            0x1D => "ROM+MBC5+RUMBLE+SRAM",
            0x1E => "ROM+MBC5+RUMBLE+SRAM+BATT",
            0x1F => "Pocket Camera",
            0x20 => "MBC6",
            0x22 => "MBC7+SENSOR+RUMBLE+RAM+BATTERY",
            0xFC => "POCKET CAMERA",
            0xFD => "Bandai TAMA5",
            0xFE => "Hudson HuC-3",
            0xFF => "Hudson HuC-1",
            _ => "UNRECOGNISED CART TYPE",
        }
    }

    fn rom_size(&self) -> &'static str {
        match self.rom[0x0148] {
            0x00 => "32KByte (no ROM banking)",
            0x01 => "64KByte (4 banks)",
            0x02 => "128KByte (8 banks)",
            0x03 => "256KByte (16 banks)",
            0x04 => "512KByte (32 banks)",
            0x05 => "1MByte (64 banks)  - only 63 banks used by MBC1",
            0x06 => "2MByte (128 banks) - only 125 banks used by MBC1",
            0x07 => "4MByte (256 banks)",
            0x08 => "8MByte (512 banks)",
            0x52 => "1.1MByte (72 banks)",
            0x53 => "1.2MByte (80 banks)",
            0x54 => "1.5MByte (96 banks)",
            _ => "UNRECOGNISED CART ROM SIZE",
        }
    }
}
<|endoftext|>


<commit_before>//
// rslex - a lexer generator for rust
//
// buffer.rs
// A lookahead buffer for input
//
// Andrei de A. Formiga, 2013-10-02
//

extern mod std;

use std::io::{SeekEnd, SeekSet};
use std::io::Seek;
use std::io::Reader;
//use std::io::Writer;
use std::io::File;

/// A lookahead buffer for reading input characters
struct LookaheadBuffer {
    contents: ~str,
    index: uint           // TODO: change to iterator to avoid encoding issues
}

impl LookaheadBuffer {
    fn new(s: ~str) -> LookaheadBuffer {
        LookaheadBuffer { contents: s, index: 0 }
    }

    fn from_file(fname: &str) -> LookaheadBuffer {
        let cont = file_contents(fname);
        LookaheadBuffer { contents: cont, index: 0 }
    }

    pub fn len(&self) -> uint {
        self.contents.len()
    }

    pub fn is_depleted(&self) -> bool {
        self.contents.len() == self.index
    }

    /// Returns the next char from the buffer. Behavior undefined
    /// if the buffer is depleted.
    fn next_char(&mut self) -> char {
        let res = self.contents[self.index];
        if self.index < self.contents.len() {
            self.index = self.index + 1;
        }
        res as char     // FIX: assume ASCII encoding
    }

    fn return_char(&mut self) {
        if self.index > 0 {
            self.index = self.index - 1;
        }
    }
}

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

    #[test]
    fn no_buffer_use() {
        let mut buffer = LookaheadBuffer::new(~"abcdef");
        assert_eq!(buffer.len(), 6);
        assert!(!buffer.is_depleted());
        assert_eq!(buffer.next_char(), 'a');
        assert_eq!(buffer.next_char(), 'b');
        assert_eq!(buffer.next_char(), 'c');
        assert_eq!(buffer.next_char(), 'd');
        assert_eq!(buffer.next_char(), 'e');
        assert_eq!(buffer.next_char(), 'f');
        assert!(buffer.is_depleted());
    }

    #[test]
    fn buffer_use() {
        let mut buffer = LookaheadBuffer::new(~"abcdef");
        assert_eq!(buffer.next_char(), 'a');
        buffer.return_char();
        assert_eq!(buffer.next_char(), 'a');
        assert_eq!(buffer.next_char(), 'b');
        assert_eq!(buffer.next_char(), 'c');
        buffer.return_char();
        assert_eq!(buffer.next_char(), 'c');
        assert_eq!(buffer.next_char(), 'd');
        assert_eq!(buffer.next_char(), 'e');
        assert_eq!(buffer.next_char(), 'f');
        assert!(buffer.is_depleted());
        buffer.return_char();
        assert!(!buffer.is_depleted());
        assert_eq!(buffer.next_char(), 'f');
        assert!(buffer.is_depleted());
    }

    #[test]
    fn from_file() {
        let mut buffer = LookaheadBuffer::from_file("Makefile");
        assert_eq!(buffer.next_char(), 'a');
        assert_eq!(buffer.next_char(), 'l');
        assert_eq!(buffer.next_char(), 'l');
        assert_eq!(buffer.next_char(), ':');
        assert_eq!(buffer.next_char(), ' ');
        assert_eq!(buffer.next_char(), 'r');
        assert_eq!(buffer.next_char(), 's');
        assert_eq!(buffer.next_char(), 'l');
        assert_eq!(buffer.next_char(), 'e');
        assert_eq!(buffer.next_char(), 'x');
        assert!(!buffer.is_depleted());
    }
}

// --- utility functions ----------------------------------------
fn file_contents(name: &str) -> ~str {
    let mut f = open_or_fail(name);
    read_contents(&mut f)
}

fn get_size(f: &mut File) -> u64 {
    f.seek(0, SeekEnd);
    let res = f.tell();
    f.seek(0, SeekSet);
    res
}

fn read_contents(f: &mut File) -> ~str {
    let size = get_size(f) as uint;
    let mut contents = std::vec::from_elem(size as uint, 0x00_u8);
    match f.read(contents) {
        Some(l) if l == size => std::str::from_utf8(contents),
        _ => fail!("Could not read file\n")
    }
}

fn open_or_fail(name: &str) -> File {
    match File::open(&Path::new(name)) {
        Some(f) => f,
        None => fail!("Could not open file\n")
    }
}
<commit_msg>Implemented LookaheadBuffer properly using character iteration<commit_after>//
// rslex - a lexer generator for rust
//
// buffer.rs
// A lookahead buffer for input
//
// Andrei de A. Formiga, 2013-10-02
//

extern mod std;

use std::io::{SeekEnd, SeekSet};
use std::io::Seek;
use std::io::Reader;
//use std::io::Writer;
use std::io::File;
use std::str::CharIterator;

/// A lookahead buffer for reading input characters
struct Buffer2 {
    contents: ~str,
    index: uint            // TODO: change to iterator to avoid encoding issues
}

impl Buffer2 {
    fn new(s: ~str) -> Buffer2 {
        Buffer2 { contents: s, index: 0 }
    }

    fn from_file(fname: &str) -> Buffer2 {
        let cont = file_contents(fname);
        Buffer2 { contents: cont, index: 0 }
    }

    pub fn len(&self) -> uint {
        self.contents.len()
    }

    pub fn is_depleted(&self) -> bool {
        self.contents.len() == self.index
    }

    /// Returns the next char from the buffer. Behavior undefined
    /// if the buffer is depleted.
    fn next_char(&mut self) -> char {
        let res = self.contents[self.index];
        if self.index < self.contents.len() {
            self.index = self.index + 1;
        }
        res as char     // FIX: assume ASCII encoding
    }

    fn return_char(&mut self) {
        if self.index > 0 {
            self.index = self.index - 1;
        }
    }
}

/// Allows the use of one "lookahead" character, which can be
/// returned to the stream. Basically similar to a `Peekable`
/// iterator but with a more convenient interface
/// (for a case where peek is used all the time
///  and it almost always should advance the iterator)
struct LookaheadBuffer<'r> {
    contents: &'r str,
    iter: CharIterator<'r>,
    peek: Option<char>
}

impl<'r> LookaheadBuffer<'r> {
    fn new(s: &'r str) -> LookaheadBuffer<'r> {
        LookaheadBuffer { contents: s, iter: s.iter(), peek: None }
    }

    fn len(&self) -> uint {
        self.contents.len()
    }

    fn next_char(&mut self) -> Option<char> {
        match self.peek {
            None => self.iter.next(),
            Some(c) => {
                self.peek = None;
                Some(c)
            }
        }
    }

    /// Returns `c` to the character stream, to be returned as the
    /// next char. If `return_char` is called twice without an intervening
    /// `next_char`, the buffer will forget the previous returned character.
    fn return_char(&mut self, c: char) {
        self.peek = Some(c)
    }
}

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

    #[test]
    fn no_buffer_use() {
        let mut buffer = LookaheadBuffer::new("abcdef");
        assert_eq!(buffer.len(), 6);
        assert_eq!(buffer.next_char(), Some('a'));
        assert_eq!(buffer.next_char(), Some('b'));
        assert_eq!(buffer.next_char(), Some('c'));
        assert_eq!(buffer.next_char(), Some('d'));
        assert_eq!(buffer.next_char(), Some('e'));
        assert_eq!(buffer.next_char(), Some('f'));
        assert_eq!(buffer.next_char(), None);
    }

    #[test]
    fn no_buffer_use_iterator() {
        let mut iter = "abcdef".iter().peekable();
        assert_eq!(iter.next(), Some('a'));
        assert_eq!(iter.next(), Some('b'));

        match iter.peek() {
            None => fail!("Should not be none"),
            Some(c) => assert_eq!(*c, 'c')
        }

        assert_eq!(iter.next(), Some('c'));
    }

    #[test]
    fn buffer_use_return_variable() {
        let mut buffer = LookaheadBuffer::new("abcdef");
        assert_eq!(buffer.next_char(), Some('a'));
        let c = match buffer.next_char() {
            None => fail!("Should not be none"),
            Some(ch) => ch
        };

        assert_eq!(c, 'b');

        buffer.return_char(c);

        assert_eq!(buffer.next_char(), Some('b'));
    }

    #[test]
    fn buffer_use() {
        let mut buffer = LookaheadBuffer::new("abcdef");
        assert_eq!(buffer.next_char(), Some('a'));
        buffer.return_char('a');
        assert_eq!(buffer.next_char(), Some('a'));
        assert_eq!(buffer.next_char(), Some('b'));
        assert_eq!(buffer.next_char(), Some('c'));
        buffer.return_char('c');
        assert_eq!(buffer.next_char(), Some('c'));
        assert_eq!(buffer.next_char(), Some('d'));
        assert_eq!(buffer.next_char(), Some('e'));
        assert_eq!(buffer.next_char(), Some('f'));
        assert_eq!(buffer.next_char(), None);
        buffer.return_char('f');
        assert_eq!(buffer.next_char(), Some('f'));
        assert_eq!(buffer.next_char(), None);
    }
}

// --- utility functions ----------------------------------------
fn file_contents(name: &str) -> ~str {
    let mut f = open_or_fail(name);
    read_contents(&mut f)
}

fn get_size(f: &mut File) -> u64 {
    f.seek(0, SeekEnd);
    let res = f.tell();
    f.seek(0, SeekSet);
    res
}

fn read_contents(f: &mut File) -> ~str {
    let size = get_size(f) as uint;
    let mut contents = std::vec::from_elem(size as uint, 0x00_u8);
    match f.read(contents) {
        Some(l) if l == size => std::str::from_utf8(contents),
        _ => fail!("Could not read file\n")
    }
}

fn open_or_fail(name: &str) -> File {
    match File::open(&Path::new(name)) {
        Some(f) => f,
        None => fail!("Could not open file\n")
    }
}
<|endoftext|>


<commit_before>// ignore-windows: Concurrency on Windows is not supported yet.

use std::sync::mpsc::{channel, sync_channel};
use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
use std::thread;

// Check if Rust barriers are working.

/// This test is taken from the Rust documentation.
fn check_barriers() {
    let mut handles = Vec::with_capacity(10);
    let barrier = Arc::new(Barrier::new(10));
    for _ in 0..10 {
        let c = barrier.clone();
        // The same messages will be printed together.
        // You will NOT see any interleaving.
        handles.push(thread::spawn(move || {
            println!("before wait");
            c.wait();
            println!("after wait");
        }));
    }
    // Wait for other threads to finish.
    for handle in handles {
        handle.join().unwrap();
    }
}

// Check if Rust conditional variables are working.

/// The test taken from the Rust documentation.
fn check_conditional_variables() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair2 = pair.clone();

    // Inside of our lock, spawn a new thread, and then wait for it to start.
    thread::spawn(move || {
        let (lock, cvar) = &*pair2;
        let mut started = lock.lock().unwrap();
        *started = true;
        // We notify the condvar that the value has changed.
        cvar.notify_one();
    });

    // Wait for the thread to start up.
    let (lock, cvar) = &*pair;
    let mut started = lock.lock().unwrap();
    while !*started {
        started = cvar.wait(started).unwrap();
    }
}

// Check if locks are working.

fn check_mutex() {
    let data = Arc::new(Mutex::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.lock().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }

    assert!(data.try_lock().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_write() {
    let data = Arc::new(RwLock::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.write().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }

    assert!(data.try_write().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_read_no_deadlock() {
    let l1 = Arc::new(RwLock::new(0));
    let l2 = Arc::new(RwLock::new(0));

    let l1_copy = Arc::clone(&l1);
    let l2_copy = Arc::clone(&l2);
    let _guard1 = l1.read().unwrap();
    let handle = thread::spawn(move || {
        let _guard2 = l2_copy.read().unwrap();
        thread::yield_now();
        let _guard1 = l1_copy.read().unwrap();
    });
    thread::yield_now();
    let _guard2 = l2.read().unwrap();
    handle.join().unwrap();
}

// Check if channels are working.

/// The test taken from the Rust documentation.
fn simple_send() {
    let (tx, rx) = channel();
    thread::spawn(move || {
        tx.send(10).unwrap();
    });
    assert_eq!(rx.recv().unwrap(), 10);
}

/// The test taken from the Rust documentation.
fn multiple_send() {
    let (tx, rx) = channel();
    for i in 0..10 {
        let tx = tx.clone();
        thread::spawn(move || {
            tx.send(i).unwrap();
        });
    }

    let mut sum = 0;
    for _ in 0..10 {
        let j = rx.recv().unwrap();
        assert!(0 <= j && j < 10);
        sum += j;
    }
    assert_eq!(sum, 45);
}

/// The test taken from the Rust documentation.
fn send_on_sync() {
    let (sender, receiver) = sync_channel(1);

    // this returns immediately
    sender.send(1).unwrap();

    thread::spawn(move || {
        // this will block until the previous message has been received
        sender.send(2).unwrap();
    });

    assert_eq!(receiver.recv().unwrap(), 1);
    assert_eq!(receiver.recv().unwrap(), 2);
}

// Check if Rust once statics are working.

static mut VAL: usize = 0;
static INIT: Once = Once::new();

fn get_cached_val() -> usize {
    unsafe {
        INIT.call_once(|| {
            VAL = expensive_computation();
        });
        VAL
    }
}

fn expensive_computation() -> usize {
    let mut i = 1;
    let mut c = 1;
    while i < 10000 {
        i *= c;
        c += 1;
    }
    i
}

/// The test taken from the Rust documentation.
fn check_once() {
    let handles: Vec<_> = (0..10)
        .map(|_| {
            thread::spawn(|| {
                thread::yield_now();
                let val = get_cached_val();
                assert_eq!(val, 40320);
            })
        })
        .collect();
    for handle in handles {
        handle.join().unwrap();
    }
}

fn main() {
    check_barriers();
    check_conditional_variables();
    check_mutex();
    check_rwlock_write();
    check_rwlock_read_no_deadlock();
    simple_send();
    multiple_send();
    send_on_sync();
    check_once();
}
<commit_msg>Add a timeout test for conditional variables.<commit_after>// ignore-windows: Concurrency on Windows is not supported yet.
// compile-flags: -Zmiri-disable-isolation

use std::sync::mpsc::{channel, sync_channel};
use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
use std::thread;
use std::time::{Duration, Instant};

// Check if Rust barriers are working.

/// This test is taken from the Rust documentation.
fn check_barriers() {
    let mut handles = Vec::with_capacity(10);
    let barrier = Arc::new(Barrier::new(10));
    for _ in 0..10 {
        let c = barrier.clone();
        // The same messages will be printed together.
        // You will NOT see any interleaving.
        handles.push(thread::spawn(move || {
            println!("before wait");
            c.wait();
            println!("after wait");
        }));
    }
    // Wait for other threads to finish.
    for handle in handles {
        handle.join().unwrap();
    }
}

// Check if Rust conditional variables are working.

/// The test taken from the Rust documentation.
fn check_conditional_variables() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair2 = pair.clone();

    // Inside of our lock, spawn a new thread, and then wait for it to start.
    thread::spawn(move || {
        let (lock, cvar) = &*pair2;
        let mut started = lock.lock().unwrap();
        *started = true;
        // We notify the condvar that the value has changed.
        cvar.notify_one();
    });

    // Wait for the thread to start up.
    let (lock, cvar) = &*pair;
    let mut started = lock.lock().unwrap();
    while !*started {
        started = cvar.wait(started).unwrap();
    }
}

/// Test that waiting on a conditional variable with a timeout does not
/// deadlock.
fn check_conditional_variables_timeout() {
    let lock = Mutex::new(());
    let cvar = Condvar::new();
    let guard = lock.lock().unwrap();
    let now = Instant::now();
    let _guard = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap().0;
    assert!(now.elapsed().as_millis() >= 100);
}

// Check if locks are working.

fn check_mutex() {
    let data = Arc::new(Mutex::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.lock().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }

    assert!(data.try_lock().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_write() {
    let data = Arc::new(RwLock::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.write().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }

    assert!(data.try_write().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_read_no_deadlock() {
    let l1 = Arc::new(RwLock::new(0));
    let l2 = Arc::new(RwLock::new(0));

    let l1_copy = Arc::clone(&l1);
    let l2_copy = Arc::clone(&l2);
    let _guard1 = l1.read().unwrap();
    let handle = thread::spawn(move || {
        let _guard2 = l2_copy.read().unwrap();
        thread::yield_now();
        let _guard1 = l1_copy.read().unwrap();
    });
    thread::yield_now();
    let _guard2 = l2.read().unwrap();
    handle.join().unwrap();
}

// Check if channels are working.

/// The test taken from the Rust documentation.
fn simple_send() {
    let (tx, rx) = channel();
    thread::spawn(move || {
        tx.send(10).unwrap();
    });
    assert_eq!(rx.recv().unwrap(), 10);
}

/// The test taken from the Rust documentation.
fn multiple_send() {
    let (tx, rx) = channel();
    for i in 0..10 {
        let tx = tx.clone();
        thread::spawn(move || {
            tx.send(i).unwrap();
        });
    }

    let mut sum = 0;
    for _ in 0..10 {
        let j = rx.recv().unwrap();
        assert!(0 <= j && j < 10);
        sum += j;
    }
    assert_eq!(sum, 45);
}

/// The test taken from the Rust documentation.
fn send_on_sync() {
    let (sender, receiver) = sync_channel(1);

    // this returns immediately
    sender.send(1).unwrap();

    thread::spawn(move || {
        // this will block until the previous message has been received
        sender.send(2).unwrap();
    });

    assert_eq!(receiver.recv().unwrap(), 1);
    assert_eq!(receiver.recv().unwrap(), 2);
}

// Check if Rust once statics are working.

static mut VAL: usize = 0;
static INIT: Once = Once::new();

fn get_cached_val() -> usize {
    unsafe {
        INIT.call_once(|| {
            VAL = expensive_computation();
        });
        VAL
    }
}

fn expensive_computation() -> usize {
    let mut i = 1;
    let mut c = 1;
    while i < 10000 {
        i *= c;
        c += 1;
    }
    i
}

/// The test taken from the Rust documentation.
fn check_once() {
    let handles: Vec<_> = (0..10)
        .map(|_| {
            thread::spawn(|| {
                thread::yield_now();
                let val = get_cached_val();
                assert_eq!(val, 40320);
            })
        })
        .collect();
    for handle in handles {
        handle.join().unwrap();
    }
}

fn main() {
    check_barriers();
    check_conditional_variables();
    check_conditional_variables_timeout();
    check_mutex();
    check_rwlock_write();
    check_rwlock_read_no_deadlock();
    simple_send();
    multiple_send();
    send_on_sync();
    check_once();
}
<|endoftext|>


<commit_before>#![cfg(all(
    not(target_os = "fuchsia"),
    not(target_os = "android"),
    not(target_os = "windows"),
    not(target_os = "macos")
))]

extern crate libc;
extern crate pagecache;
extern crate rand;
extern crate sled;
extern crate tests;

use std::fs;
use std::mem::size_of;
use std::path::Path;
use std::thread;
use std::time::Duration;

use rand::Rng;

use pagecache::{Config, ConfigBuilder};

const CYCLE: usize = 256;

/// Verifies that the keys in the tree are correctly recovered.
/// Panics if they are incorrect.
/// Returns the key that should be resumed at, and the current cycle value.
fn verify(tree: &sled::Tree) -> (u32, u32) {
    // key 0 should always be the highest value, as that's where we increment
    // at some point, it might go down by one
    // it should never return, or go down again after that
    let mut iter = tree.iter();
    let highest = match iter.next() {
        Some(Ok((_k, v))) => slice_to_u32(&*v),
        Some(Err(e)) => panic!("{:?}", e),
        None => return (0, 0),
    };

    let highest_vec = u32_to_vec(highest);

    // find how far we got
    let mut contiguous: u32 = 0;
    let mut lowest = 0;
    for res in iter {
        let (_k, v) = res.unwrap();
        if &v[..4] == &highest_vec[..4] {
            contiguous += 1;
        } else {
            let expected = if highest == 0 {
                CYCLE as u32 - 1
            } else {
                (highest - 1) % CYCLE as u32
            };
            let actual = slice_to_u32(&*v);
            assert_eq!(expected, actual);
            lowest = actual;
            break;
        }
    }

    // ensure nothing changes after this point
    let low_beginning = u32_to_vec(contiguous + 1);

    for res in tree.range(&*low_beginning..) {
        let (k, v): (sled::IVec, _) = res.unwrap();
        assert_eq!(
            slice_to_u32(&*v),
            lowest,
            "expected key {} to have value {}, instead it had value {}",
            slice_to_u32(&*k),
            lowest,
            slice_to_u32(&*v)
        );
    }

    (contiguous, highest)
}

fn u32_to_vec(u: u32) -> Vec<u8> {
    let buf: [u8; size_of::<u32>()] = u.to_be_bytes();
    buf.to_vec()
}

fn slice_to_u32(b: &[u8]) -> u32 {
    let mut buf = [0u8; size_of::<u32>()];
    buf.copy_from_slice(&b[..size_of::<u32>()]);

    u32::from_be_bytes(buf)
}

fn spawn_killah() {
    thread::spawn(|| {
        let runtime = rand::thread_rng().gen_range(0, 200);
        thread::sleep(Duration::from_millis(runtime));
        unsafe {
            libc::raise(9);
        }
    });
}

fn run(config: Config) {
    tests::setup_logger();
    let crash_during_initialization = rand::thread_rng().gen_bool(0.1);

    if crash_during_initialization {
        spawn_killah();
    }

    let tree = sled::Db::start(config).unwrap();

    if !crash_during_initialization {
        spawn_killah();
    }

    let (key, highest) = verify(&tree);

    let mut hu = ((highest as usize) * CYCLE) + key as usize;
    assert_eq!(hu % CYCLE, key as usize);
    assert_eq!(hu / CYCLE, highest as usize);

    loop {
        hu += 1;

        if hu / CYCLE >= CYCLE {
            hu = 0;
        }

        let key = u32_to_vec((hu % CYCLE) as u32);

        let mut value = u32_to_vec((hu / CYCLE) as u32);
        let additional_len = rand::thread_rng().gen_range(0, 1000);
        value.append(&mut vec![0u8; additional_len]);

        tree.set(&key, value).unwrap();
    }
}

fn run_without_snapshot() {
    let config = ConfigBuilder::new()
        .io_bufs(2)
        .blink_node_split_size(1024)
        .page_consolidation_threshold(10)
        .cache_bits(6)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        // drop io_buf_size to 1<<16, then 1<<17 to tease out
        // low hanging fruit more quickly
        .io_buf_size(1_000)
        .path("test_crashes".to_string())
        .snapshot_after_ops(1 << 56)
        .build();

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

fn run_with_snapshot() {
    let config = ConfigBuilder::new()
        .io_bufs(2)
        .blink_node_split_size(1024)
        .page_consolidation_threshold(10)
        .cache_bits(6)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        // drop io_buf_size to 1<<16, then 1<<17 to tease out
        // low hanging fruit more quickly
        .io_buf_size(1_000)
        .path("test_crashes_with_snapshot".to_string())
        .snapshot_after_ops(1 << 10)
        .build();

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

#[test]
#[ignore]
fn test_crash_recovery_with_runtime_snapshot() {
    cleanup_with_snapshots();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_with_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup_with_snapshots();
}

#[test]
#[ignore]
fn test_crash_recovery_no_runtime_snapshot() {
    cleanup();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_without_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup();
}

fn cleanup_with_snapshots() {
    let dir = Path::new("test_crashes_with_snapshot");
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}

fn cleanup() {
    let dir = Path::new("test_crashes");
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}
<commit_msg>adjust config of crash test<commit_after>#![cfg(all(
    not(target_os = "fuchsia"),
    not(target_os = "android"),
    not(target_os = "windows"),
    not(target_os = "macos")
))]

extern crate libc;
extern crate pagecache;
extern crate rand;
extern crate sled;
extern crate tests;

use std::fs;
use std::mem::size_of;
use std::path::Path;
use std::thread;
use std::time::Duration;

use rand::Rng;

use pagecache::{Config, ConfigBuilder};

const CYCLE: usize = 256;

/// Verifies that the keys in the tree are correctly recovered.
/// Panics if they are incorrect.
/// Returns the key that should be resumed at, and the current cycle value.
fn verify(tree: &sled::Tree) -> (u32, u32) {
    // key 0 should always be the highest value, as that's where we increment
    // at some point, it might go down by one
    // it should never return, or go down again after that
    let mut iter = tree.iter();
    let highest = match iter.next() {
        Some(Ok((_k, v))) => slice_to_u32(&*v),
        Some(Err(e)) => panic!("{:?}", e),
        None => return (0, 0),
    };

    let highest_vec = u32_to_vec(highest);

    // find how far we got
    let mut contiguous: u32 = 0;
    let mut lowest = 0;
    for res in iter {
        let (_k, v) = res.unwrap();
        if &v[..4] == &highest_vec[..4] {
            contiguous += 1;
        } else {
            let expected = if highest == 0 {
                CYCLE as u32 - 1
            } else {
                (highest - 1) % CYCLE as u32
            };
            let actual = slice_to_u32(&*v);
            assert_eq!(expected, actual);
            lowest = actual;
            break;
        }
    }

    // ensure nothing changes after this point
    let low_beginning = u32_to_vec(contiguous + 1);

    for res in tree.range(&*low_beginning..) {
        let (k, v): (sled::IVec, _) = res.unwrap();
        assert_eq!(
            slice_to_u32(&*v),
            lowest,
            "expected key {} to have value {}, instead it had value {} in db: {:?}",
            slice_to_u32(&*k),
            lowest,
            slice_to_u32(&*v),
            tree
        );
    }

    (contiguous, highest)
}

fn u32_to_vec(u: u32) -> Vec<u8> {
    let buf: [u8; size_of::<u32>()] = u.to_be_bytes();
    buf.to_vec()
}

fn slice_to_u32(b: &[u8]) -> u32 {
    let mut buf = [0u8; size_of::<u32>()];
    buf.copy_from_slice(&b[..size_of::<u32>()]);

    u32::from_be_bytes(buf)
}

fn spawn_killah() {
    thread::spawn(|| {
        let runtime = rand::thread_rng().gen_range(0, 200);
        thread::sleep(Duration::from_millis(runtime));
        unsafe {
            libc::raise(9);
        }
    });
}

fn run(config: Config) {
    tests::setup_logger();
    let crash_during_initialization = rand::thread_rng().gen_bool(0.1);

    if crash_during_initialization {
        spawn_killah();
    }

    let tree = sled::Db::start(config).unwrap();

    if !crash_during_initialization {
        spawn_killah();
    }

    let (key, highest) = verify(&tree);

    let mut hu = ((highest as usize) * CYCLE) + key as usize;
    assert_eq!(hu % CYCLE, key as usize);
    assert_eq!(hu / CYCLE, highest as usize);

    loop {
        hu += 1;

        if hu / CYCLE >= CYCLE {
            hu = 0;
        }

        let key = u32_to_vec((hu % CYCLE) as u32);

        let mut value = u32_to_vec((hu / CYCLE) as u32);
        let additional_len = rand::thread_rng().gen_range(0, 1000);
        value.append(&mut vec![0u8; additional_len]);

        tree.set(&key, value).unwrap();
    }
}

fn run_without_snapshot() {
    let config = ConfigBuilder::new()
        .async_io(false)
        .io_bufs(2)
        .blink_node_split_size(1024)
        .page_consolidation_threshold(10)
        .cache_bits(6)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        // drop io_buf_size to 1<<16, then 1<<17 to tease out
        // low hanging fruit more quickly
        .io_buf_size(1_000)
        .path("test_crashes".to_string())
        .snapshot_after_ops(1 << 56)
        .build();

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

fn run_with_snapshot() {
    let config = ConfigBuilder::new()
        .async_io(true)
        .io_bufs(2)
        .blink_node_split_size(1024)
        .page_consolidation_threshold(10)
        .cache_bits(6)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        // drop io_buf_size to 1<<16, then 1<<17 to tease out
        // low hanging fruit more quickly
        .io_buf_size(1_000)
        .path("test_crashes_with_snapshot".to_string())
        .snapshot_after_ops(5000)
        .build();

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

#[test]
#[ignore]
fn test_crash_recovery_with_runtime_snapshot() {
    cleanup_with_snapshots();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_with_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup_with_snapshots();
}

#[test]
#[ignore]
fn test_crash_recovery_no_runtime_snapshot() {
    cleanup();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_without_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup();
}

fn cleanup_with_snapshots() {
    let dir = Path::new("test_crashes_with_snapshot");
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}

fn cleanup() {
    let dir = Path::new("test_crashes");
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}
<|endoftext|>


<commit_before>//! Compiles the profiler part of the `compiler-rt` library.
//!
//! See the build.rs for libcompiler_builtins crate for details.

use std::env;
use std::path::Path;

fn main() {
    let target = env::var("TARGET").expect("TARGET was not set");
    let cfg = &mut cc::Build::new();

    let mut profile_sources = vec![
        "GCDAProfiling.c",
        "InstrProfiling.c",
        "InstrProfilingBuffer.c",
        "InstrProfilingFile.c",
        "InstrProfilingMerge.c",
        "InstrProfilingMergeFile.c",
        "InstrProfilingNameVar.c",
        "InstrProfilingPlatformDarwin.c",
        "InstrProfilingPlatformLinux.c",
        "InstrProfilingPlatformOther.c",
        "InstrProfilingPlatformWindows.c",
        "InstrProfilingRuntime.cc",
        "InstrProfilingUtil.c",
        "InstrProfilingValue.c",
        "InstrProfilingWriter.c",
    ];

    if target.contains("msvc") {
        // Don't pull in extra libraries on MSVC
        cfg.flag("/Zl");
        profile_sources.push("WindowsMMap.c");
        cfg.define("strdup", Some("_strdup"));
        cfg.define("open", Some("_open"));
        cfg.define("fdopen", Some("_fdopen"));
        cfg.define("getpid", Some("_getpid"));
        cfg.define("fileno", Some("_fileno"));
    } else {
        // Turn off various features of gcc and such, mostly copying
        // compiler-rt's build system already
        cfg.flag("-fno-builtin");
        cfg.flag("-fvisibility=hidden");
        cfg.flag("-fomit-frame-pointer");
        cfg.flag("-ffreestanding");
        cfg.define("VISIBILITY_HIDDEN", None);
        if !target.contains("windows") {
            cfg.define("COMPILER_RT_HAS_UNAME", Some("1"));
        } else {
            profile_sources.push("WindowsMMap.c");
        }
    }

    // Assume that the Unixes we are building this for have fnctl() available
    if env::var_os("CARGO_CFG_UNIX").is_some() {
        cfg.define("COMPILER_RT_HAS_FCNTL_LCK", Some("1"));
    }

    // This should be a pretty good heuristic for when to set
    // COMPILER_RT_HAS_ATOMICS
    if env::var_os("CARGO_CFG_TARGET_HAS_ATOMIC")
        .map(|features| features.to_string_lossy().to_lowercase().contains("cas"))
        .unwrap_or(false)
    {
        cfg.define("COMPILER_RT_HAS_ATOMICS", Some("1"));
    }

    let root = env::var_os("RUST_COMPILER_RT_ROOT").unwrap();
    let root = Path::new(&root);

    for src in profile_sources {
        cfg.file(root.join("lib").join("profile").join(src));
    }

    cfg.warnings(false);
    cfg.compile("profiler-rt");
}
<commit_msg>Add include path when compiling profiler runtime<commit_after>//! Compiles the profiler part of the `compiler-rt` library.
//!
//! See the build.rs for libcompiler_builtins crate for details.

use std::env;
use std::path::Path;

fn main() {
    let target = env::var("TARGET").expect("TARGET was not set");
    let cfg = &mut cc::Build::new();

    let mut profile_sources = vec![
        "GCDAProfiling.c",
        "InstrProfiling.c",
        "InstrProfilingBuffer.c",
        "InstrProfilingFile.c",
        "InstrProfilingMerge.c",
        "InstrProfilingMergeFile.c",
        "InstrProfilingNameVar.c",
        "InstrProfilingPlatformDarwin.c",
        "InstrProfilingPlatformLinux.c",
        "InstrProfilingPlatformOther.c",
        "InstrProfilingPlatformWindows.c",
        "InstrProfilingRuntime.cc",
        "InstrProfilingUtil.c",
        "InstrProfilingValue.c",
        "InstrProfilingWriter.c",
    ];

    if target.contains("msvc") {
        // Don't pull in extra libraries on MSVC
        cfg.flag("/Zl");
        profile_sources.push("WindowsMMap.c");
        cfg.define("strdup", Some("_strdup"));
        cfg.define("open", Some("_open"));
        cfg.define("fdopen", Some("_fdopen"));
        cfg.define("getpid", Some("_getpid"));
        cfg.define("fileno", Some("_fileno"));
    } else {
        // Turn off various features of gcc and such, mostly copying
        // compiler-rt's build system already
        cfg.flag("-fno-builtin");
        cfg.flag("-fvisibility=hidden");
        cfg.flag("-fomit-frame-pointer");
        cfg.flag("-ffreestanding");
        cfg.define("VISIBILITY_HIDDEN", None);
        if !target.contains("windows") {
            cfg.define("COMPILER_RT_HAS_UNAME", Some("1"));
        } else {
            profile_sources.push("WindowsMMap.c");
        }
    }

    // Assume that the Unixes we are building this for have fnctl() available
    if env::var_os("CARGO_CFG_UNIX").is_some() {
        cfg.define("COMPILER_RT_HAS_FCNTL_LCK", Some("1"));
    }

    // This should be a pretty good heuristic for when to set
    // COMPILER_RT_HAS_ATOMICS
    if env::var_os("CARGO_CFG_TARGET_HAS_ATOMIC")
        .map(|features| features.to_string_lossy().to_lowercase().contains("cas"))
        .unwrap_or(false)
    {
        cfg.define("COMPILER_RT_HAS_ATOMICS", Some("1"));
    }

    let root = env::var_os("RUST_COMPILER_RT_ROOT").unwrap();
    let root = Path::new(&root);

    for src in profile_sources {
        cfg.file(root.join("lib").join("profile").join(src));
    }

    cfg.include(root.join("include"));
    cfg.warnings(false);
    cfg.compile("profiler-rt");
}
<|endoftext|>


<commit_before>use app::App;
use texture::Texture;
use transform::Transform;
use component::Component;
use component::Message;
use std::collections::BTreeMap;
use std::mem;
use physics::nphysics2d::object::{RigidBody, RigidBodyHandle};
use physics::nphysics2d::math::Matrix;
use physics::nalgebra::{Rotation2, Vector2, Vector1};

pub struct GameObject {
    pub transform: Transform,
    pub texture: Texture,
    body: Option<RigidBodyHandle<f64>>,
    // When searching for a component associated with a GameObject you will need to search both of
    // these collections. At any given time either one of them could contain the Component you are
    // searching for. As messages are distributed to components they are migrated from
    // components to messaged_components and once the distribution of a message is complete
    // the two collections are swapped.
    components: BTreeMap<i32, Box<Component>>, // These have not had a message sent (yet).
    messaged_components: BTreeMap<i32, Box<Component>>, // These have had a message sent.
}

impl GameObject {
    pub fn new(app: &mut App) -> GameObject {
        GameObject {
            transform: Transform::new(),
            components: BTreeMap::new(),
            messaged_components: BTreeMap::new(),
            texture: Texture::empty(app),
            body: None,
        }
    }

    pub fn update(&mut self, app: &mut App, delta_time: f64) {
        let message = &Message::Update { delta_time: delta_time };
        for key in self.components.keys().map(|x| *x).collect::<Vec<i32>>() {
            if let Some(mut component) = self.components.remove(&key) {
                component.receive_message(app, self, &message);
                self.messaged_components.insert(key, component);
            }
        }
        assert_eq!(self.components.len(), 0);
        mem::swap(&mut self.components, &mut self.messaged_components);
    }

    pub fn component_indices(&self) -> Vec<i32> {
        self.components.keys().map(|x| *x).collect::<Vec<i32>>()
    }

    pub fn get_component(&self, index: i32) -> Option<&Box<Component>> {
        self.components.get(&index)
    }

    pub fn add_component_at_index(&mut self, component: Box<Component>, index: i32) {
        self.components.insert(index, component);
    }

    pub fn add_component(&mut self, component: Box<Component>) {
        let new_key = self.components.keys().nth(0).unwrap_or(&1) - 1;
        self.components.insert(new_key, component);
    }

    pub fn set_rigid_body(&mut self, app: &mut App, rigid_body: RigidBody<f64>) {
        self.body = Some(app.world.add_rigid_body(rigid_body));
    }
}

pub fn copy_from_physics(game_object: &mut GameObject) {
    if let &Some(ref body_box) = &game_object.body {
        let body_borrow = body_box.borrow();
        *game_object.transform.mut_x() = body_borrow.position().translation.x;
        *game_object.transform.mut_y() = body_borrow.position().translation.y;
        let matrix = body_borrow.position().rotation.submatrix();
        let y = matrix.m12;
        let x = matrix.m11;
        *game_object.transform.mut_rotation() = y.atan2(x);
    }
}

pub fn copy_to_physics(game_object: &mut GameObject) {
    if let Some(ref mut body_box) = game_object.body {
        body_box.borrow_mut().set_transformation(Matrix::<f64> {
            rotation: Rotation2::new(Vector1 { x: *game_object.transform.rotation() }),
            translation: Vector2 {
                x: *game_object.transform.x(),
                y: *game_object.transform.y(),
            },
        });
    }
}
<commit_msg>Missed a file<commit_after>use app::App;
use texture::Texture;
use transform::Transform;
use component::Component;
use component::Message;
use std::collections::BTreeMap;
use std::any::Any;
use std::any::TypeId;
use physics::nphysics2d::object::{RigidBody, RigidBodyHandle};
use physics::nphysics2d::math::Matrix;
use physics::nalgebra::{Rotation2, Vector2, Vector1};

pub struct GameObject {
    pub transform: Transform,
    pub texture: Texture,
    body: Option<RigidBodyHandle<f64>>,
    components: BTreeMap<i32, Box<Component>>,
    component_types: BTreeMap<i32, TypeId>, // Identical to components just stores their type instead.
}

impl GameObject {
    pub fn new(app: &mut App) -> GameObject {
        GameObject {
            transform: Transform::new(),
            components: BTreeMap::new(),
            component_types: BTreeMap::new(),
            texture: Texture::empty(app),
            body: None,
        }
    }

    pub fn update(&mut self, app: &mut App, delta_time: f64) {
        let message = &Message::Update { delta_time: delta_time };
        for key in self.components.keys().map(|x| *x).collect::<Vec<i32>>() {
            if let Some(mut component) = self.components.remove(&key) {
                component.receive_message(app, self, &message);
                self.components.insert(key, component);
            }
        }
    }

    pub fn component_indices(&self) -> Vec<i32> {
        self.components.keys().map(|x| *x).collect::<Vec<i32>>()
    }

    pub fn get_components_of_type<T>(&self) -> Vec<i32> where T: Component + 'static {
        self.component_types.iter().filter_map(|(k, v)| {
            if *v == TypeId::of::<T>() {Some(*k)}
            else {None}
        }).collect::<Vec<i32>>()
    }

    pub fn get_component(&mut self, index: i32) -> Option<&mut Box<Component>> {
        self.components.get_mut(&index)
    }

    pub fn add_component_at_index(&mut self, component: Box<Component>, index: i32) {
        self.components.insert(index, component);
    }

    pub fn add_component<T>(&mut self, component: T) -> i32 where T: Component + 'static {
        let new_key = self.components.keys().nth(0).unwrap_or(&1) - 1;
        self.component_types.insert(new_key, TypeId::of::<T>());
        self.components.insert(new_key, Box::new(component));
        new_key
    }

    pub fn set_rigid_body(&mut self, app: &mut App, rigid_body: RigidBody<f64>) {
        self.body = Some(app.world.add_rigid_body(rigid_body));
    }
}

pub fn copy_from_physics(game_object: &mut GameObject) {
    if let &Some(ref body_box) = &game_object.body {
        let body_borrow = body_box.borrow();
        *game_object.transform.mut_x() = body_borrow.position().translation.x;
        *game_object.transform.mut_y() = body_borrow.position().translation.y;
        let matrix = body_borrow.position().rotation.submatrix();
        let y = matrix.m12;
        let x = matrix.m11;
        *game_object.transform.mut_rotation() = y.atan2(x);
    }
}

pub fn copy_to_physics(game_object: &mut GameObject) {
    if let Some(ref mut body_box) = game_object.body {
        body_box.borrow_mut().set_transformation(Matrix::<f64> {
            rotation: Rotation2::new(Vector1 { x: *game_object.transform.rotation() }),
            translation: Vector2 {
                x: *game_object.transform.x(),
                y: *game_object.transform.y(),
            },
        });
    }
}
<|endoftext|>