<commit_before>use std::{error, marker, u32};
use std::fmt::{self, Debug, Formatter};
use Command;

/// A command wrapper which always merges with itself.
///
/// This is done by always having an [`id`] of `u32::MAX`.
///
/// [`id`]: trait.Command.html#method.id
#[allow(dead_code)]
pub struct Merger<R, C: Command<R> + 'static> {
    cmd: C,
    _marker: marker::PhantomData<Box<Command<R> + 'static>>,
}

impl<R, C: Command<R> + 'static> From<C> for Merger<R, C> {
    #[inline]
    fn from(cmd: C) -> Self {
        Merger {
            cmd,
            _marker: marker::PhantomData,
        }
    }
}

impl<R, C: Command<R> + 'static> Command<R> for Merger<R, C> {
    #[inline]
    fn apply(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd.apply(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd.undo(receiver)
    }

    #[inline]
    fn redo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd.redo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        Some(u32::MAX)
    }
}

impl<R, C: Command<R> + 'static> Debug for Merger<R, C> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merger")
            .field("cmd", &self.cmd)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<R, C: Command<R> + 'static> Display for Merger<R, C> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{cmd}", cmd = self.cmd)
    }
}

pub struct Merged<R> {
    pub cmd1: Box<Command<R> + 'static>,
    pub cmd2: Box<Command<R> + 'static>,
}

impl<R> Command<R> for Merged<R> {
    #[inline]
    fn apply(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd1.apply(receiver)?;
        self.cmd2.apply(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd2.undo(receiver)?;
        self.cmd1.undo(receiver)
    }

    #[inline]
    fn redo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd1.redo(receiver)?;
        self.cmd2.redo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        self.cmd1.id()
    }
}

impl<R> Debug for Merged<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merged")
            .field("cmd1", &self.cmd1)
            .field("cmd2", &self.cmd2)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<R> fmt::Display for Merged<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{cmd1} + {cmd2}", cmd1 = self.cmd1, cmd2 = self.cmd2)
    }
}
<commit_msg>Fix Display import<commit_after>use std::{error, marker, u32};
use std::fmt::{self, Debug, Formatter};
use Command;

/// A command wrapper which always merges with itself.
///
/// This is done by always having an [`id`] of `u32::MAX`.
///
/// [`id`]: trait.Command.html#method.id
#[allow(dead_code)]
pub struct Merger<R, C: Command<R> + 'static> {
    cmd: C,
    _marker: marker::PhantomData<Box<Command<R> + 'static>>,
}

impl<R, C: Command<R> + 'static> From<C> for Merger<R, C> {
    #[inline]
    fn from(cmd: C) -> Self {
        Merger {
            cmd,
            _marker: marker::PhantomData,
        }
    }
}

impl<R, C: Command<R> + 'static> Command<R> for Merger<R, C> {
    #[inline]
    fn apply(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd.apply(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd.undo(receiver)
    }

    #[inline]
    fn redo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd.redo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        Some(u32::MAX)
    }
}

impl<R, C: Command<R> + 'static> Debug for Merger<R, C> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merger")
            .field("cmd", &self.cmd)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<R, C: Command<R> + 'static> fmt::Display for Merger<R, C> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{cmd}", cmd = self.cmd)
    }
}

pub struct Merged<R> {
    pub cmd1: Box<Command<R> + 'static>,
    pub cmd2: Box<Command<R> + 'static>,
}

impl<R> Command<R> for Merged<R> {
    #[inline]
    fn apply(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd1.apply(receiver)?;
        self.cmd2.apply(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd2.undo(receiver)?;
        self.cmd1.undo(receiver)
    }

    #[inline]
    fn redo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd1.redo(receiver)?;
        self.cmd2.redo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        self.cmd1.id()
    }
}

impl<R> Debug for Merged<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merged")
            .field("cmd1", &self.cmd1)
            .field("cmd2", &self.cmd2)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<R> fmt::Display for Merged<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{cmd1} + {cmd2}", cmd1 = self.cmd1, cmd2 = self.cmd2)
    }
}
<|endoftext|>


<commit_before>use failure::{bail, ensure, format_err, Error};
use libc::c_ulong;
use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region};
use lucet_wasi::host::__wasi_exitcode_t;
use lucet_wasi::{WasiCtx, WasiCtxBuilder};
use lucet_wasi_sdk::{CompileOpts, Link};
use lucetc::{Bindings, Lucetc, LucetcOpts};
use rand::prelude::random;
use rayon::prelude::*;
use regex::Regex;
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::prelude::{FromRawFd, IntoRawFd, OpenOptionsExt};
use std::path::{Path, PathBuf};
use std::process::{exit, Command, Stdio};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use structopt::StructOpt;
use tempfile::TempDir;
use wait_timeout::ChildExt;

const LUCET_WASI_FUZZ_ROOT: &'static str = env!("CARGO_MANIFEST_DIR");

type Seed = c_ulong;

#[derive(StructOpt, Debug)]
#[structopt(name = "lucet-wasi-fuzz")]
enum Config {
    /// Test the Lucet toolchain against native code execution using Csmith
    #[structopt(name = "fuzz")]
    Fuzz {
        #[structopt(short = "n", long = "num-tests", default_value = "100")]
        /// The number of tests to run
        num_tests: usize,
    },

    /// Reduce a test case, starting from the given Csmith seed
    #[structopt(name = "creduce")]
    Creduce { seed: Seed },

    /// Creduce interestingness check (probably not useful directly)
    #[structopt(name = "creduce-interesting")]
    CreduceInteresting { creduce_src: PathBuf },

    /// Run a test case with the given Csmith seed
    #[structopt(name = "test-seed")]
    TestSeed { seed: Seed },
}

fn main() {
    lucet_runtime::lucet_internal_ensure_linked();

    match Config::from_args() {
        Config::Fuzz { num_tests } => run_many(num_tests),
        Config::Creduce { seed } => run_creduce_driver(seed),
        Config::CreduceInteresting { creduce_src } => run_creduce_interestingness(creduce_src),
        Config::TestSeed { seed } => run_one_seed(seed),
    }
}

fn run_creduce_driver(seed: Seed) {
    let tmpdir = TempDir::new().unwrap();

    // make the driver script

    let mut script = std::fs::OpenOptions::new()
        .create(true)
        .write(true)
        .mode(0o777)
        .open(tmpdir.path().join("script.sh"))
        .unwrap();

    let current_exe = std::env::current_exe().unwrap();

    write!(
        script,
        "{}",
        format!(
            "#!/usr/bin/env sh\n{} creduce-interesting gen.c",
            current_exe.display()
        ),
    )
    .unwrap();

    drop(script);

    // reproduce the generated program, and then preprocess it

    let st = Command::new("csmith")
        .arg("-s")
        .arg(format!("{}", seed))
        .arg("-o")
        .arg(tmpdir.path().join("gen-original.c"))
        .status()
        .unwrap();
    assert!(st.success());

    let st = Command::new("clang")
        .arg("-I/usr/include/csmith")
        .arg("-m32")
        .arg("-E")
        .arg("-P")
        .arg(tmpdir.path().join("gen-original.c"))
        .arg("-o")
        .arg(tmpdir.path().join("gen.c"))
        .status()
        .unwrap();
    assert!(st.success());

    let st = Command::new("creduce")
        .current_dir(tmpdir.path())
        .arg("--n")
        .arg(format!("{}", std::cmp::max(1, num_cpus::get() - 1)))
        .arg("script.sh")
        .arg("gen.c")
        .status()
        .unwrap();
    assert!(st.success());

    print!(
        "{}",
        std::fs::read_to_string(tmpdir.path().join("gen.c")).unwrap()
    );
}

fn run_creduce_interestingness<P: AsRef<Path>>(src: P) {
    let tmpdir = TempDir::new().unwrap();

    match run_both(&tmpdir, src, None) {
        Ok(TestResult::Passed) => println!("test passed"),
        Ok(TestResult::Ignored) => println!("native build/execution failed"),
        Ok(TestResult::Failed {
            expected, actual, ..
        }) => {
            println!("test failed:\n");
            let expected = String::from_utf8_lossy(&expected);
            let actual = String::from_utf8_lossy(&actual);
            println!("native: {}", &expected);
            println!("lucet-wasi: {}", &actual);

            let re = Regex::new(r"^checksum = ([[:xdigit:]]{8})").unwrap();

            // a coarse way to stop creduce from producing degenerate cases that happen to yield
            // different output

            let expected_checksum = if let Some(caps) = re.captures(&expected) {
                if let Some(cap) = caps.get(1) {
                    cap.as_str().to_owned()
                } else {
                    // not interesting: no checksum captured from native output
                    exit(1);
                }
            } else {
                // not interesting: no checksum captured from native output
                exit(1);
            };

            let actual_checksum = if let Some(caps) = re.captures(&actual) {
                if let Some(cap) = caps.get(1) {
                    cap.as_str().to_owned()
                } else {
                    // interesting: checksum captured from native output but not wasm
                    exit(0)
                }
            } else {
                // interesting: checksum captured from native output but not wasm
                exit(0)
            };

            if expected_checksum == actual_checksum {
                // they match; not interesting
                exit(1);
            } else {
                exit(0);
            }
        }
        Ok(TestResult::Errored { error }) | Err(error) => println!("test errored: {}", error),
    }
    exit(1);
}

fn run_one_seed(seed: Seed) {
    match run_one(Some(seed)) {
        Ok(TestResult::Passed) => println!("test passed"),
        Ok(TestResult::Ignored) => println!("native build/execution failed"),
        Ok(TestResult::Failed {
            expected, actual, ..
        }) => {
            println!("test failed:\n");
            println!("native: {}", String::from_utf8_lossy(&expected));
            println!("lucet-wasi: {}", String::from_utf8_lossy(&actual));
            exit(1);
        }
        Ok(TestResult::Errored { error }) | Err(error) => println!("test errored: {}", error),
    }
}

fn run_many(num_tests: usize) {
    let mut progress = progress::Bar::new();
    progress.set_job_title(&format!("Running {} tests", num_tests));

    let progress = Arc::new(Mutex::new(progress));
    let num_finished = Arc::new(Mutex::new(0));

    let res = (0..num_tests)
        .into_par_iter()
        .try_for_each(|_| match run_one(None) {
            Ok(TestResult::Passed) | Ok(TestResult::Ignored) => {
                let mut num_finished = num_finished.lock().unwrap();
                *num_finished += 1;
                let percentage = (*num_finished as f32 / num_tests as f32) * 100.0;
                progress
                    .lock()
                    .unwrap()
                    .reach_percent(percentage.floor() as i32);
                Ok(())
            }
            Ok(fail) => Err(fail),
            Err(error) => Err(TestResult::Errored { error }),
        });

    progress.lock().unwrap().jobs_done();

    match res {
        Err(TestResult::Failed {
            seed,
            expected,
            actual,
        }) => {
            println!("test failed with seed {}\n", seed.unwrap());
            println!("native: {}", String::from_utf8_lossy(&expected));
            println!("lucet-wasi: {}", String::from_utf8_lossy(&actual));
            exit(1);
        }
        Err(TestResult::Errored { error }) => println!("test errored: {}", error),
        Err(_) => unreachable!(),
        Ok(()) => println!("all tests passed"),
    }
}

fn gen_c<P: AsRef<Path>>(gen_c_path: P, seed: Seed) -> Result<(), Error> {
    Command::new("csmith")
        .arg("-s")
        .arg(format!("{}", seed))
        .arg("-o")
        .arg(gen_c_path.as_ref())
        .status()?;
    Ok(())
}

