<commit_before>/// Trait for data that can be linearly interpolated using type T.
pub trait Interpolate<T> {
    fn interpolate(&self, other: &Self, a: T, b: T) -> Self;
}

impl Interpolate<f64> for f64 {
    #[inline]
    fn interpolate(&self, other: &Self, a: f64, b: f64) -> Self {
        let x = a / (a - b);
        (1. - x) * *self + x * *other
    }
}

impl Interpolate<f64> for [f64; 3] {
    #[inline]
    fn interpolate(&self, other: &Self, a: f64, b: f64) -> Self {
        let x = a / (a - b);
        let v = self;
        let w = other;
        [(1. - x) * v[0] + x * w[0], (1. - x) * v[1] + x * w[1], (1. - x) * v[2] + x * w[2]]
    }
}

impl<T> Interpolate<T> for () {
    fn interpolate(&self, _other: &Self, _a: T, _b: T) -> Self {
        ()
    }
}

impl<T, U, V> Interpolate<T> for (U, V)
    where T: Copy,
          U: Interpolate<T>,
          V: Interpolate<T>
{
    fn interpolate(&self, other: &Self, a: T, b: T) -> Self {
        (self.0.interpolate(&other.0, a, b), self.1.interpolate(&other.1, a, b))
    }
}

/// Find the intersection of the zero level set of a linear function with a tetrahedron.
///
/// The level set is given by its values `u` at vertices `v`. The resulting intersection is added
/// to `verts` (vertex buffer) and `faces` (index buffer into the vertex buffer).
fn tetrahedron<T, FV, FF>(u: [f64; 4], v: [T; 4], mut emit_vertex: FV, mut emit_face: FF)
    where T: Interpolate<f64> + Copy,
          FV: FnMut(T),
          FF: FnMut([u32; 3])
{
    let u0 = u[0];
    let u1 = u[1];
    let u2 = u[2];
    let u3 = u[3];

    let v0 = v[0];
    let v1 = v[1];
    let v2 = v[2];
    let v3 = v[3];

    // avoid problems with level set going through an edge
    let tiny = 1e-15;

    // START GENERATED: generated by `scripts/tetrahedron_cuts.py`
    if u0 >= 0. {
        let u0 = u0 + tiny;
        if u1 >= 0. {
            let u1 = u1 + tiny;
            if u2 >= 0. {
                let u2 = u2 + tiny;
                if u3 >= 0. {
                } else {
                    emit_vertex(v3.interpolate(&v0, u3, u0));
                    emit_vertex(v3.interpolate(&v1, u3, u1));
                    emit_vertex(v3.interpolate(&v2, u3, u2));
                    emit_face([0, 1, 2]);
                }
            } else {
                if u3 >= 0. {
                    emit_vertex(v2.interpolate(&v0, u2, u0));
                    emit_vertex(v2.interpolate(&v1, u2, u1));
                    emit_vertex(v2.interpolate(&v3, u2, u3));
                    emit_face([0, 1, 2]);
                } else {
                    emit_vertex(v2.interpolate(&v0, u2, u0));
                    emit_vertex(v2.interpolate(&v1, u2, u1));
                    emit_vertex(v3.interpolate(&v0, u3, u0));
                    emit_vertex(v3.interpolate(&v1, u3, u1));
                    emit_face([0, 1, 2]);
                    emit_face([2, 1, 3]);
                }
            }
        } else {
            if u2 >= 0. {
                let u2 = u2 + tiny;
                if u3 >= 0. {
                    emit_vertex(v1.interpolate(&v0, u1, u0));
                    emit_vertex(v1.interpolate(&v2, u1, u2));
                    emit_vertex(v1.interpolate(&v3, u1, u3));
                    emit_face([0, 1, 2]);
                } else {
                    emit_vertex(v1.interpolate(&v0, u1, u0));
                    emit_vertex(v1.interpolate(&v2, u1, u2));
                    emit_vertex(v3.interpolate(&v0, u3, u0));
                    emit_vertex(v3.interpolate(&v2, u3, u2));
                    emit_face([0, 1, 2]);
                    emit_face([2, 1, 3]);
                }
            } else {
                if u3 >= 0. {
                    emit_vertex(v1.interpolate(&v0, u1, u0));
                    emit_vertex(v1.interpolate(&v3, u1, u3));
                    emit_vertex(v2.interpolate(&v0, u2, u0));
                    emit_vertex(v2.interpolate(&v3, u2, u3));
                    emit_face([0, 1, 2]);
                    emit_face([2, 1, 3]);
                } else {
                    emit_vertex(v1.interpolate(&v0, u1, u0));
                    emit_vertex(v2.interpolate(&v0, u2, u0));
                    emit_vertex(v3.interpolate(&v0, u3, u0));
                    emit_face([0, 1, 2]);
                }
            }
        }
    } else {
        if u1 >= 0. {
            let u1 = u1 + tiny;
            if u2 >= 0. {
                let u2 = u2 + tiny;
                if u3 >= 0. {
                    emit_vertex(v0.interpolate(&v1, u0, u1));
                    emit_vertex(v0.interpolate(&v2, u0, u2));
                    emit_vertex(v0.interpolate(&v3, u0, u3));
                    emit_face([0, 1, 2]);
                } else {
                    emit_vertex(v0.interpolate(&v1, u0, u1));
                    emit_vertex(v0.interpolate(&v2, u0, u2));
                    emit_vertex(v3.interpolate(&v1, u3, u1));
                    emit_vertex(v3.interpolate(&v2, u3, u2));
                    emit_face([0, 1, 2]);
                    emit_face([2, 1, 3]);
                }
            } else {
                if u3 >= 0. {
                    emit_vertex(v0.interpolate(&v1, u0, u1));
                    emit_vertex(v0.interpolate(&v3, u0, u3));
                    emit_vertex(v2.interpolate(&v1, u2, u1));
                    emit_vertex(v2.interpolate(&v3, u2, u3));
                    emit_face([0, 1, 2]);
                    emit_face([2, 1, 3]);
                } else {
                    emit_vertex(v0.interpolate(&v1, u0, u1));
                    emit_vertex(v2.interpolate(&v1, u2, u1));
                    emit_vertex(v3.interpolate(&v1, u3, u1));
                    emit_face([0, 1, 2]);
                }
            }
        } else {
            if u2 >= 0. {
                let u2 = u2 + tiny;
                if u3 >= 0. {
                    emit_vertex(v0.interpolate(&v2, u0, u2));
                    emit_vertex(v0.interpolate(&v3, u0, u3));
                    emit_vertex(v1.interpolate(&v2, u1, u2));
                    emit_vertex(v1.interpolate(&v3, u1, u3));
                    emit_face([0, 1, 2]);
                    emit_face([2, 1, 3]);
                } else {
                    emit_vertex(v0.interpolate(&v2, u0, u2));
                    emit_vertex(v1.interpolate(&v2, u1, u2));
                    emit_vertex(v3.interpolate(&v2, u3, u2));
                    emit_face([0, 1, 2]);
                }
            } else {
                if u3 >= 0. {
                    emit_vertex(v0.interpolate(&v3, u0, u3));
                    emit_vertex(v1.interpolate(&v3, u1, u3));
                    emit_vertex(v2.interpolate(&v3, u2, u3));
                    emit_face([0, 1, 2]);
                } else {
                }
            }
        }
    }
    // END GENERATED

}

/// Finds the isosurface at `level` of a function given by its values `u` on a regular grid  using
/// the marching tetrahedra algorithm.
///
/// `dim` is the dimension of the array `u` assumed to be in _row-major order_ (C order).
///
/// Returns vertices, faces and normals of the generated triangular mesh.
pub fn marching_tetrahedra(u: &[f64],
                           dim: (usize, usize, usize),
                           level: f64)
                           -> (Vec<[f64; 3]>, Vec<[u32; 3]>, Vec<[f64; 3]>) {

    let (verts, faces, normals, _) =
        marching_tetrahedra_with_data(u, dim, level, &vec![(); u.len()]);

    (verts, faces, normals)
}

/// As `marching_tetrahedra`, but also linearly interpolates the provided data for each vertex.
pub fn marching_tetrahedra_with_data<T>(u: &[f64],
                                        dim: (usize, usize, usize),
                                        level: f64,
                                        data: &[T])
                                        -> (Vec<[f64; 3]>, Vec<[u32; 3]>, Vec<[f64; 3]>, Vec<T>)
    where T: Interpolate<f64> + Default + Copy
{

    let (ni, nj, nk) = dim;
    assert_eq!(ni * nj * nk, u.len());

    let mut verts: Vec<[f64; 3]> = Vec::new();
    let mut normals: Vec<[f64; 3]> = Vec::new();
    let mut faces: Vec<[u32; 3]> = Vec::new();
    let mut interp_data: Vec<T> = Vec::new();

    // permutations of [0, 1, 2]
    let perms = [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]];

    // inverse permutation (index where the element goes)
    let inv_perms = {
        let mut inv_perms = [[0; 3]; 6];
        for i in 0..6 {
            for j in 0..3 {
                inv_perms[i][perms[i][j]] = j;
            }
        }
        inv_perms
    };

    let strides = [nj * nk, nk, 1];

    for i in 1..ni {
        for j in 1..nj {
            for k in 1..nk {
                // split each cube into 6 tetrahedra, emit triangles
                // vertex position
                let s = (i - 1) * nj * nk + (j - 1) * nk + (k - 1);
                let ps = [(i - 1) as f64, (j - 1) as f64, (k - 1) as f64];

                for (perm, inv_perm) in perms.iter().zip(inv_perms.iter()) {
                    // find tetrahedron data by walking along the edges of a cube
                    // in the order given by the permutation
                    let (us, vs) = {
                        let mut us = [0.; 4];
                        let mut vs = [([0.; 3], T::default()); 4];
                        let mut vi = s;
                        let mut vp = ps;
                        us[0] = u[vi] - level;
                        vs[0] = (vp, data[vi]);
                        for m in 0..3 {
                            let t = perm[m];
                            vi += strides[t];
                            vp[t] += 1.;
                            us[m + 1] = u[vi] - level;
                            vs[m + 1] = (vp, data[vi]);
                        }
                        (us, vs)
                    };

                    let cur = verts.len() as u32;
                    tetrahedron(us,
                                vs,
                                |(v, d)| {
                                    verts.push(v);
                                    interp_data.push(d);
                                },
                                |f| {
                                    faces.push([f[0] + cur, f[1] + cur, f[2] + cur]);
                                });

                    // normals
                    let n = [us[1] - us[0], us[2] - us[1], us[3] - us[2]];
                    let n = [n[inv_perm[0]], n[inv_perm[1]], n[inv_perm[2]]];

                    for _ in 0..verts.len() - normals.len() {
                        normals.push(n);
                    }
                }
            }
        }
    }

    (verts, faces, normals, interp_data)
}
<commit_msg>Skip boring cubes in matching tetrahedra more efficiently<commit_after>/// Trait for data that can be linearly interpolated using type T.
pub trait Interpolate<T> {
    fn interpolate(&self, other: &Self, a: T, b: T) -> Self;
}

impl Interpolate<f64> for f64 {
    #[inline]
    fn interpolate(&self, other: &Self, a: f64, b: f64) -> Self {
        let x = a / (a - b);
        (1. - x) * *self + x * *other
    }
}

impl Interpolate<f64> for [f64; 3] {
    #[inline]
    fn interpolate(&self, other: &Self, a: f64, b: f64) -> Self {
        let x = a / (a - b);
        let v = self;
        let w = other;
        [(1. - x) * v[0] + x * w[0], (1. - x) * v[1] + x * w[1], (1. - x) * v[2] + x * w[2]]
    }
}

impl<T> Interpolate<T> for () {
    fn interpolate(&self, _other: &Self, _a: T, _b: T) -> Self {
        ()
    }
}

