<commit_before>use std::env;
use std::process::Command;
use std::str;

fn main() {
    let rustc_minor_ver =
        rustc_minor_version().expect("Failed to get rustc version");
    let rustc_dep_of_std = env::var("CARGO_FEATURE_RUSTC_DEP_OF_STD").is_ok();
    let align_cargo_feature = env::var("CARGO_FEATURE_ALIGN").is_ok();
    let const_extern_fn_cargo_feature = env::var("CARGO_FEATURE_CONST_EXTERN_FN").is_ok();
    let libc_ci = env::var("LIBC_CI").is_ok();

    if env::var("CARGO_FEATURE_USE_STD").is_ok() {
        println!(
            "cargo:warning=\"libc's use_std cargo feature is deprecated since libc 0.2.55; \
             please consider using the `std` cargo feature instead\""
        );
    }

    // The ABI of libc used by libstd is backward compatible with FreeBSD 10.
    // The ABI of libc from crates.io is backward compatible with FreeBSD 11.
    //
    // On CI, we detect the actual FreeBSD version and match its ABI exactly,
    // running tests to ensure that the ABI is correct.
    match which_freebsd() {
        Some(10) if libc_ci || rustc_dep_of_std => {
            println!("cargo:rustc-cfg=freebsd10")
        }
        Some(11) if libc_ci => println!("cargo:rustc-cfg=freebsd11"),
        Some(12) if libc_ci => println!("cargo:rustc-cfg=freebsd12"),
        Some(13) if libc_ci => println!("cargo:rustc-cfg=freebsd13"),
        Some(_) | None => println!("cargo:rustc-cfg=freebsd11"),
    }

    // On CI: deny all warnings
    if libc_ci {
        println!("cargo:rustc-cfg=libc_deny_warnings");
    }

    // Rust >= 1.15 supports private module use:
    if rustc_minor_ver >= 15 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_priv_mod_use");
    }

    // Rust >= 1.19 supports unions:
    if rustc_minor_ver >= 19 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_union");
    }

    // Rust >= 1.24 supports const mem::size_of:
    if rustc_minor_ver >= 24 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_const_size_of");
    }

    // Rust >= 1.25 supports repr(align):
    if rustc_minor_ver >= 25 || rustc_dep_of_std || align_cargo_feature {
        println!("cargo:rustc-cfg=libc_align");
    }

    // Rust >= 1.30 supports `core::ffi::c_void`, so libc can just re-export it.
    // Otherwise, it defines an incompatible type to retaining
    // backwards-compatibility.
    if rustc_minor_ver >= 30 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_core_cvoid");
    }

    // Rust >= 1.33 supports repr(packed(N))
    if rustc_minor_ver >= 33 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_packedN");
    }

    // #[thread_local] is currently unstable
    if rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_thread_local");
    }

    if const_extern_fn_cargo_feature {
        println!("cargo:rustc-cfg=libc_const_extern_fn");
    }
}

fn rustc_minor_version() -> Option<u32> {
    macro_rules! otry {
        ($e:expr) => {
            match $e {
                Some(e) => e,
                None => return None,
            }
        };
    }

    let rustc = otry!(env::var_os("RUSTC"));
    let output = otry!(Command::new(rustc).arg("--version").output().ok());
    let version = otry!(str::from_utf8(&output.stdout).ok());
    let mut pieces = version.split('.');

    if pieces.next() != Some("rustc 1") {
        return None;
    }

    otry!(pieces.next()).parse().ok()
}

fn which_freebsd() -> Option<i32> {
    let output = std::process::Command::new("freebsd-version").output().ok();
    if output.is_none() {
        return None;
    }
    let output = output.unwrap();
    if !output.status.success() {
        return None;
    }

    let stdout = String::from_utf8(output.stdout).ok();
    if stdout.is_none() {
        return None;
    }
    let stdout = stdout.unwrap();

    match &stdout {
        s if s.starts_with("10") => Some(10),
        s if s.starts_with("11") => Some(11),
        s if s.starts_with("12") => Some(12),
        s if s.starts_with("13") => Some(13),
        _ => None,
    }
}
<commit_msg>Panic if const-extern-fn is not used on nightly<commit_after>use std::env;
use std::process::Command;
use std::str;

fn main() {
    let (rustc_minor_ver, is_nightly) =
        rustc_minor_nightly().expect("Failed to get rustc version");
    let rustc_dep_of_std = env::var("CARGO_FEATURE_RUSTC_DEP_OF_STD").is_ok();
    let align_cargo_feature = env::var("CARGO_FEATURE_ALIGN").is_ok();
    let const_extern_fn_cargo_feature = env::var("CARGO_FEATURE_CONST_EXTERN_FN").is_ok();
    let libc_ci = env::var("LIBC_CI").is_ok();

    if env::var("CARGO_FEATURE_USE_STD").is_ok() {
        println!(
            "cargo:warning=\"libc's use_std cargo feature is deprecated since libc 0.2.55; \
             please consider using the `std` cargo feature instead\""
        );
    }

    // The ABI of libc used by libstd is backward compatible with FreeBSD 10.
    // The ABI of libc from crates.io is backward compatible with FreeBSD 11.
    //
    // On CI, we detect the actual FreeBSD version and match its ABI exactly,
    // running tests to ensure that the ABI is correct.
    match which_freebsd() {
        Some(10) if libc_ci || rustc_dep_of_std => {
            println!("cargo:rustc-cfg=freebsd10")
        }
        Some(11) if libc_ci => println!("cargo:rustc-cfg=freebsd11"),
        Some(12) if libc_ci => println!("cargo:rustc-cfg=freebsd12"),
        Some(13) if libc_ci => println!("cargo:rustc-cfg=freebsd13"),
        Some(_) | None => println!("cargo:rustc-cfg=freebsd11"),
    }

    // On CI: deny all warnings
    if libc_ci {
        println!("cargo:rustc-cfg=libc_deny_warnings");
    }

    // Rust >= 1.15 supports private module use:
    if rustc_minor_ver >= 15 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_priv_mod_use");
    }

    // Rust >= 1.19 supports unions:
    if rustc_minor_ver >= 19 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_union");
    }

    // Rust >= 1.24 supports const mem::size_of:
    if rustc_minor_ver >= 24 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_const_size_of");
    }

    // Rust >= 1.25 supports repr(align):
    if rustc_minor_ver >= 25 || rustc_dep_of_std || align_cargo_feature {
        println!("cargo:rustc-cfg=libc_align");
    }

    // Rust >= 1.30 supports `core::ffi::c_void`, so libc can just re-export it.
    // Otherwise, it defines an incompatible type to retaining
    // backwards-compatibility.
    if rustc_minor_ver >= 30 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_core_cvoid");
    }

    // Rust >= 1.33 supports repr(packed(N))
    if rustc_minor_ver >= 33 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_packedN");
    }

    // #[thread_local] is currently unstable
    if rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_thread_local");
    }

    if const_extern_fn_cargo_feature {
        if !is_nightly || rustc_minor_ver < 40 {
            panic!("const-extern-fn requires a nightly compiler >= 1.40")
        }
        println!("cargo:rustc-cfg=libc_const_extern_fn");
    }
}

fn rustc_minor_nightly() -> Option<(u32, bool)> {
    macro_rules! otry {
        ($e:expr) => {
            match $e {
                Some(e) => e,
                None => return None,
            }
        };
    }

    let rustc = otry!(env::var_os("RUSTC"));
    let output = otry!(Command::new(rustc).arg("--version").output().ok());
    let version = otry!(str::from_utf8(&output.stdout).ok());
    let mut pieces = version.split('.');

    if pieces.next() != Some("rustc 1") {
        return None;
    }

    let minor = pieces.next();
    let nightly_raw = otry!(otry!(pieces.next()).split('-').nth(1));
    let nightly = nightly_raw.starts_with("dev") || nightly_raw.starts_with("nightly");
    let minor = otry!(otry!(minor).parse().ok());

    Some((minor, nightly))
}

fn which_freebsd() -> Option<i32> {
    let output = std::process::Command::new("freebsd-version").output().ok();
    if output.is_none() {
        return None;
    }
    let output = output.unwrap();
    if !output.status.success() {
        return None;
    }

    let stdout = String::from_utf8(output.stdout).ok();
    if stdout.is_none() {
        return None;
    }
    let stdout = stdout.unwrap();

    match &stdout {
        s if s.starts_with("10") => Some(10),
        s if s.starts_with("11") => Some(11),
        s if s.starts_with("12") => Some(12),
        s if s.starts_with("13") => Some(13),
        _ => None,
    }
}
<|endoftext|>


<commit_before>use rand;
use rand::Rng;
use std::f32::consts::PI;
use rand::distributions::{Normal, IndependentSample};

#[allow(unused)]
fn modulo(a: i64, b: i64) -> usize {
    (((a % b) + b) % b) as usize
}

pub struct Heightmap<T> {
    pub heights: Vec<T>,
    pub width: u16,
    pub height: u16,
}

impl<T> Heightmap<T> {
    #[allow(unused)]
    pub fn new(heights: Vec<T>, width: u16, height: u16) -> Self {
        assert_eq!(heights.len(), (width as usize) * (height as usize));
        Heightmap {
            heights,
            width,
            height,
        }
    }

    pub fn get(&self, x: u16, y: u16) -> Option<T>
    where
        T: Clone,
    {
        if x >= self.width || y >= self.height {
            return None;
        }

        self.heights
            .get(x as usize + y as usize * self.width as usize)
            .cloned()
    }

    #[allow(unused)]
    pub fn get_wrapping(&self, x: i64, y: i64) -> T
    where
        T: Clone,
    {
        let x = modulo(x, self.width as i64);
        let y = modulo(y, self.height as i64);
        self.heights[x + y * self.width as usize].clone()
    }

    /// Produces a Vec of arrays where each array consists of the height at that point followed by
    /// the slope in the x and y directions respectively.
    pub fn as_height_and_slopes(&self, spacing: f32) -> Vec<[f32; 3]>
    where
        f32: From<T>,
        T: Clone,
    {
        let mut result = Vec::with_capacity(self.width as usize * self.height as usize);
        let scale_factor = 0.5 / spacing;

        for y in 0..self.height {
            for x in 0..self.width {
                let mx: f32 = if x > 0 {
                    self.get(x - 1, y).unwrap().into()
                } else {
                    self.get(self.width - 1, y).unwrap().into()
                };
                let px: f32 = if x < self.width - 1 {
                    self.get(x + 1, y).unwrap().into()
                } else {
                    self.get(0, y).unwrap().into()
                };
                let my: f32 = if y > 0 {
                    self.get(x, y - 1).unwrap().into()
                } else {
                    self.get(x, self.height - 1).unwrap().into()
                };
                let py: f32 = if y < self.height - 1 {
                    self.get(x, y + 1).unwrap().into()
                } else {
                    self.get(x, 0).unwrap().into()
                };
                let v = [
                    self.heights[x as usize + y as usize * self.width as usize]
                        .clone()
                        .into(),
                    (mx - px) * scale_factor,
                    (my - py) * scale_factor,
                ];
                result.push(v);
            }
        }
        result
    }
}

