<commit_before>use serde_json::{Value, from_str};
use serde_json::error::Result as R;
use serde_json::Serializer;
use serde::ser::Serialize;
use serde::ser::Serializer as Ser;

use std::collections::HashMap;
use std::io::stdout;

use super::super::parser::{FileHeaderParser, ParserError};
use super::super::file::{FileHeaderSpec, FileHeaderData};

struct JsonHeaderParser<'a> {
    spec: &'a FileHeaderSpec,
}

impl JsonHeaderParser {

    fn new(spec: &'a FileHeaderSpec) -> JsonHeaderParser<'a> {
        JsonHeaderParser {
            spec: spec
        }
    }

}

impl FileHeaderParser for JsonHeaderParser {

    fn read(&self, string: Option<String>)
        -> Result<FileHeaderData, ParserError>
    {
        if string.is_some() {
            let s = string.unwrap();
            debug!("Deserializing: {}", s);
            let fromstr : R<Value> = from_str(&s[..]);
            if let Ok(content) = fromstr {
                Ok(visit_json(&content))
            } else {
                Err(ParserError::short("Unknown JSON parser error", s.clone(), 0))
            }
        } else {
            Ok(FileHeaderData::Null)
        }
    }

    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError> {
        let mut s = Vec::<u8>::new();
        {
            let mut ser = Serializer::pretty(&mut s);
            data.serialize(&mut ser);
        }

        String::from_utf8(s).or(
            Err(ParserError::short("Cannot parse utf8 bytes",
                                   String::from("<not printable>"),
                                   0)))
    }

}

// TODO: This function must be able to return a parser error
fn visit_json(v: &Value) -> FileHeaderData {
    match v {
        &Value::Null             => FileHeaderData::Null,
        &Value::Bool(b)          => FileHeaderData::Bool(b),
        &Value::I64(i)           => FileHeaderData::Integer(i),
        &Value::U64(u)           => FileHeaderData::UInteger(u),
        &Value::F64(f)           => FileHeaderData::Float(f),
        &Value::String(ref s)        => FileHeaderData::Text(s.clone()),
        &Value::Array(ref vec)       => {
            FileHeaderData::Array {
                values: Box::new(vec.clone().into_iter().map(|i| visit_json(&i)).collect())
            }
        },
        &Value::Object(ref btree)    => {
            FileHeaderData::Map{
                keys: btree.clone().iter().map(|(k, v)|
                    FileHeaderData::Key {
                        name: k.clone(),
                        value: Box::new(visit_json(v)),
                    }
                ).collect()
            }
        }
    }
}

impl Serialize for FileHeaderData {

    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Ser
    {
        match self {
            &FileHeaderData::Null               => {
                let o : Option<bool> = None;
                o.serialize(ser)
            },
            &FileHeaderData::Bool(ref b)            => b.serialize(ser),
            &FileHeaderData::Integer(ref i)         => i.serialize(ser),
            &FileHeaderData::UInteger(ref u)        => u.serialize(ser),
            &FileHeaderData::Float(ref f)           => f.serialize(ser),
            &FileHeaderData::Text(ref s)            => (&s[..]).serialize(ser),
            &FileHeaderData::Array{values: ref vs}  => vs.serialize(ser),
            &FileHeaderData::Map{keys: ref ks}      => ks.serialize(ser),
            &FileHeaderData::Key{name: ref n, value: ref v}   => {
                let mut hm = HashMap::new();
                hm.insert(n, v);
                hm.serialize(ser)
            }
        }
    }

}
<commit_msg>JsonHeaderParser: Make spec optional<commit_after>use serde_json::{Value, from_str};
use serde_json::error::Result as R;
use serde_json::Serializer;
use serde::ser::Serialize;
use serde::ser::Serializer as Ser;

use std::collections::HashMap;
use std::io::stdout;

use super::super::parser::{FileHeaderParser, ParserError};
use super::super::file::{FileHeaderSpec, FileHeaderData};

pub struct JsonHeaderParser {
    spec: Option<FileHeaderSpec>,
}

impl JsonHeaderParser {

    pub fn new(spec: Option<FileHeaderSpec>) -> JsonHeaderParser {
        JsonHeaderParser {
            spec: spec
        }
    }

}

impl FileHeaderParser for JsonHeaderParser {

    fn read(&self, string: Option<String>)
        -> Result<FileHeaderData, ParserError>
    {
        if string.is_some() {
            let s = string.unwrap();
            debug!("Deserializing: {}", s);
            let fromstr : R<Value> = from_str(&s[..]);
            if let Ok(content) = fromstr {
                Ok(visit_json(&content))
            } else {
                Err(ParserError::short("Unknown JSON parser error", s.clone(), 0))
            }
        } else {
            Ok(FileHeaderData::Null)
        }
    }

    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError> {
        let mut s = Vec::<u8>::new();
        {
            let mut ser = Serializer::pretty(&mut s);
            data.serialize(&mut ser);
        }

        String::from_utf8(s).or(
            Err(ParserError::short("Cannot parse utf8 bytes",
                                   String::from("<not printable>"),
                                   0)))
    }

}

// TODO: This function must be able to return a parser error
fn visit_json(v: &Value) -> FileHeaderData {
    match v {
        &Value::Null             => FileHeaderData::Null,
        &Value::Bool(b)          => FileHeaderData::Bool(b),
        &Value::I64(i)           => FileHeaderData::Integer(i),
        &Value::U64(u)           => FileHeaderData::UInteger(u),
        &Value::F64(f)           => FileHeaderData::Float(f),
        &Value::String(ref s)        => FileHeaderData::Text(s.clone()),
        &Value::Array(ref vec)       => {
            FileHeaderData::Array {
                values: Box::new(vec.clone().into_iter().map(|i| visit_json(&i)).collect())
            }
        },
        &Value::Object(ref btree)    => {
            FileHeaderData::Map{
                keys: btree.clone().iter().map(|(k, v)|
                    FileHeaderData::Key {
                        name: k.clone(),
                        value: Box::new(visit_json(v)),
                    }
                ).collect()
            }
        }
    }
}

impl Serialize for FileHeaderData {

    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Ser
    {
        match self {
            &FileHeaderData::Null               => {
                let o : Option<bool> = None;
                o.serialize(ser)
            },
            &FileHeaderData::Bool(ref b)            => b.serialize(ser),
            &FileHeaderData::Integer(ref i)         => i.serialize(ser),
            &FileHeaderData::UInteger(ref u)        => u.serialize(ser),
            &FileHeaderData::Float(ref f)           => f.serialize(ser),
            &FileHeaderData::Text(ref s)            => (&s[..]).serialize(ser),
            &FileHeaderData::Array{values: ref vs}  => vs.serialize(ser),
            &FileHeaderData::Map{keys: ref ks}      => ks.serialize(ser),
            &FileHeaderData::Key{name: ref n, value: ref v}   => {
                let mut hm = HashMap::new();
                hm.insert(n, v);
                hm.serialize(ser)
            }
        }
    }

}
<|endoftext|>


<commit_before>use super::dimensions::*;

pub trait Projection<D: Dimension> {
    fn project(self, d: D) -> D::Value;
}

pub fn project<T, D: Dimension>(val: T, d: D) -> D::Value
    where T: Projection<D>
{

    val.project(d)
}

macro_rules! impl_project {
    ($dt:ty, $st:ident, $dim:pat, $code:block, $($ft:ty),*) => {$(
        impl Projection<$dt> for $ft {
            fn project($st, $dim: $dt) -> <$dt as Dimension>::Value $code
        }
    )*}
}

impl_project!(Null, self, _, {
    ()
}, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64);

impl_project!(Infinite, self, _, {
    self as f64
}, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32);

impl Projection<Infinite> for f64 {
    fn project(self, _: Infinite) -> f64 {
        self
    }
}

impl_project!(Continuous, self, _, {
    self as f64
}, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32);

impl Projection<Continuous> for f64 {
    fn project(self, _: Continuous) -> f64 {
        self
    }
}

impl_project!(Partition, self, d, {
    d.to_partition(&(self as f64))
}, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32);

impl Projection<Partition> for f64 {
    fn project(self, d: Partition) -> usize {
        d.to_partition(&self)
    }
}
<commit_msg>Change to project() interface<commit_after>use super::dimensions::*;

pub trait Projection<D: Dimension> {
    fn project(self, d: D) -> D::Value;
}

pub fn project<T, D: Dimension>(d: D, val: T) -> D::Value
    where T: Projection<D>
{
    val.project(d)
}

macro_rules! impl_project {
    ($dt:ty, $st:ident, $dim:pat, $code:block, $($ft:ty),*) => {$(
        impl Projection<$dt> for $ft {
            fn project($st, $dim: $dt) -> <$dt as Dimension>::Value $code
        }
    )*}
}

impl_project!(Null, self, _, {
    ()
}, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64);

impl_project!(Infinite, self, _, {
    self as f64
}, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32);

impl Projection<Infinite> for f64 {
    fn project(self, _: Infinite) -> f64 {
        self
    }
}

impl_project!(Continuous, self, _, {
    self as f64
}, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32);

impl Projection<Continuous> for f64 {
    fn project(self, _: Continuous) -> f64 {
        self
    }
}

impl_project!(Partition, self, d, {
    d.to_partition(&(self as f64))
}, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32);

impl Projection<Partition> for f64 {
    fn project(self, d: Partition) -> usize {
        d.to_partition(&self)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::marker::PhantomData;
use std::ops::{Add, Deref, DerefMut, Mul, Sub};

use graph::geometry::{AsPosition, Cross, Geometry, Normalize};
use graph::mesh::{Face, Mesh};
use graph::storage::{EdgeKey, FaceKey, VertexKey};
use graph::topology::EdgeView;

// TODO: Generalize this pairing of a ref to a mesh and a key for topology
//       within the mesh.

// NOTE: This code assumes that any keys for topological structures in the mesh
//       are valid (hence the `unwrap` calls), which is very important for
//       `Deref`. Topological mutations using views like `FaceView` are
//       dangerous if they do not consume `self`. If these views can be used to
//       mutate that data, then they can also invalidate these constraints and
//       cause panics.

pub type FaceRef<'a, G> = FaceView<&'a Mesh<G>, G>;
pub type FaceMut<'a, G> = FaceView<&'a mut Mesh<G>, G>;

#[derive(Clone, Copy)]
pub struct FaceView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    mesh: M,
    pub key: FaceKey,
    phantom: PhantomData<G>,
}

impl<M, G> FaceView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    pub(crate) fn new(mesh: M, face: FaceKey) -> Self {
        FaceView {
            mesh: mesh,
            key: face,
            phantom: PhantomData,
        }
    }

