<commit_before>#![deny(bare_trait_objects)]

mod compiler;
mod decls;
mod error;
mod function;
mod heap;
mod load;
mod module;
mod name;
mod output;
mod pointer;
mod runtime;
pub mod signature;
mod sparsedata;
mod stack_probe;
mod table;
mod traps;
mod types;
mod validate;

use crate::load::read_bytes;
pub use crate::{
    compiler::{
        Compiler, CompilerBuilder, CpuFeatures, OptLevel, SpecificFeature, TargetCpu, TargetVersion,
    },
    error::Error,
    heap::HeapSettings,
    load::read_module,
};
pub use lucet_module::{bindings::Bindings, VersionInfo};
use signature::{PublicKey, SecretKey};
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
pub use validate::{Error as ValidationError, Validator, ValidatorBuilder, WasiMode};

// Re-export `Triple` and `BackendVariant` so that clients can use these types
// without needing a direct dependency on the respective source crates.
pub use cranelift_codegen::isa::BackendVariant;
pub use target_lexicon::Triple;

enum LucetcInput {
    Bytes(Vec<u8>),
    Path(PathBuf),
}

pub struct Lucetc {
    input: LucetcInput,
    bindings: Vec<Bindings>,
    builder: CompilerBuilder,
    sk: Option<SecretKey>,
    pk: Option<PublicKey>,
    sign: bool,
    verify: bool,
    translate_wat: bool,
}

pub trait AsLucetc {
    fn as_lucetc(&mut self) -> &mut Lucetc;
}

impl AsLucetc for Lucetc {
    fn as_lucetc(&mut self) -> &mut Lucetc {
        self
    }
}

pub trait LucetcOpts {
    fn bindings(&mut self, bindings: Bindings);
    fn with_bindings(self, bindings: Bindings) -> Self;

    fn target(&mut self, target: Triple);
    fn with_target(self, target: Triple) -> Self;

    fn target_version(&mut self, target: TargetVersion);
    fn with_target_version(self, target: TargetVersion) -> Self;

    fn backend_variant(&mut self, variant: BackendVariant);
    fn with_backend_variant(self, variant: BackendVariant) -> Self;

    fn opt_level(&mut self, opt_level: OptLevel);
    fn with_opt_level(self, opt_level: OptLevel) -> Self;

    fn cpu_features(&mut self, cpu_features: CpuFeatures);
    fn with_cpu_features(self, cpu_features: CpuFeatures) -> Self;

    fn validator(&mut self, validator: Validator);
    fn with_validator(self, validator: Validator) -> Self;

    fn version_info(&mut self, version_info: VersionInfo);
    fn with_version_info(self, version_info: VersionInfo) -> Self;

    fn min_reserved_size(&mut self, min_reserved_size: u64);
    fn with_min_reserved_size(self, min_reserved_size: u64) -> Self;

    fn max_reserved_size(&mut self, max_reserved_size: u64);
    fn with_max_reserved_size(self, max_reserved_size: u64) -> Self;

    /// Set the reserved size exactly.
    ///
    /// Equivalent to setting the minimum and maximum reserved sizes to the same value.
    fn reserved_size(&mut self, reserved_size: u64);
    /// Set the reserved size exactly.
    ///
    /// Equivalent to setting the minimum and maximum reserved sizes to the same value.
    fn with_reserved_size(self, reserved_size: u64) -> Self;

    fn guard_size(&mut self, guard_size: u64);
    fn with_guard_size(self, guard_size: u64) -> Self;

    fn pk(&mut self, pk: PublicKey);
    fn with_pk(self, pk: PublicKey) -> Self;
    fn sk(&mut self, sk: SecretKey);
    fn with_sk(self, sk: SecretKey) -> Self;
    fn verify(&mut self);
    fn with_verify(self) -> Self;
    fn sign(&mut self);
    fn with_sign(self) -> Self;
    fn count_instructions(&mut self, enable_count: bool);
    fn with_count_instructions(self, enable_count: bool) -> Self;
    fn canonicalize_nans(&mut self, enable_canonicalize_nans: bool);
    fn with_canonicalize_nans(self, enable_canonicalize_nans: bool) -> Self;
    fn veriwasm(&mut self, veriwasm: bool);
    fn with_veriwasm(self, veriwasm: bool) -> Self;
    fn translate_wat(&mut self, enable_translate_wat: bool);
    fn with_translate_wat(self, enable_translate_wat: bool) -> Self;
}

impl<T: AsLucetc> LucetcOpts for T {
    fn bindings(&mut self, bindings: Bindings) {
        self.as_lucetc().bindings.push(bindings);
    }

    fn with_bindings(mut self, bindings: Bindings) -> Self {
        self.bindings(bindings);
        self
    }

    fn target(&mut self, target: Triple) {
        self.as_lucetc().builder.target(target);
    }

    fn with_target(mut self, target: Triple) -> Self {
        self.target(target);
        self
    }

    fn target_version(&mut self, target_version: TargetVersion) {
        self.as_lucetc().builder.target_version(target_version);
    }

    fn with_target_version(mut self, target_version: TargetVersion) -> Self {
        self.target_version(target_version);
        self
    }

    fn backend_variant(&mut self, variant: BackendVariant) {
        self.as_lucetc().builder.backend_variant(variant);
    }

    fn with_backend_variant(mut self, variant: BackendVariant) -> Self {
        self.backend_variant(variant);
        self
    }

    fn opt_level(&mut self, opt_level: OptLevel) {
        self.as_lucetc().builder.opt_level(opt_level);
    }

    fn with_opt_level(mut self, opt_level: OptLevel) -> Self {
        self.opt_level(opt_level);
        self
    }

    fn cpu_features(&mut self, cpu_features: CpuFeatures) {
        self.as_lucetc().builder.cpu_features(cpu_features);
    }

    fn with_cpu_features(mut self, cpu_features: CpuFeatures) -> Self {
        self.cpu_features(cpu_features);
        self
    }

    fn validator(&mut self, validator: Validator) {
        self.as_lucetc().builder.validator(Some(validator));
    }

    fn with_validator(mut self, validator: Validator) -> Self {
        self.validator(validator);
        self
    }

    fn version_info(&mut self, version_info: VersionInfo) {
        self.as_lucetc().builder.version_info(Some(version_info));
    }

    fn with_version_info(mut self, version_info: VersionInfo) -> Self {
        self.version_info(version_info);
        self
    }

    fn min_reserved_size(&mut self, min_reserved_size: u64) {
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .min_reserved_size = min_reserved_size;
    }

    fn with_min_reserved_size(mut self, min_reserved_size: u64) -> Self {
        self.min_reserved_size(min_reserved_size);
        self
    }

    fn max_reserved_size(&mut self, max_reserved_size: u64) {
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .max_reserved_size = max_reserved_size;
    }

    fn with_max_reserved_size(mut self, max_reserved_size: u64) -> Self {
        self.max_reserved_size(max_reserved_size);
        self
    }

    fn reserved_size(&mut self, reserved_size: u64) {
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .min_reserved_size = reserved_size;
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .max_reserved_size = reserved_size;
    }

    fn with_reserved_size(mut self, reserved_size: u64) -> Self {
        self.reserved_size(reserved_size);
        self
    }

    fn guard_size(&mut self, guard_size: u64) {
        self.as_lucetc().builder.heap_settings_mut().guard_size = guard_size;
    }

    fn with_guard_size(mut self, guard_size: u64) -> Self {
        self.guard_size(guard_size);
        self
    }

    fn pk(&mut self, pk: PublicKey) {
        self.as_lucetc().pk = Some(pk);
    }

    fn with_pk(mut self, pk: PublicKey) -> Self {
        self.pk(pk);
        self
    }

    fn sk(&mut self, sk: SecretKey) {
        self.as_lucetc().sk = Some(sk);
    }

    fn with_sk(mut self, sk: SecretKey) -> Self {
        self.sk(sk);
        self
    }

    fn verify(&mut self) {
        self.as_lucetc().verify = true;
    }

    fn with_verify(mut self) -> Self {
        self.verify();
        self
    }

    fn sign(&mut self) {
        self.as_lucetc().sign = true;
    }

    fn with_sign(mut self) -> Self {
        self.sign();
        self
    }

    fn count_instructions(&mut self, count_instructions: bool) {
        self.as_lucetc()
            .builder
            .count_instructions(count_instructions);
    }

    fn with_count_instructions(mut self, count_instructions: bool) -> Self {
        self.count_instructions(count_instructions);
        self
    }

    fn canonicalize_nans(&mut self, enable_nans_canonicalization: bool) {
        self.as_lucetc()
            .builder
            .canonicalize_nans(enable_nans_canonicalization);
    }

    fn with_canonicalize_nans(mut self, enable_nans_canonicalization: bool) -> Self {
        self.canonicalize_nans(enable_nans_canonicalization);
        self
    }
    fn translate_wat(&mut self, enable_translate_wat: bool) {
        self.as_lucetc().translate_wat = enable_translate_wat;
    }

    fn with_translate_wat(mut self, enable_translate_wat: bool) -> Self {
        self.translate_wat(enable_translate_wat);
        self
    }

    fn veriwasm(&mut self, veriwasm: bool) {
        self.as_lucetc().builder.veriwasm(veriwasm);
    }

    fn with_veriwasm(mut self, veriwasm: bool) -> Self {
        self.veriwasm(veriwasm);
        self
    }
}

impl Lucetc {
    pub fn new(input: impl AsRef<Path>) -> Self {
        let input = input.as_ref();
        Self {
            input: LucetcInput::Path(input.to_owned()),
            bindings: vec![],
            builder: Compiler::builder(),
            pk: None,
            sk: None,
            sign: false,
            verify: false,
            translate_wat: true,
        }
    }

    pub fn try_from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, Error> {
        let input = read_bytes(bytes.as_ref().to_vec())?;
        Ok(Self {
            input: LucetcInput::Bytes(input),
            bindings: vec![],
            builder: Compiler::builder(),
            pk: None,
            sk: None,
            sign: false,
            verify: false,
            translate_wat: false,
        })
    }

    fn build(&self) -> Result<(Vec<u8>, Bindings), Error> {
        let module_binary = match &self.input {
            LucetcInput::Bytes(bytes) => bytes.clone(),
            LucetcInput::Path(path) => {
                read_module(&path, &self.pk, self.verify, self.translate_wat)?
            }
        };

        // Collect set of Bindings into a single Bindings:
        let mut bindings = Bindings::empty();
        for binding in self.bindings.iter() {
            bindings.extend(binding)?;
        }

        Ok((module_binary, bindings))
    }

    pub fn object_file(&self, output: impl AsRef<Path>) -> Result<(), Error> {
        let (module_contents, bindings) = self.build()?;
        let compiler = self.builder.create(&module_contents, &bindings)?;
        let obj = compiler.object_file()?;
        obj.write(output.as_ref())?;

        Ok(())
    }