impl<T, U, V> Interpolate<T> for (U, V)
    where T: Copy,
          U: Interpolate<T>,
          V: Interpolate<T>
{
    fn interpolate(&self, other: &Self, a: T, b: T) -> Self {
        (self.0.interpolate(&other.0, a, b), self.1.interpolate(&other.1, a, b))
    }
}

/// Find the intersection of the zero level set of a linear function with a tetrahedron.
///
/// The level set is given by its values `u` at vertices `v`. The resulting intersection is added
/// to `verts` (vertex buffer) and `faces` (index buffer into the vertex buffer).
fn tetrahedron<T, FV, FF>(u: [f64; 4], v: [T; 4], mut emit_vertex: FV, mut emit_face: FF)
    where T: Interpolate<f64> + Copy,
          FV: FnMut(T),
          FF: FnMut([u32; 3])
{
    let u0 = u[0];
    let u1 = u[1];
    let u2 = u[2];
    let u3 = u[3];

    let v0 = v[0];
    let v1 = v[1];
    let v2 = v[2];
    let v3 = v[3];

    // avoid problems with level set going through an edge
    let tiny = 1e-15;

    // START GENERATED: generated by `scripts/tetrahedron_cuts.py`
    if u0 >= 0. {
        let u0 = u0 + tiny;
        if u1 >= 0. {
            let u1 = u1 + tiny;
            if u2 >= 0. {
                let u2 = u2 + tiny;
                if u3 >= 0. {
                } else {
                    emit_vertex(v3.interpolate(&v0, u3, u0));
                    emit_vertex(v3.interpolate(&v1, u3, u1));
                    emit_vertex(v3.interpolate(&v2, u3, u2));
                    emit_face([0, 1, 2]);
                }
            } else {
                if u3 >= 0. {
                    emit_vertex(v2.interpolate(&v0, u2, u0));
                    emit_vertex(v2.interpolate(&v1, u2, u1));
                    emit_vertex(v2.interpolate(&v3, u2, u3));
                    emit_face([0, 1, 2]);
                } else {
                    emit_vertex(v2.interpolate(&v0, u2, u0));
                    emit_vertex(v2.interpolate(&v1, u2, u1));
                    emit_vertex(v3.interpolate(&v0, u3, u0));
                    emit_vertex(v3.interpolate(&v1, u3, u1));
                    emit_face([0, 1, 2]);
                    emit_face([2, 1, 3]);
                }
            }
        } else {
            if u2 >= 0. {
                let u2 = u2 + tiny;
                if u3 >= 0. {
                    emit_vertex(v1.interpolate(&v0, u1, u0));
                    emit_vertex(v1.interpolate(&v2, u1, u2));
                    emit_vertex(v1.interpolate(&v3, u1, u3));
                    emit_face([0, 1, 2]);
                } else {
                    emit_vertex(v1.interpolate(&v0, u1, u0));
                    emit_vertex(v1.interpolate(&v2, u1, u2));
                    emit_vertex(v3.interpolate(&v0, u3, u0));
                    emit_vertex(v3.interpolate(&v2, u3, u2));
                    emit_face([0, 1, 2]);
                    emit_face([2, 1, 3]);
                }
            } else {
                if u3 >= 0. {
                    emit_vertex(v1.interpolate(&v0, u1, u0));
                    emit_vertex(v1.interpolate(&v3, u1, u3));
                    emit_vertex(v2.interpolate(&v0, u2, u0));
                    emit_vertex(v2.interpolate(&v3, u2, u3));
                    emit_face([0, 1, 2]);
                    emit_face([2, 1, 3]);
                } else {
                    emit_vertex(v1.interpolate(&v0, u1, u0));
                    emit_vertex(v2.interpolate(&v0, u2, u0));
                    emit_vertex(v3.interpolate(&v0, u3, u0));
                    emit_face([0, 1, 2]);
                }
            }
        }
    } else {
        if u1 >= 0. {
            let u1 = u1 + tiny;
            if u2 >= 0. {
                let u2 = u2 + tiny;
                if u3 >= 0. {
                    emit_vertex(v0.interpolate(&v1, u0, u1));
                    emit_vertex(v0.interpolate(&v2, u0, u2));
                    emit_vertex(v0.interpolate(&v3, u0, u3));
                    emit_face([0, 1, 2]);
                } else {
                    emit_vertex(v0.interpolate(&v1, u0, u1));
                    emit_vertex(v0.interpolate(&v2, u0, u2));
                    emit_vertex(v3.interpolate(&v1, u3, u1));
                    emit_vertex(v3.interpolate(&v2, u3, u2));
                    emit_face([0, 1, 2]);
                    emit_face([2, 1, 3]);
                }
            } else {
                if u3 >= 0. {
                    emit_vertex(v0.interpolate(&v1, u0, u1));
                    emit_vertex(v0.interpolate(&v3, u0, u3));
                    emit_vertex(v2.interpolate(&v1, u2, u1));
                    emit_vertex(v2.interpolate(&v3, u2, u3));
                    emit_face([0, 1, 2]);
                    emit_face([2, 1, 3]);
                } else {
                    emit_vertex(v0.interpolate(&v1, u0, u1));
                    emit_vertex(v2.interpolate(&v1, u2, u1));
                    emit_vertex(v3.interpolate(&v1, u3, u1));
                    emit_face([0, 1, 2]);
                }
            }
        } else {
            if u2 >= 0. {
                let u2 = u2 + tiny;
                if u3 >= 0. {
                    emit_vertex(v0.interpolate(&v2, u0, u2));
                    emit_vertex(v0.interpolate(&v3, u0, u3));
                    emit_vertex(v1.interpolate(&v2, u1, u2));
                    emit_vertex(v1.interpolate(&v3, u1, u3));
                    emit_face([0, 1, 2]);
                    emit_face([2, 1, 3]);
                } else {
                    emit_vertex(v0.interpolate(&v2, u0, u2));
                    emit_vertex(v1.interpolate(&v2, u1, u2));
                    emit_vertex(v3.interpolate(&v2, u3, u2));
                    emit_face([0, 1, 2]);
                }
            } else {
                if u3 >= 0. {
                    emit_vertex(v0.interpolate(&v3, u0, u3));
                    emit_vertex(v1.interpolate(&v3, u1, u3));
                    emit_vertex(v2.interpolate(&v3, u2, u3));
                    emit_face([0, 1, 2]);
                } else {
                }
            }
        }
    }
    // END GENERATED

}

/// Finds the isosurface at `level` of a function given by its values `u` on a regular grid  using
/// the marching tetrahedra algorithm.
///
/// `dim` is the dimension of the array `u` assumed to be in _row-major order_ (C order).
///
/// Returns vertices, faces and normals of the generated triangular mesh.
pub fn marching_tetrahedra(u: &[f64],
                           dim: (usize, usize, usize),
                           level: f64)
                           -> (Vec<[f64; 3]>, Vec<[u32; 3]>, Vec<[f64; 3]>) {

    let (verts, faces, normals, _) =
        marching_tetrahedra_with_data(u, dim, level, &vec![(); u.len()]);

    (verts, faces, normals)
}

/// As `marching_tetrahedra`, but also linearly interpolates the provided data for each vertex.
pub fn marching_tetrahedra_with_data<T>(u: &[f64],
                                        dim: (usize, usize, usize),
                                        level: f64,
                                        data: &[T])
                                        -> (Vec<[f64; 3]>, Vec<[u32; 3]>, Vec<[f64; 3]>, Vec<T>)
    where T: Interpolate<f64> + Default + Copy
{

    let (ni, nj, nk) = dim;
    assert_eq!(ni * nj * nk, u.len());

    let mut verts: Vec<[f64; 3]> = Vec::new();
    let mut normals: Vec<[f64; 3]> = Vec::new();
    let mut faces: Vec<[u32; 3]> = Vec::new();
    let mut interp_data: Vec<T> = Vec::new();

    // permutations of [0, 1, 2]
    let perms = [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]];

    // inverse permutation (index where the element goes)
    let inv_perms = {
        let mut inv_perms = [[0; 3]; 6];
        for i in 0..6 {
            for j in 0..3 {
                inv_perms[i][perms[i][j]] = j;
            }
        }
        inv_perms
    };

    let strides = [nj * nk, nk, 1];

    let vert_offsets = {
        let mut vert_offsets = [0; 8];

        let mut c = 0;
        for i in 0..2 {
            for j in 0..2 {
                for k in 0..2 {
                    vert_offsets[c] = i * nj * nk + j * nk + k;
                    c += 1;
                }
            }
        }
        vert_offsets
    };

    for i in 1..ni {
        for j in 1..nj {
            for k in 1..nk {
                // split each cube into 6 tetrahedra, emit triangles
                // vertex position
                let s = (i - 1) * nj * nk + (j - 1) * nk + (k - 1);
                let ps = [(i - 1) as f64, (j - 1) as f64, (k - 1) as f64];

                let n_above = vert_offsets.iter().filter(|&offset| u[s + offset] >= level).count();

                if n_above == 0 || n_above == 8 {
                    continue;
                }

                for (perm, inv_perm) in perms.iter().zip(inv_perms.iter()) {
                    // find tetrahedron data by walking along the edges of a cube
                    // in the order given by the permutation
                    let (us, vs) = {
                        let mut us = [0.; 4];
                        let mut vs = [([0.; 3], T::default()); 4];
                        let mut vi = s;
                        let mut vp = ps;
                        us[0] = u[vi] - level;
                        vs[0] = (vp, data[vi]);
                        for m in 0..3 {
                            let t = perm[m];
                            vi += strides[t];
                            vp[t] += 1.;
                            us[m + 1] = u[vi] - level;
                            vs[m + 1] = (vp, data[vi]);
                        }
                        (us, vs)
                    };

                    let cur = verts.len() as u32;
                    tetrahedron(us,
                                vs,
                                |(v, d)| {
                                    verts.push(v);
                                    interp_data.push(d);
                                },
                                |f| {
                                    faces.push([f[0] + cur, f[1] + cur, f[2] + cur]);
                                });

                    // normals
                    let n = [us[1] - us[0], us[2] - us[1], us[3] - us[2]];
                    let n = [n[inv_perm[0]], n[inv_perm[1]], n[inv_perm[2]]];

                    for _ in 0..verts.len() - normals.len() {
                        normals.push(n);
                    }
                }
            }
        }
    }

    (verts, faces, normals, interp_data)
}
<|endoftext|>


<commit_before>use std::ops::{BitAnd, BitOr, BitAndAssign, BitOrAssign, Not};

mod field_shape;
mod dictionary;
mod field;
mod generator;
mod evaluator;

const MAX_VAL: i32 = 9;
const MAX_SUM: i32 = MAX_VAL * (MAX_VAL + 1) / 2;
const UNDECIDED: i32 = -1;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Cand(u32);
const CAND_ALL: Cand = Cand((1 << MAX_VAL) - 1);