fn run_both<P: AsRef<Path>>(
    tmpdir: &TempDir,
    src: P,
    seed: Option<Seed>,
) -> Result<TestResult, Error> {
    let native_stdout = if let Some(stdout) = run_native(&tmpdir, src.as_ref())? {
        stdout
    } else {
        return Ok(TestResult::Ignored);
    };

    let (exitcode, wasm_stdout) = run_with_stdout(&tmpdir, src.as_ref())?;

    assert_eq!(exitcode, 0);

    if &wasm_stdout != &native_stdout {
        Ok(TestResult::Failed {
            seed,
            expected: native_stdout,
            actual: wasm_stdout,
        })
    } else {
        Ok(TestResult::Passed)
    }
}

fn run_native<P: AsRef<Path>>(tmpdir: &TempDir, gen_c_path: P) -> Result<Option<Vec<u8>>, Error> {
    let gen_path = tmpdir.path().join("gen");

    let res = Command::new("clang")
        .arg("-m32")
        .arg("-std=c11")
        .arg("-Werror=format")
        .arg("-Werror=uninitialized")
        .arg("-Werror=conditional-uninitialized")
        .arg("-I/usr/include/csmith")
        .arg(gen_c_path.as_ref())
        .arg("-o")
        .arg(&gen_path)
        .output()?;
    ensure!(res.status.success(), "native C compilation failed");

    if String::from_utf8_lossy(&res.stderr).contains("too few arguments in call") {
        bail!("saw \"too few arguments in call\" warning");
    }

    let mut native_child = Command::new(&gen_path).stdout(Stdio::piped()).spawn()?;

    let exitcode = match native_child.wait_timeout(Duration::from_millis(1000))? {
        Some(status) => status.code(),
        None => {
            native_child.kill()?;
            native_child.wait()?.code()
        }
    };

    match exitcode {
        None => {
            // native code diverged or took too long, so was killed by the timeout
            return Ok(None);
        }
        Some(0) => (),
        Some(code) => {
            println!("native code returned non-zero exit code: {}", code);
            return Ok(None);
        }
    }

    let mut native_stdout = vec![];
    native_child
        .stdout
        .ok_or(format_err!("couldn't get stdout"))?
        .read_to_end(&mut native_stdout)?;

    Ok(Some(native_stdout))
}

enum TestResult {
    Passed,
    Ignored,
    Failed {
        seed: Option<Seed>,
        expected: Vec<u8>,
        actual: Vec<u8>,
    },
    Errored {
        error: Error,
    },
}

fn run_one(seed: Option<Seed>) -> Result<TestResult, Error> {
    let tmpdir = TempDir::new().unwrap();

    let gen_c_path = tmpdir.path().join("gen.c");

    let seed = seed.unwrap_or(random::<Seed>());
    gen_c(&gen_c_path, seed)?;

    run_both(&tmpdir, &gen_c_path, Some(seed))
}

fn run_with_stdout<P: AsRef<Path>>(
    tmpdir: &TempDir,
    path: P,
) -> Result<(__wasi_exitcode_t, Vec<u8>), Error> {
    let ctx = WasiCtxBuilder::new().args(&["gen"]);

    let (pipe_out, pipe_in) = nix::unistd::pipe()?;

    let ctx = unsafe { ctx.raw_fd(1, pipe_in) }.build()?;

    let exitcode = run(tmpdir, path, ctx)?;

    let mut stdout_file = unsafe { File::from_raw_fd(pipe_out) };
    let mut stdout = vec![];
    stdout_file.read_to_end(&mut stdout)?;
    nix::unistd::close(stdout_file.into_raw_fd())?;

    Ok((exitcode, stdout))
}

fn run<P: AsRef<Path>>(
    tmpdir: &TempDir,
    path: P,
    ctx: WasiCtx,
) -> Result<__wasi_exitcode_t, Error> {
    let region = MmapRegion::create(1, &Limits::default())?;
    let module = wasi_test(tmpdir, path)?;

    let mut inst = region
        .new_instance_builder(module)
        .with_embed_ctx(ctx)
        .build()?;

    match inst.run("_start", &[]) {
        // normal termination implies 0 exit code
        Ok(_) => Ok(0),
        Err(lucet_runtime::Error::RuntimeTerminated(
            lucet_runtime::TerminationDetails::Provided(any),
        )) => Ok(*any
            .downcast_ref::<__wasi_exitcode_t>()
            .expect("termination yields an exitcode")),
        Err(e) => bail!("runtime error: {}", e),
    }
}

fn wasi_test<P: AsRef<Path>>(tmpdir: &TempDir, c_file: P) -> Result<Arc<dyn Module>, Error> {
    let wasm_build = Link::new(&[c_file]).with_cflag("-I/usr/include/csmith");

    let wasm_file = tmpdir.path().join("out.wasm");

    wasm_build.link(wasm_file.clone())?;

    let bindings = Bindings::from_file(
        Path::new(LUCET_WASI_FUZZ_ROOT)
            .parent()
            .unwrap()
            .join("lucet-wasi")
            .join("bindings.json"),
    )?;

    let native_build = Lucetc::new(wasm_file).with_bindings(bindings);

    let so_file = tmpdir.path().join("out.so");

    native_build.shared_object_file(so_file.clone())?;

    let dlmodule = DlModule::load(so_file)?;

    Ok(dlmodule as Arc<dyn Module>)
}
<commit_msg>[lucet-wasi-fuzz] make clang configurable and add error code<commit_after>use failure::{bail, ensure, format_err, Error};
use libc::c_ulong;
use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region};
use lucet_wasi::host::__wasi_exitcode_t;
use lucet_wasi::{WasiCtx, WasiCtxBuilder};
use lucet_wasi_sdk::{CompileOpts, Link};
use lucetc::{Bindings, Lucetc, LucetcOpts};
use rand::prelude::random;
use rayon::prelude::*;
use regex::Regex;
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::prelude::{FromRawFd, IntoRawFd, OpenOptionsExt};
use std::path::{Path, PathBuf};
use std::process::{exit, Command, Stdio};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use structopt::StructOpt;
use tempfile::TempDir;
use wait_timeout::ChildExt;

const LUCET_WASI_FUZZ_ROOT: &'static str = env!("CARGO_MANIFEST_DIR");

type Seed = c_ulong;

#[derive(StructOpt, Debug)]
#[structopt(name = "lucet-wasi-fuzz")]
enum Config {
    /// Test the Lucet toolchain against native code execution using Csmith
    #[structopt(name = "fuzz")]
    Fuzz {
        #[structopt(short = "n", long = "num-tests", default_value = "100")]
        /// The number of tests to run
        num_tests: usize,
    },

    /// Reduce a test case, starting from the given Csmith seed
    #[structopt(name = "creduce")]
    Creduce { seed: Seed },

    /// Creduce interestingness check (probably not useful directly)
    #[structopt(name = "creduce-interesting")]
    CreduceInteresting { creduce_src: PathBuf },

    /// Run a test case with the given Csmith seed
    #[structopt(name = "test-seed")]
    TestSeed { seed: Seed },
}

fn main() {
    lucet_runtime::lucet_internal_ensure_linked();
    lucet_wasi::hostcalls::ensure_linked();

    match Config::from_args() {
        Config::Fuzz { num_tests } => run_many(num_tests),
        Config::Creduce { seed } => run_creduce_driver(seed),
        Config::CreduceInteresting { creduce_src } => run_creduce_interestingness(creduce_src),
        Config::TestSeed { seed } => run_one_seed(seed),
    }
}

fn run_creduce_driver(seed: Seed) {
    let tmpdir = TempDir::new().unwrap();

    // make the driver script

    let mut script = std::fs::OpenOptions::new()
        .create(true)
        .write(true)
        .mode(0o777)
        .open(tmpdir.path().join("script.sh"))
        .unwrap();

    let current_exe = std::env::current_exe().unwrap();

    write!(
        script,
        "{}",
        format!(
            "#!/usr/bin/env sh\n{} creduce-interesting gen.c",
            current_exe.display()
        ),
    )
    .unwrap();

    drop(script);

    // reproduce the generated program, and then preprocess it

    let st = Command::new("csmith")
        .arg("-s")
        .arg(format!("{}", seed))
        .arg("-o")
        .arg(tmpdir.path().join("gen-original.c"))
        .status()
        .unwrap();
    assert!(st.success());

    let st = Command::new(native_clang())
        .arg("-I/usr/include/csmith")
        .arg("-m32")
        .arg("-E")
        .arg("-P")
        .arg(tmpdir.path().join("gen-original.c"))
        .arg("-o")
        .arg(tmpdir.path().join("gen.c"))
        .status()
        .unwrap();
    assert!(st.success());

    let st = Command::new("creduce")
        .current_dir(tmpdir.path())
        .arg("--n")
        .arg(format!("{}", std::cmp::max(1, num_cpus::get() - 1)))
        .arg("script.sh")
        .arg("gen.c")
        .status()
        .unwrap();
    assert!(st.success());

    print!(
        "{}",
        std::fs::read_to_string(tmpdir.path().join("gen.c")).unwrap()
    );
}

fn run_creduce_interestingness<P: AsRef<Path>>(src: P) {
    let tmpdir = TempDir::new().unwrap();

    match run_both(&tmpdir, src, None) {
        Ok(TestResult::Passed) => println!("test passed"),
        Ok(TestResult::Ignored) => println!("native build/execution failed"),
        Ok(TestResult::Failed {
            expected, actual, ..
        }) => {
            println!("test failed:\n");
            let expected = String::from_utf8_lossy(&expected);
            let actual = String::from_utf8_lossy(&actual);
            println!("native: {}", &expected);
            println!("lucet-wasi: {}", &actual);

            let re = Regex::new(r"^checksum = ([[:xdigit:]]{8})").unwrap();

            // a coarse way to stop creduce from producing degenerate cases that happen to yield
            // different output

            let expected_checksum = if let Some(caps) = re.captures(&expected) {
                if let Some(cap) = caps.get(1) {
                    cap.as_str().to_owned()
                } else {
                    // not interesting: no checksum captured from native output
                    exit(1);
                }
            } else {
                // not interesting: no checksum captured from native output
                exit(1);
            };

            let actual_checksum = if let Some(caps) = re.captures(&actual) {
                if let Some(cap) = caps.get(1) {
                    cap.as_str().to_owned()
                } else {
                    // interesting: checksum captured from native output but not wasm
                    exit(0)
                }
            } else {
                // interesting: checksum captured from native output but not wasm
                exit(0)
            };

            if expected_checksum == actual_checksum {
                // they match; not interesting
                exit(1);
            } else {
                exit(0);
            }
        }
        Ok(TestResult::Errored { error }) | Err(error) => println!("test errored: {}", error),
    }
    exit(1);
}

fn run_one_seed(seed: Seed) {
    match run_one(Some(seed)) {
        Ok(TestResult::Passed) => println!("test passed"),
        Ok(TestResult::Ignored) => println!("native build/execution failed"),
        Ok(TestResult::Failed {
            expected, actual, ..
        }) => {
            println!("test failed:\n");
            println!("native: {}", String::from_utf8_lossy(&expected));
            println!("lucet-wasi: {}", String::from_utf8_lossy(&actual));
            exit(1);
        }
        Ok(TestResult::Errored { error }) | Err(error) => {
            println!("test errored: {}", error);
            exit(1);
        }
    }
}

fn run_many(num_tests: usize) {
    let mut progress = progress::Bar::new();
    progress.set_job_title(&format!("Running {} tests", num_tests));

    let progress = Arc::new(Mutex::new(progress));
    let num_finished = Arc::new(Mutex::new(0));

    let res = (0..num_tests)
        .into_par_iter()
        .try_for_each(|_| match run_one(None) {
            Ok(TestResult::Passed) | Ok(TestResult::Ignored) => {
                let mut num_finished = num_finished.lock().unwrap();
                *num_finished += 1;
                let percentage = (*num_finished as f32 / num_tests as f32) * 100.0;
                progress
                    .lock()
                    .unwrap()
                    .reach_percent(percentage.floor() as i32);
                Ok(())
            }
            Ok(fail) => Err(fail),
            Err(error) => Err(TestResult::Errored { error }),
        });

    progress.lock().unwrap().jobs_done();

    match res {
        Err(TestResult::Failed {
            seed,
            expected,
            actual,
        }) => {
            println!("test failed with seed {}\n", seed.unwrap());
            println!("native: {}", String::from_utf8_lossy(&expected));
            println!("lucet-wasi: {}", String::from_utf8_lossy(&actual));
            exit(1);
        }
        Err(TestResult::Errored { error }) => println!("test errored: {}", error),
        Err(_) => unreachable!(),
        Ok(()) => println!("all tests passed"),
    }
}