    pub fn edges(&self) -> EdgeCirculator<&Mesh<G>, G> {
        EdgeCirculator::new(self.with_mesh_ref())
    }

    pub fn faces(&self) -> FaceCirculator<&Mesh<G>, G> {
        FaceCirculator::new(self.with_mesh_ref())
    }

    // Resolve the `M` parameter to a concrete reference.
    fn with_mesh_ref(&self) -> FaceView<&Mesh<G>, G> {
        FaceView::new(self.mesh.as_ref(), self.key)
    }
}

impl<M, G> FaceView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
{
    pub fn faces_mut(&mut self) -> FaceCirculator<&mut Mesh<G>, G> {
        FaceCirculator::new(self.with_mesh_mut())
    }

    // Resolve the `M` parameter to a concrete reference.
    fn with_mesh_mut(&mut self) -> FaceView<&mut Mesh<G>, G> {
        FaceView::new(self.mesh.as_mut(), self.key)
    }
}

// The elaborate type constraints state that positions stored in the vertex
// geometry can be used to compute a normal of a face using vector subtraction,
// cross product, normalization, vector addition, and vector scaling.
#[cfg_attr(rustfmt, rustfmt_skip)]
impl<M, G> FaceView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
    G::Vertex: AsPosition + Clone,
    // Constraints on the vertex geometry when converted to a position:
    //
    // 1. Supports cloning.
    // 2. Supports subtraction with itself.
    // 3. Supports addition with the output of multiplication with `f64` of the
    //    cross product of subtraction with itself.
    // 4. The output of the above addition is itself.
    <G::Vertex as AsPosition>::Target: Add<<<<<G::Vertex as AsPosition>::Target as Sub>::Output as Cross>::Output as Mul<f64>>::Output, Output = <G::Vertex as AsPosition>::Target> + Clone + Sub,
    // Constraints on the output of subtraction of vertex geometry when
    // converted to a position:
    //
    // 1. Supports the cross product.
    <<G::Vertex as AsPosition>::Target as Sub>::Output: Cross,
    // Constraints on the output of the cross product of subtraction of vertex
    // geometry when converted to a position:
    //
    // 1. Supports multiplication with `f64` and normalization.
    <<<G::Vertex as AsPosition>::Target as Sub>::Output as Cross>::Output: Mul<f64> + Normalize,
    // Constraints on the output of multiplication with `f64` of the cross
    // product of subtraction of vertex geometry when converted to a position:
    //
    // 1. Supports cloning.
    <<<<G::Vertex as AsPosition>::Target as Sub>::Output as Cross>::Output as Mul<f64>>::Output: Clone,
{
    pub fn extrude(self, distance: f64) -> Result<Self, ()> {
        // Collect all the vertex keys of the face along with their translated
        // geometries.
        let geometry = self.compute_extrusion_geometry(distance)?;
        // Begin topological mutations, starting by removing the originating
        // face. These mutations invalidate the key used by the `FaceView`, so
        // destructure `self` to avoid its reuse.
        let FaceView { mut mesh, key, .. } = self;
        mesh.as_mut().remove_face(key).unwrap();
        // Use the keys for the existing vertices and the translated geometries
        // to construct the extruded face and its connective faces.
        let extrusion = {
            let mesh = mesh.as_mut();
            let vertices = geometry.into_iter()
                .map(|vertex| (vertex.0, mesh.insert_vertex(vertex.1))).collect::<Vec<_>>();
            let edges = vertices.iter().enumerate().map(|(index, &(_, a))| {
                let b = vertices[(index + 1) % vertices.len()].1;
                // TODO: Copy the geometry of the edges in the originating face.
                mesh.insert_edge((a, b), G::Edge::default()).unwrap()
            }).collect::<Vec<_>>();
            // TODO: Copy the geometry of the originating face.
            let extrusion = mesh.insert_face(&edges, G::Face::default()).unwrap();
            for index in 0..vertices.len() {
                let (a, b) = vertices[index];
                let (d, c) = vertices[(index + 1) % vertices.len()];
                let ab = mesh.insert_edge((a, b), G::Edge::default()).unwrap();
                let bc = mesh.insert_edge((b, c), G::Edge::default()).unwrap();
                let cd = mesh.insert_edge((c, d), G::Edge::default()).unwrap();
                let da = mesh.insert_edge((d, a), G::Edge::default()).unwrap();
                let ca = mesh.insert_edge((c, a), G::Edge::default()).unwrap(); // Diagonal.
                let ac = mesh.insert_edge((a, c), G::Edge::default()).unwrap(); // Diagonal.
                mesh.insert_face(&[ab, bc, ca], G::Face::default()).unwrap();
                mesh.insert_face(&[ac, cd, da], G::Face::default()).unwrap();
            }
            extrusion
        };
        Ok(FaceView::new(mesh, extrusion))
    }

    fn compute_extrusion_geometry(&self, distance: f64) -> Result<Vec<(VertexKey, G::Vertex)>, ()> {
        let mesh = self.mesh.as_ref();
        let edges = self.edges().collect::<Vec<_>>();
        if edges.len() < 3 {
            return Err(());
        }
        let (a, b, c) = (
            mesh.vertices.get(&edges[0].vertex).unwrap(),
            mesh.vertices.get(&edges[1].vertex).unwrap(),
            mesh.vertices.get(&edges[2].vertex).unwrap(),
        );
        let ab = a.geometry.as_position().clone() - b.geometry.as_position().clone();
        let bc = b.geometry.as_position().clone() - c.geometry.as_position().clone();
        let translation = ab.cross(bc).normalize() * distance;
        Ok(edges.into_iter().map(|edge| {
            let mut geometry = mesh.vertices.get(&edge.vertex).unwrap().geometry.clone();
            *geometry.as_position_mut() = geometry.as_position().clone() + translation.clone();
            (edge.vertex, geometry)
        }).collect::<Vec<_>>())
    }
}

impl<M, G> AsRef<FaceView<M, G>> for FaceView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    fn as_ref(&self) -> &FaceView<M, G> {
        self
    }
}

impl<M, G> AsMut<FaceView<M, G>> for FaceView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
{
    fn as_mut(&mut self) -> &mut FaceView<M, G> {
        self
    }
}

impl<M, G> Deref for FaceView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    type Target = Face<G::Face>;

    fn deref(&self) -> &Self::Target {
        self.mesh.as_ref().faces.get(&self.key).unwrap()
    }
}

impl<M, G> DerefMut for FaceView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.mesh.as_mut().faces.get_mut(&self.key).unwrap()
    }
}

pub struct EdgeCirculator<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    face: FaceView<M, G>,
    edge: Option<EdgeKey>,
    breadcrumbs: HashSet<EdgeKey>,
}

impl<M, G> EdgeCirculator<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    fn new(face: FaceView<M, G>) -> Self {
        let edge = face.edge;
        EdgeCirculator {
            face: face,
            edge: Some(edge),
            breadcrumbs: HashSet::with_capacity(3),
        }
    }

    fn next(&mut self) -> Option<EdgeKey> {
        let mesh = self.face.mesh.as_ref();
        if let Some((key, edge)) = self.edge.map(|edge| (edge, mesh.edges.get(&edge).unwrap())) {
            if self.breadcrumbs.contains(&key) {
                return None;
            }
            self.breadcrumbs.insert(key);
            self.edge = edge.next;
            Some(key)
        }
        else {
            None
        }
    }
}

impl<'a, G> Iterator for EdgeCirculator<&'a Mesh<G>, G>
where
    G: Geometry,
{
    type Item = EdgeView<&'a Mesh<G>, G>;

    fn next(&mut self) -> Option<Self::Item> {
        <EdgeCirculator<_, _>>::next(self).map(|edge| EdgeView::new(self.face.mesh, edge))
    }
}

pub struct FaceCirculator<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    face: FaceView<M, G>,
    edge: Option<EdgeKey>,
    breadcrumbs: HashSet<EdgeKey>,
}

impl<M, G> FaceCirculator<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    fn new(face: FaceView<M, G>) -> Self {
        let edge = face.edge;
        FaceCirculator {
            face: face,
            edge: Some(edge),
            breadcrumbs: HashSet::with_capacity(3),
        }
    }

    fn next(&mut self) -> Option<FaceKey> {
        let mesh = self.face.mesh.as_ref();
        while let Some((key, edge)) = self.edge.map(|edge| (edge, mesh.edges.get(&edge).unwrap())) {
            if self.breadcrumbs.contains(&key) {
                return None;
            }
            self.breadcrumbs.insert(key);
            self.edge = edge.next;
            if let Some(face) = edge.opposite
                .map(|opposite| mesh.edges.get(&opposite).unwrap())
                .and_then(|opposite| opposite.face)
            {
                return Some(face);
            }
            else {
                continue;
            }
        }
        None
    }
}

