<commit_before>// Copyright 2019 Jeremy Wall
//
// 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.
use std::collections::BTreeMap;

pub mod pointer;
use pointer::OpPointer;

#[derive(Debug, PartialEq, Clone)]
pub enum Primitive {
    // Primitive Types
    Int(i64),
    Float(f64),
    Str(String),
    Bool(bool),
    Empty,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Composite {
    List(Vec<Value>),
    Tuple(Vec<(String, Value)>),
}

#[derive(Debug, PartialEq, Clone)]
pub enum Value {
    // Binding names.
    S(String),
    // Primitive Types
    P(Primitive),
    // Composite Types.
    C(Composite),
    // Program Pointer
    T(usize),
}

#[derive(Debug, PartialEq, Clone)]
pub enum Op {
    // Stack and Name manipulation.
    Bind, // Bind a Val to a name in the heap
    Pop,  // Pop a Value off the value stack and discard it.
    // Math ops
    Add,
    Sub,
    Div,
    Mul,
    // Primitive Types ops
    Val(Primitive),
    // A bareword for use in bindings or lookups
    Sym(String),
    // Complex Type ops
    InitTuple,
    FIELD,
    InitList,
    Element,
    // Operations
    Cp,
    // record
    InitThunk,
    Return,
    // - Call
    // Runtime hooks
    // - Map
    // - Filter
    // - Reduce
    // - Import
    // - Out
    // - Assert
    // - Print
}

#[derive(Debug)]
pub struct Error {}

pub struct VM {
    stack: Vec<Value>,
    symbols: BTreeMap<String, Value>,
    ops: OpPointer,
}

impl VM {
    pub fn new(ops: Vec<Op>) -> Self {
        Self {
            stack: Vec::new(),
            symbols: BTreeMap::new(),
            ops: OpPointer::new(ops),
        }
    }

    pub fn run(&mut self) -> Result<(), Error> {
        while self.ops.next().is_some() {
            let idx = self.ops.ptr.unwrap();
            match self.ops.op().unwrap() {
                Op::Val(p) => self.primitive_push(p.clone())?,
                Op::Sym(s) => self.push(Value::S(s.clone()))?,
                Op::Add => self.op_add()?,
                Op::Sub => self.op_sub()?,
                Op::Mul => self.op_mul()?,
                Op::Div => self.op_div()?,
                Op::Bind => self.op_bind()?,
                // Add a Composite list value to the stack
                Op::InitList => self.composite_push(Composite::List(Vec::new()))?,
                // Add a composite tuple value to the stack
                Op::InitTuple => self.composite_push(Composite::Tuple(Vec::new()))?,
                Op::FIELD => self.op_field()?,
                Op::Element => self.op_element()?,
                Op::Cp => self.op_copy()?,
                Op::InitThunk => self.op_thunk(idx)?,
                Op::Return => {
                    // TODO(jwall): This means we return back to the start of the frame.
                }
                Op::Pop => {
                    self.pop()?;
                }
            };
        }
        Ok(())
    }

    fn op_thunk(&mut self, idx: usize) -> Result<(), Error> {
        // TODO(jwall): Record the position in the op codes.
        self.push(Value::T(idx))?;
        Ok(())
    }

    fn op_add(&mut self) -> Result<(), Error> {
        // Adds the previous two items in the stack.
        let left = self.pop()?;
        let right = self.pop()?;
        // Then pushes the result onto the stack.
        self.primitive_push(self.add(left, right)?)?;
        Ok(())
    }

    fn op_sub(&mut self) -> Result<(), Error> {
        // Subtracts the previous two items in the stack.
        let left = self.pop()?;
        let right = self.pop()?;
        // Then pushes the result onto the stack.
        self.primitive_push(self.sub(left, right)?)?;
        Ok(())
    }

    fn op_mul(&mut self) -> Result<(), Error> {
        // Multiplies the previous two items in the stack.
        let left = self.pop()?;
        let right = self.pop()?;
        // Then pushes the result onto the stack.
        self.primitive_push(self.mul(left, right)?)?;
        Ok(())
    }

    fn op_div(&mut self) -> Result<(), Error> {
        // Divides the previous two items in the stack.
        let left = self.pop()?;
        let right = self.pop()?;
        // Then pushes the result onto the stack.
        self.primitive_push(self.div(left, right)?)?;
        Ok(())
    }

    fn op_bind(&mut self) -> Result<(), Error> {
        // TODO(jwall): Okay this should actually
        // point to a location in the library op code
        // instead of storing in the heap.
        // pop val off stack.
        let val = self.pop()?;
        // pop name off stack.
        let name = self.pop()?;
        if let Value::S(name) = name {
            self.binding_push(name, val)?;
        } else {
            return Err(Error {});
        }
        Ok(())
    }

    fn op_field(&mut self) -> Result<(), Error> {
        // Add a Composite field value to a tuple on the stack
        // get value from stack
        let val = self.pop()?;
        // get name from stack.
        let name = if let Value::S(s) | Value::P(Primitive::Str(s)) = self.pop()? {
            s
        } else {
            return Err(Error {});
        };
        // get composite tuple from stack
        let tpl = self.pop()?;
        if let Value::C(Composite::Tuple(mut flds)) = tpl {
            // add name and value to tuple
            self.merge_field_into_tuple(&mut flds, name, val)?;
            // place composite tuple back on stack
            self.composite_push(Composite::Tuple(flds))?;
        } else {
            return Err(Error {});
        };
        Ok(())
    }

    fn op_element(&mut self) -> Result<(), Error> {
        // get element from stack.
        let val = self.pop()?;
        // get next value. It should be a Composite list.
        let tpl = self.pop()?;
        if let Value::C(Composite::List(mut elems)) = tpl {
            // add value to list
            elems.push(val);
            // Add that value to the list and put list back on stack.
            self.composite_push(Composite::List(elems))?;
        } else {
            return Err(Error {});
        };
        Ok(())
    }

    fn op_copy(&mut self) -> Result<(), Error> {
        // TODO Use Cow pointers for this?
        // get next value. It should be a Composite Tuple.
        if let Value::C(Composite::Tuple(flds)) = self.pop()? {
            // Make a copy of the original
            let original = Composite::Tuple(flds.clone());
            let copy = Composite::Tuple(flds);
            // Put the original on the Stack as well as the copy
            self.composite_push(original)?;
            self.composite_push(copy)?;
        } else {
            return Err(Error {});
        };
        Ok(())
    }

    fn merge_field_into_tuple(
        &self,
        src_fields: &mut Vec<(String, Value)>,
        name: String,
        value: Value,
    ) -> Result<(), Error> {
        for fld in src_fields.iter_mut() {
            if fld.0 == name {
                fld.1 = value;
                return Ok(());
            }
        }
        src_fields.push((name, value));
        Ok(())
    }

    fn push(&mut self, p: Value) -> Result<(), Error> {
        self.stack.push(p);
        Ok(())
    }

    fn primitive_push(&mut self, p: Primitive) -> Result<(), Error> {
        self.stack.push(Value::P(p));
        Ok(())
    }

    fn composite_push(&mut self, c: Composite) -> Result<(), Error> {
        self.stack.push(Value::C(c));
        Ok(())
    }

    fn binding_push(&mut self, name: String, val: Value) -> Result<(), Error> {
        // FIXME(jwall): Error if the symbol already exists.
        self.symbols.insert(name, val);
        Ok(())
    }

    pub fn get_binding(&mut self, name: &str) -> Result<&Value, Error> {
        match self.symbols.get(name) {
            Some(v) => Ok(v),
            None => Err(Error {}),
        }
    }

    fn pop(&mut self) -> Result<Value, Error> {
        match self.stack.pop() {
            Some(v) => Ok(v),
            None => Err(Error {}),
        }
    }

    fn mul(&self, left: Value, right: Value) -> Result<Primitive, Error> {
        Ok(match (left, right) {
            (Value::P(Primitive::Int(i)), Value::P(Primitive::Int(ii))) => Primitive::Int(i * ii),
            (Value::P(Primitive::Float(f)), Value::P(Primitive::Float(ff))) => {
                Primitive::Float(f * ff)
            }
            _ => return Err(Error {}),
        })
    }

    fn div(&self, left: Value, right: Value) -> Result<Primitive, Error> {
        Ok(match (left, right) {
            (Value::P(Primitive::Int(i)), Value::P(Primitive::Int(ii))) => Primitive::Int(i / ii),
            (Value::P(Primitive::Float(f)), Value::P(Primitive::Float(ff))) => {
                Primitive::Float(f / ff)
            }
            _ => return Err(Error {}),
        })
    }

    fn sub(&self, left: Value, right: Value) -> Result<Primitive, Error> {
        Ok(match (left, right) {
            (Value::P(Primitive::Int(i)), Value::P(Primitive::Int(ii))) => Primitive::Int(i - ii),
            (Value::P(Primitive::Float(f)), Value::P(Primitive::Float(ff))) => {
                Primitive::Float(f - ff)
            }
            _ => return Err(Error {}),
        })
    }

    fn add(&self, left: Value, right: Value) -> Result<Primitive, Error> {
        Ok(match (left, right) {
            (Value::P(Primitive::Int(i)), Value::P(Primitive::Int(ii))) => Primitive::Int(i + ii),
            (Value::P(Primitive::Float(f)), Value::P(Primitive::Float(ff))) => {
                Primitive::Float(f + ff)
            }
            (Value::P(Primitive::Str(s)), Value::P(Primitive::Str(ss))) => {
                let mut ns = String::new();
                ns.push_str(&s);
                ns.push_str(&ss);
                Primitive::Str(ns)
            }
            _ => return Err(Error {}),
        })
    }
}

#[cfg(test)]
mod test;
<commit_msg>REFACTOR: reference the Composite types directly.<commit_after>// Copyright 2019 Jeremy Wall
//
// 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.
use std::collections::BTreeMap;

pub mod pointer;
use pointer::OpPointer;

#[derive(Debug, PartialEq, Clone)]
pub enum Primitive {
    // Primitive Types
    Int(i64),
    Float(f64),
    Str(String),
    Bool(bool),
    Empty,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Composite {
    List(Vec<Value>),
    Tuple(Vec<(String, Value)>),
}

use Composite::{List, Tuple};

#[derive(Debug, PartialEq, Clone)]
pub enum Value {
    // Binding names.
    S(String),
    // Primitive Types
    P(Primitive),
    // Composite Types.
    C(Composite),
    // Program Pointer
    T(usize),
}

#[derive(Debug, PartialEq, Clone)]
pub enum Op {
    // Stack and Name manipulation.
    Bind, // Bind a Val to a name in the heap
    Pop,  // Pop a Value off the value stack and discard it.
    // Math ops
    Add,
    Sub,
    Div,
    Mul,
    // Primitive Types ops
    Val(Primitive),
    // A bareword for use in bindings or lookups
    Sym(String),
    // Complex Type ops
    InitTuple,
    FIELD,
    InitList,
    Element,
    // Operations
    Cp,
    // record
    InitThunk,
    Return,
    // - Call
    // Runtime hooks
    // - Map
    // - Filter
    // - Reduce
    // - Import
    // - Out
    // - Assert
    // - Print
}

#[derive(Debug)]
pub struct Error {}

pub struct VM {
    stack: Vec<Value>,
    symbols: BTreeMap<String, Value>,
    ops: OpPointer,
}

impl VM {
    pub fn new(ops: Vec<Op>) -> Self {
        Self {
            stack: Vec::new(),
            symbols: BTreeMap::new(),
            ops: OpPointer::new(ops),
        }
    }