    pub fn clif_ir(&self, output: impl AsRef<Path>) -> Result<(), Error> {
        let (module_contents, bindings) = self.build()?;

        let compiler = self.builder.create(&module_contents, &bindings)?;

        compiler.cranelift_funcs()?.write(&output)?;

        Ok(())
    }

    pub fn shared_object_file(&self, output: impl AsRef<Path>) -> Result<(), Error> {
        let dir = tempfile::Builder::new().prefix("lucetc").tempdir()?;
        let objpath = dir.path().join("tmp.o");
        self.object_file(objpath.clone())?;
        link_so(
            objpath,
            self.builder.target_ref(),
            &output,
            self.builder.target_version_ref(),
        )?;
        if self.sign {
            let sk = self.sk.as_ref().ok_or(Error::Signature(
                "signing requires a secret key".to_string(),
            ))?;
            signature::sign_module(&output, sk)?;
        }
        Ok(())
    }
}

const LD_DEFAULT: &str = "ld";

fn link_so(
    objpath: impl AsRef<Path>,
    target: &Triple,
    sopath: impl AsRef<Path>,
    target_version: &TargetVersion,
) -> Result<(), Error> {
    // Let `LD` be something like "clang --target=... ..." for convenience.
    let env_ld = env::var("LD").unwrap_or(LD_DEFAULT.into());
    let mut ld_iter = env_ld.split_whitespace();
    let ld_prog = ld_iter.next().expect("LD must not be empty");
    let mut cmd_ld = Command::new(ld_prog);
    for flag in ld_iter {
        cmd_ld.arg(flag);
    }

    cmd_ld.arg(objpath.as_ref());
    let env_ldflags =
        env::var("LDFLAGS").unwrap_or_else(|_| ldflags_default(target, target_version));
    for flag in env_ldflags.split_whitespace() {
        cmd_ld.arg(flag);
    }

    output_arg_for(&mut cmd_ld, target, sopath);

    let run_ld = cmd_ld.output()?;

    if !run_ld.status.success() {
        let message = format!(
            "ld of {} failed: {}",
            objpath.as_ref().to_str().unwrap(),
            String::from_utf8_lossy(&run_ld.stderr)
        );
        return Err(Error::LdError(message));
    }
    Ok(())
}

fn output_arg_for(cmd_ld: &mut Command, target: &Triple, sopath: impl AsRef<Path>) {
    use target_lexicon::{Environment, OperatingSystem};

    if target.operating_system != OperatingSystem::Windows || target.environment == Environment::Gnu
    {
        cmd_ld.arg("-o");
        cmd_ld.arg(sopath.as_ref());
        return;
    }

    assert!(target.environment == Environment::Msvc);

    cmd_ld.arg(format!("/out:{:?}", sopath.as_ref()));
}