impl<'a, G> Iterator for FaceCirculator<&'a Mesh<G>, G>
where
    G: Geometry,
{
    type Item = FaceView<&'a Mesh<G>, G>;

    fn next(&mut self) -> Option<Self::Item> {
        <FaceCirculator<_, _>>::next(self).map(|face| FaceView::new(self.face.mesh, face))
    }
}

impl<'a, G> Iterator for FaceCirculator<&'a mut Mesh<G>, G>
where
    G: 'a + Geometry,
{
    // TODO: One way to "unify" the output types of this iterator is to
    //       introduce an `OrphanFaceView` that holds a reference to the
    //       geometry but not the mesh. Code working with these structures
    //       would look nearly the same.
    //
    // This cannot be a `FaceView`, because that would alias the mutable
    // reference to the mesh. Instead, yield the key and a mutable reference to
    // the geometry data.
    type Item = (FaceKey, &'a mut G::Face);

    fn next(&mut self) -> Option<Self::Item> {
        <FaceCirculator<_, _>>::next(self).map(|face| {
            let geometry = {
                unsafe {
                    use std::mem;

                    // There is no way to bind the anonymous lifetime of this
                    // function to `Self::Item`. This is problematic for the
                    // call to `get_mut`, which requires autoref. However, this
                    // should be safe, because the use of this iterator
                    // requires a mutable borrow of the source mesh with
                    // lifetime `'a`. Therefore, the (disjoint) geometry data
                    // within the mesh should also be valid over the lifetime
                    // '`a'.
                    let face = mem::transmute::<_, &'a mut Face<G::Face>>(
                        self.face.mesh.faces.get_mut(&face).unwrap(),
                    );
                    &mut face.geometry
                }
            };
            (face, geometry)
        })
    }
}

#[cfg(test)]
mod tests {
    use r32;
    use generate::*;
    use graph::*;

    #[test]
    fn circulate_over_edges() {
        let mesh = sphere::UVSphere::<f32>::with_unit_radius(3, 2)
            .spatial_polygons() // 6 triangles, 18 vertices.
            .ordered::<(r32, r32, r32)>()
            .triangulate()
            .collect::<Mesh<(r32, r32, r32)>>();
        // TODO: Provide a way to get a key for the faces in the mesh. Using
        //       `default` only works if the initial face has not been removed.
        let face = mesh.face(FaceKey::default()).unwrap();

        // All faces should be triangles and should have three edges.
        assert_eq!(3, face.edges().count());
    }

    #[test]
    fn circulate_over_faces() {
        let mesh = sphere::UVSphere::<f32>::with_unit_radius(3, 2)
            .spatial_polygons() // 6 triangles, 18 vertices.
            .ordered::<(r32, r32, r32)>()
            .triangulate()
            .collect::<Mesh<(r32, r32, r32)>>();
        // TODO: Provide a way to get a key for the faces in the mesh. Using
        //       `default` only works if the initial face has not been removed.
        let face = mesh.face(FaceKey::default()).unwrap();

        // No matter which face is selected, it should have three neighbors.
        assert_eq!(3, face.faces().count());
    }
}
<commit_msg>Rename `compute_extrusion_geometry` to `extrusion_geometry`.<commit_after>use std::collections::HashSet;
use std::marker::PhantomData;
use std::ops::{Add, Deref, DerefMut, Mul, Sub};

use graph::geometry::{AsPosition, Cross, Geometry, Normalize};
use graph::mesh::{Face, Mesh};
use graph::storage::{EdgeKey, FaceKey, VertexKey};
use graph::topology::EdgeView;

// TODO: Generalize this pairing of a ref to a mesh and a key for topology
//       within the mesh.

// NOTE: This code assumes that any keys for topological structures in the mesh
//       are valid (hence the `unwrap` calls), which is very important for
//       `Deref`. Topological mutations using views like `FaceView` are
//       dangerous if they do not consume `self`. If these views can be used to
//       mutate that data, then they can also invalidate these constraints and
//       cause panics.

pub type FaceRef<'a, G> = FaceView<&'a Mesh<G>, G>;
pub type FaceMut<'a, G> = FaceView<&'a mut Mesh<G>, G>;

#[derive(Clone, Copy)]
pub struct FaceView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    mesh: M,
    pub key: FaceKey,
    phantom: PhantomData<G>,
}

impl<M, G> FaceView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    pub(crate) fn new(mesh: M, face: FaceKey) -> Self {
        FaceView {
            mesh: mesh,
            key: face,
            phantom: PhantomData,
        }
    }

    pub fn edges(&self) -> EdgeCirculator<&Mesh<G>, G> {
        EdgeCirculator::new(self.with_mesh_ref())
    }

    pub fn faces(&self) -> FaceCirculator<&Mesh<G>, G> {
        FaceCirculator::new(self.with_mesh_ref())
    }

    // Resolve the `M` parameter to a concrete reference.
    fn with_mesh_ref(&self) -> FaceView<&Mesh<G>, G> {
        FaceView::new(self.mesh.as_ref(), self.key)
    }
}

impl<M, G> FaceView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
{
    pub fn faces_mut(&mut self) -> FaceCirculator<&mut Mesh<G>, G> {
        FaceCirculator::new(self.with_mesh_mut())
    }

    // Resolve the `M` parameter to a concrete reference.
    fn with_mesh_mut(&mut self) -> FaceView<&mut Mesh<G>, G> {
        FaceView::new(self.mesh.as_mut(), self.key)
    }
}

// The elaborate type constraints state that positions stored in the vertex
// geometry can be used to compute a normal of a face using vector subtraction,
// cross product, normalization, vector addition, and vector scaling.
#[cfg_attr(rustfmt, rustfmt_skip)]
impl<M, G> FaceView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
    G::Vertex: AsPosition + Clone,
    // Constraints on the vertex geometry when converted to a position:
    //
    // 1. Supports cloning.
    // 2. Supports subtraction with itself.
    // 3. Supports addition with the output of multiplication with `f64` of the
    //    cross product of subtraction with itself.
    // 4. The output of the above addition is itself.
    <G::Vertex as AsPosition>::Target: Add<<<<<G::Vertex as AsPosition>::Target as Sub>::Output as Cross>::Output as Mul<f64>>::Output, Output = <G::Vertex as AsPosition>::Target> + Clone + Sub,
    // Constraints on the output of subtraction of vertex geometry when
    // converted to a position:
    //
    // 1. Supports the cross product.
    <<G::Vertex as AsPosition>::Target as Sub>::Output: Cross,
    // Constraints on the output of the cross product of subtraction of vertex
    // geometry when converted to a position:
    //
    // 1. Supports multiplication with `f64` and normalization.
    <<<G::Vertex as AsPosition>::Target as Sub>::Output as Cross>::Output: Mul<f64> + Normalize,
    // Constraints on the output of multiplication with `f64` of the cross
    // product of subtraction of vertex geometry when converted to a position:
    //
    // 1. Supports cloning.
    <<<<G::Vertex as AsPosition>::Target as Sub>::Output as Cross>::Output as Mul<f64>>::Output: Clone,
{
    pub fn extrude(self, distance: f64) -> Result<Self, ()> {
        // Collect all the vertex keys of the face along with their translated
        // geometries.
        let geometry = self.extrusion_geometry(distance)?;
        // Begin topological mutations, starting by removing the originating
        // face. These mutations invalidate the key used by the `FaceView`, so
        // destructure `self` to avoid its reuse.
        let FaceView { mut mesh, key, .. } = self;
        mesh.as_mut().remove_face(key).unwrap();
        // Use the keys for the existing vertices and the translated geometries
        // to construct the extruded face and its connective faces.
        let extrusion = {
            let mesh = mesh.as_mut();
            let vertices = geometry.into_iter()
                .map(|vertex| (vertex.0, mesh.insert_vertex(vertex.1))).collect::<Vec<_>>();
            let edges = vertices.iter().enumerate().map(|(index, &(_, a))| {
                let b = vertices[(index + 1) % vertices.len()].1;
                // TODO: Copy the geometry of the edges in the originating face.
                mesh.insert_edge((a, b), G::Edge::default()).unwrap()
            }).collect::<Vec<_>>();
            // TODO: Copy the geometry of the originating face.
            let extrusion = mesh.insert_face(&edges, G::Face::default()).unwrap();
            for index in 0..vertices.len() {
                let (a, b) = vertices[index];
                let (d, c) = vertices[(index + 1) % vertices.len()];
                let ab = mesh.insert_edge((a, b), G::Edge::default()).unwrap();
                let bc = mesh.insert_edge((b, c), G::Edge::default()).unwrap();
                let cd = mesh.insert_edge((c, d), G::Edge::default()).unwrap();
                let da = mesh.insert_edge((d, a), G::Edge::default()).unwrap();
                let ca = mesh.insert_edge((c, a), G::Edge::default()).unwrap(); // Diagonal.
                let ac = mesh.insert_edge((a, c), G::Edge::default()).unwrap(); // Diagonal.
                mesh.insert_face(&[ab, bc, ca], G::Face::default()).unwrap();
                mesh.insert_face(&[ac, cd, da], G::Face::default()).unwrap();
            }
            extrusion
        };
        Ok(FaceView::new(mesh, extrusion))
    }

    fn extrusion_geometry(&self, distance: f64) -> Result<Vec<(VertexKey, G::Vertex)>, ()> {
        let mesh = self.mesh.as_ref();
        let edges = self.edges().collect::<Vec<_>>();
        if edges.len() < 3 {
            return Err(());
        }
        let (a, b, c) = (
            mesh.vertices.get(&edges[0].vertex).unwrap(),
            mesh.vertices.get(&edges[1].vertex).unwrap(),
            mesh.vertices.get(&edges[2].vertex).unwrap(),
        );
        let ab = a.geometry.as_position().clone() - b.geometry.as_position().clone();
        let bc = b.geometry.as_position().clone() - c.geometry.as_position().clone();
        let translation = ab.cross(bc).normalize() * distance;
        Ok(edges.into_iter().map(|edge| {
            let mut geometry = mesh.vertices.get(&edge.vertex).unwrap().geometry.clone();
            *geometry.as_position_mut() = geometry.as_position().clone() + translation.clone();
            (edge.vertex, geometry)
        }).collect::<Vec<_>>())
    }
}