fn gen_c<P: AsRef<Path>>(gen_c_path: P, seed: Seed) -> Result<(), Error> {
    Command::new("csmith")
        .arg("-s")
        .arg(format!("{}", seed))
        .arg("-o")
        .arg(gen_c_path.as_ref())
        .status()?;
    Ok(())
}

fn run_both<P: AsRef<Path>>(
    tmpdir: &TempDir,
    src: P,
    seed: Option<Seed>,
) -> Result<TestResult, Error> {
    let native_stdout = if let Some(stdout) = run_native(&tmpdir, src.as_ref())? {
        stdout
    } else {
        return Ok(TestResult::Ignored);
    };

    let (exitcode, wasm_stdout) = run_with_stdout(&tmpdir, src.as_ref())?;

    assert_eq!(exitcode, 0);

    if &wasm_stdout != &native_stdout {
        Ok(TestResult::Failed {
            seed,
            expected: native_stdout,
            actual: wasm_stdout,
        })
    } else {
        Ok(TestResult::Passed)
    }
}

fn run_native<P: AsRef<Path>>(tmpdir: &TempDir, gen_c_path: P) -> Result<Option<Vec<u8>>, Error> {
    let gen_path = tmpdir.path().join("gen");

    let mut cmd = Command::new(native_clang());
    cmd.arg("-m32")
        .arg("-std=c11")
        .arg("-Werror=format")
        .arg("-Werror=uninitialized")
        .arg("-Werror=conditional-uninitialized")
        .arg("-I/usr/include/csmith")
        .arg(gen_c_path.as_ref())
        .arg("-o")
        .arg(&gen_path);
    if let Ok(flags) = std::env::var("NATIVE_CLANG_FLAGS") {
        cmd.args(flags.split_whitespace());
    }
    let res = cmd.output()?;

    eprintln!("{}", String::from_utf8_lossy(&res.stderr));

    ensure!(res.status.success(), "native C compilation failed");

    if String::from_utf8_lossy(&res.stderr).contains("too few arguments in call") {
        bail!("saw \"too few arguments in call\" warning");
    }

    let mut native_child = Command::new(&gen_path).stdout(Stdio::piped()).spawn()?;

    let exitcode = match native_child.wait_timeout(Duration::from_millis(1000))? {
        Some(status) => status.code(),
        None => {
            native_child.kill()?;
            native_child.wait()?.code()
        }
    };

    match exitcode {
        None => {
            // native code diverged or took too long, so was killed by the timeout
            return Ok(None);
        }
        Some(0) => (),
        Some(code) => {
            println!("native code returned non-zero exit code: {}", code);
            return Ok(None);
        }
    }

    let mut native_stdout = vec![];
    native_child
        .stdout
        .ok_or(format_err!("couldn't get stdout"))?
        .read_to_end(&mut native_stdout)?;

    Ok(Some(native_stdout))
}

enum TestResult {
    Passed,
    Ignored,
    Failed {
        seed: Option<Seed>,
        expected: Vec<u8>,
        actual: Vec<u8>,
    },
    Errored {
        error: Error,
    },
}

fn run_one(seed: Option<Seed>) -> Result<TestResult, Error> {
    let tmpdir = TempDir::new().unwrap();

    let gen_c_path = tmpdir.path().join("gen.c");

    let seed = seed.unwrap_or(random::<Seed>());
    gen_c(&gen_c_path, seed)?;

    run_both(&tmpdir, &gen_c_path, Some(seed))
}

fn run_with_stdout<P: AsRef<Path>>(
    tmpdir: &TempDir,
    path: P,
) -> Result<(__wasi_exitcode_t, Vec<u8>), Error> {
    let ctx = WasiCtxBuilder::new().args(&["gen"]);

    let (pipe_out, pipe_in) = nix::unistd::pipe()?;

    let ctx = unsafe { ctx.raw_fd(1, pipe_in) }.build()?;

    let exitcode = run(tmpdir, path, ctx)?;

    let mut stdout_file = unsafe { File::from_raw_fd(pipe_out) };
    let mut stdout = vec![];
    stdout_file.read_to_end(&mut stdout)?;
    nix::unistd::close(stdout_file.into_raw_fd())?;

    Ok((exitcode, stdout))
}

fn run<P: AsRef<Path>>(
    tmpdir: &TempDir,
    path: P,
    ctx: WasiCtx,
) -> Result<__wasi_exitcode_t, Error> {
    let region = MmapRegion::create(1, &Limits::default())?;
    let module = wasi_test(tmpdir, path)?;

    let mut inst = region
        .new_instance_builder(module)
        .with_embed_ctx(ctx)
        .build()?;

    match inst.run("_start", &[]) {
        // normal termination implies 0 exit code
        Ok(_) => Ok(0),
        Err(lucet_runtime::Error::RuntimeTerminated(
            lucet_runtime::TerminationDetails::Provided(any),
        )) => Ok(*any
            .downcast_ref::<__wasi_exitcode_t>()
            .expect("termination yields an exitcode")),
        Err(e) => bail!("runtime error: {}", e),
    }
}

fn wasi_test<P: AsRef<Path>>(tmpdir: &TempDir, c_file: P) -> Result<Arc<dyn Module>, Error> {
    let wasm_build = Link::new(&[c_file]).with_cflag("-I/usr/include/csmith");

    let wasm_file = tmpdir.path().join("out.wasm");

    wasm_build.link(wasm_file.clone())?;

    let bindings = Bindings::from_file(
        Path::new(LUCET_WASI_FUZZ_ROOT)
            .parent()
            .unwrap()
            .join("lucet-wasi")
            .join("bindings.json"),
    )?;

    let native_build = Lucetc::new(wasm_file).with_bindings(bindings);

    let so_file = tmpdir.path().join("out.so");

    native_build.shared_object_file(so_file.clone())?;

    let dlmodule = DlModule::load(so_file)?;

    Ok(dlmodule as Arc<dyn Module>)
}

fn native_clang() -> PathBuf {
    match std::env::var("NATIVE_CLANG") {
        Ok(clang) => PathBuf::from(clang),
        Err(_) => PathBuf::from("clang"),
    }
}
<|endoftext|>


<commit_before>use core::world::dungeon::map::Grid;
use core::world::dungeon::map::{Tile, TileType};

use core::object::{Actions, Creature, Fighter};
use core::object::ai::AI;

extern crate rand;
use self::rand::{thread_rng, Rng};

///
/// BlinkAI makes monster teleport around the map periodically
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct BlinkAI;

impl BlinkAI {

  pub fn blink(&mut self, map: &Grid<Tile>, _player: &Creature, me: &mut Fighter) -> (isize, isize) {
    let mut rng = thread_rng();
    let mut x = me.pos.x;
    let mut y = me.pos.y;
    x += rng.gen_range(-8, 8);
    y += rng.gen_range(-8, 8);
    if x < 0 {
      x = 0;
    }
    if y < 0 {
      y = 0;
    }
    if y >= (map[0].len() - 1) as isize {
      y = (map[0].len() - 1) as isize;
    }
    if x >= (map.len() - 1) as isize {
      x = (map.len() - 1) as isize;
    }
    return (x, y);
  }

  pub fn new() -> BlinkAI {
    BlinkAI {}
  }

}

impl AI for BlinkAI {

  ///
  /// Walk around randomly
  ///
  fn take_turn(&mut self, map: &Grid<Tile>, _player: &Creature, me: &mut Fighter) -> Actions {

    let mut rng = thread_rng();

    let mut x = me.pos.x;
    let mut y = me.pos.y;
    let mut count : usize = 0;
    let mut state = Actions::Move;

    loop {
      count += 1;

      let dice : i32;
      dice = rng.gen_range(1, 6);
      match dice {
        1 => x += 1,
        2 => x -= 1,
        3 => y += 1,
        4 => y -= 1,
        5 => {
          let bpos = self.blink(map, _player, me);
          x = bpos.0;
          y = bpos.1;
          state = Actions::Blink;
        },
        _ => unreachable!("dice machine broke")
      }

      match map[x as usize][y as usize].tiletype {
        TileType::Floor => break,
        _ => {
          if count > 100 {
            x = me.pos.x;
            y = me.pos.y;
            break;
          }
        }
      }
    }

    me.pos.x = x as isize;
    me.pos.y = y as isize;

    return state;

  }

}<commit_msg>Closes #40<commit_after>use core::world::dungeon::map::Grid;
use core::world::dungeon::map::{Tile, TileType};

use core::object::{Actions, Creature, Fighter};
use core::object::ai::AI;

extern crate rand;
use self::rand::{thread_rng, Rng};

///
/// BlinkAI makes monster teleport around the map periodically
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct BlinkAI;

impl BlinkAI {

  pub fn blink(&mut self, me: &mut Fighter) -> (isize, isize) {
    let mut rng = thread_rng();
    let mut x = me.pos.x;
    let mut y = me.pos.y;
    x += rng.gen_range(-8, 8);
    y += rng.gen_range(-8, 8);
    return (x, y);
  }

  pub fn new() -> BlinkAI {
    BlinkAI {}
  }

}

impl AI for BlinkAI {

  ///
  /// Walk around randomly
  ///
  fn take_turn(&mut self, map: &Grid<Tile>, _player: &Creature, me: &mut Fighter) -> Actions {

    let mut rng = thread_rng();

    let mut x = me.pos.x;
    let mut y = me.pos.y;
    let mut count : usize = 0;
    let mut state = Actions::Move;

    loop {
      count += 1;

      let dice : i32;
      dice = rng.gen_range(1, 6);
      match dice {
        1 => x += 1,
        2 => x -= 1,
        3 => y += 1,
        4 => y -= 1,
        5 => {
          let bpos = self.blink(me);
          x = bpos.0;
          y = bpos.1;
          state = Actions::Blink;
        },
        _ => unreachable!("dice machine broke")
      }

      // Check bounds
      if x < 0 {
        x = 0;
      }
      if y < 0 {
        y = 0;
      }
      if y >= (map[0].len() - 1) as isize {
        y = (map[0].len() - 1) as isize;
      }
      if x >= (map.len() - 1) as isize {
        x = (map.len() - 1) as isize;
      }

      match map[x as usize][y as usize].tiletype {
        TileType::Floor | TileType::Water | TileType::UpStair | TileType::DownStair => break,
        _ => {
          if count > 100 {
            x = me.pos.x;
            y = me.pos.y;
            break;
          }
        }
      }
    }

    me.pos.x = x as isize;
    me.pos.y = y as isize;

    return state;

  }

}<|endoftext|>


<commit_before>use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::ObligationCause;
use crate::traits::{self, TraitEngine};

use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::Span;
use std::ops::ControlFlow;

#[derive(Debug)]
pub enum NonStructuralMatchTy<'tcx> {
    Adt(&'tcx AdtDef),
    Param,
    Dynamic,
    Foreign,
    Opaque,
    Generator,
    Projection,
    Closure,
}