pub fn perlin_noise(grid_resolution: usize, grid_spacing: usize) -> Heightmap<f32> {
    fn dot(a: (f32, f32), b: (f32, f32)) -> f32 {
        a.0 * b.0 + a.1 * b.1
    }

    fn fade(t: f32) -> f32 {
        t * t * t * (6.0 * t * t - 15.0 * t + 10.0)
    }

    fn interp(a: f32, b: f32, t: f32) -> f32 {
        let t = fade(t);
        a * (1.0 - t) + b * t
    }

    let mut rng = rand::thread_rng();
    let gradients: Vec<(f32, f32)> = (0..(grid_resolution * grid_resolution))
        .map(|_| rng.gen_range(0.0, 2.0 * PI).sin_cos())
        .collect();

    let mut heights =
        vec![-9999.0; grid_resolution * grid_resolution * grid_spacing * grid_spacing];
    for y in 0..grid_resolution {
        for x in 0..grid_resolution {
            let xp = (x + 1) % grid_resolution;
            let yp = (y + 1) % grid_resolution;
            let a = gradients[x + y * grid_resolution];
            let b = gradients[x + yp * grid_resolution];
            let c = gradients[xp + y * grid_resolution];
            let d = gradients[xp + yp * grid_resolution];

            for k in 0..grid_spacing {
                for h in 0..grid_spacing {
                    let v = (
                        h as f32 / grid_spacing as f32,
                        k as f32 / grid_spacing as f32,
                    );

                    let ad = dot(a, v);
                    let bd = dot(b, (v.0, v.1 - 1.0));
                    let cd = dot(c, (v.0 - 1.0, v.1));
                    let dd = dot(d, (v.0 - 1.0, v.1 - 1.0));

                    let height = interp(interp(ad, bd, v.1), interp(cd, dd, v.1), v.0);

                    let i = (h + x * grid_spacing) +
                        (k + y * grid_spacing) * grid_resolution * grid_spacing;
                    heights[i] = height;
                }
            }
        }
    }

    Heightmap {
        heights,
        width: (grid_resolution * grid_spacing) as u16,
        height: (grid_resolution * grid_spacing) as u16,
    }
}

/// Evaluate wavelet noise on a grid with the given resolution and grid spacing. ///
/// The output heightmap will have a width and height of `grid_resolution` * `grid_spacing`. Values
/// will have a mean of approximately zero, and a variance of 1.
pub fn wavelet_noise(grid_resolution: usize, grid_spacing: usize) -> Heightmap<f32> {
    // See: https://graphics.pixar.com/library/WaveletNoise/paper.pdf

    fn modulo(x: i32, n: usize) -> usize {
        let m = x % n as i32;
        if m < 0 {
            (m + n as i32) as usize
        } else {
            m as usize
        }
    }
    fn downsample(from: &[f32], to: &mut [f32], n: usize, stride: usize) {
        const ARAD: i32 = 16;
        #[cfg_attr(rustfmt, rustfmt_skip)]
        const COEFFS: [f32; 32] = [
            0.000334,-0.001528, 0.000410, 0.003545,-0.000938,-0.008233, 0.002172, 0.019120,
            -0.005040,-0.044412, 0.011655, 0.103311,-0.025936,-0.243780, 0.033979, 0.655340,
            0.655340, 0.033979,-0.243780,-0.025936, 0.103311, 0.011655,-0.044412,-0.005040,
            0.019120, 0.002172,-0.008233,-0.000938, 0.003546, 0.000410,-0.001528, 0.000334
        ];
        for i in 0..(n / 2) {
            to[i * stride] = 0.0;
            let min_k = 2 * (i as i32) - ARAD;
            let max_k = 2 * (i as i32) + ARAD;
            for k in min_k..(max_k) {
                let index = (ARAD + k - 2 * i as i32) as usize;
                to[i * stride] += COEFFS[index] * from[modulo(k, n) * stride];
            }
        }
    }
    fn upsample(from: &[f32], to: &mut [f32], n: usize, stride: usize) {
        let p_coeffs = [0.25, 0.75, 0.75, 0.25];
        for i in 0..n {
            to[i * stride] = 0.0;
            for k in (i / 2)..(i / 2 + 2) {
                to[i * stride] += p_coeffs[2 + i - 2 * k] * from[(k % (n / 2)) * stride];
            }
        }
    }
    fn generate_noise_tile(n: usize) -> Vec<f32> {
        assert!(n % 2 == 0); // size must be even!

        let mut temp1 = vec![0.0; n * n];
        let mut temp2 = vec![0.0; n * n];
        let mut noise = Vec::new();

        // Step 1. Fill the tile with random numbers in the range -1 to 1.
        let normal = Normal::new(0.0, 1.0);
        for _ in 0..(n * n) {
            noise.push(normal.ind_sample(&mut rand::thread_rng()) as f32);
        }

        // Steps 2 and 3. Downsample and upsample the tile
        for iy in 0..n {
            // each x row
            let i = iy * n;
            downsample(&noise[i..], &mut temp1[i..], n, 1);
            upsample(&temp1[i..], &mut temp2[i..], n, 1);
        }
        for ix in 0..n {
            // each y row
            let i = ix;
            downsample(&temp2[i..], &mut temp1[i..], n, n);
            upsample(&temp1[i..], &mut temp2[i..], n, n);
        }

        // Step 4. Subtract out the coarse-scale contribution
        for i in 0..(n * n) {
            noise[i] -= temp2[i];
        }
        // Avoid even/odd variance difference by adding odd-offset version of noise to itself.
        let mut offset = n / 2;
        if offset % 2 == 0 {
            offset += 1;
        }
        let mut i = 0;
        for ix in 0..n {
            for iy in 0..n {
                temp1[i] = noise[((ix + offset) % n) + ((iy + offset) % n) * n];
                i += 1;
            }
        }
        for i in 0..(n * n) {
            noise[i] += temp1[i];
        }

        noise
    }

    /* Non-projected 2D noise */
    fn noise(noise_tile: &[f32], n: usize, p: [f32; 2]) -> f32 {
        let mut mid = [0; 2];
        let mut w = [[0.0; 3]; 2];

        /* Evaluate quadratic B-spline basis functions */
        for i in 0..2 {
            let center = p[i] - 0.5;
            let t = center.ceil() - center;

            mid[i] = center.ceil() as i32;
            w[i][0] = 0.5 * t * t;
            w[i][2] = 0.5 * (1.0 - t) * (1.0 - t);
            w[i][1] = 1.0 - w[i][0] - w[i][2];
        }
        /* Evaluate noise by weighting noise coefficients by basis function values */
        let mut result = 0.0;
        for fx in 0..3 {
            for fy in 0..3 {
                let cx = modulo(mid[0] + (fx as i32 - 1), n);
                let cy = modulo(mid[1] + (fy as i32 - 1), n);
                let weight = w[0][fx] * w[1][fy];
                result += weight * noise_tile[cx + cy * n];
            }
        }
        result
    }

    let noise_tile = generate_noise_tile(grid_resolution);

    let mut heights = Vec::new();
    for x in 0..(grid_resolution * grid_spacing) {
        for y in 0..(grid_resolution * grid_spacing) {
            let p = [
                x as f32 / grid_spacing as f32,
                y as f32 / grid_spacing as f32,
            ];
            heights.push(noise(&noise_tile, grid_resolution, p))
        }
    }

    let mean = heights.iter().sum::<f32>() / heights.len() as f32;
    let variance = heights.iter().map(|n| (n - mean) * (n - mean)).sum::<f32>() /
        heights.len() as f32;

    let inv_variance = 1.0 / variance;
    for h in &mut heights {
        *h *= inv_variance;
    }

    Heightmap {
        heights,
        width: (grid_resolution * grid_spacing) as u16,
        height: (grid_resolution * grid_spacing) as u16,
    }
}
<commit_msg>Supress unused function warning<commit_after>use rand;
use rand::Rng;
use std::f32::consts::PI;
use rand::distributions::{Normal, IndependentSample};

#[allow(unused)]
fn modulo(a: i64, b: i64) -> usize {
    (((a % b) + b) % b) as usize
}

pub struct Heightmap<T> {
    pub heights: Vec<T>,
    pub width: u16,
    pub height: u16,
}

impl<T> Heightmap<T> {
    #[allow(unused)]
    pub fn new(heights: Vec<T>, width: u16, height: u16) -> Self {
        assert_eq!(heights.len(), (width as usize) * (height as usize));
        Heightmap {
            heights,
            width,
            height,
        }
    }

    pub fn get(&self, x: u16, y: u16) -> Option<T>
    where
        T: Clone,
    {
        if x >= self.width || y >= self.height {
            return None;
        }

        self.heights
            .get(x as usize + y as usize * self.width as usize)
            .cloned()
    }

    #[allow(unused)]
    pub fn get_wrapping(&self, x: i64, y: i64) -> T
    where
        T: Clone,
    {
        let x = modulo(x, self.width as i64);
        let y = modulo(y, self.height as i64);
        self.heights[x + y * self.width as usize].clone()
    }

    /// Produces a Vec of arrays where each array consists of the height at that point followed by
    /// the slope in the x and y directions respectively.
    pub fn as_height_and_slopes(&self, spacing: f32) -> Vec<[f32; 3]>
    where
        f32: From<T>,
        T: Clone,
    {
        let mut result = Vec::with_capacity(self.width as usize * self.height as usize);
        let scale_factor = 0.5 / spacing;

        for y in 0..self.height {
            for x in 0..self.width {
                let mx: f32 = if x > 0 {
                    self.get(x - 1, y).unwrap().into()
                } else {
                    self.get(self.width - 1, y).unwrap().into()
                };
                let px: f32 = if x < self.width - 1 {
                    self.get(x + 1, y).unwrap().into()
                } else {
                    self.get(0, y).unwrap().into()
                };
                let my: f32 = if y > 0 {
                    self.get(x, y - 1).unwrap().into()
                } else {
                    self.get(x, self.height - 1).unwrap().into()
                };
                let py: f32 = if y < self.height - 1 {
                    self.get(x, y + 1).unwrap().into()
                } else {
                    self.get(x, 0).unwrap().into()
                };
                let v = [
                    self.heights[x as usize + y as usize * self.width as usize]
                        .clone()
                        .into(),
                    (mx - px) * scale_factor,
                    (my - py) * scale_factor,
                ];
                result.push(v);
            }
        }
        result
    }
}