    pub fn run(&mut self) -> Result<(), Error> {
        while self.ops.next().is_some() {
            let idx = self.ops.ptr.unwrap();
            match self.ops.op().unwrap() {
                Op::Val(p) => self.primitive_push(p.clone())?,
                Op::Sym(s) => self.push(Value::S(s.clone()))?,
                Op::Add => self.op_add()?,
                Op::Sub => self.op_sub()?,
                Op::Mul => self.op_mul()?,
                Op::Div => self.op_div()?,
                Op::Bind => self.op_bind()?,
                // Add a Composite list value to the stack
                Op::InitList => self.composite_push(List(Vec::new()))?,
                // Add a composite tuple value to the stack
                Op::InitTuple => self.composite_push(Tuple(Vec::new()))?,
                Op::FIELD => self.op_field()?,
                Op::Element => self.op_element()?,
                Op::Cp => self.op_copy()?,
                Op::InitThunk => self.op_thunk(idx)?,
                Op::Return => {
                    // TODO(jwall): This means we return back to the start of the frame.
                }
                Op::Pop => {
                    self.pop()?;
                }
            };
        }
        Ok(())
    }

    fn op_thunk(&mut self, idx: usize) -> Result<(), Error> {
        // TODO(jwall): Record the position in the op codes.
        self.push(Value::T(idx))?;
        Ok(())
    }

    fn op_add(&mut self) -> Result<(), Error> {
        // Adds the previous two items in the stack.
        let left = self.pop()?;
        let right = self.pop()?;
        // Then pushes the result onto the stack.
        self.primitive_push(self.add(left, right)?)?;
        Ok(())
    }

    fn op_sub(&mut self) -> Result<(), Error> {
        // Subtracts the previous two items in the stack.
        let left = self.pop()?;
        let right = self.pop()?;
        // Then pushes the result onto the stack.
        self.primitive_push(self.sub(left, right)?)?;
        Ok(())
    }

    fn op_mul(&mut self) -> Result<(), Error> {
        // Multiplies the previous two items in the stack.
        let left = self.pop()?;
        let right = self.pop()?;
        // Then pushes the result onto the stack.
        self.primitive_push(self.mul(left, right)?)?;
        Ok(())
    }

    fn op_div(&mut self) -> Result<(), Error> {
        // Divides the previous two items in the stack.
        let left = self.pop()?;
        let right = self.pop()?;
        // Then pushes the result onto the stack.
        self.primitive_push(self.div(left, right)?)?;
        Ok(())
    }

    fn op_bind(&mut self) -> Result<(), Error> {
        // TODO(jwall): Okay this should actually
        // point to a location in the library op code
        // instead of storing in the heap.
        // pop val off stack.
        let val = self.pop()?;
        // pop name off stack.
        let name = self.pop()?;
        if let Value::S(name) = name {
            self.binding_push(name, val)?;
        } else {
            return Err(Error {});
        }
        Ok(())
    }

    fn op_field(&mut self) -> Result<(), Error> {
        // Add a Composite field value to a tuple on the stack
        // get value from stack
        let val = self.pop()?;
        // get name from stack.
        let name = if let Value::S(s) | Value::P(Primitive::Str(s)) = self.pop()? {
            s
        } else {
            return Err(Error {});
        };
        // get composite tuple from stack
        let tpl = self.pop()?;
        if let Value::C(Tuple(mut flds)) = tpl {
            // add name and value to tuple
            self.merge_field_into_tuple(&mut flds, name, val)?;
            // place composite tuple back on stack
            self.composite_push(Tuple(flds))?;
        } else {
            return Err(Error {});
        };
        Ok(())
    }

    fn op_element(&mut self) -> Result<(), Error> {
        // get element from stack.
        let val = self.pop()?;
        // get next value. It should be a Composite list.
        let tpl = self.pop()?;
        if let Value::C(List(mut elems)) = tpl {
            // add value to list
            elems.push(val);
            // Add that value to the list and put list back on stack.
            self.composite_push(List(elems))?;
        } else {
            return Err(Error {});
        };
        Ok(())
    }

    fn op_copy(&mut self) -> Result<(), Error> {
        // TODO Use Cow pointers for this?
        // get next value. It should be a Composite Tuple.
        if let Value::C(Tuple(flds)) = self.pop()? {
            // Make a copy of the original
            let original = Tuple(flds.clone());
            let copy = Tuple(flds);
            // Put the original on the Stack as well as the copy
            self.composite_push(original)?;
            self.composite_push(copy)?;
        } else {
            return Err(Error {});
        };
        Ok(())
    }

    fn merge_field_into_tuple(
        &self,
        src_fields: &mut Vec<(String, Value)>,
        name: String,
        value: Value,
    ) -> Result<(), Error> {
        for fld in src_fields.iter_mut() {
            if fld.0 == name {
                fld.1 = value;
                return Ok(());
            }
        }
        src_fields.push((name, value));
        Ok(())
    }

    fn push(&mut self, p: Value) -> Result<(), Error> {
        self.stack.push(p);
        Ok(())
    }

    fn primitive_push(&mut self, p: Primitive) -> Result<(), Error> {
        self.stack.push(Value::P(p));
        Ok(())
    }

    fn composite_push(&mut self, c: Composite) -> Result<(), Error> {
        self.stack.push(Value::C(c));
        Ok(())
    }

    fn binding_push(&mut self, name: String, val: Value) -> Result<(), Error> {
        // FIXME(jwall): Error if the symbol already exists.
        self.symbols.insert(name, val);
        Ok(())
    }

    pub fn get_binding(&mut self, name: &str) -> Result<&Value, Error> {
        match self.symbols.get(name) {
            Some(v) => Ok(v),
            None => Err(Error {}),
        }
    }

    fn pop(&mut self) -> Result<Value, Error> {
        match self.stack.pop() {
            Some(v) => Ok(v),
            None => Err(Error {}),
        }
    }

    fn mul(&self, left: Value, right: Value) -> Result<Primitive, Error> {
        Ok(match (left, right) {
            (Value::P(Primitive::Int(i)), Value::P(Primitive::Int(ii))) => Primitive::Int(i * ii),
            (Value::P(Primitive::Float(f)), Value::P(Primitive::Float(ff))) => {
                Primitive::Float(f * ff)
            }
            _ => return Err(Error {}),
        })
    }

    fn div(&self, left: Value, right: Value) -> Result<Primitive, Error> {
        Ok(match (left, right) {
            (Value::P(Primitive::Int(i)), Value::P(Primitive::Int(ii))) => Primitive::Int(i / ii),
            (Value::P(Primitive::Float(f)), Value::P(Primitive::Float(ff))) => {
                Primitive::Float(f / ff)
            }
            _ => return Err(Error {}),
        })
    }

    fn sub(&self, left: Value, right: Value) -> Result<Primitive, Error> {
        Ok(match (left, right) {
            (Value::P(Primitive::Int(i)), Value::P(Primitive::Int(ii))) => Primitive::Int(i - ii),
            (Value::P(Primitive::Float(f)), Value::P(Primitive::Float(ff))) => {
                Primitive::Float(f - ff)
            }
            _ => return Err(Error {}),
        })
    }

    fn add(&self, left: Value, right: Value) -> Result<Primitive, Error> {
        Ok(match (left, right) {
            (Value::P(Primitive::Int(i)), Value::P(Primitive::Int(ii))) => Primitive::Int(i + ii),
            (Value::P(Primitive::Float(f)), Value::P(Primitive::Float(ff))) => {
                Primitive::Float(f + ff)
            }
            (Value::P(Primitive::Str(s)), Value::P(Primitive::Str(ss))) => {
                let mut ns = String::new();
                ns.push_str(&s);
                ns.push_str(&ss);
                Primitive::Str(ns)
            }
            _ => return Err(Error {}),
        })
    }
}

#[cfg(test)]
mod test;
<|endoftext|>


<commit_before>use bvh::*;
use bounding_hierarchy::BHShape;
use aabb::AABB;
use std::collections::HashSet;

// TODO Consider: Instead of getting the scene's shapes passed, let leaf nodes store an AABB
// that is updated from the outside, perhaps by passing not only the indices of the changed
// shapes, but also their new AABBs into optimize().

impl BVH {
    /// Optimizes the `BVH` by batch-reorganizing updated nodes.
    /// Based on https://github.com/jeske/SimpleScene/blob/master/SimpleScene/Util/ssBVH/ssBVH.cs
    ///
    /// Needs all the scene's shapes, plus the indices of the shapes that were updated.
    ///
    pub fn optimize<Shape: BHShape>(&mut self,
                                    refit_shape_indices: &HashSet<usize>,
                                    shapes: &[Shape]) {
        let mut refit_node_indices: HashSet<usize> = refit_shape_indices.iter()
            .map(|x| shapes[*x].bh_node_index())
            .collect();

        // As long as we have refit nodes left, take the list of refit nodes
        // with the highest depth (sweep nodes) and try to rotate them all
        while refit_node_indices.len() > 0 {
            let mut max_depth = 0;
            let mut sweep_node_indices: Vec<usize> = Vec::new();

            // Find max_depth and sweep_node_indices in one iteration
            for refit_node_index in refit_node_indices.iter() {
                let depth = match self.nodes[*refit_node_index] {
                    BVHNode::Node { depth, .. } => depth,
                    BVHNode::Leaf { depth, .. } => depth,
                    BVHNode::Dummy => panic!("Dummy node found during BVH optimization!"),
                };

                if depth > max_depth {
                    max_depth = depth;
                    sweep_node_indices.clear();
                    sweep_node_indices.push(*refit_node_index);
                } else if depth == max_depth {
                    sweep_node_indices.push(*refit_node_index);
                }
            }

            // Try to find a useful tree rotation with all nodes previously found
            for sweep_node_index in sweep_node_indices.iter() {
                // This node does not need to be checked again
                refit_node_indices.remove(&sweep_node_index);

                let new_refit_node_index = self.try_rotate(*sweep_node_index, shapes);

                // Instead of finding a useful tree rotation, we found another node
                // that we should check, so we add its index to the refit_node_indices.
                if let Some(index) = new_refit_node_index {
                    refit_node_indices.insert(index);
                }
            }
        }
    }