/// This method traverses the structure of `ty`, trying to find an
/// instance of an ADT (i.e. struct or enum) that doesn't implement
/// the structural-match traits, or a generic type parameter
/// (which cannot be determined to be structural-match).
///
/// The "structure of a type" includes all components that would be
/// considered when doing a pattern match on a constant of that
/// type.
///
///  * This means this method descends into fields of structs/enums,
///    and also descends into the inner type `T` of `&T` and `&mut T`
///
///  * The traversal doesn't dereference unsafe pointers (`*const T`,
///    `*mut T`), and it does not visit the type arguments of an
///    instantiated generic like `PhantomData<T>`.
///
/// The reason we do this search is Rust currently require all ADTs
/// reachable from a constant's type to implement the
/// structural-match traits, which essentially say that
/// the implementation of `PartialEq::eq` behaves *equivalently* to a
/// comparison against the unfolded structure.
///
/// For more background on why Rust has this requirement, and issues
/// that arose when the requirement was not enforced completely, see
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
pub fn search_for_structural_match_violation<'tcx>(
    _id: hir::HirId,
    span: Span,
    tcx: TyCtxt<'tcx>,
    ty: Ty<'tcx>,
) -> Option<NonStructuralMatchTy<'tcx>> {
    // FIXME: we should instead pass in an `infcx` from the outside.
    tcx.infer_ctxt().enter(|infcx| {
        let mut search = Search { infcx, span, found: None, seen: FxHashSet::default() };
        ty.visit_with(&mut search);
        search.found
    })
}

/// This method returns true if and only if `adt_ty` itself has been marked as
/// eligible for structural-match: namely, if it implements both
/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by
/// `#[derive(PartialEq)]` and `#[derive(Eq)]`).
///
/// Note that this does *not* recursively check if the substructure of `adt_ty`
/// implements the traits.
fn type_marked_structural(
    infcx: &InferCtxt<'_, 'tcx>,
    adt_ty: Ty<'tcx>,
    cause: ObligationCause<'tcx>,
) -> bool {
    let mut fulfillment_cx = traits::FulfillmentContext::new();
    // require `#[derive(PartialEq)]`
    let structural_peq_def_id =
        infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span));
    fulfillment_cx.register_bound(
        infcx,
        ty::ParamEnv::empty(),
        adt_ty,
        structural_peq_def_id,
        cause.clone(),
    );
    // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
    // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
    let structural_teq_def_id =
        infcx.tcx.require_lang_item(LangItem::StructuralTeq, Some(cause.span));
    fulfillment_cx.register_bound(
        infcx,
        ty::ParamEnv::empty(),
        adt_ty,
        structural_teq_def_id,
        cause,
    );

    // We deliberately skip *reporting* fulfillment errors (via
    // `report_fulfillment_errors`), for two reasons:
    //
    // 1. The error messages would mention `std::marker::StructuralPartialEq`
    //    (a trait which is solely meant as an implementation detail
    //    for now), and
    //
    // 2. We are sometimes doing future-incompatibility lints for
    //    now, so we do not want unconditional errors here.
    fulfillment_cx.select_all_or_error(infcx).is_ok()
}

/// This implements the traversal over the structure of a given type to try to
/// find instances of ADTs (specifically structs or enums) that do not implement
/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
struct Search<'a, 'tcx> {
    span: Span,

    infcx: InferCtxt<'a, 'tcx>,

    /// Records first ADT that does not implement a structural-match trait.
    found: Option<NonStructuralMatchTy<'tcx>>,

    /// Tracks ADTs previously encountered during search, so that
    /// we will not recur on them again.
    seen: FxHashSet<hir::def_id::DefId>,
}

impl Search<'a, 'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.infcx.tcx
    }

    fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
        adt_ty.is_structural_eq_shallow(self.tcx())
    }
}

impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
        debug!("Search visiting ty: {:?}", ty);

        let (adt_def, substs) = match *ty.kind() {
            ty::Adt(adt_def, substs) => (adt_def, substs),
            ty::Param(_) => {
                self.found = Some(NonStructuralMatchTy::Param);
                return ControlFlow::BREAK;
            }
            ty::Dynamic(..) => {
                self.found = Some(NonStructuralMatchTy::Dynamic);
                return ControlFlow::BREAK;
            }
            ty::Foreign(_) => {
                self.found = Some(NonStructuralMatchTy::Foreign);
                return ControlFlow::BREAK;
            }
            ty::Opaque(..) => {
                self.found = Some(NonStructuralMatchTy::Opaque);
                return ControlFlow::BREAK;
            }
            ty::Projection(..) => {
                self.found = Some(NonStructuralMatchTy::Projection);
                return ControlFlow::BREAK;
            }
            ty::Generator(..) | ty::GeneratorWitness(..) => {
                self.found = Some(NonStructuralMatchTy::Generator);
                return ControlFlow::BREAK;
            }
            ty::Closure(..) => {
                self.found = Some(NonStructuralMatchTy::Closure);
                return ControlFlow::BREAK;
            }
            ty::RawPtr(..) => {
                // structural-match ignores substructure of
                // `*const _`/`*mut _`, so skip `super_visit_with`.
                //
                // For example, if you have:
                // ```
                // struct NonStructural;
                // #[derive(PartialEq, Eq)]
                // struct T(*const NonStructural);
                // const C: T = T(std::ptr::null());
                // ```
                //
                // Even though `NonStructural` does not implement `PartialEq`,
                // structural equality on `T` does not recur into the raw
                // pointer. Therefore, one can still use `C` in a pattern.
                return ControlFlow::CONTINUE;
            }
            ty::FnDef(..) | ty::FnPtr(..) => {
                // Types of formals and return in `fn(_) -> _` are also irrelevant;
                // so we do not recur into them via `super_visit_with`
                return ControlFlow::CONTINUE;
            }
            ty::Array(_, n)
                if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } =>
            {
                // rust-lang/rust#62336: ignore type of contents
                // for empty array.
                return ControlFlow::CONTINUE;
            }
            ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => {
                // These primitive types are always structural match.
                //
                // `Never` is kind of special here, but as it is not inhabitable, this should be fine.
                return ControlFlow::CONTINUE;
            }

            ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
                // First check all contained types and then tell the caller to continue searching.
                ty.super_visit_with(self);
                return ControlFlow::CONTINUE;
            }
            ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
                bug!("unexpected type during structural-match checking: {:?}", ty);
            }
            ty::Error(_) => {
                self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check");
                // We still want to check other types after encountering an error,
                // as this may still emit relevant errors.
                return ControlFlow::CONTINUE;
            }
        };

        if !self.seen.insert(adt_def.did) {
            debug!("Search already seen adt_def: {:?}", adt_def);
            return ControlFlow::CONTINUE;
        }

        if !self.type_marked_structural(ty) {
            debug!("Search found ty: {:?}", ty);
            self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
            return ControlFlow::BREAK;
        }

        // structural-match does not care about the
        // instantiation of the generics in an ADT (it
        // instead looks directly at its fields outside
        // this match), so we skip super_visit_with.
        //
        // (Must not recur on substs for `PhantomData<T>` cf
        // rust-lang/rust#55028 and rust-lang/rust#55837; but also
        // want to skip substs when only uses of generic are
        // behind unsafe pointers `*const T`/`*mut T`.)

        // even though we skip super_visit_with, we must recur on
        // fields of ADT.
        let tcx = self.tcx();
        for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) {
            let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty);
            debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty);

            if ty.visit_with(self).is_break() {
                // found an ADT without structural-match; halt visiting!
                assert!(self.found.is_some());
                return ControlFlow::BREAK;
            }
        }

        // Even though we do not want to recur on substs, we do
        // want our caller to continue its own search.
        ControlFlow::CONTINUE
    }
}

pub fn provide(providers: &mut Providers) {
    providers.has_structural_eq_impls = |tcx, ty| {
        tcx.infer_ctxt().enter(|infcx| {
            let cause = ObligationCause::dummy();
            type_marked_structural(&infcx, ty, cause)
        })
    };
}
<commit_msg>Use `TypeVisitor::BreakTy` in `structural_match::Search`<commit_after>use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::ObligationCause;
use crate::traits::{self, TraitEngine};

use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::Span;
use std::ops::ControlFlow;

#[derive(Debug)]
pub enum NonStructuralMatchTy<'tcx> {
    Adt(&'tcx AdtDef),
    Param,
    Dynamic,
    Foreign,
    Opaque,
    Generator,
    Projection,
    Closure,
}

/// This method traverses the structure of `ty`, trying to find an
/// instance of an ADT (i.e. struct or enum) that doesn't implement
/// the structural-match traits, or a generic type parameter
/// (which cannot be determined to be structural-match).
///
/// The "structure of a type" includes all components that would be
/// considered when doing a pattern match on a constant of that
/// type.
///
///  * This means this method descends into fields of structs/enums,
///    and also descends into the inner type `T` of `&T` and `&mut T`
///
///  * The traversal doesn't dereference unsafe pointers (`*const T`,
///    `*mut T`), and it does not visit the type arguments of an
///    instantiated generic like `PhantomData<T>`.
///
/// The reason we do this search is Rust currently require all ADTs
/// reachable from a constant's type to implement the
/// structural-match traits, which essentially say that
/// the implementation of `PartialEq::eq` behaves *equivalently* to a
/// comparison against the unfolded structure.
///
/// For more background on why Rust has this requirement, and issues
/// that arose when the requirement was not enforced completely, see
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
pub fn search_for_structural_match_violation<'tcx>(
    _id: hir::HirId,
    span: Span,
    tcx: TyCtxt<'tcx>,
    ty: Ty<'tcx>,
) -> Option<NonStructuralMatchTy<'tcx>> {
    // FIXME: we should instead pass in an `infcx` from the outside.
    tcx.infer_ctxt().enter(|infcx| {
        ty.visit_with(&mut Search { infcx, span, seen: FxHashSet::default() }).break_value()
    })
}

/// This method returns true if and only if `adt_ty` itself has been marked as
/// eligible for structural-match: namely, if it implements both
/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by
/// `#[derive(PartialEq)]` and `#[derive(Eq)]`).
///
/// Note that this does *not* recursively check if the substructure of `adt_ty`
/// implements the traits.
fn type_marked_structural(
    infcx: &InferCtxt<'_, 'tcx>,
    adt_ty: Ty<'tcx>,
    cause: ObligationCause<'tcx>,
) -> bool {
    let mut fulfillment_cx = traits::FulfillmentContext::new();
    // require `#[derive(PartialEq)]`
    let structural_peq_def_id =
        infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span));
    fulfillment_cx.register_bound(
        infcx,
        ty::ParamEnv::empty(),
        adt_ty,
        structural_peq_def_id,
        cause.clone(),
    );
    // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
    // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
    let structural_teq_def_id =
        infcx.tcx.require_lang_item(LangItem::StructuralTeq, Some(cause.span));
    fulfillment_cx.register_bound(
        infcx,
        ty::ParamEnv::empty(),
        adt_ty,
        structural_teq_def_id,
        cause,
    );

    // We deliberately skip *reporting* fulfillment errors (via
    // `report_fulfillment_errors`), for two reasons:
    //
    // 1. The error messages would mention `std::marker::StructuralPartialEq`
    //    (a trait which is solely meant as an implementation detail
    //    for now), and
    //
    // 2. We are sometimes doing future-incompatibility lints for
    //    now, so we do not want unconditional errors here.
    fulfillment_cx.select_all_or_error(infcx).is_ok()
}

/// This implements the traversal over the structure of a given type to try to
/// find instances of ADTs (specifically structs or enums) that do not implement
/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
struct Search<'a, 'tcx> {
    span: Span,

    infcx: InferCtxt<'a, 'tcx>,

    /// Tracks ADTs previously encountered during search, so that
    /// we will not recur on them again.
    seen: FxHashSet<hir::def_id::DefId>,
}

impl Search<'a, 'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.infcx.tcx
    }

    fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
        adt_ty.is_structural_eq_shallow(self.tcx())
    }
}

impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
    type BreakTy = NonStructuralMatchTy<'tcx>;

    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
        debug!("Search visiting ty: {:?}", ty);

        let (adt_def, substs) = match *ty.kind() {
            ty::Adt(adt_def, substs) => (adt_def, substs),
            ty::Param(_) => {
                return ControlFlow::Break(NonStructuralMatchTy::Param);
            }
            ty::Dynamic(..) => {
                return ControlFlow::Break(NonStructuralMatchTy::Dynamic);
            }
            ty::Foreign(_) => {
                return ControlFlow::Break(NonStructuralMatchTy::Foreign);
            }
            ty::Opaque(..) => {
                return ControlFlow::Break(NonStructuralMatchTy::Opaque);
            }
            ty::Projection(..) => {
                return ControlFlow::Break(NonStructuralMatchTy::Projection);
            }
            ty::Generator(..) | ty::GeneratorWitness(..) => {
                return ControlFlow::Break(NonStructuralMatchTy::Generator);
            }
            ty::Closure(..) => {
                return ControlFlow::Break(NonStructuralMatchTy::Closure);
            }
            ty::RawPtr(..) => {
                // structural-match ignores substructure of
                // `*const _`/`*mut _`, so skip `super_visit_with`.
                //
                // For example, if you have:
                // ```
                // struct NonStructural;
                // #[derive(PartialEq, Eq)]
                // struct T(*const NonStructural);
                // const C: T = T(std::ptr::null());
                // ```
                //
                // Even though `NonStructural` does not implement `PartialEq`,
                // structural equality on `T` does not recur into the raw
                // pointer. Therefore, one can still use `C` in a pattern.
                return ControlFlow::CONTINUE;
            }
            ty::FnDef(..) | ty::FnPtr(..) => {
                // Types of formals and return in `fn(_) -> _` are also irrelevant;
                // so we do not recur into them via `super_visit_with`
                return ControlFlow::CONTINUE;
            }
            ty::Array(_, n)
                if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } =>
            {
                // rust-lang/rust#62336: ignore type of contents
                // for empty array.
                return ControlFlow::CONTINUE;
            }
            ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => {
                // These primitive types are always structural match.
                //
                // `Never` is kind of special here, but as it is not inhabitable, this should be fine.
                return ControlFlow::CONTINUE;
            }

            ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
                // First check all contained types and then tell the caller to continue searching.
                return ty.super_visit_with(self);
            }
            ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
                bug!("unexpected type during structural-match checking: {:?}", ty);
            }
            ty::Error(_) => {
                self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check");
                // We still want to check other types after encountering an error,
                // as this may still emit relevant errors.
                return ControlFlow::CONTINUE;
            }
        };

        if !self.seen.insert(adt_def.did) {
            debug!("Search already seen adt_def: {:?}", adt_def);
            return ControlFlow::CONTINUE;
        }

        if !self.type_marked_structural(ty) {
            debug!("Search found ty: {:?}", ty);
            return ControlFlow::Break(NonStructuralMatchTy::Adt(&adt_def));
        }

        // structural-match does not care about the
        // instantiation of the generics in an ADT (it
        // instead looks directly at its fields outside
        // this match), so we skip super_visit_with.
        //
        // (Must not recur on substs for `PhantomData<T>` cf
        // rust-lang/rust#55028 and rust-lang/rust#55837; but also
        // want to skip substs when only uses of generic are
        // behind unsafe pointers `*const T`/`*mut T`.)

        // even though we skip super_visit_with, we must recur on
        // fields of ADT.
        let tcx = self.tcx();
        adt_def.all_fields().map(|field| field.ty(tcx, substs)).try_for_each(|field_ty| {
            let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty);
            debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty);
            ty.visit_with(self)
        })
    }
}

pub fn provide(providers: &mut Providers) {
    providers.has_structural_eq_impls = |tcx, ty| {
        tcx.infer_ctxt().enter(|infcx| {
            let cause = ObligationCause::dummy();
            type_marked_structural(&infcx, ty, cause)
        })
    };
}
<|endoftext|>


<commit_before>use dungeon::{Dungeon};
use celloption::{Occupant};
use genotype::{Genotype};
use phenotype::{Seed};
use config::{Config};
use util::{odds};

use std::iter::{range_step};
use std::collections::{HashMap, HashSet};
use rand::{Rng};

#[derive(Clone, Debug)]
pub struct DesirableProperties {
    seed: Seed,
    room_number: u32,
    room_size: u32,
    doors: u32,
    monsters: u32,
    path_length: u32,
    branching: f64,
    occupants: Vec<(Occupant, (u32, u32))>,
    rooms: Vec<Room>,
    mazes: Vec<Maze>,
    connectors: Vec<Connector>,
}

#[derive(Clone, Debug)]
struct Room {
    x: u32,
    y: u32,
    w: u32,
    h: u32,
    region: u32,
}

#[derive(Clone, Debug)]
struct Maze {
    path: HashSet<(u32, u32)>,
    region: u32,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
enum Direction {
    North,
    East,
    South,
    West
}

static CARDINALS: [(Direction, (i32, i32)); 4] = [(Direction::North, (0, 1)),
                                                  (Direction::East, (1, 0)),
                                                  (Direction::South, (0, -1)),
                                                  (Direction::West, (-1, 0))];

// helper function: given a coordinate and a relative direction, get
// the coordinate n spaces away in that direction.
fn scale(coord: (u32, u32), dir: (i32, i32), n: i32) -> (u32, u32) {
    let (x, y) = coord;
    let (dx, dy) = dir;
    (((x as i32 + dx * n) as u32), ((y as i32 + dy * n) as u32))
}

#[derive(Clone, Debug)]
struct Connector {
    location: (u32, u32),
    regions: HashSet<u32>,
}

impl Connector {
    pub fn new(location: (u32, u32), regions: &HashSet<u32>) -> Connector {
        Connector {
            location: location,
            regions: regions.clone(),
        }
    }

    pub fn find_all(mazes: &Vec<Maze>, rooms: &Vec<Room>) -> Vec<Connector> {
        // build up a hashmap of coords to region id
        let mut lookup: HashMap<(u32, u32), u32> = HashMap::new();
        for maze in mazes {
            for coord in maze.clone().path {
                lookup.insert(coord, maze.region);
            }
        }
        for room in rooms {
            for coord in room.border() {
                lookup.insert(coord, room.region);
            }
        }
        // find connectors (blank spaces between two regions)
        let mut connectors: Vec<Connector> = Vec::new();
        let mut examined: HashSet<(u32, u32)> = HashSet::new();
        for (&coord, &region) in lookup.iter() {
            examined.insert(coord);
            let possibles: Vec<(u32, u32)> = CARDINALS.iter().map(|&(_, rel_dir)| scale(coord, rel_dir, 1)).collect();
            for new_coord in possibles {
                if !examined.contains(&new_coord) || !lookup.contains_key(&new_coord) {
                    let regions: HashSet<u32> = CARDINALS.iter().map(|&(_, rel_dir)| {
                        let coord = scale(new_coord, rel_dir, 1);
                        if lookup.contains_key(&coord) {
                            lookup[coord]
                        } else {
                            region // by design, at least two directions must fail
                        }
                    }).collect();
                    if regions.len() >= 2 {
                        let connector = Connector::new(new_coord, &regions);
                        connectors.push(connector);
                    }
                    examined.insert(new_coord);
                }
            }
        }
        connectors
    }

    pub fn merge<T: Rng>(rng: &mut T,
                         connectors: &Vec<Connector>,
                         mazes: &Vec<Maze>,
                         rooms: &Vec<Room>) -> Vec<Connector> {
        let mut current = connectors.clone();
        let mut open: HashSet<u32> = HashSet::new();
        for connector in connectors {
            for region in connector.regions.clone() {
                open.insert(region);
            }
        }
        let mut merged_connectors: Vec<Connector> = Vec::new();
        while open.len() > 1 {
            // pick a random connector and region to merge
            let index = rng.gen_range(0, current.len());
            let connector = current.remove(index);
            let regions: Vec<u32> = connector.regions.iter().cloned().collect();
            merged_connectors.push(connector);
            let region = rng.choose(regions.as_slice()).unwrap();
            open.remove(region);
        }
        merged_connectors.clone()
    }
}

pub type CollisionFn<'a> = Box<Fn(&(u32, u32)) -> bool + 'a>;

impl Maze {
    pub fn new<T: Rng>(rng: &mut T,
                       previous: &HashSet<(u32, u32)>,
                       collides: CollisionFn,
                       branching: f64,
                       region: u32,
                       x: u32,
                       y: u32) -> Maze {
        let path = Maze::grow(rng, previous, collides, branching, x, y);
        Maze {
            region: region,
            path: path
        }
    }

    fn grow<T: Rng>(rng: &mut T,
                    previous: &HashSet<(u32, u32)>,
                    collides: CollisionFn,
                    branching: f64,
                    orig_x: u32,
                    orig_y: u32) -> HashSet<(u32, u32)> {
        let branching_factor = (branching * 100.0) as u64;
        let mut path: Vec<(u32, u32)> = Vec::new();
        let mut all_paths: HashSet<(u32, u32)> = previous.clone();
        let all = vec!(Direction::North, Direction::East, Direction::South, Direction::West);
        let mut direction = rng.choose(all.as_slice()).unwrap().clone();
        path.push((orig_x, orig_y));
        all_paths.insert((orig_x, orig_y));
        // "growing-tree" algorithm
        while !path.is_empty() {
            let new_coord = path[path.len()-1];
            let uncarved: HashMap<Direction, (i32, i32)> = CARDINALS.iter().filter(|&&(_, new_dir)| {
                let coord1 = scale(new_coord, new_dir, 1);
                let coord2 = scale(new_coord, new_dir, 2);
                let coord3 = scale(new_coord, new_dir, 3);
                !all_paths.contains(&coord1) &&
                    !all_paths.contains(&coord2) &&
                    !all_paths.contains(&coord3) &&
                    !collides(&coord2) &&
                    !collides(&coord3)
            }).cloned().collect();
            if !uncarved.is_empty() {
                let same_direction = odds(rng, branching_factor, 100);
                let rel_dir = if same_direction && uncarved.contains_key(&direction) {
                    uncarved[direction]
                } else {
                    let (dir, coords) = uncarved.into_iter().next().unwrap();
                    direction = dir;
                    coords
                };
                let coord1 = scale(new_coord, rel_dir, 1);
                let coord2 = scale(new_coord, rel_dir, 2);
                all_paths.insert(coord1);
                all_paths.insert(coord2);
                path.push(coord2);
            } else {
                path.pop();
            }
        }
        all_paths.difference(previous).cloned().collect()
    }
}

impl Room {
    pub fn random<T: Rng>(rng: &mut T, width: u32, height: u32, room_size: u32, region: u32) -> Room {
        let w: u32 = rng.gen_range(3, room_size);
        let h: u32 = rng.gen_range(3, room_size);
        assert!(width >= w);
        assert!(height >= h);
        let x: u32 = rng.gen_range(1, width - w);
        let y: u32 = rng.gen_range(1, height - h);
        let make_odd = |n| if n % 2 == 0 { n - 1 } else { n };
        Room {
            x: make_odd(x),
            y: make_odd(y),
            w: make_odd(w),
            h: make_odd(h),
            region: region,
        }
    }

    pub fn intersects(&self, rooms: &Vec<Room>) -> bool {
        for r in rooms {
            let rw = r.x + r.w;
            let rh = r.y + r.h;
            let roomw = self.x + self.w;
            let roomh = self.y + self.h;
            if roomw > r.x && roomh > r.y && self.x < rw && self.y < rh {
                return true
            }
        }
        false
    }

    pub fn contains(&self, x: u32, y: u32) -> bool {
        let roomw = self.x + self.w;
        let roomh = self.y + self.h;
        x >= self.x && x < roomw && y >= self.y && y < roomh
    }