#[allow(dead_code)]
pub fn perlin_noise(grid_resolution: usize, grid_spacing: usize) -> Heightmap<f32> {
    fn dot(a: (f32, f32), b: (f32, f32)) -> f32 {
        a.0 * b.0 + a.1 * b.1
    }

    fn fade(t: f32) -> f32 {
        t * t * t * (6.0 * t * t - 15.0 * t + 10.0)
    }

    fn interp(a: f32, b: f32, t: f32) -> f32 {
        let t = fade(t);
        a * (1.0 - t) + b * t
    }

    let mut rng = rand::thread_rng();
    let gradients: Vec<(f32, f32)> = (0..(grid_resolution * grid_resolution))
        .map(|_| rng.gen_range(0.0, 2.0 * PI).sin_cos())
        .collect();

    let mut heights =
        vec![-9999.0; grid_resolution * grid_resolution * grid_spacing * grid_spacing];
    for y in 0..grid_resolution {
        for x in 0..grid_resolution {
            let xp = (x + 1) % grid_resolution;
            let yp = (y + 1) % grid_resolution;
            let a = gradients[x + y * grid_resolution];
            let b = gradients[x + yp * grid_resolution];
            let c = gradients[xp + y * grid_resolution];
            let d = gradients[xp + yp * grid_resolution];

            for k in 0..grid_spacing {
                for h in 0..grid_spacing {
                    let v = (
                        h as f32 / grid_spacing as f32,
                        k as f32 / grid_spacing as f32,
                    );

                    let ad = dot(a, v);
                    let bd = dot(b, (v.0, v.1 - 1.0));
                    let cd = dot(c, (v.0 - 1.0, v.1));
                    let dd = dot(d, (v.0 - 1.0, v.1 - 1.0));

                    let height = interp(interp(ad, bd, v.1), interp(cd, dd, v.1), v.0);

                    let i = (h + x * grid_spacing) +
                        (k + y * grid_spacing) * grid_resolution * grid_spacing;
                    heights[i] = height;
                }
            }
        }
    }

    Heightmap {
        heights,
        width: (grid_resolution * grid_spacing) as u16,
        height: (grid_resolution * grid_spacing) as u16,
    }
}

/// Evaluate wavelet noise on a grid with the given resolution and grid spacing. ///
/// The output heightmap will have a width and height of `grid_resolution` * `grid_spacing`. Values
/// will have a mean of approximately zero, and a variance of 1.
pub fn wavelet_noise(grid_resolution: usize, grid_spacing: usize) -> Heightmap<f32> {
    // See: https://graphics.pixar.com/library/WaveletNoise/paper.pdf

    fn modulo(x: i32, n: usize) -> usize {
        let m = x % n as i32;
        if m < 0 {
            (m + n as i32) as usize
        } else {
            m as usize
        }
    }
    fn downsample(from: &[f32], to: &mut [f32], n: usize, stride: usize) {
        const ARAD: i32 = 16;
        #[cfg_attr(rustfmt, rustfmt_skip)]
        const COEFFS: [f32; 32] = [
            0.000334,-0.001528, 0.000410, 0.003545,-0.000938,-0.008233, 0.002172, 0.019120,
            -0.005040,-0.044412, 0.011655, 0.103311,-0.025936,-0.243780, 0.033979, 0.655340,
            0.655340, 0.033979,-0.243780,-0.025936, 0.103311, 0.011655,-0.044412,-0.005040,
            0.019120, 0.002172,-0.008233,-0.000938, 0.003546, 0.000410,-0.001528, 0.000334
        ];
        for i in 0..(n / 2) {
            to[i * stride] = 0.0;
            let min_k = 2 * (i as i32) - ARAD;
            let max_k = 2 * (i as i32) + ARAD;
            for k in min_k..(max_k) {
                let index = (ARAD + k - 2 * i as i32) as usize;
                to[i * stride] += COEFFS[index] * from[modulo(k, n) * stride];
            }
        }
    }
    fn upsample(from: &[f32], to: &mut [f32], n: usize, stride: usize) {
        let p_coeffs = [0.25, 0.75, 0.75, 0.25];
        for i in 0..n {
            to[i * stride] = 0.0;
            for k in (i / 2)..(i / 2 + 2) {
                to[i * stride] += p_coeffs[2 + i - 2 * k] * from[(k % (n / 2)) * stride];
            }
        }
    }
    fn generate_noise_tile(n: usize) -> Vec<f32> {
        assert!(n % 2 == 0); // size must be even!

        let mut temp1 = vec![0.0; n * n];
        let mut temp2 = vec![0.0; n * n];
        let mut noise = Vec::new();

        // Step 1. Fill the tile with random numbers in the range -1 to 1.
        let normal = Normal::new(0.0, 1.0);
        for _ in 0..(n * n) {
            noise.push(normal.ind_sample(&mut rand::thread_rng()) as f32);
        }

        // Steps 2 and 3. Downsample and upsample the tile
        for iy in 0..n {
            // each x row
            let i = iy * n;
            downsample(&noise[i..], &mut temp1[i..], n, 1);
            upsample(&temp1[i..], &mut temp2[i..], n, 1);
        }
        for ix in 0..n {
            // each y row
            let i = ix;
            downsample(&temp2[i..], &mut temp1[i..], n, n);
            upsample(&temp1[i..], &mut temp2[i..], n, n);
        }

        // Step 4. Subtract out the coarse-scale contribution
        for i in 0..(n * n) {
            noise[i] -= temp2[i];
        }
        // Avoid even/odd variance difference by adding odd-offset version of noise to itself.
        let mut offset = n / 2;
        if offset % 2 == 0 {
            offset += 1;
        }
        let mut i = 0;
        for ix in 0..n {
            for iy in 0..n {
                temp1[i] = noise[((ix + offset) % n) + ((iy + offset) % n) * n];
                i += 1;
            }
        }
        for i in 0..(n * n) {
            noise[i] += temp1[i];
        }

        noise
    }

    /* Non-projected 2D noise */
    fn noise(noise_tile: &[f32], n: usize, p: [f32; 2]) -> f32 {
        let mut mid = [0; 2];
        let mut w = [[0.0; 3]; 2];

        /* Evaluate quadratic B-spline basis functions */
        for i in 0..2 {
            let center = p[i] - 0.5;
            let t = center.ceil() - center;

            mid[i] = center.ceil() as i32;
            w[i][0] = 0.5 * t * t;
            w[i][2] = 0.5 * (1.0 - t) * (1.0 - t);
            w[i][1] = 1.0 - w[i][0] - w[i][2];
        }
        /* Evaluate noise by weighting noise coefficients by basis function values */
        let mut result = 0.0;
        for fx in 0..3 {
            for fy in 0..3 {
                let cx = modulo(mid[0] + (fx as i32 - 1), n);
                let cy = modulo(mid[1] + (fy as i32 - 1), n);
                let weight = w[0][fx] * w[1][fy];
                result += weight * noise_tile[cx + cy * n];
            }
        }
        result
    }

    let noise_tile = generate_noise_tile(grid_resolution);

    let mut heights = Vec::new();
    for x in 0..(grid_resolution * grid_spacing) {
        for y in 0..(grid_resolution * grid_spacing) {
            let p = [
                x as f32 / grid_spacing as f32,
                y as f32 / grid_spacing as f32,
            ];
            heights.push(noise(&noise_tile, grid_resolution, p))
        }
    }

    let mean = heights.iter().sum::<f32>() / heights.len() as f32;
    let variance = heights.iter().map(|n| (n - mean) * (n - mean)).sum::<f32>() /
        heights.len() as f32;

    let inv_variance = 1.0 / variance;
    for h in &mut heights {
        *h *= inv_variance;
    }

    Heightmap {
        heights,
        width: (grid_resolution * grid_spacing) as u16,
        height: (grid_resolution * grid_spacing) as u16,
    }
}
<|endoftext|>


<commit_before>//! A module for user processes
// So far it just contains some test code

use core::fmt::Write;
use core::ptr;

use io::stream::InputStream;
use fs::ROOT_FS;
use sync::{Semaphore, StaticSemaphore};
use vga::rectangle::{Rectangle, Color};
use vga::input::{InputElement, TextBox};
use super::Process;
use super::focus::focus;
use super::ready_queue;
use super::proc_table::PROCESS_TABLE;

// useful constants
const ROWS: usize = 25;
const COLS: usize = 80;
const NUM_LOOP: usize = (ROWS*2 + COLS*2 - 4) * 3;

// Some test semaphores
static mut current: (usize, usize) = (0,0);
static mut s1: StaticSemaphore = StaticSemaphore::new(1);
static mut s2: StaticSemaphore = StaticSemaphore::new(1);

// Some test routines
pub fn run(this: &Process) -> usize {

    // grab focus
    focus(None);

    let mut w0 = Rectangle::new(COLS, ROWS, (0, 0));
    let msg_sem = unsafe {
        let s = 0xD000_0000 as *mut Semaphore<Rectangle>;
        ptr::write(s, Semaphore::new(Rectangle::new(60, 7, (1,1)), 1));
        &*s
    };

    unsafe { *(0xF000_0000 as *mut usize) = this.pid; }

    w0.set_bg(Color::LightBlue);
    w0.paint();

    let mut msg = msg_sem.down();
    msg.set_cursor((0,0));
    msg.set_bg(Color::LightGray);
    msg.set_fg(Color::Black);

    msg.put_str("<-- If semaphores work correctly, then only this block \
                should be red when all loop_procs finish running.");

    for _ in 0..NUM_LOOP {
        ready_queue::make_ready(Process::new("loop_proc", self::run2));
        unsafe { s1.down(); }

        // test vm
        if unsafe { *(0xF000_0000 as *mut usize) } != this.pid {
            panic!("Oh no! *0xF000_0000 should be {} but is {}",
                   this.pid, unsafe { *(0xF000_0000 as *mut usize) });
        }
    }

    msg.put_str("\n\nYay! :)");

    // test share-page IPC
    unsafe {
        // create another process
        ready_queue::make_ready(Process::new("semaphore_test", self::run3));

        // share the semaphore
        let me = &mut *PROCESS_TABLE.get(this.pid).expect("Oh no! expected Some(process)!");
        if !me.addr_space.request_share(this.pid + NUM_LOOP + 1, 0xD000_0000) {
            panic!("Share request failed!");
        }
    }

    msg.put_str("\n\nNow test IPC... ");

    0
}

fn get_prev((r,c): (usize, usize)) -> (usize, usize) {
    if r == 0 && c > 0 { // top
        (0, c-1)
    } else if c == COLS-1 { // right
        (r-1, c)
    } else if r == ROWS-1 { // bottom
        (r, c+1)
    } else { // left
        (r+1, c)
    }
}

fn get_next((r,c): (usize, usize)) -> (usize, usize) {
    if r == 0 && c < COLS-1 { // top
        (0, c+1)
    } else if c == COLS-1 && r < ROWS-1 { // right
        (r+1, c)
    } else if r == ROWS-1 && c > 0 { // bottom
        (r, c-1)
    } else { // left
        (r-1, c)
    }
}