fn ldflags_default(target: &Triple, target_version: &TargetVersion) -> String {
    use target_lexicon::OperatingSystem;

    let mut flags = match target.operating_system {
        OperatingSystem::Linux
        | OperatingSystem::Freebsd
        | OperatingSystem::Dragonfly
        | OperatingSystem::Netbsd
        | OperatingSystem::Openbsd => "-shared",
        OperatingSystem::Darwin | OperatingSystem::MacOSX { .. } => {
            "-dylib -dead_strip -export_dynamic -undefined dynamic_lookup"
        }
        _ => panic!(
            "Cannot determine default flags for {}.

Please define the LDFLAGS environment variable with the necessary command-line
flags for generating shared libraries.",
            target
        ),
    }
    .to_owned();
    if let Some(version_settings) = target_version.ld_flags() {
        flags.push(' ');
        flags.push_str(&version_settings);
    }
    flags
}
<commit_msg>show the entire command for LdError (#676)<commit_after>#![deny(bare_trait_objects)]

mod compiler;
mod decls;
mod error;
mod function;
mod heap;
mod load;
mod module;
mod name;
mod output;
mod pointer;
mod runtime;
pub mod signature;
mod sparsedata;
mod stack_probe;
mod table;
mod traps;
mod types;
mod validate;

use crate::load::read_bytes;
pub use crate::{
    compiler::{
        Compiler, CompilerBuilder, CpuFeatures, OptLevel, SpecificFeature, TargetCpu, TargetVersion,
    },
    error::Error,
    heap::HeapSettings,
    load::read_module,
};
pub use lucet_module::{bindings::Bindings, VersionInfo};
use signature::{PublicKey, SecretKey};
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
pub use validate::{Error as ValidationError, Validator, ValidatorBuilder, WasiMode};

// Re-export `Triple` and `BackendVariant` so that clients can use these types
// without needing a direct dependency on the respective source crates.
pub use cranelift_codegen::isa::BackendVariant;
pub use target_lexicon::Triple;

enum LucetcInput {
    Bytes(Vec<u8>),
    Path(PathBuf),
}

pub struct Lucetc {
    input: LucetcInput,
    bindings: Vec<Bindings>,
    builder: CompilerBuilder,
    sk: Option<SecretKey>,
    pk: Option<PublicKey>,
    sign: bool,
    verify: bool,
    translate_wat: bool,
}

pub trait AsLucetc {
    fn as_lucetc(&mut self) -> &mut Lucetc;
}

impl AsLucetc for Lucetc {
    fn as_lucetc(&mut self) -> &mut Lucetc {
        self
    }
}

pub trait LucetcOpts {
    fn bindings(&mut self, bindings: Bindings);
    fn with_bindings(self, bindings: Bindings) -> Self;

    fn target(&mut self, target: Triple);
    fn with_target(self, target: Triple) -> Self;

    fn target_version(&mut self, target: TargetVersion);
    fn with_target_version(self, target: TargetVersion) -> Self;

    fn backend_variant(&mut self, variant: BackendVariant);
    fn with_backend_variant(self, variant: BackendVariant) -> Self;

    fn opt_level(&mut self, opt_level: OptLevel);
    fn with_opt_level(self, opt_level: OptLevel) -> Self;

    fn cpu_features(&mut self, cpu_features: CpuFeatures);
    fn with_cpu_features(self, cpu_features: CpuFeatures) -> Self;

    fn validator(&mut self, validator: Validator);
    fn with_validator(self, validator: Validator) -> Self;

    fn version_info(&mut self, version_info: VersionInfo);
    fn with_version_info(self, version_info: VersionInfo) -> Self;

    fn min_reserved_size(&mut self, min_reserved_size: u64);
    fn with_min_reserved_size(self, min_reserved_size: u64) -> Self;

    fn max_reserved_size(&mut self, max_reserved_size: u64);
    fn with_max_reserved_size(self, max_reserved_size: u64) -> Self;

    /// Set the reserved size exactly.
    ///
    /// Equivalent to setting the minimum and maximum reserved sizes to the same value.
    fn reserved_size(&mut self, reserved_size: u64);
    /// Set the reserved size exactly.
    ///
    /// Equivalent to setting the minimum and maximum reserved sizes to the same value.
    fn with_reserved_size(self, reserved_size: u64) -> Self;

    fn guard_size(&mut self, guard_size: u64);
    fn with_guard_size(self, guard_size: u64) -> Self;

    fn pk(&mut self, pk: PublicKey);
    fn with_pk(self, pk: PublicKey) -> Self;
    fn sk(&mut self, sk: SecretKey);
    fn with_sk(self, sk: SecretKey) -> Self;
    fn verify(&mut self);
    fn with_verify(self) -> Self;
    fn sign(&mut self);
    fn with_sign(self) -> Self;
    fn count_instructions(&mut self, enable_count: bool);
    fn with_count_instructions(self, enable_count: bool) -> Self;
    fn canonicalize_nans(&mut self, enable_canonicalize_nans: bool);
    fn with_canonicalize_nans(self, enable_canonicalize_nans: bool) -> Self;
    fn veriwasm(&mut self, veriwasm: bool);
    fn with_veriwasm(self, veriwasm: bool) -> Self;
    fn translate_wat(&mut self, enable_translate_wat: bool);
    fn with_translate_wat(self, enable_translate_wat: bool) -> Self;
}

impl<T: AsLucetc> LucetcOpts for T {
    fn bindings(&mut self, bindings: Bindings) {
        self.as_lucetc().bindings.push(bindings);
    }

    fn with_bindings(mut self, bindings: Bindings) -> Self {
        self.bindings(bindings);
        self
    }

    fn target(&mut self, target: Triple) {
        self.as_lucetc().builder.target(target);
    }

    fn with_target(mut self, target: Triple) -> Self {
        self.target(target);
        self
    }

    fn target_version(&mut self, target_version: TargetVersion) {
        self.as_lucetc().builder.target_version(target_version);
    }

    fn with_target_version(mut self, target_version: TargetVersion) -> Self {
        self.target_version(target_version);
        self
    }

    fn backend_variant(&mut self, variant: BackendVariant) {
        self.as_lucetc().builder.backend_variant(variant);
    }

    fn with_backend_variant(mut self, variant: BackendVariant) -> Self {
        self.backend_variant(variant);
        self
    }

    fn opt_level(&mut self, opt_level: OptLevel) {
        self.as_lucetc().builder.opt_level(opt_level);
    }

    fn with_opt_level(mut self, opt_level: OptLevel) -> Self {
        self.opt_level(opt_level);
        self
    }

    fn cpu_features(&mut self, cpu_features: CpuFeatures) {
        self.as_lucetc().builder.cpu_features(cpu_features);
    }

    fn with_cpu_features(mut self, cpu_features: CpuFeatures) -> Self {
        self.cpu_features(cpu_features);
        self
    }

    fn validator(&mut self, validator: Validator) {
        self.as_lucetc().builder.validator(Some(validator));
    }

    fn with_validator(mut self, validator: Validator) -> Self {
        self.validator(validator);
        self
    }

    fn version_info(&mut self, version_info: VersionInfo) {
        self.as_lucetc().builder.version_info(Some(version_info));
    }

    fn with_version_info(mut self, version_info: VersionInfo) -> Self {
        self.version_info(version_info);
        self
    }

    fn min_reserved_size(&mut self, min_reserved_size: u64) {
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .min_reserved_size = min_reserved_size;
    }

    fn with_min_reserved_size(mut self, min_reserved_size: u64) -> Self {
        self.min_reserved_size(min_reserved_size);
        self
    }

    fn max_reserved_size(&mut self, max_reserved_size: u64) {
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .max_reserved_size = max_reserved_size;
    }

    fn with_max_reserved_size(mut self, max_reserved_size: u64) -> Self {
        self.max_reserved_size(max_reserved_size);
        self
    }

    fn reserved_size(&mut self, reserved_size: u64) {
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .min_reserved_size = reserved_size;
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .max_reserved_size = reserved_size;
    }

    fn with_reserved_size(mut self, reserved_size: u64) -> Self {
        self.reserved_size(reserved_size);
        self
    }

    fn guard_size(&mut self, guard_size: u64) {
        self.as_lucetc().builder.heap_settings_mut().guard_size = guard_size;
    }

    fn with_guard_size(mut self, guard_size: u64) -> Self {
        self.guard_size(guard_size);
        self
    }

    fn pk(&mut self, pk: PublicKey) {
        self.as_lucetc().pk = Some(pk);
    }

    fn with_pk(mut self, pk: PublicKey) -> Self {
        self.pk(pk);
        self
    }

    fn sk(&mut self, sk: SecretKey) {
        self.as_lucetc().sk = Some(sk);
    }

    fn with_sk(mut self, sk: SecretKey) -> Self {
        self.sk(sk);
        self
    }

    fn verify(&mut self) {
        self.as_lucetc().verify = true;
    }

    fn with_verify(mut self) -> Self {
        self.verify();
        self
    }

    fn sign(&mut self) {
        self.as_lucetc().sign = true;
    }

    fn with_sign(mut self) -> Self {
        self.sign();
        self
    }

    fn count_instructions(&mut self, count_instructions: bool) {
        self.as_lucetc()
            .builder
            .count_instructions(count_instructions);
    }

    fn with_count_instructions(mut self, count_instructions: bool) -> Self {
        self.count_instructions(count_instructions);
        self
    }

    fn canonicalize_nans(&mut self, enable_nans_canonicalization: bool) {
        self.as_lucetc()
            .builder
            .canonicalize_nans(enable_nans_canonicalization);
    }

    fn with_canonicalize_nans(mut self, enable_nans_canonicalization: bool) -> Self {
        self.canonicalize_nans(enable_nans_canonicalization);
        self
    }
    fn translate_wat(&mut self, enable_translate_wat: bool) {
        self.as_lucetc().translate_wat = enable_translate_wat;
    }

    fn with_translate_wat(mut self, enable_translate_wat: bool) -> Self {
        self.translate_wat(enable_translate_wat);
        self
    }

    fn veriwasm(&mut self, veriwasm: bool) {
        self.as_lucetc().builder.veriwasm(veriwasm);
    }

    fn with_veriwasm(mut self, veriwasm: bool) -> Self {
        self.veriwasm(veriwasm);
        self
    }
}

impl Lucetc {
    pub fn new(input: impl AsRef<Path>) -> Self {
        let input = input.as_ref();
        Self {
            input: LucetcInput::Path(input.to_owned()),
            bindings: vec![],
            builder: Compiler::builder(),
            pk: None,
            sk: None,
            sign: false,
            verify: false,
            translate_wat: true,
        }
    }

    pub fn try_from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, Error> {
        let input = read_bytes(bytes.as_ref().to_vec())?;
        Ok(Self {
            input: LucetcInput::Bytes(input),
            bindings: vec![],
            builder: Compiler::builder(),
            pk: None,
            sk: None,
            sign: false,
            verify: false,
            translate_wat: false,
        })
    }

    fn build(&self) -> Result<(Vec<u8>, Bindings), Error> {
        let module_binary = match &self.input {
            LucetcInput::Bytes(bytes) => bytes.clone(),
            LucetcInput::Path(path) => {
                read_module(&path, &self.pk, self.verify, self.translate_wat)?
            }
        };

        // Collect set of Bindings into a single Bindings:
        let mut bindings = Bindings::empty();
        for binding in self.bindings.iter() {
            bindings.extend(binding)?;
        }

        Ok((module_binary, bindings))
    }

    pub fn object_file(&self, output: impl AsRef<Path>) -> Result<(), Error> {
        let (module_contents, bindings) = self.build()?;
        let compiler = self.builder.create(&module_contents, &bindings)?;
        let obj = compiler.object_file()?;
        obj.write(output.as_ref())?;

        Ok(())
    }

    pub fn clif_ir(&self, output: impl AsRef<Path>) -> Result<(), Error> {
        let (module_contents, bindings) = self.build()?;

        let compiler = self.builder.create(&module_contents, &bindings)?;

        compiler.cranelift_funcs()?.write(&output)?;

        Ok(())
    }

    pub fn shared_object_file(&self, output: impl AsRef<Path>) -> Result<(), Error> {
        let dir = tempfile::Builder::new().prefix("lucetc").tempdir()?;
        let objpath = dir.path().join("tmp.o");
        self.object_file(objpath.clone())?;
        link_so(
            objpath,
            self.builder.target_ref(),
            &output,
            self.builder.target_version_ref(),
        )?;
        if self.sign {
            let sk = self.sk.as_ref().ok_or(Error::Signature(
                "signing requires a secret key".to_string(),
            ))?;
            signature::sign_module(&output, sk)?;
        }
        Ok(())
    }
}

const LD_DEFAULT: &str = "ld";

fn link_so(
    objpath: impl AsRef<Path>,
    target: &Triple,
    sopath: impl AsRef<Path>,
    target_version: &TargetVersion,
) -> Result<(), Error> {
    // Let `LD` be something like "clang --target=... ..." for convenience.
    let env_ld = env::var("LD").unwrap_or(LD_DEFAULT.into());
    let mut ld_iter = env_ld.split_whitespace();
    let ld_prog = ld_iter.next().expect("LD must not be empty");
    let mut cmd_ld = Command::new(ld_prog);
    for flag in ld_iter {
        cmd_ld.arg(flag);
    }

    cmd_ld.arg(objpath.as_ref());
    let env_ldflags =
        env::var("LDFLAGS").unwrap_or_else(|_| ldflags_default(target, target_version));
    for flag in env_ldflags.split_whitespace() {
        cmd_ld.arg(flag);
    }

    output_arg_for(&mut cmd_ld, target, sopath);

    let run_ld = cmd_ld.output()?;

    if !run_ld.status.success() {
        let message = format!(
            "ld of `{:?}` failed: {}",
            cmd_ld,
            String::from_utf8_lossy(&run_ld.stderr)
        );
        return Err(Error::LdError(message));
    }
    Ok(())
}

fn output_arg_for(cmd_ld: &mut Command, target: &Triple, sopath: impl AsRef<Path>) {
    use target_lexicon::{Environment, OperatingSystem};

    if target.operating_system != OperatingSystem::Windows || target.environment == Environment::Gnu
    {
        cmd_ld.arg("-o");
        cmd_ld.arg(sopath.as_ref());
        return;
    }

    assert!(target.environment == Environment::Msvc);

    cmd_ld.arg(format!("/out:{:?}", sopath.as_ref()));
}

fn ldflags_default(target: &Triple, target_version: &TargetVersion) -> String {
    use target_lexicon::OperatingSystem;

    let mut flags = match target.operating_system {
        OperatingSystem::Linux
        | OperatingSystem::Freebsd
        | OperatingSystem::Dragonfly
        | OperatingSystem::Netbsd
        | OperatingSystem::Openbsd => "-shared",
        OperatingSystem::Darwin | OperatingSystem::MacOSX { .. } => {
            "-dylib -dead_strip -export_dynamic -undefined dynamic_lookup"
        }
        _ => panic!(
            "Cannot determine default flags for {}.

Please define the LDFLAGS environment variable with the necessary command-line
flags for generating shared libraries.",
            target
        ),
    }
    .to_owned();
    if let Some(version_settings) = target_version.ld_flags() {
        flags.push(' ');
        flags.push_str(&version_settings);
    }
    flags
}
<|endoftext|>


<commit_before>use regex;
use std::ascii::AsciiExt;
use std::io;
use std::io::{TcpStream, IoError, BufferedReader};
use std::task::TaskBuilder;
use std::sync::Arc;
use logging;
use logging_macros;

use errors::InitializationError;

static IRC_COLOR_REGEX: regex::Regex = regex!("(\x03(\\d+,\\d+|\\d)|[\x0f\x02\x16\x1f\x02])");

pub struct IrcConnection {
    socket: TcpStream,
    data_out: Option<Sender<Option<IrcMessage>>>,
    data_in: Option<Receiver<Option<String>>>,
    logger: Arc<Box<logging::Logger + Sync + Send>>
}

impl IrcConnection {
    pub fn create(addr: &str, data_out: Sender<Option<IrcMessage>>, data_in: Receiver<Option<String>>, logger: Arc<Box<logging::Logger + Sync + Send>>) -> Result<(), IoError> {
        let socket = try!(TcpStream::connect(addr));
        let connection_receiving = IrcConnection {
            socket: socket.clone(),
            data_out: Some(data_out),
            data_in: None,
            logger: logger.clone(),
        };
        let connection_sending = IrcConnection {
            socket: socket, // No need to clone a second time, as this is the last time we are using this socket
            data_out: None,
            data_in: Some(data_in),
            logger: logger,
        };

        // Using unwrap() on these two because we know that data_out and data_in are Some() and not None
        connection_receiving.spawn_reading_thread().unwrap();
        connection_sending.spawn_writing_thread().unwrap();

        return Ok(());
    }

    fn spawn_reading_thread(self) -> Result<(), InitializationError> {
        let data_out = match self.data_out {
            Some(ref v) => v.clone(),
            None => return Err(InitializationError::new("Can't start reading thread without data_out")),
        };
        TaskBuilder::new().named("socket_reading_task").spawn(move || {
            logging_macros::init_thread_logger(self.logger);
            let mut reader = BufferedReader::new(self.socket.clone());
            loop {
                let whole_input = match reader.read_line() {
                    Ok(v) => v,
                    Err(e) => {
                        match e.kind {
                            io::IoErrorKind::EndOfFile => (),
                            _ => severe!("Error in reading thread: {}", e),
                        }
                        data_out.send(None);
                        break;
                    },
                };
                let input = IRC_COLOR_REGEX.replace_all(whole_input.trim_right(), "");
                let message_split: Vec<&str> = input.split(' ').collect();
                let (command, args, possible_mask): (&str, &[&str], IrcMask) = if message_split[0].starts_with(":") {
                    (message_split[1], message_split.slice_from(2), IrcMask::parse_from_str(message_split[0].slice_from(1)))
                } else {
                    (message_split[0], message_split.slice_from(1), IrcMask::Nonexistent)
                };
                let ctcp = if command.eq_ignore_ascii_case("PRIVMSG")
                              && args[1].starts_with(":\x01")
                              && args[args.len() -1].ends_with("\x01") {
                    let ctcp_command;
                    let mut ctcp_message;
                    if args.len() > 2 {
                        ctcp_command = args[1].slice_from(2).into_string(); // to remove :\x01
                        ctcp_message = args.slice_from(2).connect(" ");
                        ctcp_message.pop(); // to remove last \x01
                    } else {
                        ctcp_command = args[1].slice(2, args[1].len() - 1).into_string(); // remove starting :\x01 and ending \x01
                        ctcp_message = "".into_string();
                    }
                    Some((ctcp_command, ctcp_message))
                } else { None };
                let args_owned: Vec<String> = args.iter().map(|s: &&str| s.into_string()).collect();
                let message = IrcMessage::new(command.into_string(), args_owned, possible_mask, ctcp);
                data_out.send(Some(message));
            }
        });
        return Ok(());
    }

    fn spawn_writing_thread(mut self) -> Result<(), InitializationError> {
        if (&self.data_in).is_none() {
            return Err(InitializationError::new("Can't start writing thread without data_in"));
        }
        TaskBuilder::new().named("socket_writing_task").spawn(move || {
            logging_macros::init_thread_logger(self.logger);
            let data_in = self.data_in.expect("Already confirmed above");
            loop {
                let command = match data_in.recv() {
                    Some(v) => v,
                    None => break,
                };
                if !command.starts_with("PONG ") {
                    info!(">>> {}", command);
                }
                log_error_then!(self.socket.write(command.as_bytes()), return, "Failed to write to stream: {e}");
                log_error_then!(self.socket.write(b"\n"), return, "Failed to write to stream: {e}");
                log_error_then!(self.socket.flush(), return, "Failed to write to stream: {e}");
            }
        });
        return Ok(());
    }
}

pub enum IrcMask {
    Full(FullIrcMask),
    Unparseable(String),
    Nonexistent,
}

pub struct FullIrcMask {
    pub mask: String,
    pub nick: String,
    pub user: String,
    pub host: String,
}

pub struct IrcMessage {
    pub command: String,
    pub args: Vec<String>,
    pub mask: IrcMask,
    /// Option<(command, message)>
    pub ctcp: Option<(String, String)>,
}

impl IrcMessage {
    fn new(command: String, args: Vec<String>, mask: IrcMask, ctcp: Option<(String, String)>) -> IrcMessage {
        return IrcMessage {
            command: command,
            args: args,
            mask: mask,
            ctcp: ctcp,
        };
    }
}

impl IrcMask {
    fn new_full(mask: String, nick: String, user: String, host: String) -> IrcMask {
        return IrcMask::Full(FullIrcMask {
            mask: mask,
            nick: nick,
            user: user,
            host: host,
        });
    }

    fn new_mask_only(mask: String) -> IrcMask {
        return IrcMask::Unparseable(mask);
    }

    fn parse_from_str(mask: &str) -> IrcMask {
        let mask_split = mask.splitn(1, '!').collect::<Vec<&str>>();
        if mask_split.len() < 2 {
            return IrcMask::new_mask_only(mask.into_string());
        }
        let nick = mask_split[0];
        let user_and_host = mask_split[1];
        let user_and_host_split = user_and_host.splitn(1, '@').collect::<Vec<&str>>();
        if user_and_host_split.len() < 2 {
            return IrcMask::new_mask_only(mask.into_string());
        }
        let user = user_and_host_split[0];
        let host = user_and_host_split[1];
        return IrcMask::new_full(mask.into_string(), nick.into_string(), user.into_string(), host.into_string());
    }
}
<commit_msg>Add framework in irc/mod.rs to detect the channel of a message. TODO: Add this to the message events for plugins.<commit_after>use regex;
use std::ascii::AsciiExt;
use std::io;
use std::io::{TcpStream, IoError, BufferedReader};
use std::task::TaskBuilder;
use std::sync::Arc;
use logging;
use logging_macros;

use errors::InitializationError;

static IRC_COLOR_REGEX: regex::Regex = regex!("(\x03(\\d+,\\d+|\\d)|[\x0f\x02\x16\x1f\x02])");

pub struct IrcConnection {
    socket: TcpStream,
    data_out: Option<Sender<Option<IrcMessage>>>,
    data_in: Option<Receiver<Option<String>>>,
    logger: Arc<Box<logging::Logger + Sync + Send>>
}

impl IrcConnection {
    pub fn create(addr: &str, data_out: Sender<Option<IrcMessage>>, data_in: Receiver<Option<String>>, logger: Arc<Box<logging::Logger + Sync + Send>>) -> Result<(), IoError> {
        let socket = try!(TcpStream::connect(addr));
        let connection_receiving = IrcConnection {
            socket: socket.clone(),
            data_out: Some(data_out),
            data_in: None,
            logger: logger.clone(),
        };
        let connection_sending = IrcConnection {
            socket: socket, // No need to clone a second time, as this is the last time we are using this socket
            data_out: None,
            data_in: Some(data_in),
            logger: logger,
        };

        // Using unwrap() on these two because we know that data_out and data_in are Some() and not None
        connection_receiving.spawn_reading_thread().unwrap();
        connection_sending.spawn_writing_thread().unwrap();

        return Ok(());
    }

    fn spawn_reading_thread(self) -> Result<(), InitializationError> {
        let data_out = match self.data_out {
            Some(ref v) => v.clone(),
            None => return Err(InitializationError::new("Can't start reading thread without data_out")),
        };
        TaskBuilder::new().named("socket_reading_task").spawn(move || {
            logging_macros::init_thread_logger(self.logger);
            let mut reader = BufferedReader::new(self.socket.clone());
            loop {
                let whole_input = match reader.read_line() {
                    Ok(v) => v,
                    Err(e) => {
                        match e.kind {
                            io::IoErrorKind::EndOfFile => (),
                            _ => severe!("Error in reading thread: {}", e),
                        }
                        data_out.send(None);
                        break;
                    },
                };
                let input = IRC_COLOR_REGEX.replace_all(whole_input.trim_right(), "");
                let message_split: Vec<&str> = input.split(' ').collect();
                let (command, args, possible_mask): (&str, &[&str], IrcMask) = if message_split[0].starts_with(":") {
                    (message_split[1], message_split.slice_from(2), IrcMask::parse_from_str(message_split[0].slice_from(1)))
                } else {
                    (message_split[0], message_split.slice_from(1), IrcMask::Nonexistent)
                };
                let ctcp = if command.eq_ignore_ascii_case("PRIVMSG")
                              && args[1].starts_with(":\x01")
                              && args[args.len() -1].ends_with("\x01") {
                    let ctcp_command;
                    let mut ctcp_message;
                    if args.len() > 2 {
                        ctcp_command = args[1].slice_from(2).into_string(); // to remove :\x01
                        ctcp_message = args.slice_from(2).connect(" ");
                        ctcp_message.pop(); // to remove last \x01
                    } else {
                        ctcp_command = args[1].slice(2, args[1].len() - 1).into_string(); // remove starting :\x01 and ending \x01
                        ctcp_message = "".into_string();
                    }
                    Some((ctcp_command, ctcp_message))
                } else { None };
                let channel = match command {
                    "353" => Some(args[2].into_string()),
                    "PRIVMSG" | "NOTICE" | "JOIN" | "PART" | "KICK" | "TOPIC" => Some(args[0].into_string()),
                    _ => None,
                };
                // TODO: Change channel to sender nick if channel is our current nick.
                let args_owned: Vec<String> = args.iter().map(|s: &&str| s.into_string()).collect();
                let message = IrcMessage::new(command.into_string(), args_owned, possible_mask, ctcp, channel);
                data_out.send(Some(message));
            }
        });
        return Ok(());
    }

    fn spawn_writing_thread(mut self) -> Result<(), InitializationError> {
        if (&self.data_in).is_none() {
            return Err(InitializationError::new("Can't start writing thread without data_in"));
        }
        TaskBuilder::new().named("socket_writing_task").spawn(move || {
            logging_macros::init_thread_logger(self.logger);
            let data_in = self.data_in.expect("Already confirmed above");
            loop {
                let command = match data_in.recv() {
                    Some(v) => v,
                    None => break,
                };
                if !command.starts_with("PONG ") {
                    info!(">>> {}", command);
                }
                log_error_then!(self.socket.write(command.as_bytes()), return, "Failed to write to stream: {e}");
                log_error_then!(self.socket.write(b"\n"), return, "Failed to write to stream: {e}");
                log_error_then!(self.socket.flush(), return, "Failed to write to stream: {e}");
            }
        });
        return Ok(());
    }
}

pub enum IrcMask {
    Full(FullIrcMask),
    Unparseable(String),
    Nonexistent,
}

pub struct FullIrcMask {
    pub mask: String,
    pub nick: String,
    pub user: String,
    pub host: String,
}

pub struct IrcMessage {
    pub command: String,
    pub args: Vec<String>,
    pub mask: IrcMask,
    /// Option<(command, message)>
    pub ctcp: Option<(String, String)>,
    pub channel: Option<String>,
}

impl IrcMessage {
    fn new(command: String, args: Vec<String>, mask: IrcMask, ctcp: Option<(String, String)>, channel: Option<String>) -> IrcMessage {
        return IrcMessage {
            command: command,
            args: args,
            mask: mask,
            ctcp: ctcp,
            channel: channel,
        };
    }
}

impl IrcMask {
    fn new_full(mask: String, nick: String, user: String, host: String) -> IrcMask {
        return IrcMask::Full(FullIrcMask {
            mask: mask,
            nick: nick,
            user: user,
            host: host,
        });
    }

    fn new_mask_only(mask: String) -> IrcMask {
        return IrcMask::Unparseable(mask);
    }

    fn parse_from_str(mask: &str) -> IrcMask {
        let mask_split = mask.splitn(1, '!').collect::<Vec<&str>>();
        if mask_split.len() < 2 {
            return IrcMask::new_mask_only(mask.into_string());
        }
        let nick = mask_split[0];
        let user_and_host = mask_split[1];
        let user_and_host_split = user_and_host.splitn(1, '@').collect::<Vec<&str>>();
        if user_and_host_split.len() < 2 {
            return IrcMask::new_mask_only(mask.into_string());
        }
        let user = user_and_host_split[0];
        let host = user_and_host_split[1];
        return IrcMask::new_full(mask.into_string(), nick.into_string(), user.into_string(), host.into_string());
    }
}
<|endoftext|>


<commit_before>#![allow(unused_macros)]

/// An enum representing the available verbosity levels of the logger.
#[derive(Copy, Clone)]
pub enum LogLevel {
	/// Disable all our put messages
	///
	/// Designates without information
	DISABLED = 0,
	/// The "error" level.
	///
	/// Designates very serious errors.
	ERROR,
	/// The "warn" level.
	///
	/// Designates hazardous situations.
	WARNING,
	/// The "info" level.
	///
	/// Designates useful information.
	INFO,
	// The "debug" level.
	///
	/// Designates lower priority information.
	DEBUG
}

/// Data structures to filter kernel messages
pub struct KernelLogger {
	pub log_level: LogLevel,
}

/// default logger to handle kernel messages
pub static LOGGER: KernelLogger = KernelLogger { log_level: LogLevel::INFO };

/// Print formatted info text to our console, followed by a newline.
#[macro_export]
macro_rules! info {
	($fmt:expr) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::INFO as u8;

		if current_level >= cmp_level {
			println!(concat!("[INFO] ", $fmt));
		}
	});
	($fmt:expr, $($arg:tt)*) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::INFO as u8;

		if current_level >= cmp_level {
			println!(concat!("[INFO] ", $fmt), $($arg)*);
		}
	});
}