    pub fn border(&self) -> Vec<(u32, u32)> {
        let mut surrounding = vec![];
        for i in range(0, self.w) {
            surrounding.push(((self.x + i), self.y));
            surrounding.push(((self.x + i), self.y + self.h - 1));
        }
        for i in range(0, self.h) {
            surrounding.push((self.x, self.y + i));
            surrounding.push((self.x + self.w - 1, self.y + i));
        }
        surrounding
    }
}

impl DesirableProperties {
    pub fn new(config: &Config, seed: &Seed) -> DesirableProperties {
        // read in the configurations
        let desirables = config.get_table(None, "desirable_patterns");
        let room_number = config.get_integer(desirables, "room_number") as u32;
        let room_size = config.get_integer(desirables, "room_size") as u32;
        let doors = config.get_integer(desirables, "doors") as u32;
        let monsters = config.get_integer(desirables, "monsters") as u32;
        let path_length = config.get_integer(desirables, "path_length") as u32;
        let branching = config.get_float(desirables, "branching");
        DesirableProperties {
            seed: seed.clone(),
            room_size: room_size,
            room_number: room_number,
            doors: doors,
            monsters: monsters,
            path_length: path_length,
            branching: branching,
            occupants: vec![],
            rooms: vec![],
            mazes: vec![],
            connectors: vec![],
        }
    }

}

impl Genotype for DesirableProperties {
    fn initialize<T: Rng>(&self, rng: &mut T) -> DesirableProperties {
        let w = self.seed.width;
        let h = self.seed.height;
        let occupants = self.seed.random_occupants(rng).iter().take(self.monsters as usize).cloned().collect();
        let mut region = 0;
        // randomly generate rooms
        let mut rooms = vec![];
        for _ in range(0, self.room_number) {
            for _ in range(0, 10) {
                let room = Room::random(rng, w, h, self.room_size, region);
                if !room.intersects(&rooms) {
                    rooms.push(room);
                    region += 1;
                    break;
                }
            }
        }
        // fill in mazes
        let mut mazes = vec![];
        let mut positions: HashSet<(u32, u32)> = HashSet::new();
        let is_occupied = |x, y| rooms.clone().iter().fold(false, |accum, ref m| accum || m.contains(x, y));
        for x in range_step(1, w, 2) {
            for y in range_step(1, h, 2) {
                if !is_occupied(x, y) && !positions.contains(&(x, y)) {
                    let collides: CollisionFn = box |&(cx, cy)| cx >= w || cy >= h || is_occupied(cx, cy);
                    let maze = Maze::new(rng, &positions, collides, self.branching, region, x, y);
                    positions = positions.union(&maze.path).cloned().collect();
                    mazes.push(maze);
                    region += 1;
                }
            }
        }
        // find connectors
        let all_connectors = Connector::find_all(&mazes, &rooms);
        let connectors = Connector::merge(rng, &all_connectors, &mazes, &rooms);
        // remove dead ends
        DesirableProperties {
            seed: self.seed.clone(),
            room_number: self.room_number,
            room_size: self.room_size,
            doors: self.doors,
            monsters: self.monsters,
            path_length: self.path_length,
            branching: self.branching,
            occupants: occupants,
            rooms: rooms.clone(),
            mazes: mazes,
            connectors: connectors,
        }
    }

    fn mutate<T: Rng>(&mut self, _: &mut T, _: f64) {
        // mutate a certain % of the rooms and start again
    }

    fn generate(&self) -> Dungeon {
        let w = self.seed.width;
        let h = self.seed.height;
        let mut dungeon = Dungeon::new(w, h, None);
        let wall = self.seed.tiles.get("wall").unwrap();
        let door = self.seed.tiles.get("door").unwrap();
        let floor = self.seed.tiles.get("floor").unwrap();
        for room in self.rooms.iter() {
            for i in range(room.x, room.x + room.w) {
                for j in range(room.y, room.y + room.h) {
                    dungeon.cells[i as usize][j as usize].tile = Some(wall.clone())
                }
            }
            // will overdraw, but that's OK.
            for (i, j) in room.border() {
                dungeon.cells[i as usize][j as usize].tile = Some(floor.clone())
            }
        }
        for maze in self.mazes.iter() {
            for path in maze.path.iter() {
                let (x, y): (u32, u32) = *path;
                dungeon.cells[x as usize][y as usize].tile = Some(floor.clone());
            }
        }
        for connector in self.connectors.iter() {
            let (x, y) = connector.location;
            dungeon.cells[x as usize][y as usize].tile = Some(door.clone());
        }
        dungeon.clone()
    }
}
<commit_msg>Playing around with connectors.<commit_after>use dungeon::{Dungeon};
use celloption::{Occupant};
use genotype::{Genotype};
use phenotype::{Seed};
use config::{Config};
use util::{odds};

use std::iter::{range_step};
use std::collections::{HashMap, HashSet};
use rand::{Rng};

#[derive(Clone, Debug)]
pub struct DesirableProperties {
    seed: Seed,
    room_number: u32,
    room_size: u32,
    doors: u32,
    monsters: u32,
    path_length: u32,
    branching: f64,
    occupants: Vec<(Occupant, (u32, u32))>,
    rooms: Vec<Room>,
    mazes: Vec<Maze>,
    connectors: Vec<Connector>,
}

#[derive(Clone, Debug)]
struct Room {
    x: u32,
    y: u32,
    w: u32,
    h: u32,
    region: u32,
}

#[derive(Clone, Debug)]
struct Maze {
    path: HashSet<(u32, u32)>,
    region: u32,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
enum Direction {
    North,
    East,
    South,
    West
}

static CARDINALS: [(Direction, (i32, i32)); 4] = [(Direction::North, (0, 1)),
                                                  (Direction::East, (1, 0)),
                                                  (Direction::South, (0, -1)),
                                                  (Direction::West, (-1, 0))];

// helper function: given a coordinate and a relative direction, get
// the coordinate n spaces away in that direction.
fn scale(coord: (u32, u32), dir: (i32, i32), n: i32) -> (u32, u32) {
    let (x, y) = coord;
    let (dx, dy) = dir;
    (((x as i32 + dx * n) as u32), ((y as i32 + dy * n) as u32))
}

#[derive(Clone, Debug)]
struct Connector {
    location: (u32, u32),
    regions: HashSet<u32>,
}

impl Connector {
    pub fn new(location: (u32, u32), regions: &HashSet<u32>) -> Connector {
        Connector {
            location: location,
            regions: regions.clone(),
        }
    }

    pub fn find_all(mazes: &Vec<Maze>, rooms: &Vec<Room>) -> Vec<Connector> {
        // build up a hashmap of coords to region id
        let mut lookup: HashMap<(u32, u32), u32> = HashMap::new();
        for maze in mazes {
            for coord in maze.clone().path {
                lookup.insert(coord, maze.region);
            }
        }
        for room in rooms {
            for coord in room.border() {
                lookup.insert(coord, room.region);
            }
        }
        // find connectors (blank spaces between two regions)
        let mut connectors: Vec<Connector> = Vec::new();
        let mut examined: HashSet<(u32, u32)> = HashSet::new();
        for (&coord, &region) in lookup.iter() {
            examined.insert(coord);
            let possibles: Vec<(u32, u32)> = CARDINALS.iter().map(|&(_, rel_dir)| scale(coord, rel_dir, 1)).collect();
            for new_coord in possibles {
                if !examined.contains(&new_coord) || !lookup.contains_key(&new_coord) {
                    let regions: HashSet<u32> = CARDINALS.iter().map(|&(_, rel_dir)| {
                        let coord = scale(new_coord, rel_dir, 1);
                        if lookup.contains_key(&coord) {
                            lookup[coord]
                        } else {
                            region // by design, at least two directions must fail
                        }
                    }).collect();
                    if regions.len() >= 2 {
                        let connector = Connector::new(new_coord, &regions);
                        connectors.push(connector);
                    }
                    examined.insert(new_coord);
                }
            }
        }
        connectors
    }

    pub fn merge<T: Rng>(rng: &mut T,
                         connectors: &Vec<Connector>,
                         mazes: &Vec<Maze>,
                         rooms: &Vec<Room>) -> Vec<Connector> {
        let mut current = connectors.clone();
        let mut open: HashSet<u32> = HashSet::new();
        for connector in connectors {
            open = open.union(&connector.regions.clone()).cloned().collect();
        }
        let mut merged_connectors: Vec<Connector> = Vec::new();
        while current.len() > 1 {
            // pick a random connector
            let index = rng.gen_range(0, current.clone().len());
            let connector = current.remove(index);
            let regions = connector.regions.clone();
            merged_connectors.push(connector);
            // actually merge.
            for other_connector in current.iter_mut() {
                // remove only if this connector already has all regions
                let result: HashSet<u32> = other_connector.regions.union(&regions).cloned().collect();
                if result.len() == regions.len() {
                    other_connector.regions.clear();
                }

                // for other_region in regions.clone() {
                //     other_connector.regions.remove(&other_region);
                // }
                //other_connector.regions.remove(&first);
            }
            // remove unnecessary connectors
            current = current.iter().filter(|&c| c.regions.len() > 0).cloned().collect();
            //open.remove(&first);
        }
        merged_connectors.clone()
    }
}

pub type CollisionFn<'a> = Box<Fn(&(u32, u32)) -> bool + 'a>;

impl Maze {
    pub fn new<T: Rng>(rng: &mut T,
                       previous: &HashSet<(u32, u32)>,
                       collides: CollisionFn,
                       branching: f64,
                       region: u32,
                       x: u32,
                       y: u32) -> Maze {
        let path = Maze::grow(rng, previous, collides, branching, x, y);
        Maze {
            region: region,
            path: path
        }
    }

    fn grow<T: Rng>(rng: &mut T,
                    previous: &HashSet<(u32, u32)>,
                    collides: CollisionFn,
                    branching: f64,
                    orig_x: u32,
                    orig_y: u32) -> HashSet<(u32, u32)> {
        let branching_factor = (branching * 100.0) as u64;
        let mut path: Vec<(u32, u32)> = Vec::new();
        let mut all_paths: HashSet<(u32, u32)> = previous.clone();
        let all = vec!(Direction::North, Direction::East, Direction::South, Direction::West);
        let mut direction = rng.choose(all.as_slice()).unwrap().clone();
        path.push((orig_x, orig_y));
        all_paths.insert((orig_x, orig_y));
        // "growing-tree" algorithm
        while !path.is_empty() {
            let new_coord = path[path.len()-1];
            let uncarved: HashMap<Direction, (i32, i32)> = CARDINALS.iter().filter(|&&(_, new_dir)| {
                let coord1 = scale(new_coord, new_dir, 1);
                let coord2 = scale(new_coord, new_dir, 2);
                let coord3 = scale(new_coord, new_dir, 3);
                !all_paths.contains(&coord1) &&
                    !all_paths.contains(&coord2) &&
                    !all_paths.contains(&coord3) &&
                    !collides(&coord2) &&
                    !collides(&coord3)
            }).cloned().collect();
            if !uncarved.is_empty() {
                let same_direction = odds(rng, branching_factor, 100);
                let rel_dir = if same_direction && uncarved.contains_key(&direction) {
                    uncarved[direction]
                } else {
                    let (dir, coords) = uncarved.into_iter().next().unwrap();
                    direction = dir;
                    coords
                };
                let coord1 = scale(new_coord, rel_dir, 1);
                let coord2 = scale(new_coord, rel_dir, 2);
                all_paths.insert(coord1);
                all_paths.insert(coord2);
                path.push(coord2);
            } else {
                path.pop();
            }
        }
        all_paths.difference(previous).cloned().collect()
    }
}

impl Room {
    pub fn random<T: Rng>(rng: &mut T, width: u32, height: u32, room_size: u32, region: u32) -> Room {
        let w: u32 = rng.gen_range(3, room_size);
        let h: u32 = rng.gen_range(3, room_size);
        assert!(width >= w);
        assert!(height >= h);
        let x: u32 = rng.gen_range(1, width - w);
        let y: u32 = rng.gen_range(1, height - h);
        let make_odd = |n| if n % 2 == 0 { n - 1 } else { n };
        Room {
            x: make_odd(x),
            y: make_odd(y),
            w: make_odd(w),
            h: make_odd(h),
            region: region,
        }
    }