impl<M, G> AsRef<FaceView<M, G>> for FaceView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    fn as_ref(&self) -> &FaceView<M, G> {
        self
    }
}

impl<M, G> AsMut<FaceView<M, G>> for FaceView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
{
    fn as_mut(&mut self) -> &mut FaceView<M, G> {
        self
    }
}

impl<M, G> Deref for FaceView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    type Target = Face<G::Face>;

    fn deref(&self) -> &Self::Target {
        self.mesh.as_ref().faces.get(&self.key).unwrap()
    }
}

impl<M, G> DerefMut for FaceView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.mesh.as_mut().faces.get_mut(&self.key).unwrap()
    }
}

pub struct EdgeCirculator<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    face: FaceView<M, G>,
    edge: Option<EdgeKey>,
    breadcrumbs: HashSet<EdgeKey>,
}

impl<M, G> EdgeCirculator<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    fn new(face: FaceView<M, G>) -> Self {
        let edge = face.edge;
        EdgeCirculator {
            face: face,
            edge: Some(edge),
            breadcrumbs: HashSet::with_capacity(3),
        }
    }

    fn next(&mut self) -> Option<EdgeKey> {
        let mesh = self.face.mesh.as_ref();
        if let Some((key, edge)) = self.edge.map(|edge| (edge, mesh.edges.get(&edge).unwrap())) {
            if self.breadcrumbs.contains(&key) {
                return None;
            }
            self.breadcrumbs.insert(key);
            self.edge = edge.next;
            Some(key)
        }
        else {
            None
        }
    }
}

impl<'a, G> Iterator for EdgeCirculator<&'a Mesh<G>, G>
where
    G: Geometry,
{
    type Item = EdgeView<&'a Mesh<G>, G>;

    fn next(&mut self) -> Option<Self::Item> {
        <EdgeCirculator<_, _>>::next(self).map(|edge| EdgeView::new(self.face.mesh, edge))
    }
}

pub struct FaceCirculator<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    face: FaceView<M, G>,
    edge: Option<EdgeKey>,
    breadcrumbs: HashSet<EdgeKey>,
}

impl<M, G> FaceCirculator<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    fn new(face: FaceView<M, G>) -> Self {
        let edge = face.edge;
        FaceCirculator {
            face: face,
            edge: Some(edge),
            breadcrumbs: HashSet::with_capacity(3),
        }
    }

    fn next(&mut self) -> Option<FaceKey> {
        let mesh = self.face.mesh.as_ref();
        while let Some((key, edge)) = self.edge.map(|edge| (edge, mesh.edges.get(&edge).unwrap())) {
            if self.breadcrumbs.contains(&key) {
                return None;
            }
            self.breadcrumbs.insert(key);
            self.edge = edge.next;
            if let Some(face) = edge.opposite
                .map(|opposite| mesh.edges.get(&opposite).unwrap())
                .and_then(|opposite| opposite.face)
            {
                return Some(face);
            }
            else {
                continue;
            }
        }
        None
    }
}

impl<'a, G> Iterator for FaceCirculator<&'a Mesh<G>, G>
where
    G: Geometry,
{
    type Item = FaceView<&'a Mesh<G>, G>;

    fn next(&mut self) -> Option<Self::Item> {
        <FaceCirculator<_, _>>::next(self).map(|face| FaceView::new(self.face.mesh, face))
    }
}

impl<'a, G> Iterator for FaceCirculator<&'a mut Mesh<G>, G>
where
    G: 'a + Geometry,
{
    // TODO: One way to "unify" the output types of this iterator is to
    //       introduce an `OrphanFaceView` that holds a reference to the
    //       geometry but not the mesh. Code working with these structures
    //       would look nearly the same.
    //
    // This cannot be a `FaceView`, because that would alias the mutable
    // reference to the mesh. Instead, yield the key and a mutable reference to
    // the geometry data.
    type Item = (FaceKey, &'a mut G::Face);

    fn next(&mut self) -> Option<Self::Item> {
        <FaceCirculator<_, _>>::next(self).map(|face| {
            let geometry = {
                unsafe {
                    use std::mem;

                    // There is no way to bind the anonymous lifetime of this
                    // function to `Self::Item`. This is problematic for the
                    // call to `get_mut`, which requires autoref. However, this
                    // should be safe, because the use of this iterator
                    // requires a mutable borrow of the source mesh with
                    // lifetime `'a`. Therefore, the (disjoint) geometry data
                    // within the mesh should also be valid over the lifetime
                    // '`a'.
                    let face = mem::transmute::<_, &'a mut Face<G::Face>>(
                        self.face.mesh.faces.get_mut(&face).unwrap(),
                    );
                    &mut face.geometry
                }
            };
            (face, geometry)
        })
    }
}

#[cfg(test)]
mod tests {
    use r32;
    use generate::*;
    use graph::*;

    #[test]
    fn circulate_over_edges() {
        let mesh = sphere::UVSphere::<f32>::with_unit_radius(3, 2)
            .spatial_polygons() // 6 triangles, 18 vertices.
            .ordered::<(r32, r32, r32)>()
            .triangulate()
            .collect::<Mesh<(r32, r32, r32)>>();
        // TODO: Provide a way to get a key for the faces in the mesh. Using
        //       `default` only works if the initial face has not been removed.
        let face = mesh.face(FaceKey::default()).unwrap();

        // All faces should be triangles and should have three edges.
        assert_eq!(3, face.edges().count());
    }