    /// Checks if there is a way to rotate a child and a grandchild (or two grandchildren) of
    /// the given node (specified by `node_index`) that would improve the `BVH`.
    /// If there is, the best rotation found is performed.
    /// Relies on the children and transitive children of the given node having correct AABBs.
    ///
    /// Returns Some(index_of_node) if a new node was found that should be used for optimization.
    ///
    fn try_rotate<Shape: BHShape>(&mut self, node_index: usize, shapes: &[Shape]) -> Option<usize> {
        let mut nodes = &mut self.nodes;

        let mut node_clone = nodes[node_index].clone();

        // Contains the surface area that would result from applying the currently favored rotation.
        // The rotation with the smallest SA will be applied in the end.
        // The value is calculated by child_l_aabb.surface_area() + child_r_aabb.surface_area()
        let mut best_SA = 0f32;

        // TODO Re-implement without mutability
        let mut parent_index: usize = 0;

        #[derive(Debug, Copy, Clone)]
        struct NodeData {
            index: usize,
            aabb: AABB,
        }

        macro_rules! get_children_node_data {
            ($node_index:expr) => ({
                let node = &nodes[$node_index];
                match *node {
                    BVHNode::Node { child_l, child_r, child_l_aabb, child_r_aabb, .. } => {
                        Some((NodeData{ index: child_l, aabb: child_l_aabb},
                            NodeData{ index: child_r, aabb: child_r_aabb}))
                    }
                    BVHNode::Leaf { .. } => {
                        None
                    }
                    BVHNode::Dummy => panic!("Dummy node found during BVH optimization!"),
                }
            });
        }

        // If this node is not a grandparent, update the AABB,
        // queue the parent for refitting, and bail out.
        // If it is a grandparent, calculate the current best_SA.
        let (child_l, child_r) = match node_clone {
            BVHNode::Node { parent, child_l, child_r, child_l_aabb, child_r_aabb, .. } => {
                if let BVHNode::Leaf { shape, .. } = nodes[child_l] {
                    let shape_l_index = shape;
                    if let BVHNode::Leaf { shape, .. } = nodes[child_r] {
                        let shape_r_index = shape;

                        // Update the AABBs saved for the children
                        // since at least one of them changed
                        let mut node = &mut nodes[node_index];
                        match node {
                            &mut BVHNode::Node { ref mut child_l_aabb,
                                                 ref mut child_r_aabb,
                                                 .. } => {
                                *child_l_aabb = shapes[shape_l_index].aabb();
                                *child_r_aabb = shapes[shape_r_index].aabb();
                            }
                            _ => unreachable!(),
                        }

                        return Some(parent);
                    }
                }

                let left_children = match get_children_node_data!(child_l) {
                    Some(x) => x,
                    _ => unreachable!(),
                };
                let right_children = match get_children_node_data!(child_r) {
                    Some(x) => x,
                    _ => unreachable!(),
                };

                // Update the AABBs saved for the children
                // since at least one of them changed
                let aabb_l = left_children.0.aabb.join(&left_children.1.aabb);
                let aabb_r = right_children.0.aabb.join(&right_children.1.aabb);

                parent_index = parent;
                best_SA = child_l_aabb.surface_area() + child_r_aabb.surface_area();
                (NodeData{index: child_l, aabb: aabb_l},
                 NodeData{index: child_r, aabb: aabb_r})
            }
            BVHNode::Leaf { parent, .. } => {
                return Some(parent);
            }
            BVHNode::Dummy => panic!("Dummy node found during BVH optimization!"),
        };

        // Stores the Rotation that would result in the surface area best_SA,
        // thus being the favored rotation that will be executed after considering all rotations.
        let mut best_rotation: Option<(usize, usize)> = None;

        macro_rules! consider_rotation {
            ($a:expr, $b:expr) => {
                // TODO Calculate surface area that would result from rotating the given nodes.
                let surface_area = 100f32;

                if surface_area < best_SA {
                    best_SA = surface_area;
                    best_rotation = Some(($a.index, $b.index));
                }
            };
        }

        // Get indices and AABBs of all grandchildren
        let left_children_nodes = {
            let node_data: NodeData = child_l;
            let index = node_data.index;
            get_children_node_data!(index)
        };
        let right_children_nodes = {
            let node_data: NodeData = child_r;
            let index = node_data.index;
            get_children_node_data!(index)
        };

        // Child to grandchild rotations
        if let Some((child_rl, child_rr)) = right_children_nodes {
            consider_rotation!(child_l, child_rl);
            consider_rotation!(child_l, child_rr);
        }
        if let Some((child_ll, child_lr)) = left_children_nodes {
            consider_rotation!(child_r, child_ll);
            consider_rotation!(child_r, child_lr);

            // Grandchild to grandchild rotations
            if let Some((child_rl, child_rr)) = right_children_nodes {
                consider_rotation!(child_ll, child_rl);
                consider_rotation!(child_ll, child_rr);
            }
        }

        let new_refit_node_index = if parent_index > 0 {
            Some(parent_index)
        } else {
            None
        };

        if best_rotation == None {
            // TODO Recalculate this node's AABBs (child_l_aabb, child_r_aabb)
            // according to the children nodes' AABBs.

            // Even with no rotation being useful for this node, a parent node's rotation
            // could be beneficial, so queue the parent sometimes.
            // TODO Return None most of the time, randomly
            // (see https://github.com/jeske/SimpleScene/blob/master/SimpleScene/Util/ssBVH/ssBVH_Node.cs#L307)
            new_refit_node_index
        } else {
            // TODO Perform rotation using rotate()

            // TODO Update all changed node AABBs

            // Return parent node's index for upcoming refitting,
            // since this node just changed its AABB
            new_refit_node_index
        }
    }

    /// Switch two nodes by rewiring the involved indices (not by moving them in the nodes slice).
    fn rotate(&mut self, node_a_index: usize, node_b_index: usize) {
        let mut nodes = &mut self.nodes;

        macro_rules! should_not_happen {
            () => ( panic!("While rotating BVH nodes, something unexpected happened."); );
            ($s:expr) => ( panic!("While rotating BVH nodes, something unexpected happened: {}", $s); );
        }

        #[allow(dead_code)] // The compiler falsely detects dead code here
        fn get_parent_index(nodes: &Vec<BVHNode>, node_index: usize) -> usize {
            let node = &nodes[node_index];

            match *node {
                BVHNode::Node { parent, .. } |
                BVHNode::Leaf { parent, .. } => parent,
                _ => should_not_happen!(),
            }
        }

        // Get parent indices
        let node_a_parent_index = get_parent_index(nodes, node_a_index);
        let node_b_parent_index = get_parent_index(nodes, node_b_index);

        #[allow(dead_code)] // The compiler falsely detects dead code here
        fn get_is_left_child(nodes: &Vec<BVHNode>,
                             node_index: usize,
                             node_parent_index: usize)
                             -> bool {
            let node_parent = &nodes[node_parent_index];

            match *node_parent {
                BVHNode::Node { child_l, .. } => child_l == node_index,
                _ => should_not_happen!(),
            }
        }

        // Get info about the nodes being a left or right child
        let node_a_is_left_child = get_is_left_child(nodes, node_a_index, node_a_parent_index);
        let node_b_is_left_child = get_is_left_child(nodes, node_b_index, node_b_parent_index);

        #[allow(dead_code)] // The compiler falsely detects dead code here
        fn connect_nodes(nodes: &mut Vec<BVHNode>,
                         child_index: usize,
                         parent_index: usize,
                         left_child: bool) {
            // Set parent's child and get its depth
            let parent_depth = {
                let mut parent = &mut nodes[parent_index];
                match parent {
                    &mut BVHNode::Node { ref mut child_l, ref mut child_r, depth, .. } => {
                        if left_child {
                            *child_l = child_index;
                        } else {
                            *child_r = child_index;
                        }
                        depth
                    }
                    _ => should_not_happen!(),
                }
            };

            // Set child's parent and depth
            {
                let mut child = &mut nodes[child_index];
                match child {
                    &mut BVHNode::Node { ref mut parent, ref mut depth, .. } |
                    &mut BVHNode::Leaf { ref mut parent, ref mut depth, .. } => {
                        *parent = parent_index;
                        *depth = parent_depth + 1;
                    }
                    _ => should_not_happen!(),
                };
            }
        }

        // Perform the switch
        connect_nodes(nodes,
                      node_a_index,
                      node_b_parent_index,
                      node_b_is_left_child);
        connect_nodes(nodes,
                      node_b_index,
                      node_a_parent_index,
                      node_a_is_left_child);
    }
}

#[cfg(test)]
pub mod tests {
    use bvh::BVH;

    #[test]
    /// Tests if the optimize function tries to change a fresh BVH even though it shouldn't
    fn test_optimizing_new_bvh() {
        let (mut shapes, mut bvh) = build_some_bh::<BVH>();

        let refit_shape_indices: HashSet<usize> = (0..shapes.len()).collect();
        bvh.optimize(&refit_shape_indices, &mut shapes);
    }