/// Print formatted warnings to our console, followed by a newline.
#[macro_export]
macro_rules! warn {
	($fmt:expr) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::WARNING as u8;

		if current_level >= cmp_level {
			println!(concat!("[WARNING] ", $fmt));
		}
	});
	($fmt:expr, $($arg:tt)*) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::WARNING  as u8;

		if current_level >= cmp_level {
			println!(concat!("[WARNING] ", $fmt), $($arg)*);
		}
	});
}

/// Print formatted warnings to our console, followed by a newline.
#[macro_export]
macro_rules! error {
	($fmt:expr) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::ERROR as u8;

		if current_level >= cmp_level {
			println!(concat!("[ERROR] ", $fmt));
		}
	});
	($fmt:expr, $($arg:tt)*) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::ERROR  as u8;

		if current_level >= cmp_level {
			println!(concat!("[ERROR] ", $fmt), $($arg)*);
		}
	});
}

/// Print formatted debuf messages to our console, followed by a newline.
#[macro_export]
macro_rules! debug {
	($fmt:expr) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::DEBUG as u8;

		if current_level >= cmp_level {
			println!(concat!("[DEBUG] ", $fmt));
		}
	});
	($fmt:expr, $($arg:tt)*) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::DEBUG  as u8;

		if current_level >= cmp_level {
			println!(concat!("[DEBUG] ", $fmt), $($arg)*);
		}
	});
}
<commit_msg>use const variable to define the debug level<commit_after>#![allow(unused_macros)]