    pub fn intersects(&self, rooms: &Vec<Room>) -> bool {
        for r in rooms {
            let rw = r.x + r.w;
            let rh = r.y + r.h;
            let roomw = self.x + self.w;
            let roomh = self.y + self.h;
            if roomw > r.x && roomh > r.y && self.x < rw && self.y < rh {
                return true
            }
        }
        false
    }

    pub fn contains(&self, x: u32, y: u32) -> bool {
        let roomw = self.x + self.w;
        let roomh = self.y + self.h;
        x >= self.x && x < roomw && y >= self.y && y < roomh
    }

    pub fn border(&self) -> Vec<(u32, u32)> {
        let mut surrounding = vec![];
        for i in range(0, self.w) {
            surrounding.push(((self.x + i), self.y));
            surrounding.push(((self.x + i), self.y + self.h - 1));
        }
        for i in range(0, self.h) {
            surrounding.push((self.x, self.y + i));
            surrounding.push((self.x + self.w - 1, self.y + i));
        }
        surrounding
    }
}

impl DesirableProperties {
    pub fn new(config: &Config, seed: &Seed) -> DesirableProperties {
        // read in the configurations
        let desirables = config.get_table(None, "desirable_patterns");
        let room_number = config.get_integer(desirables, "room_number") as u32;
        let room_size = config.get_integer(desirables, "room_size") as u32;
        let doors = config.get_integer(desirables, "doors") as u32;
        let monsters = config.get_integer(desirables, "monsters") as u32;
        let path_length = config.get_integer(desirables, "path_length") as u32;
        let branching = config.get_float(desirables, "branching");
        DesirableProperties {
            seed: seed.clone(),
            room_size: room_size,
            room_number: room_number,
            doors: doors,
            monsters: monsters,
            path_length: path_length,
            branching: branching,
            occupants: vec![],
            rooms: vec![],
            mazes: vec![],
            connectors: vec![],
        }
    }

}

impl Genotype for DesirableProperties {
    fn initialize<T: Rng>(&self, rng: &mut T) -> DesirableProperties {
        let w = self.seed.width;
        let h = self.seed.height;
        let occupants = self.seed.random_occupants(rng).iter().take(self.monsters as usize).cloned().collect();
        let mut region = 0;
        // randomly generate rooms
        let mut rooms = vec![];
        for _ in range(0, self.room_number) {
            for _ in range(0, 10) {
                let room = Room::random(rng, w, h, self.room_size, region);
                if !room.intersects(&rooms) {
                    rooms.push(room);
                    region += 1;
                    break;
                }
            }
        }
        // fill in mazes
        let mut mazes = vec![];
        let mut positions: HashSet<(u32, u32)> = HashSet::new();
        let is_occupied = |x, y| rooms.clone().iter().fold(false, |accum, ref m| accum || m.contains(x, y));
        for x in range_step(1, w, 2) {
            for y in range_step(1, h, 2) {
                if !is_occupied(x, y) && !positions.contains(&(x, y)) {
                    let collides: CollisionFn = box |&(cx, cy)| cx >= w || cy >= h || is_occupied(cx, cy);
                    let maze = Maze::new(rng, &positions, collides, self.branching, region, x, y);
                    positions = positions.union(&maze.path).cloned().collect();
                    mazes.push(maze);
                    region += 1;
                }
            }
        }
        // find connectors
        let all_connectors = Connector::find_all(&mazes, &rooms);
        let connectors = Connector::merge(rng, &all_connectors, &mazes, &rooms);
        // remove dead ends
        DesirableProperties {
            seed: self.seed.clone(),
            room_number: self.room_number,
            room_size: self.room_size,
            doors: self.doors,
            monsters: self.monsters,
            path_length: self.path_length,
            branching: self.branching,
            occupants: occupants,
            rooms: rooms.clone(),
            mazes: mazes,
            connectors: connectors,
        }
    }

    fn mutate<T: Rng>(&mut self, _: &mut T, _: f64) {
        // mutate a certain % of the rooms and start again
    }