    // TODO Add tests for:
    // * correct parent
    // * correct depth
    // * correct BVH after optimizing
    // * correct parent and depth after optimizing
}
<commit_msg>Add SAH calculations<commit_after>use bvh::*;
use bounding_hierarchy::BHShape;
use aabb::AABB;
use std::collections::HashSet;

// TODO Consider: Instead of getting the scene's shapes passed, let leaf nodes store an AABB
// that is updated from the outside, perhaps by passing not only the indices of the changed
// shapes, but also their new AABBs into optimize().

impl BVH {
    /// Optimizes the `BVH` by batch-reorganizing updated nodes.
    /// Based on https://github.com/jeske/SimpleScene/blob/master/SimpleScene/Util/ssBVH/ssBVH.cs
    ///
    /// Needs all the scene's shapes, plus the indices of the shapes that were updated.
    ///
    pub fn optimize<Shape: BHShape>(&mut self,
                                    refit_shape_indices: &HashSet<usize>,
                                    shapes: &[Shape]) {
        let mut refit_node_indices: HashSet<usize> = refit_shape_indices.iter()
            .map(|x| shapes[*x].bh_node_index())
            .collect();

        // As long as we have refit nodes left, take the list of refit nodes
        // with the highest depth (sweep nodes) and try to rotate them all
        while refit_node_indices.len() > 0 {
            let mut max_depth = 0;
            let mut sweep_node_indices: Vec<usize> = Vec::new();

            // Find max_depth and sweep_node_indices in one iteration
            for refit_node_index in refit_node_indices.iter() {
                let depth = match self.nodes[*refit_node_index] {
                    BVHNode::Node { depth, .. } => depth,
                    BVHNode::Leaf { depth, .. } => depth,
                    BVHNode::Dummy => panic!("Dummy node found during BVH optimization!"),
                };

                if depth > max_depth {
                    max_depth = depth;
                    sweep_node_indices.clear();
                    sweep_node_indices.push(*refit_node_index);
                } else if depth == max_depth {
                    sweep_node_indices.push(*refit_node_index);
                }
            }

            // Try to find a useful tree rotation with all nodes previously found
            for sweep_node_index in sweep_node_indices.iter() {
                // This node does not need to be checked again
                refit_node_indices.remove(&sweep_node_index);

                let new_refit_node_index = self.try_rotate(*sweep_node_index, shapes);

                // Instead of finding a useful tree rotation, we found another node
                // that we should check, so we add its index to the refit_node_indices.
                if let Some(index) = new_refit_node_index {
                    refit_node_indices.insert(index);
                }
            }
        }
    }

    /// Checks if there is a way to rotate a child and a grandchild (or two grandchildren) of
    /// the given node (specified by `node_index`) that would improve the `BVH`.
    /// If there is, the best rotation found is performed.
    /// Relies on the children and transitive children of the given node having correct AABBs.
    ///
    /// Returns Some(index_of_node) if a new node was found that should be used for optimization.
    ///
    fn try_rotate<Shape: BHShape>(&mut self, node_index: usize, shapes: &[Shape]) -> Option<usize> {
        let mut nodes = &mut self.nodes;

        let node_clone = nodes[node_index].clone();

        // Contains the surface area that would result from applying the currently favored rotation.
        // The rotation with the smallest SA will be applied in the end.
        // The value is calculated by child_l_aabb.surface_area() + child_r_aabb.surface_area()
        let mut best_surface_area = 0f32;

        // TODO Re-implement without mutability
        let mut parent_index: usize = 0;

        #[derive(Debug, Copy, Clone)]
        struct NodeData {
            index: usize,
            aabb: AABB,
        }

        macro_rules! get_children_node_data {
            ($node_index:expr) => ({
                let node = &nodes[$node_index];
                match *node {
                    BVHNode::Node { child_l, child_r, child_l_aabb, child_r_aabb, .. } => {
                        Some((NodeData{ index: child_l, aabb: child_l_aabb},
                            NodeData{ index: child_r, aabb: child_r_aabb}))
                    }
                    BVHNode::Leaf { .. } => {
                        None
                    }
                    BVHNode::Dummy => panic!("Dummy node found during BVH optimization!"),
                }
            });
        }

        // If this node is not a grandparent, update the AABB,
        // queue the parent for refitting, and bail out.
        // If it is a grandparent, calculate the current best_surface_area.
        let (child_l, child_r) = match node_clone {
            BVHNode::Node { parent, child_l, child_r, child_l_aabb, child_r_aabb, .. } => {
                if let BVHNode::Leaf { shape, .. } = nodes[child_l] {
                    let shape_l_index = shape;
                    if let BVHNode::Leaf { shape, .. } = nodes[child_r] {
                        let shape_r_index = shape;

                        // Update the AABBs saved for the children
                        // since at least one of them changed
                        let mut node = &mut nodes[node_index];
                        match node {
                            &mut BVHNode::Node { ref mut child_l_aabb,
                                                 ref mut child_r_aabb,
                                                 .. } => {
                                *child_l_aabb = shapes[shape_l_index].aabb();
                                *child_r_aabb = shapes[shape_r_index].aabb();
                            }
                            _ => unreachable!(),
                        }

                        return Some(parent);
                    }
                }

                let left_children = match get_children_node_data!(child_l) {
                    Some(x) => x,
                    _ => unreachable!(),
                };
                let right_children = match get_children_node_data!(child_r) {
                    Some(x) => x,
                    _ => unreachable!(),
                };

                // Update the AABBs saved for the children
                // since at least one of them changed
                let aabb_l = left_children.0.aabb.join(&left_children.1.aabb);
                let aabb_r = right_children.0.aabb.join(&right_children.1.aabb);

                parent_index = parent;
                best_surface_area = child_l_aabb.surface_area() + child_r_aabb.surface_area();
                (NodeData {
                     index: child_l,
                     aabb: aabb_l,
                 },
                 NodeData {
                     index: child_r,
                     aabb: aabb_r,
                 })
            }
            BVHNode::Leaf { parent, .. } => {
                return Some(parent);
            }
            BVHNode::Dummy => panic!("Dummy node found during BVH optimization!"),
        };

        // Stores the Rotation that would result in the surface area best_surface_area,
        // thus being the favored rotation that will be executed after considering all rotations.
        let mut best_rotation: Option<(usize, usize)> = None;

        macro_rules! consider_rotation {
            ($a:expr, $b:expr, $sa:expr) => {
                if $sa < best_surface_area {
                    best_surface_area = $sa;
                    best_rotation = Some(($a.index, $b.index));
                }
            };
        }

        // Get indices and AABBs of all grandchildren
        let left_children_nodes = {
            let node_data: NodeData = child_l;
            let index = node_data.index;
            get_children_node_data!(index)
        };
        let right_children_nodes = {
            let node_data: NodeData = child_r;
            let index = node_data.index;
            get_children_node_data!(index)
        };

        // Child to grandchild rotations
        if let Some((child_rl, child_rr)) = right_children_nodes {
            consider_rotation!(child_l,
                               child_rl,
                               child_rl.aabb.surface_area() +
                               child_l.aabb.join(&child_rr.aabb).surface_area());
            consider_rotation!(child_l,
                               child_rr,
                               child_rr.aabb.surface_area() +
                               child_l.aabb.join(&child_rl.aabb).surface_area());
        }
        if let Some((child_ll, child_lr)) = left_children_nodes {
            consider_rotation!(child_r,
                               child_ll,
                               child_ll.aabb.surface_area() +
                               child_r.aabb.join(&child_lr.aabb).surface_area());
            consider_rotation!(child_r,
                               child_lr,
                               child_lr.aabb.surface_area() +
                               child_r.aabb.join(&child_ll.aabb).surface_area());

            // Grandchild to grandchild rotations
            if let Some((child_rl, child_rr)) = right_children_nodes {
                consider_rotation!(child_ll,
                                   child_rl,
                                   child_rl.aabb.join(&child_lr.aabb).surface_area() +
                                   child_ll.aabb.join(&child_rr.aabb).surface_area());
                consider_rotation!(child_ll,
                                   child_rr,
                                   child_ll.aabb.join(&child_rl.aabb).surface_area() +
                                   child_lr.aabb.join(&child_rr.aabb).surface_area());
            }
        }

        let new_refit_node_index = if parent_index > 0 {
            Some(parent_index)
        } else {
            None
        };

        if best_rotation == None {
            // TODO Recalculate this node's AABBs (child_l_aabb, child_r_aabb)
            // according to the children nodes' AABBs.

            // Even with no rotation being useful for this node, a parent node's rotation
            // could be beneficial, so queue the parent sometimes.
            // TODO Return None most of the time, randomly
            // (see https://github.com/jeske/SimpleScene/blob/master/SimpleScene/Util/ssBVH/ssBVH_Node.cs#L307)
            new_refit_node_index
        } else {
            // TODO Perform rotation using rotate()

            // TODO Update all changed node AABBs

            // Return parent node's index for upcoming refitting,
            // since this node just changed its AABB
            new_refit_node_index
        }
    }

    /// Switch two nodes by rewiring the involved indices (not by moving them in the nodes slice).
    fn rotate(&mut self, node_a_index: usize, node_b_index: usize) {
        let mut nodes = &mut self.nodes;

        macro_rules! should_not_happen {
            () => ( panic!("While rotating BVH nodes, something unexpected happened."); );
            ($s:expr) => ( panic!("While rotating BVH nodes, something unexpected happened: {}", $s); );
        }

        #[allow(dead_code)] // The compiler falsely detects dead code here
        fn get_parent_index(nodes: &Vec<BVHNode>, node_index: usize) -> usize {
            let node = &nodes[node_index];

            match *node {
                BVHNode::Node { parent, .. } |
                BVHNode::Leaf { parent, .. } => parent,
                _ => should_not_happen!(),
            }
        }

        // Get parent indices
        let node_a_parent_index = get_parent_index(nodes, node_a_index);
        let node_b_parent_index = get_parent_index(nodes, node_b_index);

        #[allow(dead_code)] // The compiler falsely detects dead code here
        fn get_is_left_child(nodes: &Vec<BVHNode>,
                             node_index: usize,
                             node_parent_index: usize)
                             -> bool {
            let node_parent = &nodes[node_parent_index];

            match *node_parent {
                BVHNode::Node { child_l, .. } => child_l == node_index,
                _ => should_not_happen!(),
            }
        }

        // Get info about the nodes being a left or right child
        let node_a_is_left_child = get_is_left_child(nodes, node_a_index, node_a_parent_index);
        let node_b_is_left_child = get_is_left_child(nodes, node_b_index, node_b_parent_index);

        #[allow(dead_code)] // The compiler falsely detects dead code here
        fn connect_nodes(nodes: &mut Vec<BVHNode>,
                         child_index: usize,
                         parent_index: usize,
                         left_child: bool) {
            // Set parent's child and get its depth
            let parent_depth = {
                let mut parent = &mut nodes[parent_index];
                match parent {
                    &mut BVHNode::Node { ref mut child_l, ref mut child_r, depth, .. } => {
                        if left_child {
                            *child_l = child_index;
                        } else {
                            *child_r = child_index;
                        }
                        depth
                    }
                    _ => should_not_happen!(),
                }
            };

            // Set child's parent and depth
            {
                let mut child = &mut nodes[child_index];
                match child {
                    &mut BVHNode::Node { ref mut parent, ref mut depth, .. } |
                    &mut BVHNode::Leaf { ref mut parent, ref mut depth, .. } => {
                        *parent = parent_index;
                        *depth = parent_depth + 1;
                    }
                    _ => should_not_happen!(),
                };
            }
        }

        // Perform the switch
        connect_nodes(nodes,
                      node_a_index,
                      node_b_parent_index,
                      node_b_is_left_child);
        connect_nodes(nodes,
                      node_b_index,
                      node_a_parent_index,
                      node_a_is_left_child);
    }
}

#[cfg(test)]
pub mod tests {
    use bvh::BVH;