impl Cand {
    fn singleton(n: i32) -> Cand {
        Cand(1u32 << (n - 1))
    }
    fn is_set(&self, n: i32) -> bool {
        (self.0 & (1u32 << (n - 1))) != 0
    }
    fn is_empty(&self) -> bool {
        self.0 == 0u32
    }
    fn count_set_cands(&self) -> i32 {
        self.0.count_ones() as i32
    }
    fn smallest_set_cand(&self) -> i32 {
        (self.0.trailing_zeros() + 1) as i32
    }
    fn largest_set_cand(&self) -> i32 {
        (32 - self.0.leading_zeros()) as i32
    }
    fn exclude(&self, n: i32) -> Cand {
        Cand(self.0 & !(1u32 << (n - 1)))
    }
    fn limit_upper_bound(&self, max: i32) -> Cand {
        if max >= MAX_VAL {
            *self
        } else if max >= 1 {
            Cand(self.0 & ((1u32 << max) - 1))
        } else {
            Cand(0)
        }
    }
    fn limit_lower_bound(&self, min: i32) -> Cand {
        if min <= 1 {
            *self
        } else if min <= MAX_VAL {
            Cand(self.0 & !((1u32 << (min - 1)) - 1))
        } else {
            Cand(0)
        }
    }
}
impl BitAnd for Cand {
    type Output = Cand;
    fn bitand(self, rhs: Cand) -> Cand {
        Cand(self.0 & rhs.0)
    }
}
impl BitOr for Cand {
    type Output = Cand;
    fn bitor(self, rhs: Cand) -> Cand {
        Cand(self.0 | rhs.0)
    }
}
impl BitAndAssign for Cand {
    fn bitand_assign(&mut self, rhs: Cand) {
        *self = Cand(self.0 & rhs.0);
    }
}
impl BitOrAssign for Cand {
    fn bitor_assign(&mut self, rhs: Cand) {
        *self = Cand(self.0 | rhs.0);
    }
}
impl Not for Cand {
    type Output = Cand;
    fn not(self) -> Cand {
        Cand(CAND_ALL.0 ^ self.0)
    }
}

#[derive(Clone, Copy)]
pub enum Clue {
    NoClue,
    Clue { horizontal: i32, vertical: i32 },
}

#[derive(Clone, Copy)]
pub struct FieldTechnique {
    dictionary: bool,
    unique_position: bool,
    two_cells_propagation: bool,
    naked_pair: bool,
    min_max: bool,
}

impl FieldTechnique {
    fn new() -> FieldTechnique {
        FieldTechnique {
            dictionary: true,
            unique_position: true,
            two_cells_propagation: true,
            naked_pair: true,
            min_max: true,
        }
    }
}
pub use self::field_shape::*;
pub use self::dictionary::Dictionary;
pub use self::field::*;
pub use self::generator::*;
pub use self::evaluator::*;

use super::{Grid, Coord};
pub fn answer_to_problem(ans: &Grid<i32>) -> Grid<Clue> {
    let mut has_clue = Grid::new(ans.height(), ans.width(), false);
    for y in 0..ans.height() {
        for x in 0..ans.width() {
            let loc = Coord { y: y, x: x };
            has_clue[loc] = !(1 <= ans[loc] && ans[loc] <= MAX_VAL);
        }
    }
    let shape = FieldShape::new(&has_clue);
    let mut prob_base = Grid::new(ans.height(), ans.width(), (0, 0));
    for y in 0..ans.height() {
        for x in 0..ans.width() {
            let val = ans[Coord { y: y, x: x }];
            if !(1 <= val && val <= MAX_VAL) { continue; }

            let (g1, g2) = shape.cell_to_groups[Coord { y: y, x: x }];
            match shape.clue_locations[g1 as usize] {
                ClueLocation::Horizontal(h) => prob_base[h as usize].0 += val,
                ClueLocation::Vertical(v) => prob_base[v as usize].1 += val,
            }
            match shape.clue_locations[g2 as usize] {
                ClueLocation::Horizontal(h) => prob_base[h as usize].0 += val,
                ClueLocation::Vertical(v) => prob_base[v as usize].1 += val,
            }
        }
    }
    let mut ret = Grid::new(ans.height(), ans.width(), Clue::NoClue);
    for y in 0..ans.height() {
        for x in 0..ans.width() {
            let loc = Coord { y: y, x: x };
            let v = ans[loc];
            if (1 <= v && v <= MAX_VAL) { continue; }
            ret[loc] = Clue::Clue { horizontal: prob_base[loc].0, vertical: prob_base[loc].1 };
        }
    }
    ret
}

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

    #[test]
    fn test_cand() {
        assert_eq!(Cand::singleton(1), Cand(0b1));
        assert_eq!(Cand::singleton(2), Cand(0b10));

        assert_eq!(Cand(0b101).is_set(1), true);
        assert_eq!(Cand(0b101).is_set(2), false);
        assert_eq!(Cand(0b101).is_set(3), true);

        assert_eq!(Cand(0b0).is_empty(), true);
        assert_eq!(Cand(0b1).is_empty(), false);

        assert_eq!(Cand(0b10000).count_set_cands(), 1);
        assert_eq!(Cand(0b101101).count_set_cands(), 4);

        assert_eq!(Cand(0b10100).smallest_set_cand(), 3);
        assert_eq!(Cand(0b10110).smallest_set_cand(), 2);
        assert_eq!(Cand(0b10000).smallest_set_cand(), 5);

        assert_eq!(Cand(0b1100).largest_set_cand(), 4);
        assert_eq!(Cand(0b10110).largest_set_cand(), 5);
        assert_eq!(Cand(0b10000).largest_set_cand(), 5);

        assert_eq!(Cand(0b11010).exclude(2), Cand(0b11000));
        assert_eq!(Cand(0b11010).exclude(3), Cand(0b11010));

        assert_eq!(Cand(0b11010).limit_upper_bound(5), Cand(0b11010));
        assert_eq!(Cand(0b11010).limit_upper_bound(4), Cand(0b01010));
        assert_eq!(Cand(0b11010).limit_upper_bound(3), Cand(0b00010));
        assert_eq!(Cand(0b11010).limit_upper_bound(2), Cand(0b00010));
        assert_eq!(Cand(0b11010).limit_upper_bound(1), Cand(0b00000));

        assert_eq!(Cand(0b11010).limit_lower_bound(5), Cand(0b10000));
        assert_eq!(Cand(0b11010).limit_lower_bound(4), Cand(0b11000));
        assert_eq!(Cand(0b11010).limit_lower_bound(3), Cand(0b11000));
        assert_eq!(Cand(0b11010).limit_lower_bound(2), Cand(0b11010));
        assert_eq!(Cand(0b11010).limit_lower_bound(1), Cand(0b11010));
    }
}<commit_msg>Kakuro: add auxiliary functions to Cand<commit_after>use std::ops::{BitAnd, BitOr, BitAndAssign, BitOrAssign, Not};

mod field_shape;
mod dictionary;
mod field;
mod generator;
mod evaluator;

const MAX_VAL: i32 = 9;
const MAX_SUM: i32 = MAX_VAL * (MAX_VAL + 1) / 2;
const UNDECIDED: i32 = -1;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Cand(u32);
const CAND_ALL: Cand = Cand((1 << MAX_VAL) - 1);

impl Cand {
    fn singleton(n: i32) -> Cand {
        Cand(1u32 << (n - 1))
    }
    fn is_set(&self, n: i32) -> bool {
        (self.0 & (1u32 << (n - 1))) != 0
    }
    fn is_empty(&self) -> bool {
        self.0 == 0u32
    }
    fn count_set_cands(&self) -> i32 {
        self.0.count_ones() as i32
    }
    fn smallest_set_cand(&self) -> i32 {
        (self.0.trailing_zeros() + 1) as i32
    }
    fn largest_set_cand(&self) -> i32 {
        (32 - self.0.leading_zeros()) as i32
    }
    fn exclude(&self, n: i32) -> Cand {
        Cand(self.0 & !(1u32 << (n - 1)))
    }
    fn limit_upper_bound(&self, max: i32) -> Cand {
        if max >= MAX_VAL {
            *self
        } else if max >= 1 {
            Cand(self.0 & ((1u32 << max) - 1))
        } else {
            Cand(0)
        }
    }
    fn limit_lower_bound(&self, min: i32) -> Cand {
        if min <= 1 {
            *self
        } else if min <= MAX_VAL {
            Cand(self.0 & !((1u32 << (min - 1)) - 1))
        } else {
            Cand(0)
        }
    }
    fn cand_sum(&self) -> i32 {
        let mut val = *self;
        let mut ret = 0;
        while val.0 != 0 {
            let smallest = val.smallest_set_cand();
            val = val.exclude(smallest);
            ret += smallest;
        }
        ret
    }
    fn take_smallest_k(&self, k: i32) -> (Cand, Cand) {
        let mut small = Cand(0);
        let mut large = *self;
        for _ in 0..k {
            if large.0 == 0 {
                break;
            }
            let nxt = large.smallest_set_cand();
            small |= Cand::singleton(nxt);
            large = large.exclude(nxt);
        }
        (small, large)
    }
    fn take_largest_k(&self, k: i32) -> (Cand, Cand) {
        let mut small = *self;
        let mut large = Cand(0);
        for _ in 0..k {
            if small.0 == 0 {
                break;
            }
            let nxt = small.largest_set_cand();
            large |= Cand::singleton(nxt);
            small = small.exclude(nxt);
        }
        (large, small)
    }
}
impl BitAnd for Cand {
    type Output = Cand;
    fn bitand(self, rhs: Cand) -> Cand {
        Cand(self.0 & rhs.0)
    }
}
impl BitOr for Cand {
    type Output = Cand;
    fn bitor(self, rhs: Cand) -> Cand {
        Cand(self.0 | rhs.0)
    }
}
impl BitAndAssign for Cand {
    fn bitand_assign(&mut self, rhs: Cand) {
        *self = Cand(self.0 & rhs.0);
    }
}
impl BitOrAssign for Cand {
    fn bitor_assign(&mut self, rhs: Cand) {
        *self = Cand(self.0 | rhs.0);
    }
}
impl Not for Cand {
    type Output = Cand;
    fn not(self) -> Cand {
        Cand(CAND_ALL.0 ^ self.0)
    }
}

#[derive(Clone, Copy)]
pub enum Clue {
    NoClue,
    Clue { horizontal: i32, vertical: i32 },
}

#[derive(Clone, Copy)]
pub struct FieldTechnique {
    dictionary: bool,
    unique_position: bool,
    two_cells_propagation: bool,
    naked_pair: bool,
    min_max: bool,
}

impl FieldTechnique {
    fn new() -> FieldTechnique {
        FieldTechnique {
            dictionary: true,
            unique_position: true,
            two_cells_propagation: true,
            naked_pair: true,
            min_max: true,
        }
    }
}
pub use self::field_shape::*;
pub use self::dictionary::Dictionary;
pub use self::field::*;
pub use self::generator::*;
pub use self::evaluator::*;