fn run2(this: &Process) -> usize {

    unsafe { *(0xF000_0000 as *mut usize) = this.pid; }

    // test vm
    if unsafe { *(0xF000_0000 as *mut usize) } != this.pid {
        panic!("Oh no! *0xF000_0000 should be {} but is {}",
               this.pid, unsafe { *(0xF000_0000 as *mut usize) });
    }

    unsafe { s2.down(); }

    let mut w = Rectangle::new(COLS,ROWS, (0,0));

    let me = unsafe { current };
    let prev = get_prev(me);

    unsafe {
        current = get_next(me);
    }

    printf!("Erase ({},{}) ", prev.0, prev.1);
    w.set_bg(Color::LightBlue);
    w.set_cursor(prev);
    w.put_char(' ');

    printf!("Draw ({},{})\n", me.0,me.1);
    w.set_bg(Color::Red);
    w.set_cursor(me);
    w.put_char(' ');

    unsafe { s2.up(); }

    // test vm
    if unsafe { *(0xF000_0000 as *mut usize) } != this.pid {
        panic!("Oh no! *0xF000_0000 should be {} but is {}",
               this.pid, unsafe { *(0xF000_0000 as *mut usize) });
    }

    // test process table
    unsafe {
        let me = PROCESS_TABLE.get(this.pid).expect("Oh no! expected Some(process)!");

        if (me as *const Process) != (this as *const Process) {
            panic!("Oh no! me = 0x{:X}, but should be 0x{:X}",
                   me as usize, this as *const Process as usize);
        }
    }

    unsafe { s1.up(); }

    0
}

fn run3(this: &Process) -> usize {
    unsafe {
        let me = &mut *PROCESS_TABLE.get(this.pid).expect("Oh no! expected Some(process)!");

        // accept share from the parent process
        if !me.addr_space.accept_share(3, 0xF000_0000) {
            panic!("Share accept failed");
        }

        let msg_sem = {
            let s = 0xF000_0000 as *mut Semaphore<Rectangle>;
            &*s
        };

        let mut msg = msg_sem.down();

        msg.put_str("Success! :D");
    }

    ready_queue::make_ready(Process::new("kbd_proc", self::run4));

    0
}

fn run4(_: &Process) -> usize {
    // test the keyboard

    let mut label = Rectangle::new(17,1,(8,1));
    label.set_bg(Color::Black);
    label.set_fg(Color::Yellow);
    label.set_cursor((0,0));
    label.put_str("Enter your name: ");

    let mut input_box = TextBox::new(40, (8,18));
    let string = input_box.get_str();

    let mut b = Rectangle::new(70, 10, (10, 1));
    b.set_bg(Color::LightGray);
    b.set_fg(Color::Black);
    b.set_cursor((0,0));

    let _ = write!(&mut b, "Hello, {}!\n", string);

    ready_queue::make_ready(Process::new("fs_proc", self::run5));

    0
}

fn run5(_: &Process) -> usize {
    // test the fs

    let mut f = unsafe { (*ROOT_FS).open(0) };

    // TODO: read something from the file

    0
}
<commit_msg>Adding tests for files/ofs<commit_after>//! A module for user processes
// So far it just contains some test code

use core::fmt::Write;
use core::ptr;

use io::block::BlockDataBuffer;
use io::stream::InputStream;
use fs::ROOT_FS;
use sync::{Semaphore, StaticSemaphore};
use vga::rectangle::{Rectangle, Color};
use vga::input::{InputElement, TextBox};
use super::Process;
use super::focus::focus;
use super::ready_queue;
use super::proc_table::PROCESS_TABLE;

// useful constants
const ROWS: usize = 25;
const COLS: usize = 80;
const NUM_LOOP: usize = (ROWS*2 + COLS*2 - 4) * 3;

// Some test semaphores
static mut current: (usize, usize) = (0,0);
static mut s1: StaticSemaphore = StaticSemaphore::new(1);
static mut s2: StaticSemaphore = StaticSemaphore::new(1);

// Some test routines
pub fn run(this: &Process) -> usize {

    // grab focus
    focus(None);

    let mut w0 = Rectangle::new(COLS, ROWS, (0, 0));
    let msg_sem = unsafe {
        let s = 0xD000_0000 as *mut Semaphore<Rectangle>;
        ptr::write(s, Semaphore::new(Rectangle::new(60, 7, (1,1)), 1));
        &*s
    };

    unsafe { *(0xF000_0000 as *mut usize) = this.pid; }

    w0.set_bg(Color::LightBlue);
    w0.paint();

    let mut msg = msg_sem.down();
    msg.set_cursor((0,0));
    msg.set_bg(Color::LightGray);
    msg.set_fg(Color::Black);

    msg.put_str("<-- If semaphores work correctly, then only this block \
                should be red when all loop_procs finish running.");

    for _ in 0..NUM_LOOP {
        ready_queue::make_ready(Process::new("loop_proc", self::run2));
        unsafe { s1.down(); }

        // test vm
        if unsafe { *(0xF000_0000 as *mut usize) } != this.pid {
            panic!("Oh no! *0xF000_0000 should be {} but is {}",
                   this.pid, unsafe { *(0xF000_0000 as *mut usize) });
        }
    }

    msg.put_str("\n\nYay! :)");

    // test share-page IPC
    unsafe {
        // create another process
        ready_queue::make_ready(Process::new("semaphore_test", self::run3));

        // share the semaphore
        let me = &mut *PROCESS_TABLE.get(this.pid).expect("Oh no! expected Some(process)!");
        if !me.addr_space.request_share(this.pid + NUM_LOOP + 1, 0xD000_0000) {
            panic!("Share request failed!");
        }
    }

    msg.put_str("\n\nNow test IPC... ");

    0
}

fn get_prev((r,c): (usize, usize)) -> (usize, usize) {
    if r == 0 && c > 0 { // top
        (0, c-1)
    } else if c == COLS-1 { // right
        (r-1, c)
    } else if r == ROWS-1 { // bottom
        (r, c+1)
    } else { // left
        (r+1, c)
    }
}

fn get_next((r,c): (usize, usize)) -> (usize, usize) {
    if r == 0 && c < COLS-1 { // top
        (0, c+1)
    } else if c == COLS-1 && r < ROWS-1 { // right
        (r+1, c)
    } else if r == ROWS-1 && c > 0 { // bottom
        (r, c-1)
    } else { // left
        (r-1, c)
    }
}

fn run2(this: &Process) -> usize {

    unsafe { *(0xF000_0000 as *mut usize) = this.pid; }

    // test vm
    if unsafe { *(0xF000_0000 as *mut usize) } != this.pid {
        panic!("Oh no! *0xF000_0000 should be {} but is {}",
               this.pid, unsafe { *(0xF000_0000 as *mut usize) });
    }

    unsafe { s2.down(); }

    let mut w = Rectangle::new(COLS,ROWS, (0,0));

    let me = unsafe { current };
    let prev = get_prev(me);

    unsafe {
        current = get_next(me);
    }

    printf!("Erase ({},{}) ", prev.0, prev.1);
    w.set_bg(Color::LightBlue);
    w.set_cursor(prev);
    w.put_char(' ');

    printf!("Draw ({},{})\n", me.0,me.1);
    w.set_bg(Color::Red);
    w.set_cursor(me);
    w.put_char(' ');

    unsafe { s2.up(); }

    // test vm
    if unsafe { *(0xF000_0000 as *mut usize) } != this.pid {
        panic!("Oh no! *0xF000_0000 should be {} but is {}",
               this.pid, unsafe { *(0xF000_0000 as *mut usize) });
    }

    // test process table
    unsafe {
        let me = PROCESS_TABLE.get(this.pid).expect("Oh no! expected Some(process)!");

        if (me as *const Process) != (this as *const Process) {
            panic!("Oh no! me = 0x{:X}, but should be 0x{:X}",
                   me as usize, this as *const Process as usize);
        }
    }

    unsafe { s1.up(); }

    0
}

fn run3(this: &Process) -> usize {
    unsafe {
        let me = &mut *PROCESS_TABLE.get(this.pid).expect("Oh no! expected Some(process)!");

        // accept share from the parent process
        if !me.addr_space.accept_share(3, 0xF000_0000) {
            panic!("Share accept failed");
        }

        let msg_sem = {
            let s = 0xF000_0000 as *mut Semaphore<Rectangle>;
            &*s
        };

        let mut msg = msg_sem.down();

        msg.put_str("Success! :D");
    }

    ready_queue::make_ready(Process::new("kbd_proc", self::run4));

    0
}

fn run4(_: &Process) -> usize {
    // test the keyboard

    let mut label = Rectangle::new(17,1,(8,1));
    label.set_bg(Color::Black);
    label.set_fg(Color::Yellow);
    label.set_cursor((0,0));
    label.put_str("Enter your name: ");

    let mut input_box = TextBox::new(40, (8,18));
    let string = input_box.get_str();

    let mut b = Rectangle::new(70, 10, (10, 1));
    b.set_bg(Color::LightGray);
    b.set_fg(Color::Black);
    b.set_cursor((0,0));

    let _ = write!(&mut b, "Hello, {}!\n", string);

    ready_queue::make_ready(Process::new("fs_proc", self::run5));

    0
}

fn run5(_: &Process) -> usize {
    // test the fs

    let mut f = unsafe { (*ROOT_FS).open(0) };

    // TODO: read something from the file
    let mut buf = BlockDataBuffer::new(4);

    f.read(&mut buf);

    let val1 = unsafe { *buf.get_ref::<usize>(0) };

    buf.set_offset(0);

    f.read(&mut buf);

    let val2 = unsafe { *buf.get_ref::<usize>(0) };

    let mut b = Rectangle::new(70, 10, (12, 1));
    b.set_bg(Color::LightGray);
    b.set_fg(Color::Black);
    b.set_cursor((0,0));

    let _ = write!(&mut b, "Read values from file: {:X}, {:X}!\n", val1, val2);

    0
}
<|endoftext|>


<commit_before>use cpu::{Register8, Register16};
use GameBoy;

/// Iterate the ROM
pub fn decode(gb: &mut GameBoy) {
    for i in 0..gb.cartridge.size() {
        opcode_router(gb.cartridge.read_byte(i as u16), gb);
    }
    println!("{:?}", gb.cpu);
}

/// Map Opcode to function
fn opcode_router(opcode: u8, gb: &mut GameBoy) {
    match opcode {
        0x00 => {},
        0x01 => { ld_bc_nn(gb) },
        0x02 => { ld_bcp_a(gb) },
        0x03 => { inc_bc(gb) },
        0x04 => { inc_bc(gb) },
        0x31 => { ld_sp_nn(gb) },
        _ => {}
    }
}

/// LD BC, nn 0x01
fn ld_bc_nn(gb: &mut GameBoy) {
    let v: u16 = gb.cartridge.read_word(gb.cpu.get_16(Register16::PC) + 1);
    gb.cpu.set_16(Register16::BC, v);
    gb.cpu.inc_pc(3);

}

/// LD (BC), a 0x02
fn ld_bcp_a(gb: &mut GameBoy) {
    gb.mem.write_byte(gb.cpu.get_16(Register16::BC), gb.cpu.get_8(Register8::A));
    gb.cpu.inc_pc(1);
}

/// INC BC, 0x03
fn inc_bc(gb: &mut GameBoy) {
    gb.cpu.inc_16(Register16::BC);
    gb.cpu.inc_pc(1);
}

/// INC B, 0x04
fn inc_b(gb: &mut GameBoy) {
    gb.cpu.inc_8(Register8::B);
    gb.cpu.inc_pc(1);
}