    #[test]
    /// Tests if the optimize function tries to change a fresh BVH even though it shouldn't
    fn test_optimizing_new_bvh() {
        let (mut shapes, mut bvh) = build_some_bh::<BVH>();

        let refit_shape_indices: HashSet<usize> = (0..shapes.len()).collect();
        bvh.optimize(&refit_shape_indices, &mut shapes);
    }

    // TODO Add tests for:
    // * correct parent
    // * correct depth
    // * correct BVH after optimizing
    // * correct parent and depth after optimizing
}
<|endoftext|>


<commit_before>use crate::core::shell::Verbosity;
use crate::core::{GitReference, Workspace};
use crate::ops;
use crate::sources::path::PathSource;
use crate::util::Sha256;
use crate::util::{paths, CargoResult, CargoResultExt, Config};
use failure::bail;
use serde::Serialize;
use std::collections::HashSet;
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::fs::{self, File};
use std::io::Write;
use std::path::{Path, PathBuf};

pub struct VendorOptions<'a> {
    pub no_delete: bool,
    pub destination: &'a Path,
    pub extra: Vec<PathBuf>,
}

pub fn vendor(ws: &Workspace<'_>, opts: &VendorOptions<'_>) -> CargoResult<()> {
    let mut extra_workspaces = Vec::new();
    for extra in opts.extra.iter() {
        let extra = ws.config().cwd().join(extra);
        let ws = Workspace::new(&extra, ws.config())?;
        extra_workspaces.push(ws);
    }
    let workspaces = extra_workspaces.iter().chain(Some(ws)).collect::<Vec<_>>();
    let vendor_config =
        sync(ws.config(), &workspaces, opts).chain_err(|| "failed to sync".to_string())?;

    let shell = ws.config().shell();
    if shell.verbosity() != Verbosity::Quiet {
        eprint!("To use vendored sources, add this to your .cargo/config for this project:\n\n");
        print!("{}", &toml::to_string(&vendor_config).unwrap());
    }

    Ok(())
}

#[derive(Serialize)]
struct VendorConfig {
    source: BTreeMap<String, VendorSource>,
}

#[derive(Serialize)]
#[serde(rename_all = "lowercase", untagged)]
enum VendorSource {
    Directory {
        directory: PathBuf,
    },
    Registry {
        registry: Option<String>,
        #[serde(rename = "replace-with")]
        replace_with: String,
    },
    Git {
        git: String,
        branch: Option<String>,
        tag: Option<String>,
        rev: Option<String>,
        #[serde(rename = "replace-with")]
        replace_with: String,
    },
}

fn sync(
    config: &Config,
    workspaces: &[&Workspace<'_>],
    opts: &VendorOptions<'_>,
) -> CargoResult<VendorConfig> {
    let canonical_destination = opts.destination.canonicalize();
    let canonical_destination = canonical_destination
        .as_ref()
        .map(|p| &**p)
        .unwrap_or(opts.destination);

    paths::create_dir_all(&canonical_destination)?;
    let mut to_remove = HashSet::new();
    if !opts.no_delete {
        for entry in canonical_destination.read_dir()? {
            let entry = entry?;
            if !entry
                .file_name()
                .to_str()
                .map_or(false, |s| s.starts_with('.'))
            {
                to_remove.insert(entry.path());
            }
        }
    }

    // First up attempt to work around rust-lang/cargo#5956. Apparently build
    // artifacts sprout up in Cargo's global cache for whatever reason, although
    // it's unsure what tool is causing these issues at this time. For now we
    // apply a heavy-hammer approach which is to delete Cargo's unpacked version
    // of each crate to start off with. After we do this we'll re-resolve and
    // redownload again, which should trigger Cargo to re-extract all the
    // crates.
    //
    // Note that errors are largely ignored here as this is a best-effort
    // attempt. If anything fails here we basically just move on to the next
    // crate to work with.
    for ws in workspaces {
        let (packages, resolve) =
            ops::resolve_ws(ws).chain_err(|| "failed to load pkg lockfile")?;

        packages
            .get_many(resolve.iter())
            .chain_err(|| "failed to download packages")?;

        for pkg in resolve.iter() {
            // Don't delete actual source code!
            if pkg.source_id().is_path() {
                if let Ok(path) = pkg.source_id().url().to_file_path() {
                    if let Ok(path) = path.canonicalize() {
                        to_remove.remove(&path);
                    }
                }
                continue;
            }
            if pkg.source_id().is_git() {
                continue;
            }
            if let Ok(pkg) = packages.get_one(pkg) {
                drop(fs::remove_dir_all(pkg.manifest_path().parent().unwrap()));
            }
        }
    }

    let mut checksums = HashMap::new();
    let mut ids = BTreeMap::new();

    // Next up let's actually download all crates and start storing internal
    // tables about them.
    for ws in workspaces {
        let (packages, resolve) =
            ops::resolve_ws(ws).chain_err(|| "failed to load pkg lockfile")?;

        packages
            .get_many(resolve.iter())
            .chain_err(|| "failed to download packages")?;

        for pkg in resolve.iter() {
            // No need to vendor path crates since they're already in the
            // repository
            if pkg.source_id().is_path() {
                continue;
            }
            ids.insert(
                pkg,
                packages
                    .get_one(pkg)
                    .chain_err(|| "failed to fetch package")?
                    .clone(),
            );

            checksums.insert(pkg, resolve.checksums().get(&pkg).cloned());
        }
    }

    let mut versions = HashMap::new();
    for id in ids.keys() {
        let map = versions.entry(id.name()).or_insert_with(BTreeMap::default);
        if let Some(prev) = map.get(&id.version()) {
            bail!(
                "found duplicate version of package `{} v{}` \
                 vendored from two sources:\n\
                 \n\
                 \tsource 1: {}\n\
                 \tsource 2: {}",
                id.name(),
                id.version(),
                prev,
                id.source_id()
            );
        }
        map.insert(id.version(), id.source_id());
    }

    let mut sources = BTreeSet::new();
    for (id, pkg) in ids.iter() {
        // Next up, copy it to the vendor directory
        let src = pkg
            .manifest_path()
            .parent()
            .expect("manifest_path should point to a file");
        let max_version = *versions[&id.name()].iter().rev().next().unwrap().0;
        let dir_has_version_suffix = id.version() != max_version;
        let dst_name = if dir_has_version_suffix {
            // Eg vendor/futures-0.1.13
            format!("{}-{}", id.name(), id.version())
        } else {
            // Eg vendor/futures
            id.name().to_string()
        };

        sources.insert(id.source_id());
        let dst = canonical_destination.join(&dst_name);
        to_remove.remove(&dst);
        let cksum = dst.join(".cargo-checksum.json");
        if dir_has_version_suffix && cksum.exists() {
            // Always re-copy directory without version suffix in case the version changed
            continue;
        }

        config.shell().status(
            "Vendoring",
            &format!("{} ({}) to {}", id, src.to_string_lossy(), dst.display()),
        )?;

        let _ = fs::remove_dir_all(&dst);
        let pathsource = PathSource::new(src, id.source_id(), config);
        let paths = pathsource.list_files(pkg)?;
        let mut map = BTreeMap::new();
        cp_sources(src, &paths, &dst, &mut map)
            .chain_err(|| format!("failed to copy over vendored sources for: {}", id))?;

        // Finally, emit the metadata about this package
        let json = serde_json::json!({
            "package": checksums.get(id),
            "files": map,
        });

        File::create(&cksum)?.write_all(json.to_string().as_bytes())?;
    }

    for path in to_remove {
        if path.is_dir() {
            paths::remove_dir_all(&path)?;
        } else {
            paths::remove_file(&path)?;
        }
    }

    // add our vendored source
    let mut config = BTreeMap::new();

    let merged_source_name = "vendored-sources";
    config.insert(
        merged_source_name.to_string(),
        VendorSource::Directory {
            directory: canonical_destination.to_path_buf(),
        },
    );

    // replace original sources with vendor
    for source_id in sources {
        let name = if source_id.is_default_registry() {
            "crates-io".to_string()
        } else {
            source_id.url().to_string()
        };

        let source = if source_id.is_default_registry() {
            VendorSource::Registry {
                registry: None,
                replace_with: merged_source_name.to_string(),
            }
        } else if source_id.is_git() {
            let mut branch = None;
            let mut tag = None;
            let mut rev = None;
            if let Some(reference) = source_id.git_reference() {
                match *reference {
                    GitReference::Branch(ref b) => branch = Some(b.clone()),
                    GitReference::Tag(ref t) => tag = Some(t.clone()),
                    GitReference::Rev(ref r) => rev = Some(r.clone()),
                }
            }
            VendorSource::Git {
                git: source_id.url().to_string(),
                branch,
                tag,
                rev,
                replace_with: merged_source_name.to_string(),
            }
        } else {
            panic!("Invalid source ID: {}", source_id)
        };
        config.insert(name, source);
    }

    Ok(VendorConfig { source: config })
}

fn cp_sources(
    src: &Path,
    paths: &[PathBuf],
    dst: &Path,
    cksums: &mut BTreeMap<String, String>,
) -> CargoResult<()> {
    for p in paths {
        let relative = p.strip_prefix(&src).unwrap();

        match relative.to_str() {
            // Skip git config files as they're not relevant to builds most of
            // the time and if we respect them (e.g.  in git) then it'll
            // probably mess with the checksums when a vendor dir is checked
            // into someone else's source control
            Some(".gitattributes") | Some(".gitignore") | Some(".git") => continue,

            // Temporary Cargo files
            Some(".cargo-ok") => continue,

            // Skip patch-style orig/rej files. Published crates on crates.io
            // have `Cargo.toml.orig` which we don't want to use here and
            // otherwise these are rarely used as part of the build process.
            Some(filename) => {
                if filename.ends_with(".orig") || filename.ends_with(".rej") {
                    continue;
                }
            }
            _ => {}
        };

        // Join pathname components individually to make sure that the joined
        // path uses the correct directory separators everywhere, since
        // `relative` may use Unix-style and `dst` may require Windows-style
        // backslashes.
        let dst = relative
            .iter()
            .fold(dst.to_owned(), |acc, component| acc.join(&component));

        paths::create_dir_all(dst.parent().unwrap())?;

        fs::copy(&p, &dst)
            .chain_err(|| format!("failed to copy `{}` to `{}`", p.display(), dst.display()))?;
        let cksum = Sha256::new().update_path(dst)?.finish_hex();
        cksums.insert(relative.to_str().unwrap().replace("\\", "/"), cksum);
    }
    Ok(())
}
<commit_msg>Auto merge of #7629 - jsgf:vendor-path, r=alexcrichton<commit_after>use crate::core::shell::Verbosity;
use crate::core::{GitReference, Workspace};
use crate::ops;
use crate::sources::path::PathSource;
use crate::util::Sha256;
use crate::util::{paths, CargoResult, CargoResultExt, Config};
use failure::bail;
use serde::Serialize;
use std::collections::HashSet;
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::fs::{self, File};
use std::io::Write;
use std::path::{Path, PathBuf};

pub struct VendorOptions<'a> {
    pub no_delete: bool,
    pub destination: &'a Path,
    pub extra: Vec<PathBuf>,
}

pub fn vendor(ws: &Workspace<'_>, opts: &VendorOptions<'_>) -> CargoResult<()> {
    let mut extra_workspaces = Vec::new();
    for extra in opts.extra.iter() {
        let extra = ws.config().cwd().join(extra);
        let ws = Workspace::new(&extra, ws.config())?;
        extra_workspaces.push(ws);
    }
    let workspaces = extra_workspaces.iter().chain(Some(ws)).collect::<Vec<_>>();
    let vendor_config =
        sync(ws.config(), &workspaces, opts).chain_err(|| "failed to sync".to_string())?;

    let shell = ws.config().shell();
    if shell.verbosity() != Verbosity::Quiet {
        eprint!("To use vendored sources, add this to your .cargo/config for this project:\n\n");
        print!("{}", &toml::to_string(&vendor_config).unwrap());
    }

    Ok(())
}

#[derive(Serialize)]
struct VendorConfig {
    source: BTreeMap<String, VendorSource>,
}

#[derive(Serialize)]
#[serde(rename_all = "lowercase", untagged)]
enum VendorSource {
    Directory {
        directory: PathBuf,
    },
    Registry {
        registry: Option<String>,
        #[serde(rename = "replace-with")]
        replace_with: String,
    },
    Git {
        git: String,
        branch: Option<String>,
        tag: Option<String>,
        rev: Option<String>,
        #[serde(rename = "replace-with")]
        replace_with: String,
    },
}

fn sync(
    config: &Config,
    workspaces: &[&Workspace<'_>],
    opts: &VendorOptions<'_>,
) -> CargoResult<VendorConfig> {
    let canonical_destination = opts.destination.canonicalize();
    let canonical_destination = canonical_destination
        .as_ref()
        .map(|p| &**p)
        .unwrap_or(opts.destination);

    paths::create_dir_all(&canonical_destination)?;
    let mut to_remove = HashSet::new();
    if !opts.no_delete {
        for entry in canonical_destination.read_dir()? {
            let entry = entry?;
            if !entry
                .file_name()
                .to_str()
                .map_or(false, |s| s.starts_with('.'))
            {
                to_remove.insert(entry.path());
            }
        }
    }

    // First up attempt to work around rust-lang/cargo#5956. Apparently build
    // artifacts sprout up in Cargo's global cache for whatever reason, although
    // it's unsure what tool is causing these issues at this time. For now we
    // apply a heavy-hammer approach which is to delete Cargo's unpacked version
    // of each crate to start off with. After we do this we'll re-resolve and
    // redownload again, which should trigger Cargo to re-extract all the
    // crates.
    //
    // Note that errors are largely ignored here as this is a best-effort
    // attempt. If anything fails here we basically just move on to the next
    // crate to work with.
    for ws in workspaces {
        let (packages, resolve) =
            ops::resolve_ws(ws).chain_err(|| "failed to load pkg lockfile")?;

        packages
            .get_many(resolve.iter())
            .chain_err(|| "failed to download packages")?;

        for pkg in resolve.iter() {
            // Don't delete actual source code!
            if pkg.source_id().is_path() {
                if let Ok(path) = pkg.source_id().url().to_file_path() {
                    if let Ok(path) = path.canonicalize() {
                        to_remove.remove(&path);
                    }
                }
                continue;
            }
            if pkg.source_id().is_git() {
                continue;
            }
            if let Ok(pkg) = packages.get_one(pkg) {
                drop(fs::remove_dir_all(pkg.manifest_path().parent().unwrap()));
            }
        }
    }

    let mut checksums = HashMap::new();
    let mut ids = BTreeMap::new();

    // Next up let's actually download all crates and start storing internal
    // tables about them.
    for ws in workspaces {
        let (packages, resolve) =
            ops::resolve_ws(ws).chain_err(|| "failed to load pkg lockfile")?;

        packages
            .get_many(resolve.iter())
            .chain_err(|| "failed to download packages")?;

        for pkg in resolve.iter() {
            // No need to vendor path crates since they're already in the
            // repository
            if pkg.source_id().is_path() {
                continue;
            }
            ids.insert(
                pkg,
                packages
                    .get_one(pkg)
                    .chain_err(|| "failed to fetch package")?
                    .clone(),
            );

            checksums.insert(pkg, resolve.checksums().get(&pkg).cloned());
        }
    }

    let mut versions = HashMap::new();
    for id in ids.keys() {
        let map = versions.entry(id.name()).or_insert_with(BTreeMap::default);
        if let Some(prev) = map.get(&id.version()) {
            bail!(
                "found duplicate version of package `{} v{}` \
                 vendored from two sources:\n\
                 \n\
                 \tsource 1: {}\n\
                 \tsource 2: {}",
                id.name(),
                id.version(),
                prev,
                id.source_id()
            );
        }
        map.insert(id.version(), id.source_id());
    }

    let mut sources = BTreeSet::new();
    for (id, pkg) in ids.iter() {
        // Next up, copy it to the vendor directory
        let src = pkg
            .manifest_path()
            .parent()
            .expect("manifest_path should point to a file");
        let max_version = *versions[&id.name()].iter().rev().next().unwrap().0;
        let dir_has_version_suffix = id.version() != max_version;
        let dst_name = if dir_has_version_suffix {
            // Eg vendor/futures-0.1.13
            format!("{}-{}", id.name(), id.version())
        } else {
            // Eg vendor/futures
            id.name().to_string()
        };

        sources.insert(id.source_id());
        let dst = canonical_destination.join(&dst_name);
        to_remove.remove(&dst);
        let cksum = dst.join(".cargo-checksum.json");
        if dir_has_version_suffix && cksum.exists() {
            // Always re-copy directory without version suffix in case the version changed
            continue;
        }

        config.shell().status(
            "Vendoring",
            &format!("{} ({}) to {}", id, src.to_string_lossy(), dst.display()),
        )?;

        let _ = fs::remove_dir_all(&dst);
        let pathsource = PathSource::new(src, id.source_id(), config);
        let paths = pathsource.list_files(pkg)?;
        let mut map = BTreeMap::new();
        cp_sources(src, &paths, &dst, &mut map)
            .chain_err(|| format!("failed to copy over vendored sources for: {}", id))?;

        // Finally, emit the metadata about this package
        let json = serde_json::json!({
            "package": checksums.get(id),
            "files": map,
        });

        File::create(&cksum)?.write_all(json.to_string().as_bytes())?;
    }

    for path in to_remove {
        if path.is_dir() {
            paths::remove_dir_all(&path)?;
        } else {
            paths::remove_file(&path)?;
        }
    }

    // add our vendored source
    let mut config = BTreeMap::new();

    let merged_source_name = "vendored-sources";
    config.insert(
        merged_source_name.to_string(),
        VendorSource::Directory {
            directory: opts.destination.to_path_buf(),
        },
    );

    // replace original sources with vendor
    for source_id in sources {
        let name = if source_id.is_default_registry() {
            "crates-io".to_string()
        } else {
            source_id.url().to_string()
        };

        let source = if source_id.is_default_registry() {
            VendorSource::Registry {
                registry: None,
                replace_with: merged_source_name.to_string(),
            }
        } else if source_id.is_git() {
            let mut branch = None;
            let mut tag = None;
            let mut rev = None;
            if let Some(reference) = source_id.git_reference() {
                match *reference {
                    GitReference::Branch(ref b) => branch = Some(b.clone()),
                    GitReference::Tag(ref t) => tag = Some(t.clone()),
                    GitReference::Rev(ref r) => rev = Some(r.clone()),
                }
            }
            VendorSource::Git {
                git: source_id.url().to_string(),
                branch,
                tag,
                rev,
                replace_with: merged_source_name.to_string(),
            }
        } else {
            panic!("Invalid source ID: {}", source_id)
        };
        config.insert(name, source);
    }

    Ok(VendorConfig { source: config })
}

fn cp_sources(
    src: &Path,
    paths: &[PathBuf],
    dst: &Path,
    cksums: &mut BTreeMap<String, String>,
) -> CargoResult<()> {
    for p in paths {
        let relative = p.strip_prefix(&src).unwrap();

        match relative.to_str() {
            // Skip git config files as they're not relevant to builds most of
            // the time and if we respect them (e.g.  in git) then it'll
            // probably mess with the checksums when a vendor dir is checked
            // into someone else's source control
            Some(".gitattributes") | Some(".gitignore") | Some(".git") => continue,

            // Temporary Cargo files
            Some(".cargo-ok") => continue,

            // Skip patch-style orig/rej files. Published crates on crates.io
            // have `Cargo.toml.orig` which we don't want to use here and
            // otherwise these are rarely used as part of the build process.
            Some(filename) => {
                if filename.ends_with(".orig") || filename.ends_with(".rej") {
                    continue;
                }
            }
            _ => {}
        };

        // Join pathname components individually to make sure that the joined
        // path uses the correct directory separators everywhere, since
        // `relative` may use Unix-style and `dst` may require Windows-style
        // backslashes.
        let dst = relative
            .iter()
            .fold(dst.to_owned(), |acc, component| acc.join(&component));

        paths::create_dir_all(dst.parent().unwrap())?;

        fs::copy(&p, &dst)
            .chain_err(|| format!("failed to copy `{}` to `{}`", p.display(), dst.display()))?;
        let cksum = Sha256::new().update_path(dst)?.finish_hex();
        cksums.insert(relative.to_str().unwrap().replace("\\", "/"), cksum);
    }
    Ok(())
}
<|endoftext|>


<commit_before>use libc::{c_double, c_void};
use std::cmp::{Ordering};
use std::sync::{Once, ONCE_INIT};

static EXACTINIT: Once = ONCE_INIT;

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct Point2D {
    x: c_double,
    y: c_double,
}

impl Point2D {
    pub fn new(x: c_double, y: c_double) -> Point2D {
        Point2D { x: x, y: y }
    }
}

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct Point3D {
    x: c_double,
    y: c_double,
    z: c_double,
}

impl Point3D {
    pub fn new(x: c_double, y: c_double, z: c_double) -> Point3D {
        Point3D { x: x, y: y, z: z }
    }
}

#[link(name = "predicates")]
extern "C" {
    fn exactinit() -> c_void;
    fn orient2d(pa: *const Point2D, pb: *const Point2D, pc: *const Point2D) -> c_double;
    fn incircle(pa: *const Point2D, pb: *const Point2D, pc: *const Point2D, pd: *const Point2D) -> c_double;
    fn orient3d(pa: *const Point3D, pb: *const Point3D, pc: *const Point3D, pd: *const Point3D) -> c_double;
    fn insphere(pa: *const Point3D, pb: *const Point3D, pc: *const Point3D, pd: *const Point3D, pe: *const Point3D) -> c_double;
}

fn init_predicates() {
    EXACTINIT.call_once(|| {
        unsafe { exactinit() };
    });
}

#[derive(Debug, Eq, PartialEq)]
pub enum InCircleLocation {
    Inside,
    Outside,
    On
}

#[derive(Debug, Eq, PartialEq)]
pub enum Orientation {
    Positive,
    Negative
}

impl Orientation {
    pub fn to_f64_multiplier(&self) -> f64 {
        match *self {
            Orientation::Positive => {  1.0 },
            Orientation::Negative => { -1.0 }
        }
    }
}

pub trait InCircleTestable<P> {
    fn in_circle_test(&self, point: &P) -> Option<InCircleLocation>;
}

pub trait Orientable {
    fn orientation(&self) -> Option<Orientation>;
}

pub struct Triangle<P> {
    p1: P,
    p2: P,
    p3: P,
}

pub struct Tetrahedron<P> {
    p1: P,
    p2: P,
    p3: P,
    p4: P,
}

fn det_to_in_circle_location(det: f64) -> Option<InCircleLocation> {
    match 0.0.partial_cmp(&det) {
        Some(Ordering::Greater) => { Some(InCircleLocation::Inside) }
        Some(Ordering::Less) => { Some(InCircleLocation::Outside) }
        Some(Ordering::Equal) => { Some(InCircleLocation::On) }
        None => { None }
    }
}

fn det_to_orientation(det: f64) -> Option<Orientation> {
    match 0.0.partial_cmp(&det) {
        Some(Ordering::Greater) => { Some(Orientation::Positive) }
        Some(Ordering::Less) => { Some(Orientation::Negative) }
        _ => { None }
    }
}

impl Orientable for Triangle<Point2D> {
    fn orientation(&self) -> Option<Orientation> {
        init_predicates();

        let orientation_det = unsafe { orient2d(&self.p1, &self.p2, &self.p3) };

        det_to_orientation(orientation_det)
    }
}

impl InCircleTestable<Point2D> for Triangle<Point2D> {
    fn in_circle_test(&self, point: &Point2D) -> Option<InCircleLocation> {
        init_predicates();

        let orienation_multiplier: f64 = match self.orientation() {
            Some(p) => { p.to_f64_multiplier() },
            None => { return None; }
        };

        let incircle_det = unsafe { incircle(&self.p1, &self.p2, &self.p3, point) };

        det_to_in_circle_location(orienation_multiplier * incircle_det)
    }
}

impl Orientable for Tetrahedron<Point3D> {
    fn orientation(&self) -> Option<Orientation> {
        init_predicates();

        let orientation_det = unsafe { orient3d(&self.p1, &self.p2, &self.p3, &self.p4) };

        det_to_orientation(orientation_det)
    }
}

impl InCircleTestable<Point3D> for Tetrahedron<Point3D> {
    fn in_circle_test(&self, point: &Point3D) -> Option<InCircleLocation> {
        init_predicates();

        let orienation_multiplier: f64 = match self.orientation() {
            Some(p) => { p.to_f64_multiplier() },
            None => { return None; }
        };

        let incircle_det = unsafe { insphere(&self.p1, &self.p2, &self.p3, &self.p4, point) };

        det_to_in_circle_location(orienation_multiplier * incircle_det)
    }
}

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

    use std::f64;

    #[test]
    fn in_circle_2d() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);
        let d_inside = Point2D::new(0.5, 0.5);
        let d_outside = Point2D::new(2.0, 0.0);
        let d_on = Point2D::new(1.0, 1.0);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d_inside), Some(InCircleLocation::Inside));
        assert_eq!(t.in_circle_test(&d_outside), Some(InCircleLocation::Outside));
        assert_eq!(t.in_circle_test(&d_on), Some(InCircleLocation::On));
    }

    #[test]
    fn in_circle_2d_nan_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::NAN);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_nan_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::NAN);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_infinity_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::INFINITY);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_infinity_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::INFINITY);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_neg_infinity_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::NEG_INFINITY);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_neg_infinity_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::NEG_INFINITY);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_3d() {
        let p1 = Point3D::new(-1.0,  1.0, -1.0);
        let p2 = Point3D::new( 1.0,  1.0, -1.0);
        let p3 = Point3D::new( 0.0, -1.0, -1.0);
        let p4 = Point3D::new( 0.0,  0.0,  1.0);
        let d_inside = Point3D::new(0.0, 0.0, 0.0);
        let d_outside = Point3D::new(10.0, 10.0, 10.0);
        let d_on = Point3D::new(0.0, 0.0, 1.0);

        let t = Tetrahedron { p1: p1, p2: p2, p3: p3, p4: p4 };

        assert_eq!(t.in_circle_test(&d_inside), Some(InCircleLocation::Inside));
        assert_eq!(t.in_circle_test(&d_outside), Some(InCircleLocation::Outside));
        assert_eq!(t.in_circle_test(&d_on), Some(InCircleLocation::On));
    }

}
<commit_msg>Add new method for Tetrahedron and Triangle<commit_after>use libc::{c_double, c_void};
use std::cmp::{Ordering};
use std::sync::{Once, ONCE_INIT};