use super::{Grid, Coord};
pub fn answer_to_problem(ans: &Grid<i32>) -> Grid<Clue> {
    let mut has_clue = Grid::new(ans.height(), ans.width(), false);
    for y in 0..ans.height() {
        for x in 0..ans.width() {
            let loc = Coord { y: y, x: x };
            has_clue[loc] = !(1 <= ans[loc] && ans[loc] <= MAX_VAL);
        }
    }
    let shape = FieldShape::new(&has_clue);
    let mut prob_base = Grid::new(ans.height(), ans.width(), (0, 0));
    for y in 0..ans.height() {
        for x in 0..ans.width() {
            let val = ans[Coord { y: y, x: x }];
            if !(1 <= val && val <= MAX_VAL) { continue; }

            let (g1, g2) = shape.cell_to_groups[Coord { y: y, x: x }];
            match shape.clue_locations[g1 as usize] {
                ClueLocation::Horizontal(h) => prob_base[h as usize].0 += val,
                ClueLocation::Vertical(v) => prob_base[v as usize].1 += val,
            }
            match shape.clue_locations[g2 as usize] {
                ClueLocation::Horizontal(h) => prob_base[h as usize].0 += val,
                ClueLocation::Vertical(v) => prob_base[v as usize].1 += val,
            }
        }
    }
    let mut ret = Grid::new(ans.height(), ans.width(), Clue::NoClue);
    for y in 0..ans.height() {
        for x in 0..ans.width() {
            let loc = Coord { y: y, x: x };
            let v = ans[loc];
            if (1 <= v && v <= MAX_VAL) { continue; }
            ret[loc] = Clue::Clue { horizontal: prob_base[loc].0, vertical: prob_base[loc].1 };
        }
    }
    ret
}

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

    #[test]
    fn test_cand() {
        assert_eq!(Cand::singleton(1), Cand(0b1));
        assert_eq!(Cand::singleton(2), Cand(0b10));

        assert_eq!(Cand(0b101).is_set(1), true);
        assert_eq!(Cand(0b101).is_set(2), false);
        assert_eq!(Cand(0b101).is_set(3), true);

        assert_eq!(Cand(0b0).is_empty(), true);
        assert_eq!(Cand(0b1).is_empty(), false);

        assert_eq!(Cand(0b10000).count_set_cands(), 1);
        assert_eq!(Cand(0b101101).count_set_cands(), 4);

        assert_eq!(Cand(0b10100).smallest_set_cand(), 3);
        assert_eq!(Cand(0b10110).smallest_set_cand(), 2);
        assert_eq!(Cand(0b10000).smallest_set_cand(), 5);

        assert_eq!(Cand(0b1100).largest_set_cand(), 4);
        assert_eq!(Cand(0b10110).largest_set_cand(), 5);
        assert_eq!(Cand(0b10000).largest_set_cand(), 5);

        assert_eq!(Cand(0b11010).exclude(2), Cand(0b11000));
        assert_eq!(Cand(0b11010).exclude(3), Cand(0b11010));

        assert_eq!(Cand(0b11010).limit_upper_bound(5), Cand(0b11010));
        assert_eq!(Cand(0b11010).limit_upper_bound(4), Cand(0b01010));
        assert_eq!(Cand(0b11010).limit_upper_bound(3), Cand(0b00010));
        assert_eq!(Cand(0b11010).limit_upper_bound(2), Cand(0b00010));
        assert_eq!(Cand(0b11010).limit_upper_bound(1), Cand(0b00000));

        assert_eq!(Cand(0b11010).limit_lower_bound(5), Cand(0b10000));
        assert_eq!(Cand(0b11010).limit_lower_bound(4), Cand(0b11000));
        assert_eq!(Cand(0b11010).limit_lower_bound(3), Cand(0b11000));
        assert_eq!(Cand(0b11010).limit_lower_bound(2), Cand(0b11010));
        assert_eq!(Cand(0b11010).limit_lower_bound(1), Cand(0b11010));

        assert_eq!(Cand(0b0).cand_sum(), 0);
        assert_eq!(Cand(0b10110).cand_sum(), 10);
        assert_eq!(Cand(0b100000000).cand_sum(), 9);
        assert_eq!(Cand(0b111111111).cand_sum(), 45);

        assert_eq!(Cand(0b1011011).take_smallest_k(2), (Cand(0b11), Cand(0b1011000)));
        assert_eq!(Cand(0b1011011).take_largest_k(2), (Cand(0b1010000), Cand(0b1011)));
    }
}
<|endoftext|>


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

//! Basic functions for dealing with memory
//!
//! This module contains functions for querying the size and alignment of
//! types, initializing and manipulating memory.

#[allow(missing_doc)]; // FIXME

use cast;
use ptr;
use unstable::intrinsics;
use unstable::intrinsics::{bswap16, bswap32, bswap64};

/// Returns the size of a type
#[inline]
pub fn size_of<T>() -> uint {
    unsafe { intrinsics::size_of::<T>() }
}

/// Returns the size of the type that `_val` points to
#[inline]
pub fn size_of_val<T>(_val: &T) -> uint {
    size_of::<T>()
}

/// Returns the size of a type, or 1 if the actual size is zero.
///
/// Useful for building structures containing variable-length arrays.
#[inline]
pub fn nonzero_size_of<T>() -> uint {
    let s = size_of::<T>();
    if s == 0 { 1 } else { s }
}

/// Returns the size of the type of the value that `_val` points to
#[inline]
pub fn nonzero_size_of_val<T>(_val: &T) -> uint {
    nonzero_size_of::<T>()
}

/// Returns the ABI-required minimum alignment of a type
///
/// This is the alignment used for struct fields. It may be smaller
/// than the preferred alignment.
#[inline]
pub fn min_align_of<T>() -> uint {
    unsafe { intrinsics::min_align_of::<T>() }
}

/// Returns the ABI-required minimum alignment of the type of the value that
/// `_val` points to
#[inline]
pub fn min_align_of_val<T>(_val: &T) -> uint {
    min_align_of::<T>()
}

/// Returns the preferred alignment of a type
#[inline]
pub fn pref_align_of<T>() -> uint {
    unsafe { intrinsics::pref_align_of::<T>() }
}

/// Returns the preferred alignment of the type of the value that
/// `_val` points to
#[inline]
pub fn pref_align_of_val<T>(_val: &T) -> uint {
    pref_align_of::<T>()
}

/// Create a value initialized to zero.
///
/// `init` is unsafe because it returns a zeroed-out datum,
/// which is unsafe unless T is Pod.
#[inline]
pub unsafe fn init<T>() -> T {
    intrinsics::init()
}

/// Create an uninitialized value.
#[inline]
pub unsafe fn uninit<T>() -> T {
    intrinsics::uninit()
}

/// Move a value to an uninitialized memory location.
///
/// Drop glue is not run on the destination.
#[inline]
pub unsafe fn move_val_init<T>(dst: &mut T, src: T) {
    intrinsics::move_val_init(dst, src)
}

#[cfg(target_endian = "little")] #[inline] pub fn to_le16(x: i16) -> i16 { x }
#[cfg(target_endian = "big")]    #[inline] pub fn to_le16(x: i16) -> i16 { unsafe { bswap16(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn to_le32(x: i32) -> i32 { x }
#[cfg(target_endian = "big")]    #[inline] pub fn to_le32(x: i32) -> i32 { unsafe { bswap32(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn to_le64(x: i64) -> i64 { x }
#[cfg(target_endian = "big")]    #[inline] pub fn to_le64(x: i64) -> i64 { unsafe { bswap64(x) } }

#[cfg(target_endian = "little")] #[inline] pub fn to_be16(x: i16) -> i16 { unsafe { bswap16(x) } }
#[cfg(target_endian = "big")]    #[inline] pub fn to_be16(x: i16) -> i16 { x }
#[cfg(target_endian = "little")] #[inline] pub fn to_be32(x: i32) -> i32 { unsafe { bswap32(x) } }
#[cfg(target_endian = "big")]    #[inline] pub fn to_be32(x: i32) -> i32 { x }
#[cfg(target_endian = "little")] #[inline] pub fn to_be64(x: i64) -> i64 { unsafe { bswap64(x) } }
#[cfg(target_endian = "big")]    #[inline] pub fn to_be64(x: i64) -> i64 { x }

#[cfg(target_endian = "little")] #[inline] pub fn from_le16(x: i16) -> i16 { x }
#[cfg(target_endian = "big")]    #[inline] pub fn from_le16(x: i16) -> i16 { unsafe { bswap16(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn from_le32(x: i32) -> i32 { x }
#[cfg(target_endian = "big")]    #[inline] pub fn from_le32(x: i32) -> i32 { unsafe { bswap32(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn from_le64(x: i64) -> i64 { x }
#[cfg(target_endian = "big")]    #[inline] pub fn from_le64(x: i64) -> i64 { unsafe { bswap64(x) } }

#[cfg(target_endian = "little")] #[inline] pub fn from_be16(x: i16) -> i16 { unsafe { bswap16(x) } }
#[cfg(target_endian = "big")]    #[inline] pub fn from_be16(x: i16) -> i16 { x }
#[cfg(target_endian = "little")] #[inline] pub fn from_be32(x: i32) -> i32 { unsafe { bswap32(x) } }
#[cfg(target_endian = "big")]    #[inline] pub fn from_be32(x: i32) -> i32 { x }
#[cfg(target_endian = "little")] #[inline] pub fn from_be64(x: i64) -> i64 { unsafe { bswap64(x) } }
#[cfg(target_endian = "big")]    #[inline] pub fn from_be64(x: i64) -> i64 { x }

/**
 * Swap the values at two mutable locations of the same type, without
 * deinitialising or copying either one.
 */
#[inline]
pub fn swap<T>(x: &mut T, y: &mut T) {
    unsafe {
        // Give ourselves some scratch space to work with
        let mut t: T = uninit();

        // Perform the swap, `&mut` pointers never alias
        ptr::copy_nonoverlapping_memory(&mut t, &*x, 1);
        ptr::copy_nonoverlapping_memory(x, &*y, 1);
        ptr::copy_nonoverlapping_memory(y, &t, 1);

        // y and t now point to the same thing, but we need to completely forget `tmp`
        // because it's no longer relevant.
        cast::forget(t);
    }
}

/**
 * Replace the value at a mutable location with a new one, returning the old
 * value, without deinitialising or copying either one.
 */
#[inline]
pub fn replace<T>(dest: &mut T, mut src: T) -> T {
    swap(dest, &mut src);
    src
}

/// Disposes of a value.
#[inline]
pub fn drop<T>(_x: T) { }

#[cfg(test)]
mod tests {
    use mem::*;
    use option::{Some,None};

    #[test]
    fn size_of_basic() {
        assert_eq!(size_of::<u8>(), 1u);
        assert_eq!(size_of::<u16>(), 2u);
        assert_eq!(size_of::<u32>(), 4u);
        assert_eq!(size_of::<u64>(), 8u);
    }

    #[test]
    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "arm")]
    #[cfg(target_arch = "mips")]
    fn size_of_32() {
        assert_eq!(size_of::<uint>(), 4u);
        assert_eq!(size_of::<*uint>(), 4u);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn size_of_64() {
        assert_eq!(size_of::<uint>(), 8u);
        assert_eq!(size_of::<*uint>(), 8u);
    }

    #[test]
    fn size_of_val_basic() {
        assert_eq!(size_of_val(&1u8), 1);
        assert_eq!(size_of_val(&1u16), 2);
        assert_eq!(size_of_val(&1u32), 4);
        assert_eq!(size_of_val(&1u64), 8);
    }

    #[test]
    fn nonzero_size_of_basic() {
        type Z = [i8, ..0];
        assert_eq!(size_of::<Z>(), 0u);
        assert_eq!(nonzero_size_of::<Z>(), 1u);
        assert_eq!(nonzero_size_of::<uint>(), size_of::<uint>());
    }

    #[test]
    fn nonzero_size_of_val_basic() {
        let z = [0u8, ..0];
        assert_eq!(size_of_val(&z), 0u);
        assert_eq!(nonzero_size_of_val(&z), 1u);
        assert_eq!(nonzero_size_of_val(&1u), size_of_val(&1u));
    }

    #[test]
    fn align_of_basic() {
        assert_eq!(pref_align_of::<u8>(), 1u);
        assert_eq!(pref_align_of::<u16>(), 2u);
        assert_eq!(pref_align_of::<u32>(), 4u);
    }

    #[test]
    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "arm")]
    #[cfg(target_arch = "mips")]
    fn align_of_32() {
        assert_eq!(pref_align_of::<uint>(), 4u);
        assert_eq!(pref_align_of::<*uint>(), 4u);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn align_of_64() {
        assert_eq!(pref_align_of::<uint>(), 8u);
        assert_eq!(pref_align_of::<*uint>(), 8u);
    }

    #[test]
    fn align_of_val_basic() {
        assert_eq!(pref_align_of_val(&1u8), 1u);
        assert_eq!(pref_align_of_val(&1u16), 2u);
        assert_eq!(pref_align_of_val(&1u32), 4u);
    }

    #[test]
    fn test_swap() {
        let mut x = 31337;
        let mut y = 42;
        swap(&mut x, &mut y);
        assert_eq!(x, 42);
        assert_eq!(y, 31337);
    }

    #[test]
    fn test_replace() {
        let mut x = Some(~"test");
        let y = replace(&mut x, None);
        assert!(x.is_none());
        assert!(y.is_some());
    }
}