/// LD SP, nn 0x31
fn ld_sp_nn(gb: &mut GameBoy) {
    let v: u16 = gb.cartridge.read_word(gb.cpu.get_16(Register16::PC) + 1);
    gb.cpu.set_16(Register16::SP, v);
    gb.cpu.inc_pc(3);
}
<commit_msg>add all routes<commit_after>use cpu::{Flag, Register8, Register16};
use GameBoy;

/// Iterate the ROM
pub fn decode(gb: &mut GameBoy) {
    for i in 0..gb.cartridge.size() {
        opcode_router(gb.cartridge.read_byte(i as u16), gb);
    }
    println!("{:?}", gb.cpu);
}

/// Map Opcode to function
fn opcode_router(opcode: u8, gb: &mut GameBoy) {
    match opcode {
        0x00 => {},
        0x01 => { ld_bc_nn(gb) },
        0x02 => { ld_bcp_a(gb) },
        0x03 => { inc_bc(gb) },
        0x04 => { inc_bc(gb) },
        0x05 => { unimplemented!() },
        0x06 => { unimplemented!() },
        0x07 => { unimplemented!() },
        0x08 => { unimplemented!() },
        0x09 => { unimplemented!() },
        0x0a => { unimplemented!() },
        0x0b => { unimplemented!() },
        0x0c => { unimplemented!() },
        0x0d => { unimplemented!() },
        0x0e => { unimplemented!() },
        0x0f => { unimplemented!() },
        0x10 => { unimplemented!() },
        0x11 => { unimplemented!() },
        0x12 => { unimplemented!() },
        0x13 => { unimplemented!() },
        0x14 => { unimplemented!() },
        0x15 => { unimplemented!() },
        0x16 => { unimplemented!() },
        0x17 => { unimplemented!() },
        0x18 => { unimplemented!() },
        0x19 => { unimplemented!() },
        0x1a => { unimplemented!() },
        0x1b => { unimplemented!() },
        0x1c => { unimplemented!() },
        0x1d => { unimplemented!() },
        0x1e => { unimplemented!() },
        0x1f => { unimplemented!() },
        0x20 => { unimplemented!() },
        0x21 => { unimplemented!() },
        0x22 => { unimplemented!() },
        0x23 => { unimplemented!() },
        0x24 => { unimplemented!() },
        0x25 => { unimplemented!() },
        0x26 => { unimplemented!() },
        0x27 => { unimplemented!() },
        0x28 => { unimplemented!() },
        0x29 => { unimplemented!() },
        0x2a => { unimplemented!() },
        0x2b => { unimplemented!() },
        0x2c => { unimplemented!() },
        0x2d => { unimplemented!() },
        0x2e => { unimplemented!() },
        0x2f => { unimplemented!() },
        0x30 => { unimplemented!() },
        0x31 => { ld_sp_nn(gb) },
        0x32 => { unimplemented!() },
        0x33 => { unimplemented!() },
        0x34 => { unimplemented!() },
        0x35 => { unimplemented!() },
        0x36 => { unimplemented!() },
        0x37 => { unimplemented!() },
        0x38 => { unimplemented!() },
        0x39 => { unimplemented!() },
        0x3a => { unimplemented!() },
        0x3b => { unimplemented!() },
        0x3c => { unimplemented!() },
        0x3d => { unimplemented!() },
        0x3e => { unimplemented!() },
        0x3f => { unimplemented!() },
        0x40 => { unimplemented!() },
        0x41 => { unimplemented!() },
        0x42 => { unimplemented!() },
        0x43 => { unimplemented!() },
        0x44 => { unimplemented!() },
        0x45 => { unimplemented!() },
        0x46 => { unimplemented!() },
        0x47 => { unimplemented!() },
        0x48 => { unimplemented!() },
        0x49 => { unimplemented!() },
        0x4a => { unimplemented!() },
        0x4b => { unimplemented!() },
        0x4c => { unimplemented!() },
        0x4d => { unimplemented!() },
        0x4e => { unimplemented!() },
        0x4f => { unimplemented!() },
        0x50 => { unimplemented!() },
        0x51 => { unimplemented!() },
        0x52 => { unimplemented!() },
        0x53 => { unimplemented!() },
        0x54 => { unimplemented!() },
        0x55 => { unimplemented!() },
        0x56 => { unimplemented!() },
        0x57 => { unimplemented!() },
        0x58 => { unimplemented!() },
        0x59 => { unimplemented!() },
        0x5a => { unimplemented!() },
        0x5b => { unimplemented!() },
        0x5c => { unimplemented!() },
        0x5d => { unimplemented!() },
        0x5e => { unimplemented!() },
        0x5f => { unimplemented!() },
        0x60 => { unimplemented!() },
        0x61 => { unimplemented!() },
        0x62 => { unimplemented!() },
        0x63 => { unimplemented!() },
        0x64 => { unimplemented!() },
        0x65 => { unimplemented!() },
        0x66 => { unimplemented!() },
        0x67 => { unimplemented!() },
        0x68 => { unimplemented!() },
        0x69 => { unimplemented!() },
        0x6a => { unimplemented!() },
        0x6b => { unimplemented!() },
        0x6c => { unimplemented!() },
        0x6d => { unimplemented!() },
        0x6e => { unimplemented!() },
        0x6f => { unimplemented!() },
        0x70 => { unimplemented!() },
        0x71 => { unimplemented!() },
        0x72 => { unimplemented!() },
        0x73 => { unimplemented!() },
        0x74 => { unimplemented!() },
        0x75 => { unimplemented!() },
        0x76 => { unimplemented!() },
        0x77 => { unimplemented!() },
        0x78 => { unimplemented!() },
        0x79 => { unimplemented!() },
        0x7a => { unimplemented!() },
        0x7b => { unimplemented!() },
        0x7c => { unimplemented!() },
        0x7d => { unimplemented!() },
        0x7e => { unimplemented!() },
        0x7f => { unimplemented!() },
        0x80 => { unimplemented!() },
        0x81 => { unimplemented!() },
        0x82 => { unimplemented!() },
        0x83 => { unimplemented!() },
        0x84 => { unimplemented!() },
        0x85 => { unimplemented!() },
        0x86 => { unimplemented!() },
        0x87 => { unimplemented!() },
        0x88 => { unimplemented!() },
        0x89 => { unimplemented!() },
        0x8a => { unimplemented!() },
        0x8b => { unimplemented!() },
        0x8c => { unimplemented!() },
        0x8d => { unimplemented!() },
        0x8e => { unimplemented!() },
        0x8f => { unimplemented!() },
        0x90 => { unimplemented!() },
        0x91 => { unimplemented!() },
        0x92 => { unimplemented!() },
        0x93 => { unimplemented!() },
        0x94 => { unimplemented!() },
        0x95 => { unimplemented!() },
        0x96 => { unimplemented!() },
        0x97 => { unimplemented!() },
        0x98 => { unimplemented!() },
        0x99 => { unimplemented!() },
        0x9a => { unimplemented!() },
        0x9b => { unimplemented!() },
        0x9c => { unimplemented!() },
        0x9d => { unimplemented!() },
        0x9e => { unimplemented!() },
        0x9f => { unimplemented!() },
        0xa0 => { unimplemented!() },
        0xa1 => { unimplemented!() },
        0xa2 => { unimplemented!() },
        0xa3 => { unimplemented!() },
        0xa4 => { unimplemented!() },
        0xa5 => { unimplemented!() },
        0xa6 => { unimplemented!() },
        0xa7 => { unimplemented!() },
        0xa8 => { unimplemented!() },
        0xa9 => { unimplemented!() },
        0xaa => { unimplemented!() },
        0xab => { unimplemented!() },
        0xac => { unimplemented!() },
        0xad => { unimplemented!() },
        0xae => { unimplemented!() },
        0xaf => { xor(gb, Register8::A) }
        0xb0 => { unimplemented!() },
        0xb1 => { unimplemented!() },
        0xb2 => { unimplemented!() },
        0xb3 => { unimplemented!() },
        0xb4 => { unimplemented!() },
        0xb5 => { unimplemented!() },
        0xb6 => { unimplemented!() },
        0xb7 => { unimplemented!() },
        0xb8 => { unimplemented!() },
        0xb9 => { unimplemented!() },
        0xba => { unimplemented!() },
        0xbb => { unimplemented!() },
        0xbc => { unimplemented!() },
        0xbd => { unimplemented!() },
        0xbe => { unimplemented!() },
        0xbf => { unimplemented!() },
        0xc0 => { unimplemented!() },
        0xc1 => { unimplemented!() },
        0xc2 => { unimplemented!() },
        0xc3 => { unimplemented!() },
        0xc4 => { unimplemented!() },
        0xc5 => { unimplemented!() },
        0xc6 => { unimplemented!() },
        0xc7 => { unimplemented!() },
        0xc8 => { unimplemented!() },
        0xc9 => { unimplemented!() },
        0xca => { unimplemented!() },
        0xcb => { unimplemented!() },
        0xcc => { unimplemented!() },
        0xcd => { unimplemented!() },
        0xce => { unimplemented!() },
        0xcf => { unimplemented!() },
        0xd0 => { unimplemented!() },
        0xd1 => { unimplemented!() },
        0xd2 => { unimplemented!() },
        0xd3 => { unimplemented!() },
        0xd4 => { unimplemented!() },
        0xd5 => { unimplemented!() },
        0xd6 => { unimplemented!() },
        0xd7 => { unimplemented!() },
        0xd8 => { unimplemented!() },
        0xd9 => { unimplemented!() },
        0xda => { unimplemented!() },
        0xdb => { unimplemented!() },
        0xdc => { unimplemented!() },
        0xdd => { unimplemented!() },
        0xde => { unimplemented!() },
        0xdf => { unimplemented!() },
        0xe0 => { unimplemented!() },
        0xe1 => { unimplemented!() },
        0xe2 => { unimplemented!() },
        0xe3 => { unimplemented!() },
        0xe4 => { unimplemented!() },
        0xe5 => { unimplemented!() },
        0xe6 => { unimplemented!() },
        0xe7 => { unimplemented!() },
        0xe8 => { unimplemented!() },
        0xe9 => { unimplemented!() },
        0xea => { unimplemented!() },
        0xeb => { unimplemented!() },
        0xec => { unimplemented!() },
        0xed => { unimplemented!() },
        0xee => { unimplemented!() },
        0xef => { unimplemented!() },
        0xf0 => { unimplemented!() },
        0xf1 => { unimplemented!() },
        0xf2 => { unimplemented!() },
        0xf3 => { unimplemented!() },
        0xf4 => { unimplemented!() },
        0xf5 => { unimplemented!() },
        0xf6 => { unimplemented!() },
        0xf7 => { unimplemented!() },
        0xf8 => { unimplemented!() },
        0xf9 => { unimplemented!() },
        0xfa => { unimplemented!() },
        0xfb => { unimplemented!() },
        0xfc => { unimplemented!() },
        0xfd => { unimplemented!() },
        0xfe => { unimplemented!() },
        0xff => { unimplemented!() },
        _ => {}
    }
}