static EXACTINIT: Once = ONCE_INIT;

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct Point2D {
    x: c_double,
    y: c_double,
}

impl Point2D {
    pub fn new(x: c_double, y: c_double) -> Point2D {
        Point2D { x: x, y: y }
    }
}

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct Point3D {
    x: c_double,
    y: c_double,
    z: c_double,
}

impl Point3D {
    pub fn new(x: c_double, y: c_double, z: c_double) -> Point3D {
        Point3D { x: x, y: y, z: z }
    }
}

#[link(name = "predicates")]
extern "C" {
    fn exactinit() -> c_void;
    fn orient2d(pa: *const Point2D, pb: *const Point2D, pc: *const Point2D) -> c_double;
    fn incircle(pa: *const Point2D, pb: *const Point2D, pc: *const Point2D, pd: *const Point2D) -> c_double;
    fn orient3d(pa: *const Point3D, pb: *const Point3D, pc: *const Point3D, pd: *const Point3D) -> c_double;
    fn insphere(pa: *const Point3D, pb: *const Point3D, pc: *const Point3D, pd: *const Point3D, pe: *const Point3D) -> c_double;
}

fn init_predicates() {
    EXACTINIT.call_once(|| {
        unsafe { exactinit() };
    });
}

#[derive(Debug, Eq, PartialEq)]
pub enum InCircleLocation {
    Inside,
    Outside,
    On
}