    fn generate(&self) -> Dungeon {
        let w = self.seed.width;
        let h = self.seed.height;
        let mut dungeon = Dungeon::new(w, h, None);
        let wall = self.seed.tiles.get("wall").unwrap();
        let door = self.seed.tiles.get("door").unwrap();
        let floor = self.seed.tiles.get("floor").unwrap();
        for room in self.rooms.iter() {
            for i in range(room.x, room.x + room.w) {
                for j in range(room.y, room.y + room.h) {
                    dungeon.cells[i as usize][j as usize].tile = Some(wall.clone())
                }
            }
            // will overdraw, but that's OK.
            for (i, j) in room.border() {
                dungeon.cells[i as usize][j as usize].tile = Some(floor.clone())
            }
        }
        for maze in self.mazes.iter() {
            for path in maze.path.iter() {
                let (x, y): (u32, u32) = *path;
                dungeon.cells[x as usize][y as usize].tile = Some(floor.clone());
            }
        }
        for connector in self.connectors.iter() {
            let (x, y) = connector.location;
            dungeon.cells[x as usize][y as usize].tile = Some(door.clone());
        }
        dungeon.clone()
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate diesel;

use diesel::*;
use diesel::pg::PgConnection;

table! {
    users {
        id -> Integer,
        name -> VarChar,
    }
}

fn main() {
    use self::users::dsl::*;

    let connection = PgConnection::establish("").unwrap();
    let select_id = users.select(id);
    let select_name = users.select(name);

    let ids = select_name.load::<i32>(&connection);
    //~^ ERROR the trait `diesel::Queryable<diesel::types::VarChar, _>` is not implemented for the type `i32`
    let names = select_id.load::<String>(&connection);
    //~^ ERROR the trait `diesel::Queryable<diesel::types::Integer, _>` is not implemented
}
<commit_msg>Fix failing compile test<commit_after>#[macro_use]
extern crate diesel;

use diesel::*;
use diesel::pg::PgConnection;

table! {
    users {
        id -> Integer,
        name -> VarChar,
    }
}

fn main() {
    use self::users::dsl::*;

    let connection = PgConnection::establish("").unwrap();
    let select_id = users.select(id);
    let select_name = users.select(name);

    let ids = select_name.load::<i32>(&connection);
    //~^ ERROR the trait bound `i32: diesel::Queryable<diesel::types::VarChar, _>` is not satisfied
    let names = select_id.load::<String>(&connection);
    //~^ ERROR the trait bound `std::string::String: diesel::Queryable<diesel::types::Integer, _>` is not satisfied
}
<|endoftext|>


<commit_before>use crate::error::{Error, Result};
use crate::gen::fs;
use crate::Project;
use std::env;
use std::ffi::OsString;
use std::path::{Path, PathBuf};

pub(crate) enum TargetDir {
    Path(PathBuf),
    Unknown,
}

pub(crate) fn out_dir() -> Result<PathBuf> {
    env::var_os("OUT_DIR")
        .map(PathBuf::from)
        .ok_or(Error::MissingOutDir)
}

pub(crate) fn cc_build(prj: &Project) -> cc::Build {
    let mut build = cc::Build::new();
    build.include(include_dir(prj));
    if let TargetDir::Path(target_dir) = &prj.target_dir {
        build.include(target_dir.parent().unwrap());
    }
    build
}

// Symlink the header file into a predictable place. The header generated from
// path/to/mod.rs gets linked to target/cxxbridge/path/to/mod.rs.h.
pub(crate) fn symlink_header(prj: &Project, path: &Path, original: &Path) {
    if let TargetDir::Unknown = prj.target_dir {
        return;
    }
    let _ = try_symlink_header(prj, path, original);
}

fn try_symlink_header(prj: &Project, path: &Path, original: &Path) -> Result<()> {
    let mut dst = include_dir(prj);
    dst.extend(package_name());
    dst.push(original);

    let parent = dst.parent().unwrap();
    fs::create_dir_all(parent)?;
    let _ = fs::remove_file(&dst);
    symlink_or_copy(path, &dst)?;

    let mut file_name = dst.file_name().unwrap().to_os_string();
    file_name.push(".h");
    let ref dst2 = dst.with_file_name(file_name);
    symlink_or_copy(path, dst2)?;

    Ok(())
}

pub(crate) fn out_with_extension(prj: &Project, rel_path: &Path, ext: &str) -> PathBuf {
    let mut file_name = rel_path.file_name().unwrap().to_owned();
    file_name.push(ext);

    let mut res = prj.out_dir.clone();
    res.push("cxxbridge");
    res.extend(package_name());
    res.push(rel_path);
    res.with_file_name(file_name)
}

pub(crate) fn include_dir(prj: &Project) -> PathBuf {
    match &prj.target_dir {
        TargetDir::Path(target_dir) => target_dir.join("cxxbridge"),
        TargetDir::Unknown => prj.out_dir.join("cxxbridge"),
    }
}

fn package_name() -> Option<OsString> {
    env::var_os("CARGO_PKG_NAME")
}

pub(crate) fn search_parents_for_target_dir(out_dir: &Path) -> TargetDir {
    // fs::canonicalize on Windows produces UNC paths which cl.exe is unable to
    // handle in includes.
    // https://github.com/rust-lang/rust/issues/42869
    // https://github.com/alexcrichton/cc-rs/issues/169
    let mut also_try_canonical = cfg!(not(windows));

    let mut dir = out_dir.to_owned();
    loop {
        let is_target = dir.ends_with("target");
        let parent_contains_cargo_toml = dir.with_file_name("Cargo.toml").exists();
        if is_target && parent_contains_cargo_toml {
            return TargetDir::Path(dir);
        }
        if dir.pop() {
            continue;
        }
        if also_try_canonical {
            if let Ok(canonical_dir) = out_dir.canonicalize() {
                dir = canonical_dir;
                also_try_canonical = false;
                continue;
            }
        }
        return TargetDir::Unknown;
    }
}

#[cfg(unix)]
use self::fs::symlink_file as symlink_or_copy;

#[cfg(windows)]
fn symlink_or_copy(src: &Path, dst: &Path) -> Result<()> {
    // Pre-Windows 10, symlinks require admin privileges. Since Windows 10, they
    // require Developer Mode. If it fails, fall back to copying the file.
    if fs::symlink_file(src, dst).is_err() {
        fs::copy(src, dst)?;
    }
    Ok(())
}

#[cfg(not(any(unix, windows)))]
use self::fs::copy as symlink_or_copy;
<commit_msg>Remove "parent of target dir" from include path<commit_after>use crate::error::{Error, Result};
use crate::gen::fs;
use crate::Project;
use std::env;
use std::ffi::OsString;
use std::path::{Path, PathBuf};

pub(crate) enum TargetDir {
    Path(PathBuf),
    Unknown,
}

pub(crate) fn out_dir() -> Result<PathBuf> {
    env::var_os("OUT_DIR")
        .map(PathBuf::from)
        .ok_or(Error::MissingOutDir)
}

pub(crate) fn cc_build(prj: &Project) -> cc::Build {
    let mut build = cc::Build::new();
    build.include(include_dir(prj));
    build
}

// Symlink the header file into a predictable place. The header generated from
// path/to/mod.rs gets linked to target/cxxbridge/path/to/mod.rs.h.
pub(crate) fn symlink_header(prj: &Project, path: &Path, original: &Path) {
    if let TargetDir::Unknown = prj.target_dir {
        return;
    }
    let _ = try_symlink_header(prj, path, original);
}

fn try_symlink_header(prj: &Project, path: &Path, original: &Path) -> Result<()> {
    let mut dst = include_dir(prj);
    dst.extend(package_name());
    dst.push(original);

    let parent = dst.parent().unwrap();
    fs::create_dir_all(parent)?;
    let _ = fs::remove_file(&dst);
    symlink_or_copy(path, &dst)?;

    let mut file_name = dst.file_name().unwrap().to_os_string();
    file_name.push(".h");
    let ref dst2 = dst.with_file_name(file_name);
    symlink_or_copy(path, dst2)?;

    Ok(())
}

pub(crate) fn out_with_extension(prj: &Project, rel_path: &Path, ext: &str) -> PathBuf {
    let mut file_name = rel_path.file_name().unwrap().to_owned();
    file_name.push(ext);

    let mut res = prj.out_dir.clone();
    res.push("cxxbridge");
    res.extend(package_name());
    res.push(rel_path);
    res.with_file_name(file_name)
}

pub(crate) fn include_dir(prj: &Project) -> PathBuf {
    match &prj.target_dir {
        TargetDir::Path(target_dir) => target_dir.join("cxxbridge"),
        TargetDir::Unknown => prj.out_dir.join("cxxbridge"),
    }
}

fn package_name() -> Option<OsString> {
    env::var_os("CARGO_PKG_NAME")
}

pub(crate) fn search_parents_for_target_dir(out_dir: &Path) -> TargetDir {
    // fs::canonicalize on Windows produces UNC paths which cl.exe is unable to
    // handle in includes.
    // https://github.com/rust-lang/rust/issues/42869
    // https://github.com/alexcrichton/cc-rs/issues/169
    let mut also_try_canonical = cfg!(not(windows));

    let mut dir = out_dir.to_owned();
    loop {
        let is_target = dir.ends_with("target");
        let parent_contains_cargo_toml = dir.with_file_name("Cargo.toml").exists();
        if is_target && parent_contains_cargo_toml {
            return TargetDir::Path(dir);
        }
        if dir.pop() {
            continue;
        }
        if also_try_canonical {
            if let Ok(canonical_dir) = out_dir.canonicalize() {
                dir = canonical_dir;
                also_try_canonical = false;
                continue;
            }
        }
        return TargetDir::Unknown;
    }
}

#[cfg(unix)]
use self::fs::symlink_file as symlink_or_copy;

#[cfg(windows)]
fn symlink_or_copy(src: &Path, dst: &Path) -> Result<()> {
    // Pre-Windows 10, symlinks require admin privileges. Since Windows 10, they
    // require Developer Mode. If it fails, fall back to copying the file.
    if fs::symlink_file(src, dst).is_err() {
        fs::copy(src, dst)?;
    }
    Ok(())
}

#[cfg(not(any(unix, windows)))]
use self::fs::copy as symlink_or_copy;
<|endoftext|>


<commit_before>fn main() {
    let test = vec![
        30, 63, 83, 40, 15, 45, 46, 15, 56, 39, 82, 97, 59, 88, 3, 1, 40, 95, 83, 32, 38, 70, 4,
        87, 54, 48, 19, 8, 52, 49, 64, 72, 46, 72, 59, 36, 21, 68, 81, 34, 23, 6, 70, 80, 80, 12,
        32, 84, 17, 19, 28, 58, 68, 19, 65, 46, 43, 22, 12, 95, 89, 15, 39, 88, 64, 95, 99, 25, 2,
        7, 86, 36, 73, 90, 30, 31, 0, 62, 73, 35, 4, 26, 0, 93, 91, 77, 34, 92, 31, 56, 34, 61, 23,
        47, 78, 5, 5, 26, 36, 71, 50, 5, 59, 22, 21, 0, 72, 72, 72, 69, 5, 11, 95, 5, 0, 14, 34,
        91, 4, 27, 46, 21, 94, 96, 48, 58, 79, 21, 65, 35, 17, 16, 57, 91, 36, 50, 16, 82, 92, 1,
        29, 52, 74, 90, 48, 79, 81, 53, 46, 82, 36, 43, 64, 24, 55, 48, 27, 21, 69, 93, 49, 70, 58,
        8, 50, 97, 30, 68, 1, 34, 15, 38, 52, 27, 50, 10, 22, 67, 25, 37, 84, 91, 13, 15, 0, 5, 31,
        18, 5, 31, 49, 93, 95, 3, 86, 11, 37, 68, 43, 74,
    ];
}
<commit_msg>finish<commit_after>fn bubble_sort<T>(a: Vec<T>) -> Vec<T>
where
    T: PartialEq + PartialOrd + Clone,
{
    let length = a.len();
    let mut flag = true;
    let mut b = a;
    while (flag) {
        flag = false;
        let mut temp: Vec<T> = vec![];
        let mut this = b[0].clone();
        for i in 1..length {
            if b[i] < this {
                temp.push(b[i].clone());
                flag = true;
            } else {
                temp.push(this);
                this = b[i].clone();
            }
        }
        temp.push(this);
        b = temp;
    }
    b
}

fn main() {
    let test = vec![
        30, 63, 83, 40, 15, 45, 46, 15, 56, 39, 82, 97, 59, 88, 3, 1, 40, 95, 83, 32, 38, 70, 4,
        87, 54, 48, 19, 8, 52, 49, 64, 72, 46, 72, 59, 36, 21, 68, 81, 34, 23, 6, 70, 80, 80, 12,
        32, 84, 17, 19, 28, 58, 68, 19, 65, 46, 43, 22, 12, 95, 89, 15, 39, 88, 64, 95, 99, 25, 2,
        7, 86, 36, 73, 90, 30, 31, 0, 62, 73, 35, 4, 26, 0, 93, 91, 77, 34, 92, 31, 56, 34, 61, 23,
        47, 78, 5, 5, 26, 36, 71, 50, 5, 59, 22, 21, 0, 72, 72, 72, 69, 5, 11, 95, 5, 0, 14, 34,
        91, 4, 27, 46, 21, 94, 96, 48, 58, 79, 21, 65, 35, 17, 16, 57, 91, 36, 50, 16, 82, 92, 1,
        29, 52, 74, 90, 48, 79, 81, 53, 46, 82, 36, 43, 64, 24, 55, 48, 27, 21, 69, 93, 49, 70, 58,
        8, 50, 97, 30, 68, 1, 34, 15, 38, 52, 27, 50, 10, 22, 67, 25, 37, 84, 91, 13, 15, 0, 5, 31,
        18, 5, 31, 49, 93, 95, 3, 86, 11, 37, 68, 43, 74,
    ];
    println!("{:?}", bubble_sort(test));
}
<|endoftext|>


<commit_before>use crate::error::{Error, Result};
use std::env;
use std::fs;
use std::os;
use std::path::{Path, PathBuf};

fn out_dir() -> Result<PathBuf> {
    env::var_os("OUT_DIR")
        .map(PathBuf::from)
        .ok_or(Error::MissingOutDir)
}

pub(crate) fn cc_build() -> cc::Build {
    try_cc_build().unwrap_or_default()
}

fn try_cc_build() -> Result<cc::Build> {
    let mut build = cc::Build::new();
    build.include(include_dir()?);
    build.include(target_dir()?.parent().unwrap());
    Ok(build)
}

// Symlink the header file into a predictable place. The header generated from
// path/to/mod.rs gets linked to targets/cxxbridge/path/to/mod.h.
pub(crate) fn symlink_header(path: &Path, original: &Path) {
    let _ = try_symlink_header(path, original);
}

fn try_symlink_header(path: &Path, original: &Path) -> Result<()> {
    let suffix = relative_to_parent_of_target_dir(original)?;
    let ref dst = include_dir()?.join(suffix);

    fs::create_dir_all(dst.parent().unwrap())?;
    let _ = fs::remove_file(dst);
    #[cfg(unix)]
    os::unix::fs::symlink(path, dst)?;
    #[cfg(windows)]
    os::windows::fs::symlink_file(path, dst)?;

    Ok(())
}

fn relative_to_parent_of_target_dir(original: &Path) -> Result<PathBuf> {
    let target_dir = target_dir()?;
    let mut outer = target_dir.parent().unwrap();
    let original = original.canonicalize()?;
    loop {
        if let Ok(suffix) = original.strip_prefix(outer) {
            return Ok(suffix.to_owned());
        }
        match outer.parent() {
            Some(parent) => outer = parent,
            None => return Ok(original.components().skip(1).collect()),
        }
    }
}

pub(crate) fn out_with_extension(path: &Path, ext: &str) -> Result<PathBuf> {
    let mut file_name = path.file_name().unwrap().to_owned();
    file_name.push(ext);

    let out_dir = out_dir()?;
    let rel = relative_to_parent_of_target_dir(path)?;
    Ok(out_dir.join(rel).with_file_name(file_name))
}

pub(crate) fn include_dir() -> Result<PathBuf> {
    let target_dir = target_dir()?;
    Ok(target_dir.join("cxxbridge"))
}

fn target_dir() -> Result<PathBuf> {
    let mut dir = out_dir()?.canonicalize()?;
    loop {
        if dir.ends_with("target") {
            return Ok(dir);
        }
        if !dir.pop() {
            return Err(Error::TargetDir);
        }
    }
}
<commit_msg>Remove reliance on fs::canonicalize on Windows<commit_after>use crate::error::{Error, Result};
use std::env;
use std::fs;
use std::os;
use std::path::{Path, PathBuf};

fn out_dir() -> Result<PathBuf> {
    env::var_os("OUT_DIR")
        .map(PathBuf::from)
        .ok_or(Error::MissingOutDir)
}

pub(crate) fn cc_build() -> cc::Build {
    try_cc_build().unwrap_or_default()
}

fn try_cc_build() -> Result<cc::Build> {
    let mut build = cc::Build::new();
    build.include(include_dir()?);
    build.include(target_dir()?.parent().unwrap());
    Ok(build)
}

// Symlink the header file into a predictable place. The header generated from
// path/to/mod.rs gets linked to targets/cxxbridge/path/to/mod.h.
pub(crate) fn symlink_header(path: &Path, original: &Path) {
    let _ = try_symlink_header(path, original);
}

fn try_symlink_header(path: &Path, original: &Path) -> Result<()> {
    let suffix = relative_to_parent_of_target_dir(original)?;
    let ref dst = include_dir()?.join(suffix);

    fs::create_dir_all(dst.parent().unwrap())?;
    let _ = fs::remove_file(dst);
    #[cfg(unix)]
    os::unix::fs::symlink(path, dst)?;
    #[cfg(windows)]
    os::windows::fs::symlink_file(path, dst)?;

    Ok(())
}

fn relative_to_parent_of_target_dir(original: &Path) -> Result<PathBuf> {
    let target_dir = target_dir()?;
    let mut outer = target_dir.parent().unwrap();
    let original = canonicalize(original)?;
    loop {
        if let Ok(suffix) = original.strip_prefix(outer) {
            return Ok(suffix.to_owned());
        }
        match outer.parent() {
            Some(parent) => outer = parent,
            None => return Ok(original.components().skip(1).collect()),
        }
    }
}

pub(crate) fn out_with_extension(path: &Path, ext: &str) -> Result<PathBuf> {
    let mut file_name = path.file_name().unwrap().to_owned();
    file_name.push(ext);

    let out_dir = out_dir()?;
    let rel = relative_to_parent_of_target_dir(path)?;
    Ok(out_dir.join(rel).with_file_name(file_name))
}

pub(crate) fn include_dir() -> Result<PathBuf> {
    let target_dir = target_dir()?;
    Ok(target_dir.join("cxxbridge"))
}

fn target_dir() -> Result<PathBuf> {
    let mut dir = out_dir().and_then(canonicalize)?;
    loop {
        if dir.ends_with("target") {
            return Ok(dir);
        }
        if !dir.pop() {
            return Err(Error::TargetDir);
        }
    }
}

#[cfg(not(windows))]
fn canonicalize(path: impl AsRef<Path>) -> Result<PathBuf> {
    Ok(fs::canonicalize(path)?)
}

#[cfg(windows)]
fn canonicalize(path: impl AsRef<Path>) -> Result<PathBuf> {
    // Real fs::canonicalize on Windows produces UNC paths which cl.exe is
    // unable to handle in includes. Use a poor approximation instead.
    // https://github.com/rust-lang/rust/issues/42869
    // https://github.com/alexcrichton/cc-rs/issues/169
    Ok(env::current_dir()?.join(path))
}
<|endoftext|>