    #[test]
    fn circulate_over_faces() {
        let mesh = sphere::UVSphere::<f32>::with_unit_radius(3, 2)
            .spatial_polygons() // 6 triangles, 18 vertices.
            .ordered::<(r32, r32, r32)>()
            .triangulate()
            .collect::<Mesh<(r32, r32, r32)>>();
        // TODO: Provide a way to get a key for the faces in the mesh. Using
        //       `default` only works if the initial face has not been removed.
        let face = mesh.face(FaceKey::default()).unwrap();

        // No matter which face is selected, it should have three neighbors.
        assert_eq!(3, face.faces().count());
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
extern crate quickcheck;
extern crate fail;
extern crate rand;
extern crate sled;
extern crate pagecache;

use std::collections::{BTreeMap, HashSet};
use std::sync::Mutex;

use quickcheck::{Arbitrary, Gen, QuickCheck, StdGen};

use sled::*;

#[derive(Debug, Clone)]
enum Op {
    Set,
    Del(u8),
    Restart,
    FailPoint(&'static str),
}

use Op::*;

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Op {
        let fail_points = vec![
            "initial allocation",
            "initial allocation post",
            "zero segment",
            "zero segment post",
            "zero garbage segment",
            "zero garbage segment post",
            //B"buffer write",
            //B"buffer write post",
            "write_config bytes",
            "write_config crc",
            "write_config post",
            "trailer write",
            "trailer write post",
            "snap write",
            "snap write len",
            "snap write crc",
            "snap write post",
            "snap write mv",
            "snap write mv post",
            "snap write rm old",
        ];

        if g.gen_weighted_bool(100) {
            return FailPoint((*g.choose(&fail_points).unwrap()));
        }

        if g.gen_weighted_bool(10) {
            return Restart;
        }

        let choice = g.gen_range(0, 2);

        match choice {
            0 => Set,
            1 => Del(g.gen::<u8>()),
            _ => panic!("impossible choice"),
        }
    }
}

fn v(b: &Vec<u8>) -> u16 {
    assert_eq!(b.len(), 2);
    ((b[0] as u16) << 8) + b[1] as u16
}

fn prop_tree_crashes_nicely(ops: Vec<Op>) -> bool {
    lazy_static! {
        // forces quickcheck to run one thread at a time
        static ref M: Mutex<()> = Mutex::new(());
    }

    let _lock = M.lock().unwrap();

    // clear all failpoints that may be left over from the last run
    fail::teardown();

    let config = ConfigBuilder::new()
        .temporary(true)
        .snapshot_after_ops(1)
        .flush_every_ms(None) // FIXME also do this with Some(1)
        .io_buf_size(300)
        .min_items_per_segment(1)
        .blink_fanout(2) // smol pages for smol buffers
        .cache_capacity(40)
        .build();

    let mut tree = sled::Tree::start(config.clone()).unwrap();
    let mut reference = BTreeMap::new();
    let mut fail_points = HashSet::new();

    macro_rules! restart {
        () => {
            drop(tree);
            let tree_res = sled::Tree::start(config.clone());
            if let Err(ref e) = tree_res {
                if e == &Error::FailPoint {
                    return true;
                }

                println!("could not start database: {}", e);
                return false;
            }

            tree = tree_res.unwrap();

            let tree_iter = tree.iter().map(|res| {
                let (ref tk, ref tv) = res.unwrap();
                (v(tk), v(tv))
            });
            let ref_iter = reference.iter().map(|(ref rk, ref rv)| (**rk, **rv));
            for (t, r) in tree_iter.zip(ref_iter) {
                if t != r {
                    println!("tree verification failed: expected {:?} got {:?}", r, t);
                    return false;
                }
            }
        }
    }

    macro_rules! fp_crash {
        ($e:expr) => {
            match $e {
                Ok(thing) => thing,
                Err(Error::FailPoint) => {
                    fail::teardown();
                    restart!();
                    continue;
                }
                other => {
                    println!("got non-failpoint err: {:?}", other);
                    return false;
                },
            }
        }
    }

    // we always increase set_counter because
    let mut set_counter = 0u16;

    for op in ops.into_iter() {
        match op {
            Set => {
                let hi = (set_counter >> 8) as u8;
                let lo = set_counter as u8;
                fp_crash!(tree.set(vec![hi, lo], vec![hi, lo]));
                tree.flush().unwrap();
                reference.insert(set_counter, set_counter);
                set_counter += 1;
            }
            Del(k) => {
                fp_crash!(tree.del(&*vec![0, k]));
                tree.flush().unwrap();
                reference.remove(&(k as u16));
            }
            Restart => {
                restart!();
            }
            FailPoint(fp) => {
                fail_points.insert(fp.clone());
                fail::cfg(&*fp, "return").unwrap();
            }
        }
    }

    fail::teardown();

    true
}

#[test]
fn quickcheck_tree_with_failpoints() {
    // use fewer tests for travis OSX builds that stall out all the time
    #[cfg(target_os = "macos")]
    let n_tests = 50;

    #[cfg(not(target_os = "macos"))]
    let n_tests = 100;

    QuickCheck::new()
        .gen(StdGen::new(rand::thread_rng(), 100))
        .tests(n_tests)
        .max_tests(10000)
        .quickcheck(prop_tree_crashes_nicely as fn(Vec<Op>) -> bool);
}

#[test]
fn failpoints_bug_1() {
    // postmortem 1: model did not account for proper reasons to fail to start
    assert!(prop_tree_crashes_nicely(vec![FailPoint("snap write"), Restart]));
}

#[test]
fn failpoints_bug_2() {
    // postmortem 1: the system was assuming the happy path across failpoints
    assert!(prop_tree_crashes_nicely(
        vec![FailPoint("buffer write post"), Set, Set, Restart],
    ))
}

#[test]
fn failpoints_bug_3() {
    // postmortem 1: this was a regression that happened because we
    // chose to eat errors about advancing snapshots, which trigger
    // log flushes. We should not trigger flushes from snapshots,
    // but first we need to make sure we are better about detecting
    // tears, by not also using 0 as a failed flush signifier.
    assert!(prop_tree_crashes_nicely(vec![
        Set,
        Set,
        Set,
        Set,
        FailPoint("trailer write"),
        Set,
        Set,
        Set,
        Set,
        Restart,
    ]))
}
<commit_msg>improve failpoint test to include concept of uncertain state<commit_after>#[macro_use]
extern crate lazy_static;
extern crate quickcheck;
extern crate fail;
extern crate rand;
extern crate sled;
extern crate pagecache;

use std::collections::{BTreeMap, HashSet};
use std::sync::Mutex;

use quickcheck::{Arbitrary, Gen, QuickCheck, StdGen};

use sled::*;

#[derive(Debug, Clone)]
enum Op {
    Set,
    Del(u8),
    Restart,
    FailPoint(&'static str),
}

use Op::*;

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Op {
        let fail_points = vec![
            "initial allocation",
            "initial allocation post",
            "zero segment",
            "zero segment post",
            "zero garbage segment",
            "zero garbage segment post",
            "buffer write",
            "buffer write post",
            "write_config bytes",
            "write_config crc",
            "write_config post",
            "trailer write",
            "trailer write post",
            "snap write",
            "snap write len",
            "snap write crc",
            "snap write post",
            "snap write mv",
            "snap write mv post",
            "snap write rm old",
        ];

        if g.gen_weighted_bool(30) {
            return FailPoint((*g.choose(&fail_points).unwrap()));
        }

        if g.gen_weighted_bool(10) {
            return Restart;
        }

        let choice = g.gen_range(0, 2);

        match choice {
            0 => Set,
            1 => Del(g.gen::<u8>()),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<Iterator<Item = Op>> {
        match *self {
            Op::Del(ref lid) if *lid > 0 => Box::new(
                vec![Op::Del(*lid - 1)].into_iter(),
            ),
            _ => Box::new(vec![].into_iter()),
        }
    }
}

fn v(b: &Vec<u8>) -> u16 {
    assert_eq!(b.len(), 2);
    ((b[0] as u16) << 8) + b[1] as u16
}

fn prop_tree_crashes_nicely(ops: Vec<Op>) -> bool {
    lazy_static! {
        // forces quickcheck to run one thread at a time
        static ref M: Mutex<()> = Mutex::new(());
    }

    let _lock = M.lock().unwrap();

    // clear all failpoints that may be left over from the last run
    fail::teardown();

    let config = ConfigBuilder::new()
        .temporary(true)
        .snapshot_after_ops(1)
        .flush_every_ms(None) // FIXME also do this with Some(1)
        .io_buf_size(300)
        .min_items_per_segment(1)
        .blink_fanout(2) // smol pages for smol buffers
        .cache_capacity(40)
        .build();

    let mut tree = sled::Tree::start(config.clone()).unwrap();
    let mut reference = BTreeMap::new();
    let mut fail_points = HashSet::new();

    macro_rules! restart {
        () => {
            drop(tree);
            let tree_res = sled::Tree::start(config.clone());
            if let Err(ref e) = tree_res {
                if e == &Error::FailPoint {
                    return true;
                }

                println!("could not start database: {}", e);
                return false;
            }

            tree = tree_res.unwrap();

            let tree_iter = tree.iter().map(|res| {
                let (ref tk, _) = res.unwrap();
                v(tk)
            });
            let mut ref_iter = reference.iter().map(|(ref rk, ref rv)| (**rk, **rv));
            for t in tree_iter {
                // make sure the tree value is in there
                while let Some((r, (_rv, certainty))) = ref_iter.next() {
                    if certainty {
                        // tree MUST match reference if we have a certain reference
                        if t != r {
                            return false;
                        }
                        break;
                    } else {
                        // we have an uncertain reference, so we iterate through
                        // it and guarantee the reference is never higher than
                        // the tree value.
                        if t == r {
                            // we can move on to the next tree item
                            break;
                        }

                        if r > t {
                            // we have a bug, the reference iterator should always be <= tree
                            println!("tree verification failed: expected {:?} got {:?}", r, t);
                            return false;
                        }

                        // we are iterating through the reference until we have a certain
                        // item or an item that matches the tree's real item anyway
                    }
                }
            }
        }
    }

    macro_rules! fp_crash {
        ($e:expr) => {
            match $e {
                Ok(thing) => thing,
                Err(Error::FailPoint) => {
                    fail::teardown();
                    restart!();
                    continue;
                }
                other => {
                    println!("got non-failpoint err: {:?}", other);
                    return false;
                },
            }
        }
    }

    // we always increase set_counter because
    let mut set_counter = 0u16;

    for op in ops.into_iter() {
        match op {
            Set => {
                let hi = (set_counter >> 8) as u8;
                let lo = set_counter as u8;

                // insert false certainty until it fully completes
                reference.insert(set_counter, (set_counter, false));

                fp_crash!(tree.set(vec![hi, lo], vec![hi, lo]));

                // make sure we keep the disk and reference in-sync
                // maybe in the future put pending things in their own
                // reference and have a Flush op that syncs them.
                // just because the set above didn't hit a failpoint,
                // it doesn't mean this flush won't hit one, so we
                // also use the fp_crash macro here for handling it.
                fp_crash!(tree.flush());

                // now we should be certain the thing is in there, set certainty to true
                reference.insert(set_counter, (set_counter, true));

                set_counter += 1;
            }
            Del(k) => {
                // insert false certainty before completes
                reference.insert(k as u16, (k as u16, false));

                fp_crash!(tree.del(&*vec![0, k]));
                tree.flush().unwrap();

                reference.remove(&(k as u16));
            }
            Restart => {
                restart!();
            }
            FailPoint(fp) => {
                fail_points.insert(fp.clone());
                fail::cfg(&*fp, "return").unwrap();
            }
        }
    }

    fail::teardown();

    true
}

#[test]
fn quickcheck_tree_with_failpoints() {
    // use fewer tests for travis OSX builds that stall out all the time
    #[cfg(target_os = "macos")]
    let n_tests = 50;

    #[cfg(not(target_os = "macos"))]
    let n_tests = 100;

    QuickCheck::new()
        .gen(StdGen::new(rand::thread_rng(), 100))
        .tests(n_tests)
        .max_tests(10000)
        .quickcheck(prop_tree_crashes_nicely as fn(Vec<Op>) -> bool);
}

#[test]
fn failpoints_bug_1() {
    // postmortem 1: model did not account for proper reasons to fail to start
    assert!(prop_tree_crashes_nicely(vec![FailPoint("snap write"), Restart]));
}

#[test]
fn failpoints_bug_2() {
    // postmortem 1: the system was assuming the happy path across failpoints
    assert!(prop_tree_crashes_nicely(
        vec![FailPoint("buffer write post"), Set, Set, Restart],
    ))
}

#[test]
fn failpoints_bug_3() {
    // postmortem 1: this was a regression that happened because we
    // chose to eat errors about advancing snapshots, which trigger
    // log flushes. We should not trigger flushes from snapshots,
    // but first we need to make sure we are better about detecting
    // tears, by not also using 0 as a failed flush signifier.
    assert!(prop_tree_crashes_nicely(vec![
        Set,
        Set,
        Set,
        Set,
        FailPoint("trailer write"),
        Set,
        Set,
        Set,
        Set,
        Restart,
    ]))
}

#[test]
fn failpoints_bug_4() {
    // postmortem 1: the test model was not properly accounting for
    // writes that may-or-may-not be present due to an error.
    assert!(prop_tree_crashes_nicely(
        vec![Set, FailPoint("snap write"), Del(0), Set, Restart],
    ))
}

#[test]
#[ignore]
fn failpoints_bug_5() {
    // postmortem 1:
    assert!(prop_tree_crashes_nicely(vec![
        Set,
        FailPoint("snap write mv post"),
        Set,
        FailPoint("snap write"),
        Set,
        Set,
        Set,
        Restart,
        FailPoint("zero segment"),
        Set,
        Set,
        Set,
        Restart,
    ]))
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

use serde_json::value::Value as Json;

use helpers::HelperDef;
use registry::Registry;
use context::{JsonTruthy, to_json};
use render::{Renderable, RenderContext, Helper};
use error::RenderError;

#[derive(Clone, Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper {
    fn call(&self, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
        let value = try!(h.param(0).ok_or_else(|| {
            RenderError::new("Param not found for helper \"each\"")
        }));

        let template = h.template();

        match template {
            Some(t) => {
                rc.promote_local_vars();
                let local_path_root = value.path_root().map(
                    |p| format!("{}/{}", rc.get_path(), p),
                );

                debug!("each value {:?}", value.value());
                let rendered = match (value.value().is_truthy(), value.value()) {
                    (true, &Json::Array(ref list)) => {
                        let len = list.len();
                        for i in 0..len {
                            let mut local_rc = rc.derive();
                            if let Some(ref p) = local_path_root {
                                local_rc.push_local_path_root(p.clone());
                            }

                            local_rc.set_local_var("@first".to_string(), to_json(&(i == 0usize)));
                            local_rc.set_local_var("@last".to_string(), to_json(&(i == len - 1)));
                            local_rc.set_local_var("@index".to_string(), to_json(&i));

                            if let Some(inner_path) = value.path() {
                                let new_path =
                                    format!("{}/{}/[{}]", local_rc.get_path(), inner_path, i);
                                debug!("each path {:?}", new_path);
                                local_rc.set_path(new_path.clone());
                            }

                            if let Some(block_param) = h.block_param() {
                                let mut map = BTreeMap::new();
                                map.insert(block_param.to_string(), to_json(&list[i]));
                                local_rc.push_block_context(&map)?;
                            }

                            try!(t.render(r, &mut local_rc));

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }

                            if local_path_root.is_some() {
                                local_rc.pop_local_path_root();
                            }
                        }
                        Ok(())
                    }
                    (true, &Json::Object(ref obj)) => {
                        let mut first: bool = true;
                        for k in obj.keys() {
                            let mut local_rc = rc.derive();
                            if let Some(ref p) = local_path_root {
                                local_rc.push_local_path_root(p.clone());
                            }
                            local_rc.set_local_var("@first".to_string(), to_json(&first));
                            if first {
                                first = false;
                            }

                            local_rc.set_local_var("@key".to_string(), to_json(k));

                            if let Some(inner_path) = value.path() {
                                let new_path =
                                    format!("{}/{}/[{}]", local_rc.get_path(), inner_path, k);
                                local_rc.set_path(new_path);
                            }

                            if let Some((bp_key, bp_val)) = h.block_param_pair() {
                                let mut map = BTreeMap::new();
                                map.insert(bp_key.to_string(), to_json(k));
                                map.insert(bp_val.to_string(), to_json(obj.get(k).unwrap()));
                                local_rc.push_block_context(&map)?;
                            }

                            try!(t.render(r, &mut local_rc));

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }

                            if local_path_root.is_some() {
                                local_rc.pop_local_path_root();
                            }
                        }

                        Ok(())
                    }
                    (false, _) => {
                        if let Some(else_template) = h.inverse() {
                            try!(else_template.render(r, rc));
                        }
                        Ok(())
                    }
                    _ => {
                        Err(RenderError::new(
                            format!("Param type is not iterable: {:?}", template),
                        ))
                    }
                };

                rc.demote_local_vars();
                rendered
            }
            None => Ok(()),
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use registry::Registry;
    use context::to_json;

    use std::collections::BTreeMap;
    use std::str::FromStr;
    use serde_json::value::Value as Json;

    #[test]
    fn test_each() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string(
                    "t0",
                    "{{#each this}}{{@first}}|{{@last}}|{{@index}}:{{this}}|{{/each}}",
                )
                .is_ok()
        );
        assert!(
            handlebars
                .register_template_string(
                    "t1",
                    "{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}",
                )
                .is_ok()
        );

        let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]);
        assert_eq!(
            r0.ok().unwrap(),
            "true|false|0:1|false|false|1:2|false|true|2:3|".to_string()
        );

        let mut m: BTreeMap<String, u16> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

    #[test]
    fn test_each_with_parent() {

        let json_str = r#"{"a":{"a":99,"c":[{"d":100},{"d":200}]}}"#;

        let data = Json::from_str(json_str).unwrap();
        // println!("data: {}", data);
        let mut handlebars = Registry::new();

        // previously, to access the parent in an each block,
        // a user would need to specify ../../b, as the path
        // that is computed includes the array index: ./a.c.[0]
        assert!(
            handlebars
                .register_template_string("t0", "{{#each a.c}} d={{d}} b={{../a.a}} {{/each}}")
                .is_ok()
        );

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), " d=100 b=99  d=200 b=99 ".to_string());
    }

    #[test]
    fn test_nested_each_with_parent() {

        let json_str = r#"{"a": [{"b": [{"d": 100}], "c": 200}]}"#;

        let data = Json::from_str(json_str).unwrap();
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string(
                    "t0",
                    "{{#each a}}{{#each b}}{{d}}:{{../c}}{{/each}}{{/each}}",
                )
                .is_ok()
        );

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), "100:200".to_string());
    }

    #[test]
    fn test_nested_each() {

        let json_str = r#"{"a": [{"b": true}], "b": [[1, 2, 3],[4, 5]]}"#;

        let data = Json::from_str(json_str).unwrap();

        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string(
                    "t0",
                    "{{#each b}}{{#if ../a}}{{#each this}}{{this}}{{/each}}{{/if}}{{/each}}",
                )
                .is_ok()
        );

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), "12345".to_string());
    }

    #[test]
    fn test_nested_array() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string("t0", "{{#each this.[0]}}{{this}}{{/each}}")
                .is_ok()
        );

        let r0 = handlebars.render("t0", &(vec![vec![1, 2, 3]]));

        assert_eq!(r0.ok().unwrap(), "123".to_string());
    }

    #[test]
    fn test_empty_key() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string("t0", "{{#each this}}{{@key}}-{{value}}\n{{/each}}")
                .is_ok()
        );

        let r0 = handlebars
            .render(
                "t0",
                &({
                      let mut rv = BTreeMap::new();
                      rv.insert("foo".to_owned(), {
                        let mut rv = BTreeMap::new();
                        rv.insert("value".to_owned(), "bar".to_owned());
                        rv
                    });
                      rv.insert("".to_owned(), {
                        let mut rv = BTreeMap::new();
                        rv.insert("value".to_owned(), "baz".to_owned());
                        rv
                    });
                      rv
                  }),
            )
            .unwrap();

        let mut r0_sp: Vec<_> = r0.split('\n').collect();
        r0_sp.sort();

        assert_eq!(r0_sp, vec!["", "-baz", "foo-bar"]);
    }

    #[test]
    fn test_each_else() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string("t0", "{{#each a}}1{{else}}empty{{/each}}")
                .is_ok()
        );
        let m1 =
            btreemap! {
            "a".to_string() => Vec::<String>::new(),
        };
        let r0 = handlebars.render("t0", &m1).unwrap();
        assert_eq!(r0, "empty");

        let m2 =
            btreemap!{
            "b".to_string() => Vec::<String>::new()
        };
        let r1 = handlebars.render("t0", &m2).unwrap();
        assert_eq!(r1, "empty");
    }

    #[test]
    fn test_block_param() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string("t0", "{{#each a as |i|}}{{i}}{{/each}}")
                .is_ok()
        );
        let m1 =
            btreemap! {
            "a".to_string() => vec![1,2,3,4,5]
        };
        let r0 = handlebars.render("t0", &m1).unwrap();
        assert_eq!(r0, "12345");
    }

    #[test]
    fn test_each_object_block_param() {
        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", "{{#each this as |k v|}}{{#with k as |inner_k|}}{{inner_k}}{{/with}}:{{v}}|{{/each}}").is_ok());

        let m =
            btreemap!{
            "ftp".to_string() => 21,
            "http".to_string() => 80
        };
        let r0 = handlebars.render("t0", &m);
        assert_eq!(r0.ok().unwrap(), "ftp:21|http:80|".to_string());
    }

    #[test]
    fn test_nested_each_with_path_ups() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string(
                    "t0",
                    "{{#each a.b}}{{#each c}}{{../../d}}{{/each}}{{/each}}",
                )
                .is_ok()
        );

        let data =
            btreemap! {
            "a".to_string() => to_json(&btreemap! {
                "b".to_string() => vec![btreemap!{"c".to_string() => vec![1]}]
            }),
            "d".to_string() => to_json(&1)
        };

        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "1".to_string());
    }

    #[test]
    fn test_nested_each_with_path_up_this() {
        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", "{{#each variant}}{{#each ../typearg}}{{#if @first}}template<{{/if}}{{this}}{{#if @last}}>{{else}},{{/if}}{{/each}}{{/each}}").is_ok());
        let data =
            btreemap! {
            "typearg".to_string() => vec!["T".to_string()],
            "variant".to_string() => vec!["1".to_string(), "2".to_string()]
        };
        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "template<T>template<T>".to_string());
    }
}
<commit_msg>(test) added test case for #173 and #174<commit_after>use std::collections::BTreeMap;