#[derive(Debug, Eq, PartialEq)]
pub enum Orientation {
    Positive,
    Negative
}

impl Orientation {
    pub fn to_f64_multiplier(&self) -> f64 {
        match *self {
            Orientation::Positive => {  1.0 },
            Orientation::Negative => { -1.0 }
        }
    }
}

pub trait InCircleTestable<P> {
    fn in_circle_test(&self, point: &P) -> Option<InCircleLocation>;
}

pub trait Orientable {
    fn orientation(&self) -> Option<Orientation>;
}

pub struct Triangle<P> {
    p1: P,
    p2: P,
    p3: P,
}

impl<P> Triangle<P> {
    pub fn new(p1: P, p2: P, p3: P) -> Triangle<P> {
        Triangle {
            p1: p1,
            p2: p2,
            p3: p3,
        }
    }
}

pub struct Tetrahedron<P> {
    p1: P,
    p2: P,
    p3: P,
    p4: P,
}

impl<P> Tetrahedron<P> {
    pub fn new(p1: P, p2: P, p3: P, p4: P) -> Tetrahedron<P> {
        Tetrahedron {
            p1: p1,
            p2: p2,
            p3: p3,
            p4: p4,
        }
    }
}

fn det_to_in_circle_location(det: f64) -> Option<InCircleLocation> {
    match 0.0.partial_cmp(&det) {
        Some(Ordering::Greater) => { Some(InCircleLocation::Inside) }
        Some(Ordering::Less) => { Some(InCircleLocation::Outside) }
        Some(Ordering::Equal) => { Some(InCircleLocation::On) }
        None => { None }
    }
}

fn det_to_orientation(det: f64) -> Option<Orientation> {
    match 0.0.partial_cmp(&det) {
        Some(Ordering::Greater) => { Some(Orientation::Positive) }
        Some(Ordering::Less) => { Some(Orientation::Negative) }
        _ => { None }
    }
}

impl Orientable for Triangle<Point2D> {
    fn orientation(&self) -> Option<Orientation> {
        init_predicates();

        let orientation_det = unsafe { orient2d(&self.p1, &self.p2, &self.p3) };

        det_to_orientation(orientation_det)
    }
}

impl InCircleTestable<Point2D> for Triangle<Point2D> {
    fn in_circle_test(&self, point: &Point2D) -> Option<InCircleLocation> {
        init_predicates();

        let orienation_multiplier: f64 = match self.orientation() {
            Some(p) => { p.to_f64_multiplier() },
            None => { return None; }
        };

        let incircle_det = unsafe { incircle(&self.p1, &self.p2, &self.p3, point) };

        det_to_in_circle_location(orienation_multiplier * incircle_det)
    }
}