fn xor(gb: &mut GameBoy, reg: Register8) {
    let mut acc = gb.cpu.get_8(Register8::A);
    acc ^= gb.cpu.get_8(reg);
    gb.cpu.set_8(Register8::A, acc);
    gb.cpu.reset_flags();
    match acc {
       0 => gb.cpu.set_flag(Flag::Z, true),
        _ => gb.cpu.set_flag(Flag::Z, false),
    }
    gb.cpu.inc_pc(1);
}

/// LD BC, nn 0x01
fn ld_bc_nn(gb: &mut GameBoy) {
    let v: u16 = gb.cartridge.read_word(gb.cpu.get_16(Register16::PC) + 1);
    gb.cpu.set_16(Register16::BC, v);
    gb.cpu.inc_pc(3);

}

/// LD (BC), a 0x02
fn ld_bcp_a(gb: &mut GameBoy) {
    gb.mem.write_byte(gb.cpu.get_16(Register16::BC), gb.cpu.get_8(Register8::A));
    gb.cpu.inc_pc(1);
}

/// INC BC, 0x03
fn inc_bc(gb: &mut GameBoy) {
    gb.cpu.inc_16(Register16::BC);
    gb.cpu.inc_pc(1);
}

/// INC B, 0x04
fn inc_b(gb: &mut GameBoy) {
    gb.cpu.inc_8(Register8::B);
    gb.cpu.inc_pc(1);
}

/// LD SP, nn 0x31
fn ld_sp_nn(gb: &mut GameBoy) {
    let v: u16 = gb.cartridge.read_word(gb.cpu.get_16(Register16::PC) + 1);
    gb.cpu.set_16(Register16::SP, v);
    gb.cpu.inc_pc(3);
}
<|endoftext|>


<commit_before>extern crate num_cpus;
extern crate pkg_config;
extern crate cmake;

use std::path::Path;
use std::process::{Command, self};
use std::io::Write;
use std::env;

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn run_command_or_fail(dir: &str, cmd: &str, args: &[&str]) {
    println_stderr!("Running command: \"{} {}\" in dir: {}", cmd, args.join(" "), dir);
    let ret = Command::new(cmd).current_dir(dir).args(args).status();
    match ret.map(|status| (status.success(), status.code())) {
        Ok((true, _)) => { return },
        Ok((false, Some(c))) => { panic!("Command failed with error code {}", c) },
        Ok((false, None)) => { panic!("Command got killed") },
        Err(e) => { panic!("Command failed with error: {}", e) },
    }
}

fn main() {
    let librdkafka_version = env!("CARGO_PKG_VERSION")
        .split('-')
        .next()
        .expect("Crate version is not valid");

    if env::var("CARGO_FEATURE_DYNAMIC_LINKING").is_ok() {
        println_stderr!("librdkafka will be linked dynamically");
        let pkg_probe = pkg_config::Config::new()
            .cargo_metadata(true)
            .atleast_version(librdkafka_version)
            .probe("rdkafka");

        match pkg_probe {
            Ok(library) => {
                println_stderr!("librdkafka found on the system:");
                println_stderr!("  Name: {:?}", library.libs);
                println_stderr!("  Path: {:?}", library.link_paths);
                println_stderr!("  Version: {}", library.version);
            }
            Err(_) => {
                println_stderr!("librdkafka {} cannot be found on the system", librdkafka_version);
                println_stderr!("Dynamic linking failed. Exiting.");
                process::exit(1);
            }
        }
    } else {
        println_stderr!("Building and linking librdkafka statically");
        build_librdkafka();
    }
}

fn build_librdkafka() {
    let mut configure_flags = Vec::new();

    if env::var("CARGO_FEATURE_SASL").is_ok() {
        configure_flags.push("--enable-sasl");
    } else {
        configure_flags.push("--disable-sasl");
    }

    if env::var("CARGO_FEATURE_SSL").is_ok() {
        configure_flags.push("--enable-ssl");
    } else {
        configure_flags.push("--disable-ssl");
    }

    if env::var("CARGO_FEATURE_EXTERNAL_LZ4").is_ok() {
        configure_flags.push("--enable-lz4");
    } else {
        configure_flags.push("--disable-lz4");
    }

    configure_flags.push("--enable-static");

    if !Path::new("librdkafka/LICENSE").exists() {
        println_stderr!("Setting up submodules");
        run_command_or_fail("../", "git", &["submodule", "update", "--init"]);
    }

    env::set_var("NUM_JOBS", num_cpus::get().to_string());
    let mut config = cmake::Config::new("librdkafka");
    config.define("RDKAFKA_BUILD_STATIC", "1")
          .build_target("rdkafka");
    if env::var("CARGO_FEATURE_SASL").is_ok() {
        config.define("WITH_SASL", "1");
    } else {
        config.define("WITH_SASL", "0");
    }
    let dst = config.build();
    println!("cargo:rustc-link-search=native={}/build/src", dst.display());
    println!("cargo:rustc-link-lib=static=rdkafka");
}
<commit_msg>Add back ssl feature<commit_after>extern crate num_cpus;
extern crate pkg_config;
extern crate cmake;

use std::path::Path;
use std::process::{Command, self};
use std::io::Write;
use std::env;

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn run_command_or_fail(dir: &str, cmd: &str, args: &[&str]) {
    println_stderr!("Running command: \"{} {}\" in dir: {}", cmd, args.join(" "), dir);
    let ret = Command::new(cmd).current_dir(dir).args(args).status();
    match ret.map(|status| (status.success(), status.code())) {
        Ok((true, _)) => { return },
        Ok((false, Some(c))) => { panic!("Command failed with error code {}", c) },
        Ok((false, None)) => { panic!("Command got killed") },
        Err(e) => { panic!("Command failed with error: {}", e) },
    }
}

fn main() {
    let librdkafka_version = env!("CARGO_PKG_VERSION")
        .split('-')
        .next()
        .expect("Crate version is not valid");

    if env::var("CARGO_FEATURE_DYNAMIC_LINKING").is_ok() {
        println_stderr!("librdkafka will be linked dynamically");
        let pkg_probe = pkg_config::Config::new()
            .cargo_metadata(true)
            .atleast_version(librdkafka_version)
            .probe("rdkafka");

        match pkg_probe {
            Ok(library) => {
                println_stderr!("librdkafka found on the system:");
                println_stderr!("  Name: {:?}", library.libs);
                println_stderr!("  Path: {:?}", library.link_paths);
                println_stderr!("  Version: {}", library.version);
            }
            Err(_) => {
                println_stderr!("librdkafka {} cannot be found on the system", librdkafka_version);
                println_stderr!("Dynamic linking failed. Exiting.");
                process::exit(1);
            }
        }
    } else {
        println_stderr!("Building and linking librdkafka statically");
        build_librdkafka();
    }
}

fn build_librdkafka() {
    let mut configure_flags = Vec::new();

    if env::var("CARGO_FEATURE_SASL").is_ok() {
        configure_flags.push("--enable-sasl");
    } else {
        configure_flags.push("--disable-sasl");
    }

    if env::var("CARGO_FEATURE_SSL").is_ok() {
        configure_flags.push("--enable-ssl");
    } else {
        configure_flags.push("--disable-ssl");
    }

    if env::var("CARGO_FEATURE_EXTERNAL_LZ4").is_ok() {
        configure_flags.push("--enable-lz4");
    } else {
        configure_flags.push("--disable-lz4");
    }

    configure_flags.push("--enable-static");

    if !Path::new("librdkafka/LICENSE").exists() {
        println_stderr!("Setting up submodules");
        run_command_or_fail("../", "git", &["submodule", "update", "--init"]);
    }

    env::set_var("NUM_JOBS", num_cpus::get().to_string());
    let mut config = cmake::Config::new("librdkafka");
    config.define("RDKAFKA_BUILD_STATIC", "1")
          .build_target("rdkafka");
    if env::var("CARGO_FEATURE_SSL").is_ok() {
        config.define("WITH_SSL", "1");
    } else {
        config.define("WITH_SSL", "0");
    }
    if env::var("CARGO_FEATURE_SASL").is_ok() {
        config.define("WITH_SASL", "1");
    } else {
        config.define("WITH_SASL", "0");
    }
    let dst = config.build();
    println!("cargo:rustc-link-search=native={}/build/src", dst.display());
    println!("cargo:rustc-link-lib=static=rdkafka");
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::fmt;
use std::num::NonZeroU64;

use log::trace;

use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol};

use crate::stacked_borrows::{AccessKind, SbTag};
use crate::*;

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort(String),
    UnsupportedInIsolation(String),
    ExperimentalUb {
        msg: String,
        url: String,
    },
    Deadlock,
    MultipleSymbolDefinitions {
        link_name: Symbol,
        first: SpanData,
        first_crate: Symbol,
        second: SpanData,
        second_crate: Symbol,
    },
    SymbolShimClashing {
        link_name: Symbol,
        span: SpanData,
    },
}

impl fmt::Display for TerminationInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use TerminationInfo::*;
        match self {
            Exit(code) => write!(f, "the evaluated program completed with exit code {}", code),
            Abort(msg) => write!(f, "{}", msg),
            UnsupportedInIsolation(msg) => write!(f, "{}", msg),
            ExperimentalUb { msg, .. } => write!(f, "{}", msg),
            Deadlock => write!(f, "the evaluated program deadlocked"),
            MultipleSymbolDefinitions { link_name, .. } =>
                write!(f, "multiple definitions of symbol `{}`", link_name),
            SymbolShimClashing { link_name, .. } =>
                write!(
                    f,
                    "found `{}` symbol definition that clashes with a built-in shim",
                    link_name
                ),
        }
    }
}

impl MachineStopType for TerminationInfo {}

/// Miri specific diagnostics
pub enum NonHaltingDiagnostic {
    CreatedPointerTag(NonZeroU64),
    /// This `Item` was popped from the borrow stack, either due to a grant of
    /// `AccessKind` to `SbTag` or a deallocation when the second argument is `None`.
    PoppedPointerTag(Item, Option<(SbTag, AccessKind)>),
    CreatedCallId(CallId),
    CreatedAlloc(AllocId),
    FreedAlloc(AllocId),
    RejectedIsolatedOp(String),
}

/// Level of Miri specific diagnostics
enum DiagLevel {
    Error,
    Warning,
    Note,
}