/// Completely miscellaneous language-construct benchmarks.
#[cfg(test)]
mod bench {

    use extra::test::BenchHarness;
    use option::{Some,None};

    // Static/dynamic method dispatch

    struct Struct {
        field: int
    }

    trait Trait {
        fn method(&self) -> int;
    }

    impl Trait for Struct {
        fn method(&self) -> int {
            self.field
        }
    }

    #[bench]
    fn trait_vtable_method_call(bh: &mut BenchHarness) {
        let s = Struct { field: 10 };
        let t = &s as &Trait;
        bh.iter(|| {
            t.method()
        });
    }

    #[bench]
    fn trait_static_method_call(bh: &mut BenchHarness) {
        let s = Struct { field: 10 };
        bh.iter(|| {
            s.method()
        });
    }

    // Overhead of various match forms

    #[bench]
    fn match_option_some(bh: &mut BenchHarness) {
        let x = Some(10);
        bh.iter(|| {
            match x {
                Some(y) => y,
                None => 11
            }
        });
    }

    #[bench]
    fn match_vec_pattern(bh: &mut BenchHarness) {
        let x = [1,2,3,4,5,6];
        bh.iter(|| {
            match x {
                [1,2,3,..] => 10,
                _ => 11
            }
        });
    }
}
<commit_msg>auto merge of #12374 : dylanbraithwaite/rust/size_of_unit_clarification, r=cmr<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Basic functions for dealing with memory
//!
//! This module contains functions for querying the size and alignment of
//! types, initializing and manipulating memory.

#[allow(missing_doc)]; // FIXME

use cast;
use ptr;
use unstable::intrinsics;
use unstable::intrinsics::{bswap16, bswap32, bswap64};

/// Returns the size of a type in bytes.
#[inline]
pub fn size_of<T>() -> uint {
    unsafe { intrinsics::size_of::<T>() }
}

/// Returns the size of the type that `_val` points to in bytes.
#[inline]
pub fn size_of_val<T>(_val: &T) -> uint {
    size_of::<T>()
}

/// Returns the size of a type in bytes, or 1 if the actual size is zero.
///
/// Useful for building structures containing variable-length arrays.
#[inline]
pub fn nonzero_size_of<T>() -> uint {
    let s = size_of::<T>();
    if s == 0 { 1 } else { s }
}

/// Returns the size in bytes of the type of the value that `_val` points to.
#[inline]
pub fn nonzero_size_of_val<T>(_val: &T) -> uint {
    nonzero_size_of::<T>()
}

/// Returns the ABI-required minimum alignment of a type
///
/// This is the alignment used for struct fields. It may be smaller
/// than the preferred alignment.
#[inline]
pub fn min_align_of<T>() -> uint {
    unsafe { intrinsics::min_align_of::<T>() }
}

/// Returns the ABI-required minimum alignment of the type of the value that
/// `_val` points to
#[inline]
pub fn min_align_of_val<T>(_val: &T) -> uint {
    min_align_of::<T>()
}

/// Returns the preferred alignment of a type
#[inline]
pub fn pref_align_of<T>() -> uint {
    unsafe { intrinsics::pref_align_of::<T>() }
}

/// Returns the preferred alignment of the type of the value that
/// `_val` points to
#[inline]
pub fn pref_align_of_val<T>(_val: &T) -> uint {
    pref_align_of::<T>()
}

/// Create a value initialized to zero.
///
/// `init` is unsafe because it returns a zeroed-out datum,
/// which is unsafe unless T is Pod.
#[inline]
pub unsafe fn init<T>() -> T {
    intrinsics::init()
}

/// Create an uninitialized value.
#[inline]
pub unsafe fn uninit<T>() -> T {
    intrinsics::uninit()
}

/// Move a value to an uninitialized memory location.
///
/// Drop glue is not run on the destination.
#[inline]
pub unsafe fn move_val_init<T>(dst: &mut T, src: T) {
    intrinsics::move_val_init(dst, src)
}

#[cfg(target_endian = "little")] #[inline] pub fn to_le16(x: i16) -> i16 { x }
#[cfg(target_endian = "big")]    #[inline] pub fn to_le16(x: i16) -> i16 { unsafe { bswap16(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn to_le32(x: i32) -> i32 { x }
#[cfg(target_endian = "big")]    #[inline] pub fn to_le32(x: i32) -> i32 { unsafe { bswap32(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn to_le64(x: i64) -> i64 { x }
#[cfg(target_endian = "big")]    #[inline] pub fn to_le64(x: i64) -> i64 { unsafe { bswap64(x) } }

#[cfg(target_endian = "little")] #[inline] pub fn to_be16(x: i16) -> i16 { unsafe { bswap16(x) } }
#[cfg(target_endian = "big")]    #[inline] pub fn to_be16(x: i16) -> i16 { x }
#[cfg(target_endian = "little")] #[inline] pub fn to_be32(x: i32) -> i32 { unsafe { bswap32(x) } }
#[cfg(target_endian = "big")]    #[inline] pub fn to_be32(x: i32) -> i32 { x }
#[cfg(target_endian = "little")] #[inline] pub fn to_be64(x: i64) -> i64 { unsafe { bswap64(x) } }
#[cfg(target_endian = "big")]    #[inline] pub fn to_be64(x: i64) -> i64 { x }

#[cfg(target_endian = "little")] #[inline] pub fn from_le16(x: i16) -> i16 { x }
#[cfg(target_endian = "big")]    #[inline] pub fn from_le16(x: i16) -> i16 { unsafe { bswap16(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn from_le32(x: i32) -> i32 { x }
#[cfg(target_endian = "big")]    #[inline] pub fn from_le32(x: i32) -> i32 { unsafe { bswap32(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn from_le64(x: i64) -> i64 { x }
#[cfg(target_endian = "big")]    #[inline] pub fn from_le64(x: i64) -> i64 { unsafe { bswap64(x) } }

#[cfg(target_endian = "little")] #[inline] pub fn from_be16(x: i16) -> i16 { unsafe { bswap16(x) } }
#[cfg(target_endian = "big")]    #[inline] pub fn from_be16(x: i16) -> i16 { x }
#[cfg(target_endian = "little")] #[inline] pub fn from_be32(x: i32) -> i32 { unsafe { bswap32(x) } }
#[cfg(target_endian = "big")]    #[inline] pub fn from_be32(x: i32) -> i32 { x }
#[cfg(target_endian = "little")] #[inline] pub fn from_be64(x: i64) -> i64 { unsafe { bswap64(x) } }
#[cfg(target_endian = "big")]    #[inline] pub fn from_be64(x: i64) -> i64 { x }

/**
 * Swap the values at two mutable locations of the same type, without
 * deinitialising or copying either one.
 */
#[inline]
pub fn swap<T>(x: &mut T, y: &mut T) {
    unsafe {
        // Give ourselves some scratch space to work with
        let mut t: T = uninit();

        // Perform the swap, `&mut` pointers never alias
        ptr::copy_nonoverlapping_memory(&mut t, &*x, 1);
        ptr::copy_nonoverlapping_memory(x, &*y, 1);
        ptr::copy_nonoverlapping_memory(y, &t, 1);

        // y and t now point to the same thing, but we need to completely forget `tmp`
        // because it's no longer relevant.
        cast::forget(t);
    }
}

/**
 * Replace the value at a mutable location with a new one, returning the old
 * value, without deinitialising or copying either one.
 */
#[inline]
pub fn replace<T>(dest: &mut T, mut src: T) -> T {
    swap(dest, &mut src);
    src
}

/// Disposes of a value.
#[inline]
pub fn drop<T>(_x: T) { }

#[cfg(test)]
mod tests {
    use mem::*;
    use option::{Some,None};

    #[test]
    fn size_of_basic() {
        assert_eq!(size_of::<u8>(), 1u);
        assert_eq!(size_of::<u16>(), 2u);
        assert_eq!(size_of::<u32>(), 4u);
        assert_eq!(size_of::<u64>(), 8u);
    }

    #[test]
    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "arm")]
    #[cfg(target_arch = "mips")]
    fn size_of_32() {
        assert_eq!(size_of::<uint>(), 4u);
        assert_eq!(size_of::<*uint>(), 4u);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn size_of_64() {
        assert_eq!(size_of::<uint>(), 8u);
        assert_eq!(size_of::<*uint>(), 8u);
    }

    #[test]
    fn size_of_val_basic() {
        assert_eq!(size_of_val(&1u8), 1);
        assert_eq!(size_of_val(&1u16), 2);
        assert_eq!(size_of_val(&1u32), 4);
        assert_eq!(size_of_val(&1u64), 8);
    }

    #[test]
    fn nonzero_size_of_basic() {
        type Z = [i8, ..0];
        assert_eq!(size_of::<Z>(), 0u);
        assert_eq!(nonzero_size_of::<Z>(), 1u);
        assert_eq!(nonzero_size_of::<uint>(), size_of::<uint>());
    }

    #[test]
    fn nonzero_size_of_val_basic() {
        let z = [0u8, ..0];
        assert_eq!(size_of_val(&z), 0u);
        assert_eq!(nonzero_size_of_val(&z), 1u);
        assert_eq!(nonzero_size_of_val(&1u), size_of_val(&1u));
    }

    #[test]
    fn align_of_basic() {
        assert_eq!(pref_align_of::<u8>(), 1u);
        assert_eq!(pref_align_of::<u16>(), 2u);
        assert_eq!(pref_align_of::<u32>(), 4u);
    }

    #[test]
    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "arm")]
    #[cfg(target_arch = "mips")]
    fn align_of_32() {
        assert_eq!(pref_align_of::<uint>(), 4u);
        assert_eq!(pref_align_of::<*uint>(), 4u);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn align_of_64() {
        assert_eq!(pref_align_of::<uint>(), 8u);
        assert_eq!(pref_align_of::<*uint>(), 8u);
    }

    #[test]
    fn align_of_val_basic() {
        assert_eq!(pref_align_of_val(&1u8), 1u);
        assert_eq!(pref_align_of_val(&1u16), 2u);
        assert_eq!(pref_align_of_val(&1u32), 4u);
    }

    #[test]
    fn test_swap() {
        let mut x = 31337;
        let mut y = 42;
        swap(&mut x, &mut y);
        assert_eq!(x, 42);
        assert_eq!(y, 31337);
    }

    #[test]
    fn test_replace() {
        let mut x = Some(~"test");
        let y = replace(&mut x, None);
        assert!(x.is_none());
        assert!(y.is_some());
    }
}

/// Completely miscellaneous language-construct benchmarks.
#[cfg(test)]
mod bench {

    use extra::test::BenchHarness;
    use option::{Some,None};

    // Static/dynamic method dispatch

    struct Struct {
        field: int
    }

    trait Trait {
        fn method(&self) -> int;
    }

    impl Trait for Struct {
        fn method(&self) -> int {
            self.field
        }
    }

    #[bench]
    fn trait_vtable_method_call(bh: &mut BenchHarness) {
        let s = Struct { field: 10 };
        let t = &s as &Trait;
        bh.iter(|| {
            t.method()
        });
    }

    #[bench]
    fn trait_static_method_call(bh: &mut BenchHarness) {
        let s = Struct { field: 10 };
        bh.iter(|| {
            s.method()
        });
    }

    // Overhead of various match forms

    #[bench]
    fn match_option_some(bh: &mut BenchHarness) {
        let x = Some(10);
        bh.iter(|| {
            match x {
                Some(y) => y,
                None => 11
            }
        });
    }

    #[bench]
    fn match_vec_pattern(bh: &mut BenchHarness) {
        let x = [1,2,3,4,5,6];
        bh.iter(|| {
            match x {
                [1,2,3,..] => 10,
                _ => 11
            }
        });
    }
}
<|endoftext|>


<commit_before>use diesel::prelude::*;
use diesel_migrations::run_pending_migrations;
use dotenv::dotenv;
use std::env;