/// An enum representing the available verbosity levels of the logger.
#[derive(Copy, Clone)]
pub enum LogLevel {
	/// Disable all our put messages
	///
	/// Designates without information
	DISABLED = 0,
	/// The "error" level.
	///
	/// Designates very serious errors.
	ERROR,
	/// The "warn" level.
	///
	/// Designates hazardous situations.
	WARNING,
	/// The "info" level.
	///
	/// Designates useful information.
	INFO,
	// The "debug" level.
	///
	/// Designates lower priority information.
	DEBUG
}

/// Data structures to filter kernel messages
pub struct KernelLogger {
	pub log_level: LogLevel,
}

/// default logger to handle kernel messages
pub const LOGGER: KernelLogger = KernelLogger { log_level: LogLevel::INFO };

/// Print formatted info text to our console, followed by a newline.
#[macro_export]
macro_rules! info {
	($fmt:expr) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::INFO as u8;

		if current_level >= cmp_level {
			println!(concat!("[INFO] ", $fmt));
		}
	});
	($fmt:expr, $($arg:tt)*) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::INFO as u8;

		if current_level >= cmp_level {
			println!(concat!("[INFO] ", $fmt), $($arg)*);
		}
	});
}

/// Print formatted warnings to our console, followed by a newline.
#[macro_export]
macro_rules! warn {
	($fmt:expr) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::WARNING as u8;

		if current_level >= cmp_level {
			println!(concat!("[WARNING] ", $fmt));
		}
	});
	($fmt:expr, $($arg:tt)*) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::WARNING  as u8;

		if current_level >= cmp_level {
			println!(concat!("[WARNING] ", $fmt), $($arg)*);
		}
	});
}

/// Print formatted warnings to our console, followed by a newline.
#[macro_export]
macro_rules! error {
	($fmt:expr) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::ERROR as u8;

		if current_level >= cmp_level {
			println!(concat!("[ERROR] ", $fmt));
		}
	});
	($fmt:expr, $($arg:tt)*) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::ERROR  as u8;

		if current_level >= cmp_level {
			println!(concat!("[ERROR] ", $fmt), $($arg)*);
		}
	});
}

/// Print formatted debuf messages to our console, followed by a newline.
#[macro_export]
macro_rules! debug {
	($fmt:expr) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::DEBUG as u8;

		if current_level >= cmp_level {
			println!(concat!("[DEBUG] ", $fmt));
		}
	});
	($fmt:expr, $($arg:tt)*) => ({
		let current_level = LOGGER.log_level as u8;
		let cmp_level = LogLevel::DEBUG  as u8;

		if current_level >= cmp_level {
			println!(concat!("[DEBUG] ", $fmt), $($arg)*);
		}
	});
}
<|endoftext|>


<commit_before>
use std::fmt;

use opcode::{Opcode, OpcodeError, SetRegMode};

const PROGRAM_START: u16 = 0x200;

const MEMORY_SIZE: usize = 4096;
const REGISTER_COUNT: usize = 16;

pub enum RuntimeError {
    EmptyCallStack,
    InvalidRegister(u8),
    AddressOutOfBounds(u16),
    OpcodeErr(OpcodeError),
}

pub struct Chip8 {
    memory: [u8; MEMORY_SIZE],
    regs: [u8; REGISTER_COUNT], // registers V0 - V15
    addressReg: u16, // register I

    pc: u16,
    // Stores the program counters of sub routine calls, used to return after a sub routine ends
    stack: Vec<u16>,

    screen: [[bool; 64]; 32],
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            memory: [0; 4096],
            regs: [0; 16],
            addressReg: 0,

            pc: PROGRAM_START,
            stack: Vec::new(),

            screen: [[false; 64]; 32],
        }
    }

    pub fn cycle(&mut self) -> Result<(), RuntimeError> {
        use self::RuntimeError::*;
        use opcode::Opcode::*;

        let pc_index = self.pc as usize;
        let opcode_bytes = (self.memory[pc_index] as u16) << 8 | (self.memory[pc_index + 1] as u16);

        let opcode = match Opcode::from_u16(opcode_bytes) {
            Ok(opcode) => opcode,
            Err(err) => return Err(OpcodeErr(err)),
        };

        match opcode {
            ClearScreen => self.clear_screen(),
            Return => {
                self.pc = match self.stack.pop() {
                    Some(addr) => addr,
                    None => return Err(EmptyCallStack),
                };
            },

            JumpTo { addr, plus_v0 } => {
                self.pc = addr;

                if plus_v0 {
                    self.pc += self.regs[0] as u16;
                }
            },
            Call(addr) => {
                self.stack.push(self.pc);
                self.pc = addr;
            },

            SkipIfRegEqualConst { not_equal, reg, value } => {
                let mut should_jump = self.regs[reg as usize] == value;

                if not_equal {
                    should_jump = !should_jump; // Effectively computes self.regs[reg] != value
                }

                if should_jump {
                    self.pc += 4;
                    return Ok(());
                }
            },
            SkipIfRegsEqual { not_equal, regs: (v_x, v_y) } => {
                let mut should_jump = self.regs[v_x as usize] == self.regs[v_y as usize];

                if not_equal {
                    should_jump = !should_jump;
                }

                if should_jump {
                    self.pc += 4;
                    return Ok(());
                }
            },

            SetRegToConst { add, reg, value } => {
                if add {
                    self.regs[reg as usize] += value;
                } else {
                    self.regs[reg as usize] = value;
                }
            },
            SetRegToReg { regs: (v_x, v_y), mode } => {
                let v_x = v_x as usize;
                let v_y = v_y as usize;

                match mode {
                    SetRegMode::Copy => {
                        self.regs[v_x] = self.regs[v_y];
                    },
                    SetRegMode::Or => {
                        self.regs[v_x] |= self.regs[v_y];
                    },
                    SetRegMode::And => {
                        self.regs[v_x] &= self.regs[v_y];
                    },
                    SetRegMode::Xor => {
                        self.regs[v_x] ^= self.regs[v_y];
                    },

                    SetRegMode::Add => {
                        let reg_value = self.regs[v_x] as usize + self.regs[v_y] as usize;
                        if reg_value > 255 {
                            reg_value -= 255;
                            self.regs[0xF] = 1;
                        }

                        self.regs[v_x] = reg_value as u8;
                    },
                    SetRegMode::Subtract | SetRegMode::InverseSubtract => {
                        let reg_value = if let SetRegMode::Subtract = mode {
                            self.regs[v_x] as isize - self.regs[v_y] as isize;
                        else { // Must be InverseSubtract
                            self.regs[v_y] as isize - self.regs[v_x] as isize;
                        };

                        if reg_value < 0 {
                            reg_value += 255;
                            self.regs[0xF] = 1;
                        }

                        self.regs[v_x] = reg_value as u8;
                    },
                    SetRegMode::InverseSubtract => {

                    },

                    SetRegMode::ShiftLeft => {

                    },
                    SetRegMode::ShiftRight => {

                    }
                }
            },
            _ => unreachable!(),
        }

        self.pc += 2;

        Ok(())
    }

    pub fn clear_screen(&mut self) {
        for row in self.screen.iter_mut() {
            for col in row.iter_mut() {
                *col = false;
            }
        }
    }
}

impl fmt::<commit_msg>Formatting fixes<commit_after>
use std::fmt;

use opcode::{Opcode, OpcodeError, SetRegMode};

const PROGRAM_START: u16 = 0x200;

const MEMORY_SIZE: usize = 4096;
const REGISTER_COUNT: usize = 16;

pub enum RuntimeError {
    EmptyCallStack,
    InvalidRegister(u8),
    AddressOutOfBounds(u16),
    OpcodeErr(OpcodeError),
}

pub struct Chip8 {
    memory: [u8; MEMORY_SIZE],
    regs: [u8; REGISTER_COUNT], // registers V0 - V15
    addressReg: u16, // register I

    pc: u16,
    // Stores the program counters of sub routine calls, used to return after a sub routine ends
    stack: Vec<u16>,

    screen: [[bool; 64]; 32],
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            memory: [0; 4096],
            regs: [0; 16],
            addressReg: 0,

            pc: PROGRAM_START,
            stack: Vec::new(),