/// Emit a custom diagnostic without going through the miri-engine machinery
pub fn report_error<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
    e: InterpErrorInfo<'tcx>,
) -> Option<i64> {
    use InterpError::*;

    let (title, helps) = match &e.kind() {
        MachineStop(info) => {
            let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
            use TerminationInfo::*;
            let title = match info {
                Exit(code) => return Some(*code),
                Abort(_) => Some("abnormal termination"),
                UnsupportedInIsolation(_) => Some("unsupported operation"),
                ExperimentalUb { .. } => Some("Undefined Behavior"),
                Deadlock => Some("deadlock"),
                MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None,
            };
            #[rustfmt::skip]
            let helps = match info {
                UnsupportedInIsolation(_) =>
                    vec![
                        (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")),
                        (None, format!("or pass `-Zmiri-isolation-error=warn to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")),
                    ],
                ExperimentalUb { url, .. } =>
                    vec![
                        (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")),
                        (None, format!("see {} for further information", url)),
                    ],
                MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } =>
                    vec![
                        (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)),
                        (Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)),
                    ],
                SymbolShimClashing { link_name, span } =>
                    vec![(Some(*span), format!("the `{}` symbol is defined here", link_name))],
                _ => vec![],
            };
            (title, helps)
        }
        _ => {
            #[rustfmt::skip]
            let title = match e.kind() {
                Unsupported(_) =>
                    "unsupported operation",
                UndefinedBehavior(_) =>
                    "Undefined Behavior",
                ResourceExhaustion(_) =>
                    "resource exhaustion",
                InvalidProgram(InvalidProgramInfo::ReferencedConstant) =>
                    "post-monomorphization error",
                InvalidProgram(InvalidProgramInfo::AlreadyReported(_)) =>
                    "error occurred",
                kind =>
                    bug!("This error should be impossible in Miri: {:?}", kind),
            };
            #[rustfmt::skip]
            let helps = match e.kind() {
                Unsupported(UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) =>
                    panic!("Error should never be raised by Miri: {:?}", e.kind()),
                Unsupported(_) =>
                    vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))],
                UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. })
                    if ecx.memory.extra.check_alignment == AlignmentCheck::Symbolic
                =>
                    vec![
                        (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")),
                        (None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")),
                    ],
                UndefinedBehavior(_) =>
                    vec![
                        (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
                        (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
                    ],
                _ => vec![],
            };
            (Some(title), helps)
        }
    };

    let mut stacktrace = ecx.generate_stacktrace();
    let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local());
    match ecx.machine.backtrace_style {
        BacktraceStyle::Off => {
            // Retain one frame so that we can print a span for the error itself
            stacktrace.truncate(1);
        }
        BacktraceStyle::Short => {
            // Only prune frames if there is at least one local frame. This check ensures that if
            // we get a backtrace that never makes it to the user code because it has detected a
            // bug in the Rust runtime, we don't prune away every frame.
            if has_local_frame {
                // This is part of the logic that `std` uses to select the relevant part of a
                // backtrace. But here, we only look for __rust_begin_short_backtrace, not
                // __rust_end_short_backtrace because the end symbol comes from a call to the default
                // panic handler.
                stacktrace = stacktrace
                    .into_iter()
                    .take_while(|frame| {
                        let def_id = frame.instance.def_id();
                        let path = ecx.tcx.tcx.def_path_str(def_id);
                        !path.contains("__rust_begin_short_backtrace")
                    })
                    .collect::<Vec<_>>();

                // After we prune frames from the bottom, there are a few left that are part of the
                // Rust runtime. So we remove frames until we get to a local symbol, which should be
                // main or a test.
                // This len check ensures that we don't somehow remove every frame, as doing so breaks
                // the primary error message.
                while stacktrace.len() > 1
                    && stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local())
                {
                    stacktrace.pop();
                }
            }
        }
        BacktraceStyle::Full => {}
    }

    e.print_backtrace();
    let msg = e.to_string();
    report_msg(
        *ecx.tcx,
        DiagLevel::Error,
        &if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() },
        msg,
        helps,
        &stacktrace,
    );

    // Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we
    // do not include a note when backtraces are off.
    if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame {
        ecx.tcx.sess.diagnostic().note_without_error(
            "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
        );
    }

    // Debug-dump all locals.
    for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
        trace!("-------------------");
        trace!("Frame {}", i);
        trace!("    return: {:?}", frame.return_place.map(|p| *p));
        for (i, local) in frame.locals.iter().enumerate() {
            trace!("    local {}: {:?}", i, local.value);
        }
    }

    // Extra output to help debug specific issues.
    match e.kind() {
        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
            eprintln!(
                "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:",
                access.uninit_offset.bytes(),
                access.uninit_offset.bytes() + access.uninit_size.bytes(),
            );
            eprintln!("{:?}", ecx.memory.dump_alloc(*alloc_id));
        }
        _ => {}
    }

    None
}

/// Report an error or note (depending on the `error` argument) with the given stacktrace.
/// Also emits a full stacktrace of the interpreter stack.
fn report_msg<'tcx>(
    tcx: TyCtxt<'tcx>,
    diag_level: DiagLevel,
    title: &str,
    span_msg: String,
    mut helps: Vec<(Option<SpanData>, String)>,
    stacktrace: &[FrameInfo<'tcx>],
) {
    let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
    let mut err = match diag_level {
        DiagLevel::Error => tcx.sess.struct_span_err(span, title),
        DiagLevel::Warning => tcx.sess.struct_span_warn(span, title),
        DiagLevel::Note => tcx.sess.diagnostic().span_note_diag(span, title),
    };

    // Show main message.
    if span != DUMMY_SP {
        err.span_label(span, span_msg);
    } else {
        // Make sure we show the message even when it is a dummy span.
        err.note(&span_msg);
        err.note("(no span available)");
    }
    // Show help messages.
    if !helps.is_empty() {
        // Add visual separator before backtrace.
        helps.last_mut().unwrap().1.push_str("\n");
        for (span_data, help) in helps {
            if let Some(span_data) = span_data {
                err.span_help(span_data.span(), &help);
            } else {
                err.help(&help);
            }
        }
    }
    // Add backtrace
    for (idx, frame_info) in stacktrace.iter().enumerate() {
        let is_local = frame_info.instance.def_id().is_local();
        // No span for non-local frames and the first frame (which is the error site).
        if is_local && idx > 0 {
            err.span_note(frame_info.span, &frame_info.to_string());
        } else {
            err.note(&frame_info.to_string());
        }
    }

    err.emit();
}

thread_local! {
    static DIAGNOSTICS: RefCell<Vec<NonHaltingDiagnostic>> = RefCell::new(Vec::new());
}

/// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available.
/// The diagnostic will be emitted after the current interpreter step is finished.
pub fn register_diagnostic(e: NonHaltingDiagnostic) {
    DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e));
}

/// Remember enough about the topmost frame so that we can restore the stack
/// after a step was taken.
pub struct TopFrameInfo<'tcx> {
    stack_size: usize,
    instance: Option<ty::Instance<'tcx>>,
    span: Span,
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn preprocess_diagnostics(&self) -> TopFrameInfo<'tcx> {
        // Ensure we have no lingering diagnostics.
        DIAGNOSTICS.with(|diagnostics| assert!(diagnostics.borrow().is_empty()));

        let this = self.eval_context_ref();
        if this.active_thread_stack().is_empty() {
            // Diagnostics can happen even with the empty stack (e.g. deallocation of thread-local statics).
            return TopFrameInfo { stack_size: 0, instance: None, span: DUMMY_SP };
        }
        let frame = this.frame();

        TopFrameInfo {
            stack_size: this.active_thread_stack().len(),
            instance: Some(frame.instance),
            span: frame.current_span(),
        }
    }

    /// Emit all diagnostics that were registed with `register_diagnostics`
    fn process_diagnostics(&self, info: TopFrameInfo<'tcx>) {
        let this = self.eval_context_ref();
        DIAGNOSTICS.with(|diagnostics| {
            let mut diagnostics = diagnostics.borrow_mut();
            if diagnostics.is_empty() {
                return;
            }
            // We need to fix up the stack trace, because the machine has already
            // stepped to the next statement.
            let mut stacktrace = this.generate_stacktrace();
            // Remove newly pushed frames.
            while stacktrace.len() > info.stack_size {
                stacktrace.remove(0);
            }
            // Add popped frame back.
            if stacktrace.len() < info.stack_size {
                assert!(
                    stacktrace.len() == info.stack_size - 1,
                    "we should never pop more than one frame at once"
                );
                let frame_info = FrameInfo {
                    instance: info.instance.unwrap(),
                    span: info.span,
                    lint_root: None,
                };
                stacktrace.insert(0, frame_info);
            } else if let Some(instance) = info.instance {
                // Adjust topmost frame.
                stacktrace[0].span = info.span;
                assert_eq!(
                    stacktrace[0].instance, instance,
                    "we should not pop and push a frame in one step"
                );
            }

            // Show diagnostics.
            for e in diagnostics.drain(..) {
                use NonHaltingDiagnostic::*;
                let msg = match e {
                    CreatedPointerTag(tag) => format!("created tag {:?}", tag),
                    PoppedPointerTag(item, tag) =>
                        match tag {
                            None =>
                                format!(
                                    "popped tracked tag for item {:?} due to deallocation",
                                    item
                                ),
                            Some((tag, access)) => {
                                format!(
                                    "popped tracked tag for item {:?} due to {:?} access for {:?}",
                                    item, access, tag
                                )
                            }
                        },
                    CreatedCallId(id) => format!("function call with id {}", id),
                    CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id),
                    FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id),
                    RejectedIsolatedOp(ref op) =>
                        format!("{} was made to return an error due to isolation", op),
                };

                let (title, diag_level) = match e {
                    RejectedIsolatedOp(_) =>
                        ("operation rejected by isolation", DiagLevel::Warning),
                    _ => ("tracking was triggered", DiagLevel::Note),
                };

                report_msg(*this.tcx, diag_level, title, msg, vec![], &stacktrace);
            }
        });
    }
}
<commit_msg>Auto merge of #1987 - saethlin:short-backtraces, r=oli-obk<commit_after>use std::cell::RefCell;
use std::fmt;
use std::num::NonZeroU64;

use log::trace;

use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol};

use crate::stacked_borrows::{AccessKind, SbTag};
use crate::*;

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort(String),
    UnsupportedInIsolation(String),
    ExperimentalUb {
        msg: String,
        url: String,
    },
    Deadlock,
    MultipleSymbolDefinitions {
        link_name: Symbol,
        first: SpanData,
        first_crate: Symbol,
        second: SpanData,
        second_crate: Symbol,
    },
    SymbolShimClashing {
        link_name: Symbol,
        span: SpanData,
    },
}

impl fmt::Display for TerminationInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use TerminationInfo::*;
        match self {
            Exit(code) => write!(f, "the evaluated program completed with exit code {}", code),
            Abort(msg) => write!(f, "{}", msg),
            UnsupportedInIsolation(msg) => write!(f, "{}", msg),
            ExperimentalUb { msg, .. } => write!(f, "{}", msg),
            Deadlock => write!(f, "the evaluated program deadlocked"),
            MultipleSymbolDefinitions { link_name, .. } =>
                write!(f, "multiple definitions of symbol `{}`", link_name),
            SymbolShimClashing { link_name, .. } =>
                write!(
                    f,
                    "found `{}` symbol definition that clashes with a built-in shim",
                    link_name
                ),
        }
    }
}

impl MachineStopType for TerminationInfo {}