impl Orientable for Tetrahedron<Point3D> {
    fn orientation(&self) -> Option<Orientation> {
        init_predicates();

        let orientation_det = unsafe { orient3d(&self.p1, &self.p2, &self.p3, &self.p4) };

        det_to_orientation(orientation_det)
    }
}

impl InCircleTestable<Point3D> for Tetrahedron<Point3D> {
    fn in_circle_test(&self, point: &Point3D) -> Option<InCircleLocation> {
        init_predicates();

        let orienation_multiplier: f64 = match self.orientation() {
            Some(p) => { p.to_f64_multiplier() },
            None => { return None; }
        };

        let incircle_det = unsafe { insphere(&self.p1, &self.p2, &self.p3, &self.p4, point) };

        det_to_in_circle_location(orienation_multiplier * incircle_det)
    }
}

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

    use std::f64;

    #[test]
    fn in_circle_2d() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);
        let d_inside = Point2D::new(0.5, 0.5);
        let d_outside = Point2D::new(2.0, 0.0);
        let d_on = Point2D::new(1.0, 1.0);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d_inside), Some(InCircleLocation::Inside));
        assert_eq!(t.in_circle_test(&d_outside), Some(InCircleLocation::Outside));
        assert_eq!(t.in_circle_test(&d_on), Some(InCircleLocation::On));
    }

    #[test]
    fn in_circle_2d_nan_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::NAN);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_nan_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::NAN);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_infinity_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::INFINITY);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_infinity_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::INFINITY);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_neg_infinity_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::NEG_INFINITY);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_neg_infinity_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::NEG_INFINITY);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_3d() {
        let p1 = Point3D::new(-1.0,  1.0, -1.0);
        let p2 = Point3D::new( 1.0,  1.0, -1.0);
        let p3 = Point3D::new( 0.0, -1.0, -1.0);
        let p4 = Point3D::new( 0.0,  0.0,  1.0);
        let d_inside = Point3D::new(0.0, 0.0, 0.0);
        let d_outside = Point3D::new(10.0, 10.0, 10.0);
        let d_on = Point3D::new(0.0, 0.0, 1.0);

        let t = Tetrahedron::new(p1, p2, p3, p4);

        assert_eq!(t.in_circle_test(&d_inside), Some(InCircleLocation::Inside));
        assert_eq!(t.in_circle_test(&d_outside), Some(InCircleLocation::Outside));
        assert_eq!(t.in_circle_test(&d_on), Some(InCircleLocation::On));
    }

}
<|endoftext|>


<commit_before>use std::str;
use std::fmt;

extern crate backtrace;

#[derive(Debug)]
pub enum Error {
    InvalidLevel,
    NoSymbolName,
    NoMethodSeparator,
    Utf8(str::Utf8Error),
    Demangle(fmt::Error),
}

impl From<str::Utf8Error> for Error {
    fn from(err: str::Utf8Error) -> Error {
        Error::Utf8(err)
    }
}

impl From<fmt::Error> for Error {
    fn from(err: fmt::Error) -> Error {
        Error::Demangle(err)
    }
}

pub fn get_method_name() -> Result<String, Error> {
    let mut result = Err(Error::InvalidLevel);
    let mut level = 0;

    backtrace::trace(&mut |frame| {
        let ip = frame.ip();

        backtrace::resolve(ip, &mut |symbol| result = resolve_method(symbol, level));

        level = level + 1;

        match result {
            Err(Error::InvalidLevel) => true,
            _ => false,
        }
    });

    result
}

fn resolve_method(symbol: &backtrace::Symbol, level: usize) -> Result<String, Error> {
    // 0 - backtrace::trace
    // 1 - get_method_name
    // 2 - approve
    // 3 - your_method_name
    if level < 3 {
        return Err(Error::InvalidLevel);
    }

    let name = try!(symbol.name().ok_or(Error::NoSymbolName));

    let mut demangled = String::new();
    let mangled = try!(str::from_utf8(name));

    try!(backtrace::demangle(&mut demangled, mangled));

    let index = try!(demangled.rfind(':').ok_or(Error::NoMethodSeparator));
    let method_name = try!(str::from_utf8(&(demangled.as_bytes())[..(index - 1)]));

    Ok(method_name.to_string())
}
<commit_msg>Removed Debug implementation for get_method_name::Error<commit_after>use std::str;
use std::fmt;

extern crate backtrace;

pub enum Error {
    InvalidLevel,
    NoSymbolName,
    NoMethodSeparator,
    Utf8(str::Utf8Error),
    Demangle(fmt::Error),
}

impl From<str::Utf8Error> for Error {
    fn from(err: str::Utf8Error) -> Error {
        Error::Utf8(err)
    }
}

impl From<fmt::Error> for Error {
    fn from(err: fmt::Error) -> Error {
        Error::Demangle(err)
    }
}

pub fn get_method_name() -> Result<String, Error> {
    let mut result = Err(Error::InvalidLevel);
    let mut level = 0;

    backtrace::trace(&mut |frame| {
        let ip = frame.ip();

        backtrace::resolve(ip, &mut |symbol| result = resolve_method(symbol, level));

        level = level + 1;

        match result {
            Err(Error::InvalidLevel) => true,
            _ => false,
        }
    });

    result
}

fn resolve_method(symbol: &backtrace::Symbol, level: usize) -> Result<String, Error> {
    // 0 - backtrace::trace
    // 1 - get_method_name
    // 2 - approve
    // 3 - your_method_name
    if level < 3 {
        return Err(Error::InvalidLevel);
    }

    let name = try!(symbol.name().ok_or(Error::NoSymbolName));

    let mut demangled = String::new();
    let mangled = try!(str::from_utf8(name));

    try!(backtrace::demangle(&mut demangled, mangled));

    let index = try!(demangled.rfind(':').ok_or(Error::NoMethodSeparator));
    let method_name = try!(str::from_utf8(&(demangled.as_bytes())[..(index - 1)]));

    Ok(method_name.to_string())
}
<|endoftext|>


<commit_before>use game_state::{GameState, GameMode};
use command::{CommandProcessor, HelpInfo};
use items::Item;
use items::Item::*;

use self::InventoryCommand::*;

pub enum InventoryCommand {
  Buy(Item),
  Leave,
}

impl CommandProcessor<InventoryCommand> for InventoryCommand {
  fn prompt() -> &'static str { "What do you want to buy? " }

  fn get_help() -> Vec<HelpInfo> {
    let buy = |item: Item| format!("buy {} (${})", item, item.price());

    HelpInfo::list(vec![
      ('1', buy(Torch)),
      ('2', buy(Axe)),
      ('3', buy(Sword)),
      ('4', buy(Food)),
      ('5', buy(Amulet)),
      ('6', buy(Armor)),
      ('0', String::from("continue adventure")),
    ])
  }

  fn from_char(c: char) -> Option<InventoryCommand> {
    match c {
      '1' => Some(Buy(Torch)),
      '2' => Some(Buy(Axe)),
      '3' => Some(Buy(Sword)),
      '4' => Some(Buy(Food)),
      '5' => Some(Buy(Amulet)),
      '6' => Some(Buy(Armor)),
      _ => Some(Leave),
    }
  }
}

impl<'a> GameState<'a> {
  pub fn tick_inventory_mode(&mut self) {
    if self.show_desc {
      println!("Provisions & inventory\n");
      self.print_wealth();
      println!("");
      InventoryCommand::show_help();
      println!("");
      self.show_desc = false;
    }

    if let Some(cmd) = InventoryCommand::get() {
      match cmd {
        Buy(item) => {
          let price = item.price();
          if price > self.wealth {
            println!("You don't have enough money to buy that.");
          } else {
            self.wealth -= price;
            println!("You bought {}.", item);
            self.print_wealth();
            match item {
              Torch => self.light = true,
              Axe => self.axe = true,
              Sword => self.sword = true,
              Food => self.food += 1,
              Amulet => self.amulet = true,
              Armor => self.suit = true,
            }
          }
          println!("");
        },
        Leave => { self.set_mode(GameMode::Primary) },
      }
    }
  }
}
<commit_msg>Don't let players buy the same unique item twice.<commit_after>use game_state::{GameState, GameMode};
use command::{CommandProcessor, HelpInfo};
use items::Item;
use items::Item::*;

use self::InventoryCommand::*;

pub enum InventoryCommand {
  Buy(Item),
  Leave,
}

impl CommandProcessor<InventoryCommand> for InventoryCommand {
  fn prompt() -> &'static str { "What do you want to buy? " }

  fn get_help() -> Vec<HelpInfo> {
    let buy = |item: Item| format!("buy {} (${})", item, item.price());

    HelpInfo::list(vec![
      ('1', buy(Torch)),
      ('2', buy(Axe)),
      ('3', buy(Sword)),
      ('4', buy(Food)),
      ('5', buy(Amulet)),
      ('6', buy(Armor)),
      ('0', String::from("continue adventure")),
    ])
  }

  fn from_char(c: char) -> Option<InventoryCommand> {
    match c {
      '1' => Some(Buy(Torch)),
      '2' => Some(Buy(Axe)),
      '3' => Some(Buy(Sword)),
      '4' => Some(Buy(Food)),
      '5' => Some(Buy(Amulet)),
      '6' => Some(Buy(Armor)),
      _ => Some(Leave),
    }
  }
}

impl<'a> GameState<'a> {
  pub fn tick_inventory_mode(&mut self) {
    if self.show_desc {
      println!("Provisions & inventory\n");
      self.print_wealth();
      println!("");
      InventoryCommand::show_help();
      println!("");
      self.show_desc = false;
    }

    if let Some(cmd) = InventoryCommand::get() {
      match cmd {
        Buy(item) => {
          let price = item.price();
          if price > self.wealth {
            println!("You don't have enough money to buy that.");
          } else {
            if match item {
              Torch => self.light,
              Axe => self.axe,
              Sword => self.sword,
              Food => false,
              Amulet => self.amulet,
              Armor => self.suit,
            } {
              println!("You already own {}.", item);
            } else {
              self.wealth -= price;
              println!("You bought {}.", item);
              self.print_wealth();
              match item {
                Torch => self.light = true,
                Axe => self.axe = true,
                Sword => self.sword = true,
                Food => self.food += 1,
                Amulet => self.amulet = true,
                Armor => self.suit = true,
              }
            }
          }
          println!("");
        },
        Leave => { self.set_mode(GameMode::Primary) },
      }
    }
  }
}
<|endoftext|>