            screen: [[false; 64]; 32],
        }
    }

    pub fn cycle(&mut self) -> Result<(), RuntimeError> {
        use self::RuntimeError::*;
        use opcode::Opcode::*;

        let pc_index = self.pc as usize;
        let opcode_bytes = (self.memory[pc_index] as u16) << 8 | (self.memory[pc_index + 1] as u16);

        let opcode = match Opcode::from_u16(opcode_bytes) {
            Ok(opcode) => opcode,
            Err(err) => return Err(OpcodeErr(err)),
        };

        match opcode {
            ClearScreen => self.clear_screen(),
            Return => {
                self.pc = match self.stack.pop() {
                    Some(addr) => addr,
                    None => return Err(EmptyCallStack),
                };
            },

            JumpTo { addr, plus_v0 } => {
                self.pc = addr;

                if plus_v0 {
                    self.pc += self.regs[0] as u16;
                }
            },
            Call(addr) => {
                self.stack.push(self.pc);
                self.pc = addr;
            },

            SkipIfRegEqualConst { not_equal, reg, value } => {
                let mut should_jump = self.regs[reg as usize] == value;

                if not_equal {
                    should_jump = !should_jump; // Effectively computes self.regs[reg] != value
                }

                if should_jump {
                    self.pc += 4;
                    return Ok(());
                }
            },
            SkipIfRegsEqual { not_equal, regs: (v_x, v_y) } => {
                let mut should_jump = self.regs[v_x as usize] == self.regs[v_y as usize];

                if not_equal {
                    should_jump = !should_jump;
                }

                if should_jump {
                    self.pc += 4;
                    return Ok(());
                }
            },

            SetRegToConst { add, reg, value } => {
                if add {
                    self.regs[reg as usize] += value;
                } else {
                    self.regs[reg as usize] = value;
                }
            },
            SetRegToReg { regs: (v_x, v_y), mode } => {
                let v_x = v_x as usize;
                let v_y = v_y as usize;

                match mode {
                    SetRegMode::Copy => self.regs[v_x] = self.regs[v_y],

                    SetRegMode::Or => self.regs[v_x] |= self.regs[v_y],
                    SetRegMode::And => self.regs[v_x] &= self.regs[v_y],
                    SetRegMode::Xor => self.regs[v_x] ^= self.regs[v_y],

                    SetRegMode::Add => {
                        let reg_value = self.regs[v_x] as usize + self.regs[v_y] as usize;
                        if reg_value > 255 {
                            reg_value -= 255;
                            self.regs[0xF] = 1;
                        }

                        self.regs[v_x] = reg_value as u8;
                    },
                    SetRegMode::Subtract | SetRegMode::InverseSubtract => {
                        let reg_value = if let SetRegMode::Subtract = mode {
                            self.regs[v_x] as isize - self.regs[v_y] as isize;
                        else { // Must be InverseSubtract
                            self.regs[v_y] as isize - self.regs[v_x] as isize;
                        };

                        if reg_value < 0 {
                            reg_value += 255;
                            self.regs[0xF] = 1;
                        }

                        self.regs[v_x] = reg_value as u8;
                    },

                    // v_y is ignored for the shift opcodes, not sure why
                    SetRegMode::ShiftLeft => {
                        self.regs[0xF] = self.regs[v_x] & 0xF0 >> 8;
                        self.regs[v_x] <<= 1;
                    },
                    SetRegMode::ShiftRight => {
                        self.regs[0xF] = self.regs[v_x] & 0x0F;
                        self.regs[v_x] >>= 1;
                    }
                }
            },
            _ => unreachable!(),
        }

        self.pc += 2;

        Ok(())
    }

    pub fn clear_screen(&mut self) {
        for row in self.screen.iter_mut() {
            for col in row.iter_mut() {
                *col = false;
            }
        }
    }
}

impl fmt::Debug for Chip8 {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "Register Contents: {:?}", self.regs);
    }
}<|endoftext|>


<commit_before>//! A YAML mapping and its iterator types.

use crate::Value;
use indexmap::IndexMap;
use serde::{Deserialize, Deserializer, Serialize};
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::ops::{Index, IndexMut};

/// A YAML mapping in which the keys and values are both `serde_yaml::Value`.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Mapping {
    map: IndexMap<Value, Value>,
}

impl Mapping {
    /// Creates an empty YAML map.
    #[inline]
    pub fn new() -> Self {
        Self::default()
    }

    /// Creates an empty YAML map with the given initial capacity.
    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        Mapping {
            map: IndexMap::with_capacity(capacity),
        }
    }

    /// Reserves capacity for at least `additional` more elements to be inserted
    /// into the map. The map may reserve more space to avoid frequent
    /// allocations.
    ///
    /// # Panics
    ///
    /// Panics if the new allocation size overflows `usize`.
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.map.reserve(additional);
    }

    /// Shrinks the capacity of the map as much as possible. It will drop down
    /// as much as possible while maintaining the internal rules and possibly
    /// leaving some space in accordance with the resize policy.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.map.shrink_to_fit();
    }

    /// Inserts a key-value pair into the map. If the key already existed, the
    /// old value is returned.
    #[inline]
    pub fn insert(&mut self, k: Value, v: Value) -> Option<Value> {
        self.map.insert(k, v)
    }

    /// Checks if the map contains the given key.
    #[inline]
    pub fn contains_key(&self, k: &Value) -> bool {
        self.map.contains_key(k)
    }

    /// Returns the value corresponding to the key in the map.
    #[inline]
    pub fn get(&self, k: &Value) -> Option<&Value> {
        self.map.get(k)
    }

    /// Returns the mutable reference corresponding to the key in the map.
    #[inline]
    pub fn get_mut(&mut self, k: &Value) -> Option<&mut Value> {
        self.map.get_mut(k)
    }

    /// Removes and returns the value corresponding to the key from the map.
    #[inline]
    pub fn remove(&mut self, k: &Value) -> Option<Value> {
        self.map.remove(k)
    }

    /// Returns the maximum number of key-value pairs the map can hold without
    /// reallocating.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }

    /// Returns the number of key-value pairs in the map.
    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Returns whether the map is currently empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Clears the map of all key-value pairs.
    #[inline]
    pub fn clear(&mut self) {
        self.map.clear();
    }

    /// Returns a double-ended iterator visiting all key-value pairs in order of
    /// insertion. Iterator element type is `(&'a Value, &'a Value)`.
    #[inline]
    pub fn iter(&self) -> Iter {
        Iter {
            iter: self.map.iter(),
        }
    }

    /// Returns a double-ended iterator visiting all key-value pairs in order of
    /// insertion. Iterator element type is `(&'a Value, &'a mut ValuE)`.
    #[inline]
    pub fn iter_mut(&mut self) -> IterMut {
        IterMut {
            iter: self.map.iter_mut(),
        }
    }
}

#[allow(clippy::derive_hash_xor_eq)]
impl Hash for Mapping {
    fn hash<H: Hasher>(&self, state: &mut H) {
        // Hash the kv pairs in a way that is not sensitive to their order.
        let mut xor = 0;
        for (k, v) in self {
            let mut hasher = DefaultHasher::new();
            k.hash(&mut hasher);
            v.hash(&mut hasher);
            xor ^= hasher.finish();
        }
        xor.hash(state);
    }
}

impl PartialOrd for Mapping {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        let mut self_entries = Vec::from_iter(self);
        let mut other_entries = Vec::from_iter(other);

        // Sort in an arbitrary order that is consistent with Value's PartialOrd
        // impl.
        fn total_cmp(a: &Value, b: &Value) -> Ordering {
            match (a, b) {
                (Value::Null, Value::Null) => Ordering::Equal,
                (Value::Null, _) => Ordering::Less,
                (_, Value::Null) => Ordering::Greater,

                (Value::Bool(a), Value::Bool(b)) => a.cmp(b),
                (Value::Bool(_), _) => Ordering::Less,
                (_, Value::Bool(_)) => Ordering::Greater,

                (Value::Number(a), Value::Number(b)) => a.total_cmp(b),
                (Value::Number(_), _) => Ordering::Less,
                (_, Value::Number(_)) => Ordering::Greater,

                (Value::String(a), Value::String(b)) => a.cmp(b),
                (Value::String(_), _) => Ordering::Less,
                (_, Value::String(_)) => Ordering::Greater,

                (Value::Sequence(a), Value::Sequence(b)) => iter_cmp_by(a, b, total_cmp),
                (Value::Sequence(_), _) => Ordering::Less,
                (_, Value::Sequence(_)) => Ordering::Greater,

                (Value::Mapping(a), Value::Mapping(b)) => {
                    iter_cmp_by(a, b, |(ak, av), (bk, bv)| {
                        total_cmp(ak, bk).then_with(|| total_cmp(av, bv))
                    })
                }
            }
        }

        fn iter_cmp_by<I, F>(this: I, other: I, mut cmp: F) -> Ordering
        where
            I: IntoIterator,
            F: FnMut(I::Item, I::Item) -> Ordering,
        {
            let mut this = this.into_iter();
            let mut other = other.into_iter();

            loop {
                let x = match this.next() {
                    None => {
                        if other.next().is_none() {
                            return Ordering::Equal;
                        } else {
                            return Ordering::Less;
                        }
                    }
                    Some(val) => val,
                };

                let y = match other.next() {
                    None => return Ordering::Greater,
                    Some(val) => val,
                };

                match cmp(x, y) {
                    Ordering::Equal => {}
                    non_eq => return non_eq,
                }
            }
        }

        // While sorting by map key, we get to assume that no two keys are
        // equal, otherwise they wouldn't both be in the map. This is not a safe
        // assumption outside of this situation.
        let total_cmp = |&(a, _): &_, &(b, _): &_| total_cmp(a, b);
        self_entries.sort_by(total_cmp);
        other_entries.sort_by(total_cmp);
        self_entries.partial_cmp(&other_entries)
    }
}

impl<'a> Index<&'a Value> for Mapping {
    type Output = Value;
    #[inline]
    fn index(&self, index: &'a Value) -> &Value {
        self.map.index(index)
    }
}

impl<'a> IndexMut<&'a Value> for Mapping {
    #[inline]
    fn index_mut(&mut self, index: &'a Value) -> &mut Value {
        self.map.index_mut(index)
    }
}

impl Extend<(Value, Value)> for Mapping {
    #[inline]
    fn extend<I: IntoIterator<Item = (Value, Value)>>(&mut self, iter: I) {
        self.map.extend(iter);
    }
}

impl FromIterator<(Value, Value)> for Mapping {
    #[inline]
    fn from_iter<I: IntoIterator<Item = (Value, Value)>>(iter: I) -> Self {
        Mapping {
            map: IndexMap::from_iter(iter),
        }
    }
}

macro_rules! delegate_iterator {
    (($name:ident $($generics:tt)*) => $item:ty) => {
        impl $($generics)* Iterator for $name $($generics)* {
            type Item = $item;
            #[inline]
            fn next(&mut self) -> Option<Self::Item> {
                self.iter.next()
            }
            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                self.iter.size_hint()
            }
        }

        impl $($generics)* ExactSizeIterator for $name $($generics)* {
            #[inline]
            fn len(&self) -> usize {
                self.iter.len()
            }
        }
    }
}

/// Iterator over `&serde_yaml::Mapping`.
pub struct Iter<'a> {
    iter: indexmap::map::Iter<'a, Value, Value>,
}