/// Miri specific diagnostics
pub enum NonHaltingDiagnostic {
    CreatedPointerTag(NonZeroU64),
    /// This `Item` was popped from the borrow stack, either due to a grant of
    /// `AccessKind` to `SbTag` or a deallocation when the second argument is `None`.
    PoppedPointerTag(Item, Option<(SbTag, AccessKind)>),
    CreatedCallId(CallId),
    CreatedAlloc(AllocId),
    FreedAlloc(AllocId),
    RejectedIsolatedOp(String),
}

/// Level of Miri specific diagnostics
enum DiagLevel {
    Error,
    Warning,
    Note,
}

fn has_local_frame(stacktrace: &[FrameInfo<'_>]) -> bool {
    stacktrace.iter().any(|frame| frame.instance.def_id().is_local())
}

fn prune_stacktrace<'mir, 'tcx>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
    mut stacktrace: Vec<FrameInfo<'tcx>>,
) -> Vec<FrameInfo<'tcx>> {
    match ecx.machine.backtrace_style {
        BacktraceStyle::Off => {
            // Retain one frame so that we can print a span for the error itself
            stacktrace.truncate(1);
        }
        BacktraceStyle::Short => {
            // Only prune frames if there is at least one local frame. This check ensures that if
            // we get a backtrace that never makes it to the user code because it has detected a
            // bug in the Rust runtime, we don't prune away every frame.
            if has_local_frame(&stacktrace) {
                // This is part of the logic that `std` uses to select the relevant part of a
                // backtrace. But here, we only look for __rust_begin_short_backtrace, not
                // __rust_end_short_backtrace because the end symbol comes from a call to the default
                // panic handler.
                stacktrace = stacktrace
                    .into_iter()
                    .take_while(|frame| {
                        let def_id = frame.instance.def_id();
                        let path = ecx.tcx.tcx.def_path_str(def_id);
                        !path.contains("__rust_begin_short_backtrace")
                    })
                    .collect::<Vec<_>>();

                // After we prune frames from the bottom, there are a few left that are part of the
                // Rust runtime. So we remove frames until we get to a local symbol, which should be
                // main or a test.
                // This len check ensures that we don't somehow remove every frame, as doing so breaks
                // the primary error message.
                while stacktrace.len() > 1
                    && stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local())
                {
                    stacktrace.pop();
                }
            }
        }
        BacktraceStyle::Full => {}
    }
    stacktrace
}

/// Emit a custom diagnostic without going through the miri-engine machinery
pub fn report_error<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
    e: InterpErrorInfo<'tcx>,
) -> Option<i64> {
    use InterpError::*;

    let (title, helps) = match &e.kind() {
        MachineStop(info) => {
            let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
            use TerminationInfo::*;
            let title = match info {
                Exit(code) => return Some(*code),
                Abort(_) => Some("abnormal termination"),
                UnsupportedInIsolation(_) => Some("unsupported operation"),
                ExperimentalUb { .. } => Some("Undefined Behavior"),
                Deadlock => Some("deadlock"),
                MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None,
            };
            #[rustfmt::skip]
            let helps = match info {
                UnsupportedInIsolation(_) =>
                    vec![
                        (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")),
                        (None, format!("or pass `-Zmiri-isolation-error=warn to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")),
                    ],
                ExperimentalUb { url, .. } =>
                    vec![
                        (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")),
                        (None, format!("see {} for further information", url)),
                    ],
                MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } =>
                    vec![
                        (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)),
                        (Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)),
                    ],
                SymbolShimClashing { link_name, span } =>
                    vec![(Some(*span), format!("the `{}` symbol is defined here", link_name))],
                _ => vec![],
            };
            (title, helps)
        }
        _ => {
            #[rustfmt::skip]
            let title = match e.kind() {
                Unsupported(_) =>
                    "unsupported operation",
                UndefinedBehavior(_) =>
                    "Undefined Behavior",
                ResourceExhaustion(_) =>
                    "resource exhaustion",
                InvalidProgram(InvalidProgramInfo::ReferencedConstant) =>
                    "post-monomorphization error",
                InvalidProgram(InvalidProgramInfo::AlreadyReported(_)) =>
                    "error occurred",
                kind =>
                    bug!("This error should be impossible in Miri: {:?}", kind),
            };
            #[rustfmt::skip]
            let helps = match e.kind() {
                Unsupported(UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) =>
                    panic!("Error should never be raised by Miri: {:?}", e.kind()),
                Unsupported(_) =>
                    vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))],
                UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. })
                    if ecx.memory.extra.check_alignment == AlignmentCheck::Symbolic
                =>
                    vec![
                        (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")),
                        (None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")),
                    ],
                UndefinedBehavior(_) =>
                    vec![
                        (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
                        (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
                    ],
                _ => vec![],
            };
            (Some(title), helps)
        }
    };

    let stacktrace = ecx.generate_stacktrace();
    let stacktrace = prune_stacktrace(ecx, stacktrace);
    e.print_backtrace();
    let msg = e.to_string();
    report_msg(
        *ecx.tcx,
        DiagLevel::Error,
        &if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() },
        msg,
        helps,
        &stacktrace,
    );

    // Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we
    // do not include a note when backtraces are off.
    if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame(&stacktrace) {
        ecx.tcx.sess.diagnostic().note_without_error(
            "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
        );
    }

    // Debug-dump all locals.
    for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
        trace!("-------------------");
        trace!("Frame {}", i);
        trace!("    return: {:?}", frame.return_place.map(|p| *p));
        for (i, local) in frame.locals.iter().enumerate() {
            trace!("    local {}: {:?}", i, local.value);
        }
    }

    // Extra output to help debug specific issues.
    match e.kind() {
        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
            eprintln!(
                "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:",
                access.uninit_offset.bytes(),
                access.uninit_offset.bytes() + access.uninit_size.bytes(),
            );
            eprintln!("{:?}", ecx.memory.dump_alloc(*alloc_id));
        }
        _ => {}
    }

    None
}

/// Report an error or note (depending on the `error` argument) with the given stacktrace.
/// Also emits a full stacktrace of the interpreter stack.
fn report_msg<'tcx>(
    tcx: TyCtxt<'tcx>,
    diag_level: DiagLevel,
    title: &str,
    span_msg: String,
    mut helps: Vec<(Option<SpanData>, String)>,
    stacktrace: &[FrameInfo<'tcx>],
) {
    let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
    let mut err = match diag_level {
        DiagLevel::Error => tcx.sess.struct_span_err(span, title),
        DiagLevel::Warning => tcx.sess.struct_span_warn(span, title),
        DiagLevel::Note => tcx.sess.diagnostic().span_note_diag(span, title),
    };

    // Show main message.
    if span != DUMMY_SP {
        err.span_label(span, span_msg);
    } else {
        // Make sure we show the message even when it is a dummy span.
        err.note(&span_msg);
        err.note("(no span available)");
    }
    // Show help messages.
    if !helps.is_empty() {
        // Add visual separator before backtrace.
        helps.last_mut().unwrap().1.push_str("\n");
        for (span_data, help) in helps {
            if let Some(span_data) = span_data {
                err.span_help(span_data.span(), &help);
            } else {
                err.help(&help);
            }
        }
    }
    // Add backtrace
    for (idx, frame_info) in stacktrace.iter().enumerate() {
        let is_local = frame_info.instance.def_id().is_local();
        // No span for non-local frames and the first frame (which is the error site).
        if is_local && idx > 0 {
            err.span_note(frame_info.span, &frame_info.to_string());
        } else {
            err.note(&frame_info.to_string());
        }
    }

    err.emit();
}

thread_local! {
    static DIAGNOSTICS: RefCell<Vec<NonHaltingDiagnostic>> = RefCell::new(Vec::new());
}

/// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available.
/// The diagnostic will be emitted after the current interpreter step is finished.
pub fn register_diagnostic(e: NonHaltingDiagnostic) {
    DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e));
}

/// Remember enough about the topmost frame so that we can restore the stack
/// after a step was taken.
pub struct TopFrameInfo<'tcx> {
    stack_size: usize,
    instance: Option<ty::Instance<'tcx>>,
    span: Span,
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn preprocess_diagnostics(&self) -> TopFrameInfo<'tcx> {
        // Ensure we have no lingering diagnostics.
        DIAGNOSTICS.with(|diagnostics| assert!(diagnostics.borrow().is_empty()));

        let this = self.eval_context_ref();
        if this.active_thread_stack().is_empty() {
            // Diagnostics can happen even with the empty stack (e.g. deallocation of thread-local statics).
            return TopFrameInfo { stack_size: 0, instance: None, span: DUMMY_SP };
        }
        let frame = this.frame();

        TopFrameInfo {
            stack_size: this.active_thread_stack().len(),
            instance: Some(frame.instance),
            span: frame.current_span(),
        }
    }

    /// Emit all diagnostics that were registed with `register_diagnostics`
    fn process_diagnostics(&self, info: TopFrameInfo<'tcx>) {
        let this = self.eval_context_ref();
        DIAGNOSTICS.with(|diagnostics| {
            let mut diagnostics = diagnostics.borrow_mut();
            if diagnostics.is_empty() {
                return;
            }
            // We need to fix up the stack trace, because the machine has already
            // stepped to the next statement.
            let mut stacktrace = this.generate_stacktrace();
            // Remove newly pushed frames.
            while stacktrace.len() > info.stack_size {
                stacktrace.remove(0);
            }
            // Add popped frame back.
            if stacktrace.len() < info.stack_size {
                assert!(
                    stacktrace.len() == info.stack_size - 1,
                    "we should never pop more than one frame at once"
                );
                let frame_info = FrameInfo {
                    instance: info.instance.unwrap(),
                    span: info.span,
                    lint_root: None,
                };
                stacktrace.insert(0, frame_info);
            } else if let Some(instance) = info.instance {
                // Adjust topmost frame.
                stacktrace[0].span = info.span;
                assert_eq!(
                    stacktrace[0].instance, instance,
                    "we should not pop and push a frame in one step"
                );
            }

            let stacktrace = prune_stacktrace(this, stacktrace);

            // Show diagnostics.
            for e in diagnostics.drain(..) {
                use NonHaltingDiagnostic::*;
                let msg = match e {
                    CreatedPointerTag(tag) => format!("created tag {:?}", tag),
                    PoppedPointerTag(item, tag) =>
                        match tag {
                            None =>
                                format!(
                                    "popped tracked tag for item {:?} due to deallocation",
                                    item
                                ),
                            Some((tag, access)) => {
                                format!(
                                    "popped tracked tag for item {:?} due to {:?} access for {:?}",
                                    item, access, tag
                                )
                            }
                        },
                    CreatedCallId(id) => format!("function call with id {}", id),
                    CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id),
                    FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id),
                    RejectedIsolatedOp(ref op) =>
                        format!("{} was made to return an error due to isolation", op),
                };

                let (title, diag_level) = match e {
                    RejectedIsolatedOp(_) =>
                        ("operation rejected by isolation", DiagLevel::Warning),
                    _ => ("tracking was triggered", DiagLevel::Note),
                };

                report_msg(*this.tcx, diag_level, title, msg, vec![], &stacktrace);
            }
        });
    }
}
<|endoftext|>