use serde_json::value::Value as Json;

use helpers::HelperDef;
use registry::Registry;
use context::{JsonTruthy, to_json};
use render::{Renderable, RenderContext, Helper};
use error::RenderError;

#[derive(Clone, Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper {
    fn call(&self, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
        let value = try!(h.param(0).ok_or_else(|| {
            RenderError::new("Param not found for helper \"each\"")
        }));

        let template = h.template();

        match template {
            Some(t) => {
                rc.promote_local_vars();
                let local_path_root = value.path_root().map(
                    |p| format!("{}/{}", rc.get_path(), p),
                );

                debug!("each value {:?}", value.value());
                let rendered = match (value.value().is_truthy(), value.value()) {
                    (true, &Json::Array(ref list)) => {
                        let len = list.len();
                        for i in 0..len {
                            let mut local_rc = rc.derive();
                            if let Some(ref p) = local_path_root {
                                local_rc.push_local_path_root(p.clone());
                            }

                            local_rc.set_local_var("@first".to_string(), to_json(&(i == 0usize)));
                            local_rc.set_local_var("@last".to_string(), to_json(&(i == len - 1)));
                            local_rc.set_local_var("@index".to_string(), to_json(&i));

                            if let Some(inner_path) = value.path() {
                                let new_path =
                                    format!("{}/{}/[{}]", local_rc.get_path(), inner_path, i);
                                debug!("each path {:?}", new_path);
                                local_rc.set_path(new_path.clone());
                            }

                            if let Some(block_param) = h.block_param() {
                                let mut map = BTreeMap::new();
                                map.insert(block_param.to_string(), to_json(&list[i]));
                                local_rc.push_block_context(&map)?;
                            }

                            try!(t.render(r, &mut local_rc));

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }

                            if local_path_root.is_some() {
                                local_rc.pop_local_path_root();
                            }
                        }
                        Ok(())
                    }
                    (true, &Json::Object(ref obj)) => {
                        let mut first: bool = true;
                        for k in obj.keys() {
                            let mut local_rc = rc.derive();
                            if let Some(ref p) = local_path_root {
                                local_rc.push_local_path_root(p.clone());
                            }
                            local_rc.set_local_var("@first".to_string(), to_json(&first));
                            if first {
                                first = false;
                            }

                            local_rc.set_local_var("@key".to_string(), to_json(k));

                            if let Some(inner_path) = value.path() {
                                let new_path =
                                    format!("{}/{}/[{}]", local_rc.get_path(), inner_path, k);
                                local_rc.set_path(new_path);
                            }

                            if let Some((bp_key, bp_val)) = h.block_param_pair() {
                                let mut map = BTreeMap::new();
                                map.insert(bp_key.to_string(), to_json(k));
                                map.insert(bp_val.to_string(), to_json(obj.get(k).unwrap()));
                                local_rc.push_block_context(&map)?;
                            }

                            try!(t.render(r, &mut local_rc));

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }

                            if local_path_root.is_some() {
                                local_rc.pop_local_path_root();
                            }
                        }

                        Ok(())
                    }
                    (false, _) => {
                        if let Some(else_template) = h.inverse() {
                            try!(else_template.render(r, rc));
                        }
                        Ok(())
                    }
                    _ => {
                        Err(RenderError::new(
                            format!("Param type is not iterable: {:?}", template),
                        ))
                    }
                };

                rc.demote_local_vars();
                rendered
            }
            None => Ok(()),
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use registry::Registry;
    use context::to_json;

    use std::collections::BTreeMap;
    use std::str::FromStr;
    use serde_json::value::Value as Json;

    #[test]
    fn test_each() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string(
                    "t0",
                    "{{#each this}}{{@first}}|{{@last}}|{{@index}}:{{this}}|{{/each}}",
                )
                .is_ok()
        );
        assert!(
            handlebars
                .register_template_string(
                    "t1",
                    "{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}",
                )
                .is_ok()
        );

        let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]);
        assert_eq!(
            r0.ok().unwrap(),
            "true|false|0:1|false|false|1:2|false|true|2:3|".to_string()
        );

        let mut m: BTreeMap<String, u16> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

    #[test]
    fn test_each_with_parent() {

        let json_str = r#"{"a":{"a":99,"c":[{"d":100},{"d":200}]}}"#;

        let data = Json::from_str(json_str).unwrap();
        // println!("data: {}", data);
        let mut handlebars = Registry::new();

        // previously, to access the parent in an each block,
        // a user would need to specify ../../b, as the path
        // that is computed includes the array index: ./a.c.[0]
        assert!(
            handlebars
                .register_template_string("t0", "{{#each a.c}} d={{d}} b={{../a.a}} {{/each}}")
                .is_ok()
        );

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), " d=100 b=99  d=200 b=99 ".to_string());
    }

    #[test]
    fn test_nested_each_with_parent() {

        let json_str = r#"{"a": [{"b": [{"d": 100}], "c": 200}]}"#;

        let data = Json::from_str(json_str).unwrap();
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string(
                    "t0",
                    "{{#each a}}{{#each b}}{{d}}:{{../c}}{{/each}}{{/each}}",
                )
                .is_ok()
        );

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), "100:200".to_string());
    }

    #[test]
    fn test_nested_each() {

        let json_str = r#"{"a": [{"b": true}], "b": [[1, 2, 3],[4, 5]]}"#;

        let data = Json::from_str(json_str).unwrap();

        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string(
                    "t0",
                    "{{#each b}}{{#if ../a}}{{#each this}}{{this}}{{/each}}{{/if}}{{/each}}",
                )
                .is_ok()
        );

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), "12345".to_string());
    }

    #[test]
    fn test_nested_array() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string("t0", "{{#each this.[0]}}{{this}}{{/each}}")
                .is_ok()
        );

        let r0 = handlebars.render("t0", &(vec![vec![1, 2, 3]]));

        assert_eq!(r0.ok().unwrap(), "123".to_string());
    }

    #[test]
    fn test_empty_key() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string("t0", "{{#each this}}{{@key}}-{{value}}\n{{/each}}")
                .is_ok()
        );

        let r0 = handlebars
            .render(
                "t0",
                &({
                      let mut rv = BTreeMap::new();
                      rv.insert("foo".to_owned(), {
                        let mut rv = BTreeMap::new();
                        rv.insert("value".to_owned(), "bar".to_owned());
                        rv
                    });
                      rv.insert("".to_owned(), {
                        let mut rv = BTreeMap::new();
                        rv.insert("value".to_owned(), "baz".to_owned());
                        rv
                    });
                      rv
                  }),
            )
            .unwrap();

        let mut r0_sp: Vec<_> = r0.split('\n').collect();
        r0_sp.sort();

        assert_eq!(r0_sp, vec!["", "-baz", "foo-bar"]);
    }

    #[test]
    fn test_each_else() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string("t0", "{{#each a}}1{{else}}empty{{/each}}")
                .is_ok()
        );
        let m1 =
            btreemap! {
            "a".to_string() => Vec::<String>::new(),
        };
        let r0 = handlebars.render("t0", &m1).unwrap();
        assert_eq!(r0, "empty");

        let m2 =
            btreemap!{
            "b".to_string() => Vec::<String>::new()
        };
        let r1 = handlebars.render("t0", &m2).unwrap();
        assert_eq!(r1, "empty");
    }

    #[test]
    fn test_block_param() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string("t0", "{{#each a as |i|}}{{i}}{{/each}}")
                .is_ok()
        );
        let m1 =
            btreemap! {
            "a".to_string() => vec![1,2,3,4,5]
        };
        let r0 = handlebars.render("t0", &m1).unwrap();
        assert_eq!(r0, "12345");
    }

    #[test]
    fn test_each_object_block_param() {
        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", "{{#each this as |k v|}}{{#with k as |inner_k|}}{{inner_k}}{{/with}}:{{v}}|{{/each}}").is_ok());

        let m =
            btreemap!{
            "ftp".to_string() => 21,
            "http".to_string() => 80
        };
        let r0 = handlebars.render("t0", &m);
        assert_eq!(r0.ok().unwrap(), "ftp:21|http:80|".to_string());
    }

    #[test]
    fn test_nested_each_with_path_ups() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string(
                    "t0",
                    "{{#each a.b}}{{#each c}}{{../../d}}{{/each}}{{/each}}",
                )
                .is_ok()
        );

        let data =
            btreemap! {
            "a".to_string() => to_json(&btreemap! {
                "b".to_string() => vec![btreemap!{"c".to_string() => vec![1]}]
            }),
            "d".to_string() => to_json(&1)
        };

        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "1".to_string());
    }

    #[test]
    fn test_nested_each_with_path_up_this() {
        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", "{{#each variant}}{{#each ../typearg}}{{#if @first}}template<{{/if}}{{this}}{{#if @last}}>{{else}},{{/if}}{{/each}}{{/each}}").is_ok());
        let data =
            btreemap! {
            "typearg".to_string() => vec!["T".to_string()],
            "variant".to_string() => vec!["1".to_string(), "2".to_string()]
        };
        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "template<T>template<T>".to_string());
    }

    #[test]
    fn test_key_iteration_with_unicode() {
        let mut handlebars = Registry::new();
        assert!(
            handlebars
                .register_template_string("t0", "{{#each this}}{{@key}}: {{this}}\n{{/each}}")
                .is_ok()
        );
        let data = json!({
            "normal": 1,
            "你好": 2,
            "#special key": 3,
            "😂": 4,
            "me.dot.key": 5
        });
        let r0 = handlebars.render("t0", &data).ok().unwrap();
        assert!(r0.contains("normal: 1"));
        assert!(r0.contains("你好: 2"));
        assert!(r0.contains("#special key: 3"));
        assert!(r0.contains("😂: 4"));
        assert!(r0.contains("me.dot.key: 5"));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// 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.

//! Utilities for working with packets, eg. checksumming.

use ip::IpNextHeaderProtocol;
use pnet_macros_support::types::u16be;

use std::net::{Ipv4Addr, Ipv6Addr};
use std::slice;
use std::u8;
use std::u16;
use std::convert::TryInto;

/// Convert a value to a byte array.
pub trait Octets {
    /// Output type - bytes array.
    type Output;

    /// Return a value as bytes (big-endian order).
    fn octets(&self) -> Self::Output;
}

impl Octets for u64 {
    type Output = [u8; 8];

    fn octets(&self) -> Self::Output {
        [(*self >> 56) as u8,
         (*self >> 48) as u8,
         (*self >> 40) as u8,
         (*self >> 32) as u8,
         (*self >> 24) as u8,
         (*self >> 16) as u8,
         (*self >> 8) as u8,
         *self as u8]
    }
}

impl Octets for u32 {
    type Output = [u8; 4];

    fn octets(&self) -> Self::Output {
        [(*self >> 24) as u8, (*self >> 16) as u8, (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u16 {
    type Output = [u8; 2];

    fn octets(&self) -> Self::Output {
        [(*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u8 {
    type Output = [u8; 1];

    fn octets(&self) -> Self::Output {
        [*self]
    }
}

/// Calculates a checksum. Used by ipv4 and icmp. The two bytes starting at `skipword * 2` will be
/// ignored. Supposed to be the checksum field, which is regarded as zero during calculation.
pub fn checksum(data: &[u8], skipword: usize) -> u16be {
    if data.len() == 0 { return 0 }
    let sum = sum_be_words(data, skipword);
    finalize_checksum(sum)
}

fn finalize_checksum(mut sum: u32) -> u16be {
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    !sum as u16
}

/// Calculate the checksum for a packet built on IPv4. Used by UDP and TCP.
pub fn ipv4_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: &Ipv4Addr,
                     destination: &Ipv4Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv4_word_sum(source);
    sum += ipv4_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv4_word_sum(ip: &Ipv4Addr) -> u32 {
    let octets = ip.octets();
    ((octets[0] as u32) << 8 | octets[1] as u32) + ((octets[2] as u32) << 8 | octets[3] as u32)
}

/// Calculate the checksum for a packet built on IPv6.
pub fn ipv6_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: &Ipv6Addr,
                     destination: &Ipv6Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv6_word_sum(source);
    sum += ipv6_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv6_word_sum(ip: &Ipv6Addr) -> u32 {
    ip.segments().iter().map(|x| *x as u32).sum()
}

/// Sum all words (16 bit chunks) in the given data. The word at word offset
/// `skipword` will be skipped. Each word is treated as big endian.
fn sum_be_words(data: &[u8], mut skipword: usize) -> u32 {
    if data.len() == 0 { return 0 }
    let len = data.len();
    let mut cur_data = &data[..];
    let mut sum = 0u32;
    let mut i = 0;
    while cur_data.len() >= 2 {
        if i != skipword {
            // It's safe to unwrap because we verified there are at least 2 bytes
            sum += u16::from_be_bytes(cur_data[0..2].try_into().unwrap()) as u32;
        }
        cur_data = &cur_data[2..];
        i += 1;
    }

    // If the length is odd, make sure to checksum the final byte
    if len & 1 != 0 {
        sum += (data[len - 1] as u32) << 8;
    }

    sum
}

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

    #[test]
    fn sum_be_words_different_skipwords() {
        let data = (0..11).collect::<Vec<u8>>();
        assert_eq!(7190, sum_be_words(&data, 1));
        assert_eq!(6676, sum_be_words(&data, 2));
        // Assert having the skipword outside the range gives correct and equal
        // results
        assert_eq!(7705, sum_be_words(&data, 99));
        assert_eq!(7705, sum_be_words(&data, 101));
    }
}

#[cfg(all(test, feature = "benchmark"))]
mod checksum_benchmarks {
    use super::checksum;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_checksum_small(b: &mut Bencher) {
        let data = vec![99u8; 20];
        b.iter(|| checksum(black_box(&data), 5));
    }

    #[bench]
    fn bench_checksum_large(b: &mut Bencher) {
        let data = vec![123u8; 1024];
        b.iter(|| checksum(black_box(&data), 5));
    }
}

<commit_msg>Fix warnings.<commit_after>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// 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.

//! Utilities for working with packets, eg. checksumming.

use ip::IpNextHeaderProtocol;
use pnet_macros_support::types::u16be;

use std::net::{Ipv4Addr, Ipv6Addr};
use std::u8;
use std::u16;
use std::convert::TryInto;

/// Convert a value to a byte array.
pub trait Octets {
    /// Output type - bytes array.
    type Output;

    /// Return a value as bytes (big-endian order).
    fn octets(&self) -> Self::Output;
}

impl Octets for u64 {
    type Output = [u8; 8];

    fn octets(&self) -> Self::Output {
        [(*self >> 56) as u8,
         (*self >> 48) as u8,
         (*self >> 40) as u8,
         (*self >> 32) as u8,
         (*self >> 24) as u8,
         (*self >> 16) as u8,
         (*self >> 8) as u8,
         *self as u8]
    }
}

impl Octets for u32 {
    type Output = [u8; 4];

    fn octets(&self) -> Self::Output {
        [(*self >> 24) as u8, (*self >> 16) as u8, (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u16 {
    type Output = [u8; 2];

    fn octets(&self) -> Self::Output {
        [(*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u8 {
    type Output = [u8; 1];

    fn octets(&self) -> Self::Output {
        [*self]
    }
}

/// Calculates a checksum. Used by ipv4 and icmp. The two bytes starting at `skipword * 2` will be
/// ignored. Supposed to be the checksum field, which is regarded as zero during calculation.
pub fn checksum(data: &[u8], skipword: usize) -> u16be {
    if data.len() == 0 { return 0 }
    let sum = sum_be_words(data, skipword);
    finalize_checksum(sum)
}

fn finalize_checksum(mut sum: u32) -> u16be {
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    !sum as u16
}

/// Calculate the checksum for a packet built on IPv4. Used by UDP and TCP.
pub fn ipv4_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: &Ipv4Addr,
                     destination: &Ipv4Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv4_word_sum(source);
    sum += ipv4_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv4_word_sum(ip: &Ipv4Addr) -> u32 {
    let octets = ip.octets();
    ((octets[0] as u32) << 8 | octets[1] as u32) + ((octets[2] as u32) << 8 | octets[3] as u32)
}

/// Calculate the checksum for a packet built on IPv6.
pub fn ipv6_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: &Ipv6Addr,
                     destination: &Ipv6Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv6_word_sum(source);
    sum += ipv6_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv6_word_sum(ip: &Ipv6Addr) -> u32 {
    ip.segments().iter().map(|x| *x as u32).sum()
}

/// Sum all words (16 bit chunks) in the given data. The word at word offset
/// `skipword` will be skipped. Each word is treated as big endian.
fn sum_be_words(data: &[u8], skipword: usize) -> u32 {
    if data.len() == 0 { return 0 }
    let len = data.len();
    let mut cur_data = &data[..];
    let mut sum = 0u32;
    let mut i = 0;
    while cur_data.len() >= 2 {
        if i != skipword {
            // It's safe to unwrap because we verified there are at least 2 bytes
            sum += u16::from_be_bytes(cur_data[0..2].try_into().unwrap()) as u32;
        }
        cur_data = &cur_data[2..];
        i += 1;
    }

    // If the length is odd, make sure to checksum the final byte
    if len & 1 != 0 {
        sum += (data[len - 1] as u32) << 8;
    }

    sum
}

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

    #[test]
    fn sum_be_words_different_skipwords() {
        let data = (0..11).collect::<Vec<u8>>();
        assert_eq!(7190, sum_be_words(&data, 1));
        assert_eq!(6676, sum_be_words(&data, 2));
        // Assert having the skipword outside the range gives correct and equal
        // results
        assert_eq!(7705, sum_be_words(&data, 99));
        assert_eq!(7705, sum_be_words(&data, 101));
    }
}

#[cfg(all(test, feature = "benchmark"))]
mod checksum_benchmarks {
    use super::checksum;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_checksum_small(b: &mut Bencher) {
        let data = vec![99u8; 20];
        b.iter(|| checksum(black_box(&data), 5));
    }

    #[bench]
    fn bench_checksum_large(b: &mut Bencher) {
        let data = vec![123u8; 1024];
        b.iter(|| checksum(black_box(&data), 5));
    }
}

<|endoftext|>