delegate_iterator!((Iter<'a>) => (&'a Value, &'a Value));

impl<'a> IntoIterator for &'a Mapping {
    type Item = (&'a Value, &'a Value);
    type IntoIter = Iter<'a>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            iter: self.map.iter(),
        }
    }
}

/// Iterator over `&mut serde_yaml::Mapping`.
pub struct IterMut<'a> {
    iter: indexmap::map::IterMut<'a, Value, Value>,
}

delegate_iterator!((IterMut<'a>) => (&'a Value, &'a mut Value));

impl<'a> IntoIterator for &'a mut Mapping {
    type Item = (&'a Value, &'a mut Value);
    type IntoIter = IterMut<'a>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            iter: self.map.iter_mut(),
        }
    }
}

/// Iterator over `serde_yaml::Mapping` by value.
pub struct IntoIter {
    iter: indexmap::map::IntoIter<Value, Value>,
}

delegate_iterator!((IntoIter) => (Value, Value));

impl IntoIterator for Mapping {
    type Item = (Value, Value);
    type IntoIter = IntoIter;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IntoIter {
            iter: self.map.into_iter(),
        }
    }
}

impl Serialize for Mapping {
    #[inline]
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        use serde::ser::SerializeMap;
        let mut map_serializer = serializer.serialize_map(Some(self.len()))?;
        for (k, v) in self {
            map_serializer.serialize_entry(k, v)?;
        }
        map_serializer.end()
    }
}

impl<'de> Deserialize<'de> for Mapping {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct Visitor;

        impl<'de> serde::de::Visitor<'de> for Visitor {
            type Value = Mapping;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a YAML mapping")
            }

            #[inline]
            fn visit_unit<E>(self) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                Ok(Mapping::new())
            }

            #[inline]
            fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
            where
                V: serde::de::MapAccess<'de>,
            {
                let mut values = Mapping::new();
                while let Some((k, v)) = visitor.next_entry()? {
                    values.insert(k, v);
                }
                Ok(values)
            }
        }

        deserializer.deserialize_map(Visitor)
    }
}
<commit_msg>Add an Entry API for Mapping<commit_after>//! A YAML mapping and its iterator types.

use crate::Value;
use indexmap::IndexMap;
use serde::{Deserialize, Deserializer, Serialize};
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::ops::{Index, IndexMut};

/// A YAML mapping in which the keys and values are both `serde_yaml::Value`.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Mapping {
    map: IndexMap<Value, Value>,
}

impl Mapping {
    /// Creates an empty YAML map.
    #[inline]
    pub fn new() -> Self {
        Self::default()
    }

    /// Creates an empty YAML map with the given initial capacity.
    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        Mapping {
            map: IndexMap::with_capacity(capacity),
        }
    }

    /// Reserves capacity for at least `additional` more elements to be inserted
    /// into the map. The map may reserve more space to avoid frequent
    /// allocations.
    ///
    /// # Panics
    ///
    /// Panics if the new allocation size overflows `usize`.
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.map.reserve(additional);
    }

    /// Shrinks the capacity of the map as much as possible. It will drop down
    /// as much as possible while maintaining the internal rules and possibly
    /// leaving some space in accordance with the resize policy.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.map.shrink_to_fit();
    }

    /// Inserts a key-value pair into the map. If the key already existed, the
    /// old value is returned.
    #[inline]
    pub fn insert(&mut self, k: Value, v: Value) -> Option<Value> {
        self.map.insert(k, v)
    }

    /// Checks if the map contains the given key.
    #[inline]
    pub fn contains_key(&self, k: &Value) -> bool {
        self.map.contains_key(k)
    }

    /// Returns the value corresponding to the key in the map.
    #[inline]
    pub fn get(&self, k: &Value) -> Option<&Value> {
        self.map.get(k)
    }

    /// Returns the mutable reference corresponding to the key in the map.
    #[inline]
    pub fn get_mut(&mut self, k: &Value) -> Option<&mut Value> {
        self.map.get_mut(k)
    }

    /// Gets the given key’s corresponding entry in the map for insertion and/or
    /// in-place manipulation.
    #[inline]
    pub fn entry(&mut self, k: Value) -> Entry {
        match self.map.entry(k) {
            indexmap::map::Entry::Occupied(occupied) => Entry::Occupied(OccupiedEntry { occupied }),
            indexmap::map::Entry::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant }),
        }
    }

    /// Removes and returns the value corresponding to the key from the map.
    #[inline]
    pub fn remove(&mut self, k: &Value) -> Option<Value> {
        self.map.remove(k)
    }

    /// Returns the maximum number of key-value pairs the map can hold without
    /// reallocating.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }

    /// Returns the number of key-value pairs in the map.
    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Returns whether the map is currently empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Clears the map of all key-value pairs.
    #[inline]
    pub fn clear(&mut self) {
        self.map.clear();
    }

    /// Returns a double-ended iterator visiting all key-value pairs in order of
    /// insertion. Iterator element type is `(&'a Value, &'a Value)`.
    #[inline]
    pub fn iter(&self) -> Iter {
        Iter {
            iter: self.map.iter(),
        }
    }

    /// Returns a double-ended iterator visiting all key-value pairs in order of
    /// insertion. Iterator element type is `(&'a Value, &'a mut ValuE)`.
    #[inline]
    pub fn iter_mut(&mut self) -> IterMut {
        IterMut {
            iter: self.map.iter_mut(),
        }
    }
}

#[allow(clippy::derive_hash_xor_eq)]
impl Hash for Mapping {
    fn hash<H: Hasher>(&self, state: &mut H) {
        // Hash the kv pairs in a way that is not sensitive to their order.
        let mut xor = 0;
        for (k, v) in self {
            let mut hasher = DefaultHasher::new();
            k.hash(&mut hasher);
            v.hash(&mut hasher);
            xor ^= hasher.finish();
        }
        xor.hash(state);
    }
}

impl PartialOrd for Mapping {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        let mut self_entries = Vec::from_iter(self);
        let mut other_entries = Vec::from_iter(other);

        // Sort in an arbitrary order that is consistent with Value's PartialOrd
        // impl.
        fn total_cmp(a: &Value, b: &Value) -> Ordering {
            match (a, b) {
                (Value::Null, Value::Null) => Ordering::Equal,
                (Value::Null, _) => Ordering::Less,
                (_, Value::Null) => Ordering::Greater,

                (Value::Bool(a), Value::Bool(b)) => a.cmp(b),
                (Value::Bool(_), _) => Ordering::Less,
                (_, Value::Bool(_)) => Ordering::Greater,

                (Value::Number(a), Value::Number(b)) => a.total_cmp(b),
                (Value::Number(_), _) => Ordering::Less,
                (_, Value::Number(_)) => Ordering::Greater,

                (Value::String(a), Value::String(b)) => a.cmp(b),
                (Value::String(_), _) => Ordering::Less,
                (_, Value::String(_)) => Ordering::Greater,

                (Value::Sequence(a), Value::Sequence(b)) => iter_cmp_by(a, b, total_cmp),
                (Value::Sequence(_), _) => Ordering::Less,
                (_, Value::Sequence(_)) => Ordering::Greater,

                (Value::Mapping(a), Value::Mapping(b)) => {
                    iter_cmp_by(a, b, |(ak, av), (bk, bv)| {
                        total_cmp(ak, bk).then_with(|| total_cmp(av, bv))
                    })
                }
            }
        }

        fn iter_cmp_by<I, F>(this: I, other: I, mut cmp: F) -> Ordering
        where
            I: IntoIterator,
            F: FnMut(I::Item, I::Item) -> Ordering,
        {
            let mut this = this.into_iter();
            let mut other = other.into_iter();

            loop {
                let x = match this.next() {
                    None => {
                        if other.next().is_none() {
                            return Ordering::Equal;
                        } else {
                            return Ordering::Less;
                        }
                    }
                    Some(val) => val,
                };

                let y = match other.next() {
                    None => return Ordering::Greater,
                    Some(val) => val,
                };

                match cmp(x, y) {
                    Ordering::Equal => {}
                    non_eq => return non_eq,
                }
            }
        }

        // While sorting by map key, we get to assume that no two keys are
        // equal, otherwise they wouldn't both be in the map. This is not a safe
        // assumption outside of this situation.
        let total_cmp = |&(a, _): &_, &(b, _): &_| total_cmp(a, b);
        self_entries.sort_by(total_cmp);
        other_entries.sort_by(total_cmp);
        self_entries.partial_cmp(&other_entries)
    }
}

impl<'a> Index<&'a Value> for Mapping {
    type Output = Value;
    #[inline]
    fn index(&self, index: &'a Value) -> &Value {
        self.map.index(index)
    }
}

impl<'a> IndexMut<&'a Value> for Mapping {
    #[inline]
    fn index_mut(&mut self, index: &'a Value) -> &mut Value {
        self.map.index_mut(index)
    }
}

impl Extend<(Value, Value)> for Mapping {
    #[inline]
    fn extend<I: IntoIterator<Item = (Value, Value)>>(&mut self, iter: I) {
        self.map.extend(iter);
    }
}

impl FromIterator<(Value, Value)> for Mapping {
    #[inline]
    fn from_iter<I: IntoIterator<Item = (Value, Value)>>(iter: I) -> Self {
        Mapping {
            map: IndexMap::from_iter(iter),
        }
    }
}

macro_rules! delegate_iterator {
    (($name:ident $($generics:tt)*) => $item:ty) => {
        impl $($generics)* Iterator for $name $($generics)* {
            type Item = $item;
            #[inline]
            fn next(&mut self) -> Option<Self::Item> {
                self.iter.next()
            }
            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                self.iter.size_hint()
            }
        }

        impl $($generics)* ExactSizeIterator for $name $($generics)* {
            #[inline]
            fn len(&self) -> usize {
                self.iter.len()
            }
        }
    }
}

/// Iterator over `&serde_yaml::Mapping`.
pub struct Iter<'a> {
    iter: indexmap::map::Iter<'a, Value, Value>,
}

delegate_iterator!((Iter<'a>) => (&'a Value, &'a Value));

impl<'a> IntoIterator for &'a Mapping {
    type Item = (&'a Value, &'a Value);
    type IntoIter = Iter<'a>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            iter: self.map.iter(),
        }
    }
}

/// Iterator over `&mut serde_yaml::Mapping`.
pub struct IterMut<'a> {
    iter: indexmap::map::IterMut<'a, Value, Value>,
}

delegate_iterator!((IterMut<'a>) => (&'a Value, &'a mut Value));

impl<'a> IntoIterator for &'a mut Mapping {
    type Item = (&'a Value, &'a mut Value);
    type IntoIter = IterMut<'a>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            iter: self.map.iter_mut(),
        }
    }
}