fn main() {
    println!("cargo:rerun-if-env-changed=TEST_DATABASE_URL");
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=migrations/");
    if env::var("PROFILE") == Ok("debug".into()) {
        let _ = dotenv();
        if let Ok(database_url) = env::var("TEST_DATABASE_URL") {
            let connection = PgConnection::establish(&database_url)
                .expect("Could not connect to TEST_DATABASE_URL");
            run_pending_migrations(&connection).expect("Error running migrations");
        }
    }
}
<commit_msg>Rerun the build script if `.env` has been changed.<commit_after>use diesel::prelude::*;
use diesel_migrations::run_pending_migrations;
use std::env;

fn main() {
    println!("cargo:rerun-if-env-changed=TEST_DATABASE_URL");
    println!("cargo:rerun-if-changed=.env");
    println!("cargo:rerun-if-changed=migrations/");
    if env::var("PROFILE") == Ok("debug".into()) {
        if let Ok(database_url) = dotenv::var("TEST_DATABASE_URL") {
            let connection = PgConnection::establish(&database_url)
                .expect("Could not connect to TEST_DATABASE_URL");
            run_pending_migrations(&connection).expect("Error running migrations");
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "skeptic")]
mod gen_skeptic {
    extern crate skeptic;

    use std::env;
    use std::fs::File;
    use std::io::prelude::*;
    use std::path::Path;

    /// skeptic templates look for `rust` after the opening code fences so writing
    /// ```f#,rust
    /// ```
    /// gives f# syntax highlight while still running the tests through the template
    const TEMPLATE: &'static str = r##"
```rust,skeptic-template
extern crate env_logger;
extern crate gluon;

use gluon::vm::api::{{Hole, OpaqueValue}};
use gluon::{{new_vm, Compiler, Thread}};

fn main() {{
    let _ = ::env_logger::init();
    let text = r#\"{}\"#;
    let vm = new_vm();
    match Compiler::new().run_expr::<OpaqueValue<&Thread, Hole>>(&vm, \"example\", text) .sync_or_error() {{
        Ok(_value) => (),
        Err(err) => {{
            panic!(\"{{}}\", err);
        }}
    }}
    return;
}}
```

"##;

    fn generate_skeptic_tests(file: &str) -> String {
        // Preprocess the readme to inject the skeptic template needed to to run the examples
        let out_file_name = Path::new(&env::var("OUT_DIR").unwrap()).join(file);
        let mut contents = TEMPLATE.as_bytes().into();
        File::open(file)
            .and_then(|mut raw_file| raw_file.read_to_end(&mut contents))
            .unwrap();
        File::create(&out_file_name)
            .and_then(|mut out_file| out_file.write(&contents))
            .unwrap();
        out_file_name.to_str().expect("UTF-8 string").into()
    }

    pub fn generate() {
        let test_locations: Vec<_> = ["README.md", "TUTORIAL.md"]
            .iter()
            .cloned()
            .map(generate_skeptic_tests)
            .collect();

        let str_vec: Vec<_> = test_locations.iter().map(|s| &s[..]).collect();
        skeptic::generate_doc_tests(&str_vec);
    }
}

#[cfg(not(feature = "skeptic"))]
mod gen_skeptic {
    pub fn generate() {
        // If we dont run skeptic we do not need to rebuild anything unless the script itself is
        // changed
        println!("rerun-if-changed=build.rs");
    }
}

fn main() {
    gen_skeptic::generate();
}
<commit_msg>chore: Avoid rebuilding gluon everytime due to the build script<commit_after>#[cfg(feature = "skeptic")]
mod gen_skeptic {
    extern crate skeptic;

    use std::env;
    use std::fs::File;
    use std::io::prelude::*;
    use std::path::Path;

    /// skeptic templates look for `rust` after the opening code fences so writing
    /// ```f#,rust
    /// ```
    /// gives f# syntax highlight while still running the tests through the template
    const TEMPLATE: &'static str = r##"
```rust,skeptic-template
extern crate env_logger;
extern crate gluon;

use gluon::vm::api::{{Hole, OpaqueValue}};
use gluon::{{new_vm, Compiler, Thread}};

fn main() {{
    let _ = ::env_logger::init();
    let text = r#\"{}\"#;
    let vm = new_vm();
    match Compiler::new().run_expr::<OpaqueValue<&Thread, Hole>>(&vm, \"example\", text) .sync_or_error() {{
        Ok(_value) => (),
        Err(err) => {{
            panic!(\"{{}}\", err);
        }}
    }}
    return;
}}
```

"##;

    fn generate_skeptic_tests(file: &str) -> String {
        // Preprocess the readme to inject the skeptic template needed to to run the examples
        let out_file_name = Path::new(&env::var("OUT_DIR").unwrap()).join(file);
        let mut contents = TEMPLATE.as_bytes().into();
        File::open(file)
            .and_then(|mut raw_file| raw_file.read_to_end(&mut contents))
            .unwrap();
        File::create(&out_file_name)
            .and_then(|mut out_file| out_file.write(&contents))
            .unwrap();
        out_file_name.to_str().expect("UTF-8 string").into()
    }

    pub fn generate() {
        let test_locations: Vec<_> = ["README.md", "TUTORIAL.md"]
            .iter()
            .cloned()
            .map(generate_skeptic_tests)
            .collect();

        let str_vec: Vec<_> = test_locations.iter().map(|s| &s[..]).collect();
        skeptic::generate_doc_tests(&str_vec);
    }
}

#[cfg(not(feature = "skeptic"))]
mod gen_skeptic {
    pub fn generate() {
        // If we dont run skeptic we do not need to rebuild anything unless the script itself is
        // changed
        println!("cargo:rerun-if-changed=build.rs");
    }
}

fn main() {
    gen_skeptic::generate();
}
<|endoftext|>


<commit_before>//! This build script checks that all files in the `src` directory have lines of at most 100
//! characters and don't contain trailing whitespace.
//!
//! It also ensures that comment indicating which task a file solves is at the top.
//!
//! In case we find a line that doesn't comply with this rules, the build will fail and indicate
//! the cause of the problem.
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate toml;
extern crate unicode_segmentation;
extern crate walkdir;

use std::fs::{self, File};
use std::io::Read;
use std::path::Path;

use regex::Regex;
use unicode_segmentation::UnicodeSegmentation;
use walkdir::WalkDir;

lazy_static!{
    static ref LIB_OR_MOD_RE: Regex = Regex::new("^lib|mod$").unwrap();
    static ref TASK_COMMENT_RE: Regex =
            Regex::new(r"^// http://rosettacode\.org/wiki/[^#]+$").unwrap();
}

/// Checks that all binaries are in lexicographic order in `Cargo.toml`.
fn check_toml() {
    let mut cargo_toml_file = File::open("Cargo.toml").unwrap();
    let mut cargo_toml_string = String::new();
    cargo_toml_file.read_to_string(&mut cargo_toml_string).unwrap();

    let cargo_toml = toml::Parser::new(&cargo_toml_string).parse().unwrap();
    let binaries = cargo_toml.get("bin").unwrap().as_slice().unwrap().to_owned();
    let mut sorted_binaries = binaries.clone();
    sorted_binaries.sort_by(|a, b| {
        let a_name = a.as_table().unwrap().get("name").unwrap().as_str().unwrap();
        let b_name = b.as_table().unwrap().get("name").unwrap().as_str().unwrap();
        a_name.cmp(b_name)
    });

    for (bin, correct_bin) in binaries.iter().zip(sorted_binaries) {
        let bin_name = bin.as_table().unwrap().get("name").unwrap().as_str().unwrap();
        let correct_bin_name = correct_bin.as_table()
                                          .unwrap()
                                          .get("name")
                                          .unwrap()
                                          .as_str()
                                          .unwrap();
        if bin_name != correct_bin_name {
            panic!("{} is not in the correct order in Cargo.toml!", bin_name);
        }
    }
}

fn main() {
    check_toml();

    for entry in WalkDir::new("src") {
        let entry = entry.unwrap();
        if fs::metadata(&entry.path()).unwrap().is_file() {

            // Only check Rust files
            if let Some("rs") = entry.path().extension().and_then(|s| s.to_str()) {
                check(&entry.path());
            }
        }
    }
}

/// Checks that all tasks contain a comment with a link to the Rosetta Code task they are
/// implementing as the first line of the file.
fn check_task_name(path: &Path, line: &str) {
    // Ensure the first line has a URL of the proper form
    if !TASK_COMMENT_RE.is_match(line) {
        line_error(1,
                   path,
                   "header is missing or malformed. The line should exactly match '// \
                    http://rosettacode.org/wiki/<TASK NAME>'");
    }
}

/// Performs all checks on a particular file.
fn check(path: &Path) {
    let mut content = String::new();
    File::open(&path).unwrap().read_to_string(&mut content).unwrap();

    for (i, mut line) in content.lines().enumerate() {
        // Ignore lib and mod files.
        if i == 0 && !LIB_OR_MOD_RE.is_match(path.file_stem().unwrap().to_str().unwrap()) {
            check_task_name(&path, &line);
        }

        // Ignore '\r'
        if let Some('\r') = line.chars().rev().next() {
            line = &line[..line.len() - 1];
        }

        // Check length
        if UnicodeSegmentation::graphemes(line, true).count() > 100 {
            line_error(i + 1, path, "line is longer than 100 characters");
        }

        // Check trailing whitespace
        if let Some(last_char) = line.chars().rev().next() {
            if last_char.is_whitespace() {
                line_error(i + 1, path, "line has trailing whitespace");
            }
        }
    }
}

fn line_error(line: usize, path: &Path, msg: &str) {
    panic!("Formatting error, {} (line {} of file \"{}\")",
           msg,
           line,
           path.to_str().unwrap())
}
<commit_msg>fix clippy warnings in build script<commit_after>//! This build script checks that all files in the `src` directory have lines of at most 100
//! characters and don't contain trailing whitespace.
//!
//! It also ensures that comment indicating which task a file solves is at the top.
//!
//! In case we find a line that doesn't comply with this rules, the build will fail and indicate
//! the cause of the problem.
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate toml;
extern crate unicode_segmentation;
extern crate walkdir;

use std::fs::{self, File};
use std::io::Read;
use std::path::Path;

use regex::Regex;
use unicode_segmentation::UnicodeSegmentation;
use walkdir::WalkDir;

lazy_static!{
    static ref LIB_OR_MOD_RE: Regex = Regex::new("^lib|mod$").unwrap();
    static ref TASK_COMMENT_RE: Regex =
            Regex::new(r"^// http://rosettacode\.org/wiki/[^#]+$").unwrap();
}

/// Checks that all binaries are in lexicographic order in `Cargo.toml`.
fn check_toml() {
    let mut cargo_toml_file = File::open("Cargo.toml").unwrap();
    let mut cargo_toml_string = String::new();
    cargo_toml_file.read_to_string(&mut cargo_toml_string).unwrap();

    let cargo_toml = toml::Parser::new(&cargo_toml_string).parse().unwrap();
    let binaries = cargo_toml.get("bin").unwrap().as_slice().unwrap().to_owned();
    let mut sorted_binaries = binaries.clone();
    sorted_binaries.sort_by(|a, b| {
        let a_name = a.as_table().unwrap().get("name").unwrap().as_str().unwrap();
        let b_name = b.as_table().unwrap().get("name").unwrap().as_str().unwrap();
        a_name.cmp(b_name)
    });

    for (bin, correct_bin) in binaries.iter().zip(sorted_binaries) {
        let bin_name = bin.as_table().unwrap().get("name").unwrap().as_str().unwrap();
        let correct_bin_name = correct_bin.as_table()
            .unwrap()
            .get("name")
            .unwrap()
            .as_str()
            .unwrap();
        if bin_name != correct_bin_name {
            panic!("{} is not in the correct order in Cargo.toml!", bin_name);
        }
    }
}

fn main() {
    check_toml();

    for entry in WalkDir::new("src") {
        let entry = entry.unwrap();
        if fs::metadata(&entry.path()).unwrap().is_file() {

            // Only check Rust files
            if let Some("rs") = entry.path().extension().and_then(|s| s.to_str()) {
                check(&entry.path());
            }
        }
    }
}

/// Checks that all tasks contain a comment with a link to the Rosetta Code task they are
/// implementing as the first line of the file.
fn check_task_name<P>(path: &P, line: &str)
    where P: AsRef<Path>
{
    // Ensure the first line has a URL of the proper form
    if !TASK_COMMENT_RE.is_match(line) {
        line_error(1,
                   path,
                   "header is missing or malformed. The line should exactly match '// \
                    http://rosettacode.org/wiki/<TASK NAME>'");
    }
}

/// Performs all checks on a particular file.
fn check<P>(path: &P)
    where P: AsRef<Path>
{
    let mut content = String::new();
    File::open(&path).unwrap().read_to_string(&mut content).unwrap();

    for (i, mut line) in content.lines().enumerate() {
        // Ignore lib and mod files.
        if i == 0 && !LIB_OR_MOD_RE.is_match(path.as_ref().file_stem().unwrap().to_str().unwrap()) {
            check_task_name(&path, line);
        }

        // Ignore '\r'
        if let Some('\r') = line.chars().rev().next() {
            line = &line[..line.len() - 1];
        }

        // Check length
        if UnicodeSegmentation::graphemes(line, true).count() > 100 {
            line_error(i + 1, path, "line is longer than 100 characters");
        }

        // Check trailing whitespace
        if let Some(last_char) = line.chars().rev().next() {
            if last_char.is_whitespace() {
                line_error(i + 1, path, "line has trailing whitespace");
            }
        }
    }
}

fn line_error<P>(line: usize, path: &P, msg: &str)
    where P: AsRef<Path>
{
    panic!("Formatting error, {} (line {} of file \"{}\")",
           msg,
           line,
           path.as_ref().to_str().unwrap())
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016-2017 Nathan Fiedler
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
extern crate bindgen;
extern crate pkg_config;

use std::collections::HashSet;
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;

const MIN_VERSION: &'static str = "7.0";
const MAX_VERSION: &'static str = "7.1";

static HEADER: &'static str = "#include <MagickWand/MagickWand.h>\n";

fn main() {
    if cfg!(target_os = "freebsd") {
        // pkg_config does not seem to work properly on FreeBSD, so
        // hard-code the builder settings for the time being.
        env_var_set_default("IMAGE_MAGICK_INCLUDE_DIRS", "/usr/local/include/ImageMagick-7");
        // Need to hack the linker flags as well.
        env_var_set_default("IMAGE_MAGICK_LIB_DIRS", "/usr/local/lib");
        env_var_set_default("IMAGE_MAGICK_LIBS", "MagickWand-7");
    }

    let lib_dirs = find_image_magick_lib_dirs();
    for d in &lib_dirs {
        if !d.exists() {
            panic!("ImageMagick library directory does not exist: {}", d.to_string_lossy());
        }
        println!( "cargo:rustc-link-search=native={}", d.to_string_lossy());
    }
    let include_dirs = find_image_magick_include_dirs();
    for d in &include_dirs {
        if !d.exists() {
            panic!("ImageMagick include directory does not exist: {}", d.to_string_lossy());
        }
        println!("cargo:include={}", d.to_string_lossy());
    }
    println!("cargo:rerun-if-env-changed=IMAGE_MAGICK_LIBS");

    let target = env::var("TARGET").unwrap();
    let libs_env = env::var("IMAGE_MAGICK_LIBS").ok();
    let libs = match libs_env {
        Some(ref v) => v.split(":").map(|x| x.to_owned()).collect(),
        None => {
            if target.contains("windows") {
                vec!["CORE_RL_MagickWand_".to_string()]
            } else if target.contains("freebsd") {
                vec!["MagickWand-7".to_string()]
            } else {
                run_pkg_config().libs
            }
        }
    };

    let kind = determine_mode(&lib_dirs, libs.as_slice());
    for lib in libs.into_iter() {
        println!("cargo:rustc-link-lib={}={}", kind, lib);
    }

    // If the generated bindings are missing, generate them now.
    let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    let bindings_path_str = out_dir.join("bindings.rs");

    if !Path::new(&bindings_path_str).exists() {
        // Create the header file that rust-bindgen needs as input.
        let gen_h_path = out_dir.join("gen.h");
        let mut gen_h = File::create(&gen_h_path).expect("could not create file");
        gen_h.write_all(HEADER.as_bytes()).expect("could not write header file");

        // Geneate the bindings.
        let mut builder = bindgen::Builder::default()
            .emit_builtins()
            .ctypes_prefix("libc")
            .raw_line("extern crate libc;")
            .header(gen_h_path.to_str().unwrap())
            // https://github.com/rust-lang-nursery/rust-bindgen/issues/687
            .hide_type("FP_NAN")
            .hide_type("FP_INFINITE")
            .hide_type("FP_ZERO")
            .hide_type("FP_SUBNORMAL")
            .hide_type("FP_NORMAL");

        for d in include_dirs {
            builder = builder.clang_arg(format!("-I{}", d.to_string_lossy()));
        }

        let bindings = builder.generate().unwrap();
        let mut file = File::create(&bindings_path_str).expect("could not create bindings file");
        // Work around the include! issue in rustc (as described in the
        // rust-bindgen README file) by wrapping the generated code in a
        // `pub mod` declaration; see issue #359 in (old) rust-bindgen.
        file.write(b"pub mod bindings {\n").unwrap();
        file.write(bindings.to_string().as_bytes()).unwrap();
        file.write(b"\n}").unwrap();

        std::fs::remove_file(&gen_h_path).expect("could not remove header file");
    }
}

fn env_var_set_default(name: &str, value: &str) {
    if env::var(name).is_err() {
        env::set_var(name, value);
    }
}

fn find_image_magick_lib_dirs() -> Vec<PathBuf> {
    println!("cargo:rerun-if-env-changed=IMAGE_MAGICK_LIB_DIRS");
    env::var("IMAGE_MAGICK_LIB_DIRS")
        .map(|x| x.split(":").map(PathBuf::from).collect::<Vec<PathBuf>>())
        .or_else(|_| Ok(vec![find_image_magick_dir()?.join("lib")]))
        .or_else(|_: env::VarError| -> Result<_, env::VarError> {
            Ok(run_pkg_config().link_paths)
        })
        .expect("Couldn't find ImageMagick library directory")
}

fn find_image_magick_include_dirs() -> Vec<PathBuf> {
    println!("cargo:rerun-if-env-changed=IMAGE_MAGICK_INCLUDE_DIRS");
    env::var("IMAGE_MAGICK_INCLUDE_DIRS")
        .map(|x| x.split(":").map(PathBuf::from).collect::<Vec<PathBuf>>())
        .or_else(|_| Ok(vec![find_image_magick_dir()?.join("include")]))
        .or_else(|_: env::VarError| -> Result<_, env::VarError> {
             Ok(run_pkg_config().include_paths)
        })
        .expect("Couldn't find ImageMagick include directory")
}

fn find_image_magick_dir() -> Result<PathBuf, env::VarError> {
    println!("cargo:rerun-if-env-changed=IMAGE_MAGICK_DIR");
    env::var("IMAGE_MAGICK_DIR")
        .map(PathBuf::from)
}

fn determine_mode<T: AsRef<str>>(libdirs: &Vec<PathBuf>, libs: &[T]) -> &'static str {
    println!("cargo:rerun-if-env-changed=IMAGE_MAGICK_STATIC");
    let kind = env::var("IMAGE_MAGICK_STATIC").ok();
    match kind.as_ref().map(|s| &s[..]) {
        Some("0") => return "dylib",
        Some(_) => return "static",
        None => {}
    }

    // See what files we actually have to link against, and see what our
    // possibilities even are.
    let files = libdirs.into_iter().flat_map(|d| d.read_dir().unwrap())
        .map(|e| e.unwrap())
        .map(|e| e.file_name())
        .filter_map(|e| e.into_string().ok())
        .collect::<HashSet<_>>();
    let can_static = libs.iter().all(|l| {
        files.contains(&format!("lib{}.a", l.as_ref())) ||
            files.contains(&format!("{}.lib", l.as_ref()))
    });
    let can_dylib = libs.iter().all(|l| {
        files.contains(&format!("lib{}.so", l.as_ref())) ||
            files.contains(&format!("{}.dll", l.as_ref())) ||
            files.contains(&format!("lib{}.dylib", l.as_ref()))
    });

    match (can_static, can_dylib) {
        (true, false) => return "static",
        (false, true) => return "dylib",
        (false, false) => {
            panic!(
                "ImageMagick libdirs at `{:?}` do not contain the required files \
                    to either statically or dynamically link ImageMagick",
                libdirs
            );
        }
        (true, true) => {}
    }

    // default
    "dylib"
}

fn run_pkg_config() -> pkg_config::Library {
    // Assert that the appropriate version of MagickWand is installed,
    // since we are very dependent on the particulars of MagickWand.
    pkg_config::Config::new()
        .cargo_metadata(false)
        .atleast_version(MIN_VERSION)
        .probe("MagickWand")
        .unwrap();
    // Check the maximum version separately as pkg-config will ignore that
    // option when combined with (certain) other options. And since the
    // pkg-config crate always adds those other flags, we must run the
    // command directly.
    if !Command::new("pkg-config")
                .arg(format!("--max-version={}", MAX_VERSION))
                .arg("MagickWand")
                .status().unwrap().success() {
        panic!(format!("MagickWand version must be no higher than {}", MAX_VERSION));
    }
    // We have to split the version check and the cflags/libs check because
    // you can't do both at the same time on RHEL (apparently).
    pkg_config::Config::new()
        .cargo_metadata(false)
        .probe("MagickWand").unwrap()
}
<commit_msg>Hide more types to fix build (#29)<commit_after>/*
 * Copyright 2016-2017 Nathan Fiedler
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
extern crate bindgen;
extern crate pkg_config;

use std::collections::HashSet;
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;

const MIN_VERSION: &'static str = "7.0";
const MAX_VERSION: &'static str = "7.1";

static HEADER: &'static str = "#include <MagickWand/MagickWand.h>\n";

fn main() {
    if cfg!(target_os = "freebsd") {
        // pkg_config does not seem to work properly on FreeBSD, so
        // hard-code the builder settings for the time being.
        env_var_set_default("IMAGE_MAGICK_INCLUDE_DIRS", "/usr/local/include/ImageMagick-7");
        // Need to hack the linker flags as well.
        env_var_set_default("IMAGE_MAGICK_LIB_DIRS", "/usr/local/lib");
        env_var_set_default("IMAGE_MAGICK_LIBS", "MagickWand-7");
    }

    let lib_dirs = find_image_magick_lib_dirs();
    for d in &lib_dirs {
        if !d.exists() {
            panic!("ImageMagick library directory does not exist: {}", d.to_string_lossy());
        }
        println!( "cargo:rustc-link-search=native={}", d.to_string_lossy());
    }
    let include_dirs = find_image_magick_include_dirs();
    for d in &include_dirs {
        if !d.exists() {
            panic!("ImageMagick include directory does not exist: {}", d.to_string_lossy());
        }
        println!("cargo:include={}", d.to_string_lossy());
    }
    println!("cargo:rerun-if-env-changed=IMAGE_MAGICK_LIBS");

    let target = env::var("TARGET").unwrap();
    let libs_env = env::var("IMAGE_MAGICK_LIBS").ok();
    let libs = match libs_env {
        Some(ref v) => v.split(":").map(|x| x.to_owned()).collect(),
        None => {
            if target.contains("windows") {
                vec!["CORE_RL_MagickWand_".to_string()]
            } else if target.contains("freebsd") {
                vec!["MagickWand-7".to_string()]
            } else {
                run_pkg_config().libs
            }
        }
    };

    let kind = determine_mode(&lib_dirs, libs.as_slice());
    for lib in libs.into_iter() {
        println!("cargo:rustc-link-lib={}={}", kind, lib);
    }

    // If the generated bindings are missing, generate them now.
    let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    let bindings_path_str = out_dir.join("bindings.rs");

    if !Path::new(&bindings_path_str).exists() {
        // Create the header file that rust-bindgen needs as input.
        let gen_h_path = out_dir.join("gen.h");
        let mut gen_h = File::create(&gen_h_path).expect("could not create file");
        gen_h.write_all(HEADER.as_bytes()).expect("could not write header file");

        // Geneate the bindings.
        let mut builder = bindgen::Builder::default()
            .emit_builtins()
            .ctypes_prefix("libc")
            .raw_line("extern crate libc;")
            .header(gen_h_path.to_str().unwrap())
            // https://github.com/rust-lang-nursery/rust-bindgen/issues/687
            .hide_type("FP_NAN")
            .hide_type("FP_INFINITE")
            .hide_type("FP_ZERO")
            .hide_type("FP_SUBNORMAL")
            .hide_type("FP_NORMAL")
            .hide_type("FP_INT_UPWARD")
            .hide_type("FP_INT_DOWNWARD")
            .hide_type("FP_INT_TOWARDZERO")
            .hide_type("FP_INT_TONEARESTFROMZERO")
            .hide_type("FP_INT_TONEAREST");

        for d in include_dirs {
            builder = builder.clang_arg(format!("-I{}", d.to_string_lossy()));
        }

        let bindings = builder.generate().unwrap();
        let mut file = File::create(&bindings_path_str).expect("could not create bindings file");
        // Work around the include! issue in rustc (as described in the
        // rust-bindgen README file) by wrapping the generated code in a
        // `pub mod` declaration; see issue #359 in (old) rust-bindgen.
        file.write(b"pub mod bindings {\n").unwrap();
        file.write(bindings.to_string().as_bytes()).unwrap();
        file.write(b"\n}").unwrap();

        std::fs::remove_file(&gen_h_path).expect("could not remove header file");
    }
}

fn env_var_set_default(name: &str, value: &str) {
    if env::var(name).is_err() {
        env::set_var(name, value);
    }
}

fn find_image_magick_lib_dirs() -> Vec<PathBuf> {
    println!("cargo:rerun-if-env-changed=IMAGE_MAGICK_LIB_DIRS");
    env::var("IMAGE_MAGICK_LIB_DIRS")
        .map(|x| x.split(":").map(PathBuf::from).collect::<Vec<PathBuf>>())
        .or_else(|_| Ok(vec![find_image_magick_dir()?.join("lib")]))
        .or_else(|_: env::VarError| -> Result<_, env::VarError> {
            Ok(run_pkg_config().link_paths)
        })
        .expect("Couldn't find ImageMagick library directory")
}

fn find_image_magick_include_dirs() -> Vec<PathBuf> {
    println!("cargo:rerun-if-env-changed=IMAGE_MAGICK_INCLUDE_DIRS");
    env::var("IMAGE_MAGICK_INCLUDE_DIRS")
        .map(|x| x.split(":").map(PathBuf::from).collect::<Vec<PathBuf>>())
        .or_else(|_| Ok(vec![find_image_magick_dir()?.join("include")]))
        .or_else(|_: env::VarError| -> Result<_, env::VarError> {
             Ok(run_pkg_config().include_paths)
        })
        .expect("Couldn't find ImageMagick include directory")
}

fn find_image_magick_dir() -> Result<PathBuf, env::VarError> {
    println!("cargo:rerun-if-env-changed=IMAGE_MAGICK_DIR");
    env::var("IMAGE_MAGICK_DIR")
        .map(PathBuf::from)
}

fn determine_mode<T: AsRef<str>>(libdirs: &Vec<PathBuf>, libs: &[T]) -> &'static str {
    println!("cargo:rerun-if-env-changed=IMAGE_MAGICK_STATIC");
    let kind = env::var("IMAGE_MAGICK_STATIC").ok();
    match kind.as_ref().map(|s| &s[..]) {
        Some("0") => return "dylib",
        Some(_) => return "static",
        None => {}
    }

    // See what files we actually have to link against, and see what our
    // possibilities even are.
    let files = libdirs.into_iter().flat_map(|d| d.read_dir().unwrap())
        .map(|e| e.unwrap())
        .map(|e| e.file_name())
        .filter_map(|e| e.into_string().ok())
        .collect::<HashSet<_>>();
    let can_static = libs.iter().all(|l| {
        files.contains(&format!("lib{}.a", l.as_ref())) ||
            files.contains(&format!("{}.lib", l.as_ref()))
    });
    let can_dylib = libs.iter().all(|l| {
        files.contains(&format!("lib{}.so", l.as_ref())) ||
            files.contains(&format!("{}.dll", l.as_ref())) ||
            files.contains(&format!("lib{}.dylib", l.as_ref()))
    });

    match (can_static, can_dylib) {
        (true, false) => return "static",
        (false, true) => return "dylib",
        (false, false) => {
            panic!(
                "ImageMagick libdirs at `{:?}` do not contain the required files \
                    to either statically or dynamically link ImageMagick",
                libdirs
            );
        }
        (true, true) => {}
    }

    // default
    "dylib"
}

fn run_pkg_config() -> pkg_config::Library {
    // Assert that the appropriate version of MagickWand is installed,
    // since we are very dependent on the particulars of MagickWand.
    pkg_config::Config::new()
        .cargo_metadata(false)
        .atleast_version(MIN_VERSION)
        .probe("MagickWand")
        .unwrap();
    // Check the maximum version separately as pkg-config will ignore that
    // option when combined with (certain) other options. And since the
    // pkg-config crate always adds those other flags, we must run the
    // command directly.
    if !Command::new("pkg-config")
                .arg(format!("--max-version={}", MAX_VERSION))
                .arg("MagickWand")
                .status().unwrap().success() {
        panic!(format!("MagickWand version must be no higher than {}", MAX_VERSION));
    }
    // We have to split the version check and the cflags/libs check because
    // you can't do both at the same time on RHEL (apparently).
    pkg_config::Config::new()
        .cargo_metadata(false)
        .probe("MagickWand").unwrap()
}
<|endoftext|>


<commit_before>#[allow(dead_code)]
fn add_xcode_private_framework_path() {
    // PrivateFramework dir:
    // `xcode-select -p`/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks/
    let xcode_dir = std::process::Command::new("xcode-select")
        .arg("-p")
        .output()
        .expect("Failed to run xcode-select");
    let mut xcode_dir = String::from_utf8(xcode_dir.stdout).unwrap();
    xcode_dir.pop(); // remove trailing newline

    let private_framework_dirs = vec![
        format!("{}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks/",
                xcode_dir),
        "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks/DFRFoundation.framework/".into(),
    ];
    let framework_dir = private_framework_dirs.iter().filter(|dir| {
        std::path::Path::new(dir).is_dir()
    }).next().expect("XCode PrivateFramework directory not found.");

    println!("XCode PrivateFramework dir: {}", framework_dir);
    println!("cargo:rustc-link-search=framework={}", framework_dir);
}

fn main() {
    #[cfg(target_os = "macos")]
    #[cfg(feature = "private_api")]
    add_xcode_private_framework_path();
}
<commit_msg>Add another private framework location<commit_after>#[allow(dead_code)]
fn add_xcode_private_framework_path() {
    // PrivateFramework dir:
    // `xcode-select -p`/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks/
    let xcode_dir = std::process::Command::new("xcode-select")
        .arg("-p")
        .output()
        .expect("Failed to run xcode-select");
    let mut xcode_dir = String::from_utf8(xcode_dir.stdout).unwrap();
    xcode_dir.pop(); // remove trailing newline

    let private_framework_dirs = vec![
        format!("{}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks/",
                xcode_dir),
        "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks/DFRFoundation.framework/".into(),
        "/System/Library/PrivateFrameworks/".into(),
    ];
    let framework_dir = private_framework_dirs.iter().filter(|dir| {
        let fwork = format!("{}/DFRFoundation.framework", dir);
        std::path::Path::new(&fwork).is_dir()
    }).next().expect("XCode PrivateFramework directory not found.");

    println!("XCode PrivateFramework dir: {}", framework_dir);
    println!("cargo:rustc-link-search=framework={}", framework_dir);
}

fn main() {
    #[cfg(target_os = "macos")]
    #[cfg(feature = "private_api")]
    add_xcode_private_framework_path();
}
<|endoftext|>


<commit_before>use std::env;

fn main() {
    // Cargo sets the host and target env vars for build scripts, but not crates:
    // https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
    // So we just re-export them to the crate code.
    println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap());
    // By default Cargo only runs the build script when a file changes.
    // This makes it re-run on target change
     println!("cargo:rerun-if-changed-env=TARGET")
}
<commit_msg>cargo fmt<commit_after>use std::env;