/// Iterator over `serde_yaml::Mapping` by value.
pub struct IntoIter {
    iter: indexmap::map::IntoIter<Value, Value>,
}

delegate_iterator!((IntoIter) => (Value, Value));

impl IntoIterator for Mapping {
    type Item = (Value, Value);
    type IntoIter = IntoIter;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IntoIter {
            iter: self.map.into_iter(),
        }
    }
}

/// Entry for an existing key-value pair or a vacant location to insert one.
pub enum Entry<'a> {
    /// Existing slot with equivalent key.
    Occupied(OccupiedEntry<'a>),
    /// Vacant slot (no equivalent key in the map).
    Vacant(VacantEntry<'a>),
}

/// A view into an occupied entry in a [`Mapping`]. It is part of the [`Entry`]
/// enum.
pub struct OccupiedEntry<'a> {
    occupied: indexmap::map::OccupiedEntry<'a, Value, Value>,
}

/// A view into a vacant entry in a [`Mapping`]. It is part of the [`Entry`]
/// enum.
pub struct VacantEntry<'a> {
    vacant: indexmap::map::VacantEntry<'a, Value, Value>,
}

impl<'a> Entry<'a> {
    /// Returns a reference to this entry's key.
    pub fn key(&self) -> &Value {
        match self {
            Entry::Vacant(e) => e.key(),
            Entry::Occupied(e) => e.key(),
        }
    }

    /// Ensures a value is in the entry by inserting the default if empty, and
    /// returns a mutable reference to the value in the entry.
    pub fn or_insert(self, default: Value) -> &'a mut Value {
        match self {
            Entry::Vacant(entry) => entry.insert(default),
            Entry::Occupied(entry) => entry.into_mut(),
        }
    }

    /// Ensures a value is in the entry by inserting the result of the default
    /// function if empty, and returns a mutable reference to the value in the
    /// entry.
    pub fn or_insert_with<F>(self, default: F) -> &'a mut Value
    where
        F: FnOnce() -> Value,
    {
        match self {
            Entry::Vacant(entry) => entry.insert(default()),
            Entry::Occupied(entry) => entry.into_mut(),
        }
    }

    /// Provides in-place mutable access to an occupied entry before any
    /// potential inserts into the map.
    pub fn and_modify<F>(self, f: F) -> Self
    where
        F: FnOnce(&mut Value),
    {
        match self {
            Entry::Occupied(mut entry) => {
                f(entry.get_mut());
                Entry::Occupied(entry)
            }
            Entry::Vacant(entry) => Entry::Vacant(entry),
        }
    }
}

impl<'a> OccupiedEntry<'a> {
    /// Gets a reference to the key in the entry.
    #[inline]
    pub fn key(&self) -> &Value {
        self.occupied.key()
    }

    /// Gets a reference to the value in the entry.
    #[inline]
    pub fn get(&self) -> &Value {
        self.occupied.get()
    }

    /// Gets a mutable reference to the value in the entry.
    #[inline]
    pub fn get_mut(&mut self) -> &mut Value {
        self.occupied.get_mut()
    }

    /// Converts the entry into a mutable reference to its value.
    #[inline]
    pub fn into_mut(self) -> &'a mut Value {
        self.occupied.into_mut()
    }

    /// Sets the value of the entry with the `OccupiedEntry`'s key, and returns
    /// the entry's old value.
    #[inline]
    pub fn insert(&mut self, value: Value) -> Value {
        self.occupied.insert(value)
    }

    /// Takes the value of the entry out of the map, and returns it.
    #[inline]
    pub fn remove(self) -> Value {
        self.occupied.swap_remove()
    }
}

impl<'a> VacantEntry<'a> {
    /// Gets a reference to the key that would be used when inserting a value
    /// through the VacantEntry.
    #[inline]
    pub fn key(&self) -> &Value {
        self.vacant.key()
    }

    /// Sets the value of the entry with the VacantEntry's key, and returns a
    /// mutable reference to it.
    #[inline]
    pub fn insert(self, value: Value) -> &'a mut Value {
        self.vacant.insert(value)
    }
}

impl Serialize for Mapping {
    #[inline]
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        use serde::ser::SerializeMap;
        let mut map_serializer = serializer.serialize_map(Some(self.len()))?;
        for (k, v) in self {
            map_serializer.serialize_entry(k, v)?;
        }
        map_serializer.end()
    }
}

impl<'de> Deserialize<'de> for Mapping {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct Visitor;

        impl<'de> serde::de::Visitor<'de> for Visitor {
            type Value = Mapping;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a YAML mapping")
            }

            #[inline]
            fn visit_unit<E>(self) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                Ok(Mapping::new())
            }

            #[inline]
            fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
            where
                V: serde::de::MapAccess<'de>,
            {
                let mut values = Mapping::new();
                while let Some((k, v)) = visitor.next_entry()? {
                    values.insert(k, v);
                }
                Ok(values)
            }
        }

        deserializer.deserialize_map(Visitor)
    }
}
<|endoftext|>


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

use std::collections::BTreeMap;
use std::io;
use std::path::{Path, PathBuf};

use syntax::ast;
use syntax::codemap::{self, FileName};
use syntax::parse::parser;

use utils::contains_skip;

/// List all the files containing modules of a crate.
/// If a file is used twice in a crate, it appears only once.
pub fn list_files<'a>(
    krate: &'a ast::Crate,
    codemap: &codemap::CodeMap,
) -> Result<BTreeMap<FileName, &'a ast::Mod>, io::Error> {
    let mut result = BTreeMap::new(); // Enforce file order determinism
    let root_filename = codemap.span_to_filename(krate.span);
    {
        let parent = match root_filename {
            FileName::Real(ref path) => path.parent().unwrap(),
            _ => Path::new(""),
        };
        list_submodules(&krate.module, parent, codemap, &mut result)?;
    }
    result.insert(root_filename, &krate.module);
    Ok(result)
}

/// Recursively list all external modules included in a module.
fn list_submodules<'a>(
    module: &'a ast::Mod,
    search_dir: &Path,
    codemap: &codemap::CodeMap,
    result: &mut BTreeMap<FileName, &'a ast::Mod>,
) -> Result<(), io::Error> {
    debug!("list_submodules: search_dir: {:?}", search_dir);
    for item in &module.items {
        if let ast::ItemKind::Mod(ref sub_mod) = item.node {
            if !contains_skip(&item.attrs) {
                let is_internal =
                    codemap.span_to_filename(item.span) == codemap.span_to_filename(sub_mod.inner);
                let dir_path = if is_internal {
                    search_dir.join(&item.ident.to_string())
                } else {
                    let mod_path = module_file(item.ident, &item.attrs, search_dir, codemap)?;
                    let dir_path = mod_path.parent().unwrap().to_owned();
                    result.insert(FileName::Real(mod_path), sub_mod);
                    dir_path
                };
                list_submodules(sub_mod, &dir_path, codemap, result)?;
            }
        }
    }
    Ok(())
}

/// Find the file corresponding to an external mod
fn module_file(
    id: ast::Ident,
    attrs: &[ast::Attribute],
    dir_path: &Path,
    codemap: &codemap::CodeMap,
) -> Result<PathBuf, io::Error> {
    if let Some(path) = parser::Parser::submod_path_from_attr(attrs, dir_path) {
        return Ok(path);
    }

    match parser::Parser::default_submod_path(id, None, dir_path, codemap).result {
        Ok(parser::ModulePathSuccess { path, .. }) => Ok(path),
        Err(_) => Err(io::Error::new(
            io::ErrorKind::Other,
            format!("Couldn't find module {}", id),
        )),
    }
}
<commit_msg>Fix handling of modules in non_modrs_mods style<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::BTreeMap;
use std::io;
use std::path::{Path, PathBuf};

use syntax::ast;
use syntax::codemap::{self, FileName};
use syntax::parse::{parser, DirectoryOwnership};

use utils::contains_skip;

/// List all the files containing modules of a crate.
/// If a file is used twice in a crate, it appears only once.
pub fn list_files<'a>(
    krate: &'a ast::Crate,
    codemap: &codemap::CodeMap,
) -> Result<BTreeMap<FileName, &'a ast::Mod>, io::Error> {
    let mut result = BTreeMap::new(); // Enforce file order determinism
    let root_filename = codemap.span_to_filename(krate.span);
    {
        let parent = match root_filename {
            FileName::Real(ref path) => path.parent().unwrap(),
            _ => Path::new(""),
        };
        list_submodules(&krate.module, parent, None, codemap, &mut result)?;
    }
    result.insert(root_filename, &krate.module);
    Ok(result)
}

/// Recursively list all external modules included in a module.
fn list_submodules<'a>(
    module: &'a ast::Mod,
    search_dir: &Path,
    relative: Option<ast::Ident>,
    codemap: &codemap::CodeMap,
    result: &mut BTreeMap<FileName, &'a ast::Mod>,
) -> Result<(), io::Error> {
    debug!("list_submodules: search_dir: {:?}", search_dir);
    for item in &module.items {
        if let ast::ItemKind::Mod(ref sub_mod) = item.node {
            if !contains_skip(&item.attrs) {
                let is_internal =
                    codemap.span_to_filename(item.span) == codemap.span_to_filename(sub_mod.inner);
                let (dir_path, relative) = if is_internal {
                    (search_dir.join(&item.ident.to_string()), None)
                } else {
                    let (mod_path, relative) =
                        module_file(item.ident, &item.attrs, search_dir, relative, codemap)?;
                    let dir_path = mod_path.parent().unwrap().to_owned();
                    result.insert(FileName::Real(mod_path), sub_mod);
                    (dir_path, relative)
                };
                list_submodules(sub_mod, &dir_path, relative, codemap, result)?;
            }
        }
    }
    Ok(())
}

/// Find the file corresponding to an external mod
fn module_file(
    id: ast::Ident,
    attrs: &[ast::Attribute],
    dir_path: &Path,
    relative: Option<ast::Ident>,
    codemap: &codemap::CodeMap,
) -> Result<(PathBuf, Option<ast::Ident>), io::Error> {
    eprintln!("module_file {:?} {:?} {:?}", id, attrs, dir_path);
    if let Some(path) = parser::Parser::submod_path_from_attr(attrs, dir_path) {
        return Ok((path, None));
    }

    match parser::Parser::default_submod_path(id, relative, dir_path, codemap).result {
        Ok(parser::ModulePathSuccess {
            path,
            directory_ownership,
            ..
        }) => {
            let relative = if let DirectoryOwnership::Owned { relative } = directory_ownership {
                relative
            } else {
                None
            };
            Ok((path, relative))
        }
        Err(_) => Err(io::Error::new(
            io::ErrorKind::Other,
            format!("Couldn't find module {}", id),
        )),
    }
}
<|endoftext|>