fn main() {
    // Cargo sets the host and target env vars for build scripts, but not crates:
    // https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
    // So we just re-export them to the crate code.
    println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap());
    // By default Cargo only runs the build script when a file changes.
    // This makes it re-run on target change
    println!("cargo:rerun-if-changed-env=TARGET")
}
<|endoftext|>


<commit_before>use std::{env, fs::File, io::Write, path::Path, process::Command};

fn tags() -> String {
    let output = Command::new("git")
        .args(&["describe", "--abbrev=0"])
        .output()
        .expect("Failed to execute git describe");
    String::from_utf8_lossy(&output.stdout).trim().to_string()
}

fn branch() -> String {
    let output = Command::new("git")
        .args(&["rev-parse", "--abbrev-ref", "HEAD"])
        .output()
        .expect("Failed to execute git rev-parse");
    String::from_utf8_lossy(&output.stdout).trim().to_string()
}

fn date() -> String {
    let output = Command::new("date")
        .output()
        .expect("Failed to execute date");
    String::from_utf8_lossy(&output.stdout).trim().to_string()
}

fn commit_sha() -> String {
    let output = Command::new("git")
        .args(&["rev-parse", "HEAD"])
        .output()
        .expect("Failed to execute git rev-parse");
    String::from_utf8_lossy(&output.stdout).trim().to_string()
}

fn local_changes() -> bool {
    let output = Command::new("git")
        .args(&["diff", "--exit-code"])
        .output()
        .expect("Failed to execute git diff");
    !output.status.success()
}

fn kernel_version() -> String {
    let output = Command::new("uname")
        .arg("-r")
        .output()
        .expect("Failed to execute uname");
    String::from_utf8_lossy(&output.stdout).trim().to_string()
}

fn main() {
    let version = env!("CARGO_PKG_VERSION");
    let tag = tags();
    let tag_message = if !tag.is_empty() {
        format!("Tag: {}\n", tag)
    } else {
        String::new()
    };
    let mut change_message = "";

    if local_changes() {
        change_message = " with local changes";
    }

    let version_info = format!(
        "RustyVisor Version: {}\nCommit: {}{}\n{}Branch: {}\nBuilt on: {}\nKernel version: {}",
        version,
        commit_sha(),
        change_message,
        tag_message,
        branch(),
        date(),
        kernel_version()
    );

    let version_code = format!("const VERSION: &'_ str = \"{}\";", version_info);

    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("version.rs");
    let mut f = File::create(&dest_path).unwrap();

    f.write_all(version_code.as_bytes()).unwrap();
}
<commit_msg>Remove dead code<commit_after><|endoftext|>