<commit_before>use geometry::Point;
use geometry::Rect;
use geometry::Size;

/**
 Elements that may be contained by a quadtree node.
 Either child nodes, a single rect, or nothing.
 */
pub enum Elements {
    /// Children are top left, top right, bottom right, and bottom left, respectively.
    Children(~QuadTree, ~QuadTree, ~QuadTree, ~QuadTree),
    /// A single rectangle.
    Member(Rect),
    /// Nothing.
    NoElements,
}

/**
 A quadtree node that can contain either one rectangle,
 or exactly four child nodes.
 */
pub struct QuadTree {
    rect: Rect,
    elements: Elements,
}

impl QuadTree {
    /**
     Create a quadtree with a root node with the given origin and size.
     */
    pub fn new(origin: Point, size: Size, elems: Elements) -> QuadTree {
        let tree =
        match elems {
            Children(tl, tr, br, bl) => QuadTree::newWithChildren(origin, size, tl, tr, br, bl),
            Member(rect) => QuadTree::newWithMember(origin, size, rect),
            NoElements => QuadTree::newWithSize(origin, size),
        };

        tree
    }

    /**
     Create a quadtree with a root node with the same origin and a square
     size with side length matching the longer dimension of `rect`.
     */
    pub fn newAutosized(rect: Rect) -> QuadTree {
        let largerDimen = if rect.size.width > rect.size.height {
            rect.size.width
        } else {
            rect.size.height
        };

        let size = Size { width: largerDimen, height: largerDimen };

        QuadTree::newWithMember(rect.origin, size, rect)
    }

    /**
     Create an empty quadtree with a zero-sized root node.
     */
    pub fn newEmpty() -> QuadTree {
        let origin = Point { x: 0 as f32, y: 0 as f32 };
        let size = Size { width: 0 as f32, height: 0 as f32 };
        let tree = QuadTree::new(origin, size, NoElements);

        tree
    }

    /**
     Create a quadtree with a root node with the given origin, size, and child rectangles.
     Child nodes `tl`, `tr`, `br`, and `bl` should form the rect specified by `origin` and `size`.
     */
    fn newWithChildren(origin: Point, size: Size, tl: ~QuadTree, tr: ~QuadTree, br: ~QuadTree, bl: ~QuadTree) -> QuadTree {
        let nodeRect = Rect { origin: origin, size: size };

        // Assert that our rect and our childrens' rects match up.
        assert!(tl.rect.minX() == bl.rect.minX(), "Top left and bottom left children should have same minX coordinate.");
        assert!(tl.rect.maxX() == bl.rect.maxX(), "Top left and bottom left children should have same maxX coordinate.");
        assert!(tl.rect.maxY() == bl.rect.minY(), "Top left and bottom left children should have same maxY and minY coordinates, respectively.");

        assert!(tl.rect.maxX() == tr.rect.minX(), "Top left and top right children should share their maxX and minX coordinates, respectively.");
        assert!(tl.rect.minY() == tr.rect.minY(), "Top left and top right children should have same minY coordinate.");
        assert!(tl.rect.maxY() == tr.rect.maxY(), "Top left and top right children should have same maxY coordinate.");

        assert!(bl.rect.maxX() == br.rect.minX(), "Bottom left and bottom right children should share their maxX and minX coordinates, respectively.");
        assert!(bl.rect.minY() == br.rect.minY(), "Bottom left and bottom right children should have same minY coordinate.");
        assert!(bl.rect.maxY() == br.rect.maxY(), "Bottom left and bottom right children should have same maxY coordinate.");

        assert!(tr.rect.minX() == br.rect.minX(), "Top right and bottom right children should have same minX coordinate.");
        assert!(tr.rect.maxX() == br.rect.maxX(), "Top right and bottom right children should have same maxX coordinate.");
        assert!(tr.rect.maxY() == br.rect.minY(), "Top right and bottom right children should have same maxY and minY coordinates, respectively.");

        assert!(nodeRect.minX() == tl.rect.minX(), "Tree node's minX should match its top left child's minX coordinate.");
        assert!(nodeRect.maxX() == tr.rect.maxX(), "Tree node's maxX should match its top right child's maxX coordinate.");
        assert!(nodeRect.minY() == tl.rect.minY(), "Tree node's minY should match its top left child's minY coordinate.");
        assert!(nodeRect.maxY() == bl.rect.maxY(), "Tree node's maxY should match its top left child's maxY coordinate.");

        let tree = QuadTree { rect: nodeRect, elements: Children(tl, tr, br, bl) };

        tree
    }

    /**
     Create a quadtree with a root node with the given origin, size, and member rectangle.
     */
    fn newWithMember(origin: Point, size: Size, insertRect: Rect) -> QuadTree {
        let node = QuadTree::newWithSize(origin, size);

        let (success, tree) = node.insertRect(insertRect);
        assert!(success, "Failed inserting a node into an empty quadtree.");

        tree
    }

    /**
     Create a quadtree with only a specified size and position.
     */
    fn newWithSize(origin: Point, size: Size) -> QuadTree {
        let nodeRect = Rect { origin: origin, size: size };
        let tree = QuadTree { rect: nodeRect, elements: NoElements };

        tree
    }

    /**
     Insert a rectangle into the quadtree. If `toInsert` overlaps another rectangle
     already in the tree, the return value will be (false, self).
     If the root node is zero-sized, the resulting tree will have a square root node
     large enough to hold `toInsert`.
     */
    pub fn insertRect(self, toInsert: Rect) -> (bool, QuadTree) {
        if self.rect.width() == 0.0 {
            return (true, QuadTree::newAutosized(toInsert))
        }

        let rectsInChildren = self.rectsInChildNodesIntersectedByRect(&toInsert);
        if rectsInChildren.len() > 0 {
            return (false, self)
        }

        let mut node = self;
        let mut needBigger = node.rect.contains(&toInsert);

        while needBigger {
            let width = node.rect.width();
            let height = node.rect.height();
            let origin = node.rect.origin;
            let size = node.rect.size;

            let wPoint = Point { x: width, y: 0. };
            let hPoint = Point { x: 0., y: height };

            // Check if the rect to insert extends to the left or "above" our origin,
            // i.e. has a lower x or y coordinate in its origin.
            // Use this information to determine if we must grow the tree left, up, right, or down.
            let left = node.rect.minX() < toInsert.minX();
            let top = node.rect.minX() < toInsert.minY();

            let (tl, tr, bl, br) =
            match (left, top) {
                (true, true) => (QuadTree::newWithSize(origin.subtract(wPoint).add(hPoint), size),
                                 QuadTree::newWithSize(origin.subtract(hPoint), size),
                                 QuadTree::newWithSize(origin.subtract(wPoint), size),
                                 node),
                (true, false) => (QuadTree::newWithSize(origin.subtract(wPoint), size),
                                  node,
                                  QuadTree::newWithSize(origin.subtract(wPoint).subtract(hPoint), size),
                                  QuadTree::newWithSize(origin.subtract(hPoint), size)),
                (false, true) => (QuadTree::newWithSize(origin.add(hPoint), size),
                                  QuadTree::newWithSize(origin.add(hPoint).add(wPoint), size),
                                  node,
                                  QuadTree::newWithSize(origin.add(wPoint), size)),
                (false, false) => (node,
                                   QuadTree::newWithSize(origin.add(wPoint), size),
                                   QuadTree::newWithSize(origin.add(hPoint), size),
                                   QuadTree::newWithSize(origin.add(wPoint).add(hPoint), size)),
            };

            let (tl, tr, bl, br) = (tl.insertRectIfIntersects(toInsert),
                                    tr.insertRectIfIntersects(toInsert),
                                    bl.insertRectIfIntersects(toInsert),
                                    br.insertRectIfIntersects(toInsert),);

            node = QuadTree::newWithChildren(tl.rect.origin,
                Size { width: width * 2., height: height * 2. },
                ~tl, ~tr, ~br, ~bl);

            needBigger = node.rect.contains(&toInsert);
        }

        (true, node)
    }

    /**
     Insert a rectangle into the node IFF the rectangle intersects the node.
     Does nothing if `toInsert` intersects our existing member rect.
     */
    fn insertRectIfIntersects(self, toInsert: Rect) -> QuadTree {
        if self.rect.intersects(&toInsert) {
            let origin = self.rect.origin;
            let size = self.rect.size;
            match self.elements {
                Children(~tl, ~tr, ~br, ~bl) => {
                    let (tl, tr, br, bl) = (tl.insertRectIfIntersects(toInsert),
                                            tr.insertRectIfIntersects(toInsert),
                                            br.insertRectIfIntersects(toInsert),
                                            bl.insertRectIfIntersects(toInsert),);
                    QuadTree::newWithChildren(origin, size, ~tl, ~tr, ~br, ~bl)
                },
                Member(rect) => {
                    if rect.intersects(&toInsert) {
                        self
                    } else {
                        let (tl, tr, br, bl) = QuadTree::makeChildrenForRect(&self.rect);

                        let (tl, tr, br, bl) = (tl.insertRectIfIntersects(rect),
                                                tr.insertRectIfIntersects(rect),
                                                br.insertRectIfIntersects(rect),
                                                bl.insertRectIfIntersects(rect),);
                        let (tl, tr, br, bl) = (tl.insertRectIfIntersects(toInsert),
                                                tr.insertRectIfIntersects(toInsert),
                                                br.insertRectIfIntersects(toInsert),
                                                bl.insertRectIfIntersects(toInsert),);

                        QuadTree::newWithChildren(origin, size, ~tl, ~tr, ~br, ~bl)
                    }
                },
                NoElements => QuadTree::newWithMember(origin, size, toInsert),
            }
        } else {
            self
        }
    }

    /**
     Create four nodes suitable for use as children, covering the passed in rect.
     */
    fn makeChildrenForRect(rect: &Rect) -> (~QuadTree, ~QuadTree, ~QuadTree, ~QuadTree,) {
        let origin = rect.origin;
        let size = rect.size;

        let newSize = Size { width: size.width / 2., height: size.height / 2. };
        let wPoint = Point { x: newSize.width, y: 0. };
        let hPoint = Point { x: 0., y: newSize.height };

        let (tl, tr, br, bl) = (QuadTree::newWithSize(origin, newSize),
                                QuadTree::newWithSize(origin.add(wPoint), newSize),
                                QuadTree::newWithSize(origin.add(wPoint).add(hPoint), newSize),
                                QuadTree::newWithSize(origin.add(hPoint), newSize),);

        (~tl, ~tr, ~br, ~bl)
    }

    /**
     Find all of the rects in `self`, or its children, that are in nodes
     intersected by the given rect.
     */
    pub fn rectsInChildNodesIntersectedByRect(&self, testRect: &Rect) -> ~[Rect] {
        // If the test rect doesn't intersect us, then it can't intersect
        // any rects that we have.
        match self.rect.intersect(testRect) {
            Some(intersection) => {
                let mut rects = ~[];
                let mut nodesToCheck = ~[self];

                while nodesToCheck.len() > 0 {
                    let mut newNodesToCheck = ~[];

                    for node in nodesToCheck.iter() {
                        match node.elements {
                            Children(~ref tl, ~ref tr, ~ref br, ~ref bl) => {
                                let mut check = ~[];
                                let intersection = &intersection;
                                if tl.rect.intersects(intersection) {
                                    check.push(tl);
                                }
                                if tr.rect.intersects(intersection) {
                                    check.push(tr);
                                }
                                if br.rect.intersects(intersection) {
                                    check.push(br);
                                }
                                if bl.rect.intersects(intersection) {
                                    check.push(bl);
                                }
                                newNodesToCheck.push_all(check);
                            }
                            Member(memberRect) => rects.push(memberRect),
                            NoElements => ()
                        };
                    }

                    nodesToCheck = newNodesToCheck;
                }

                rects
            },
            None => ~[],
        }
    }
}
<commit_msg>Create the structs in geometry.rs using new() functions.<commit_after>use geometry::Point;
use geometry::Rect;
use geometry::Size;

/**
 Elements that may be contained by a quadtree node.
 Either child nodes, a single rect, or nothing.
 */
pub enum Elements {
    /// Children are top left, top right, bottom right, and bottom left, respectively.
    Children(~QuadTree, ~QuadTree, ~QuadTree, ~QuadTree),
    /// A single rectangle.
    Member(Rect),
    /// Nothing.
    NoElements,
}

/**
 A quadtree node that can contain either one rectangle,
 or exactly four child nodes.
 */
pub struct QuadTree {
    rect: Rect,
    elements: Elements,
}

impl QuadTree {
    /**
     Create a quadtree with a root node with the given origin and size.
     */
    pub fn new(origin: Point, size: Size, elems: Elements) -> QuadTree {
        let tree =
        match elems {
            Children(tl, tr, br, bl) => QuadTree::newWithChildren(origin, size, tl, tr, br, bl),
            Member(rect) => QuadTree::newWithMember(origin, size, rect),
            NoElements => QuadTree::newWithSize(origin, size),
        };

        tree
    }

    /**
     Create a quadtree with a root node with the same origin and a square
     size with side length matching the longer dimension of `rect`.
     */
    pub fn newAutosized(rect: Rect) -> QuadTree {
        let largerDimen = if rect.size.width > rect.size.height {
            rect.size.width
        } else {
            rect.size.height
        };

        let size = Size::new(largerDimen, largerDimen);

        QuadTree::newWithMember(rect.origin, size, rect)
    }

    /**
     Create an empty quadtree with a zero-sized root node.
     */
    pub fn newEmpty() -> QuadTree {
        let origin = Point::new(0., 0.);
        let size = Size::new(0., 0.);
        let tree = QuadTree::new(origin, size, NoElements);

        tree
    }

    /**
     Create a quadtree with a root node with the given origin, size, and child rectangles.
     Child nodes `tl`, `tr`, `br`, and `bl` should form the rect specified by `origin` and `size`.
     */
    fn newWithChildren(origin: Point, size: Size, tl: ~QuadTree, tr: ~QuadTree, br: ~QuadTree, bl: ~QuadTree) -> QuadTree {
        let nodeRect = Rect::new(origin, size);

        // Assert that our rect and our childrens' rects match up.
        assert!(tl.rect.minX() == bl.rect.minX(), "Top left and bottom left children should have same minX coordinate.");
        assert!(tl.rect.maxX() == bl.rect.maxX(), "Top left and bottom left children should have same maxX coordinate.");
        assert!(tl.rect.maxY() == bl.rect.minY(), "Top left and bottom left children should have same maxY and minY coordinates, respectively.");

        assert!(tl.rect.maxX() == tr.rect.minX(), "Top left and top right children should share their maxX and minX coordinates, respectively.");
        assert!(tl.rect.minY() == tr.rect.minY(), "Top left and top right children should have same minY coordinate.");
        assert!(tl.rect.maxY() == tr.rect.maxY(), "Top left and top right children should have same maxY coordinate.");

        assert!(bl.rect.maxX() == br.rect.minX(), "Bottom left and bottom right children should share their maxX and minX coordinates, respectively.");
        assert!(bl.rect.minY() == br.rect.minY(), "Bottom left and bottom right children should have same minY coordinate.");
        assert!(bl.rect.maxY() == br.rect.maxY(), "Bottom left and bottom right children should have same maxY coordinate.");

        assert!(tr.rect.minX() == br.rect.minX(), "Top right and bottom right children should have same minX coordinate.");
        assert!(tr.rect.maxX() == br.rect.maxX(), "Top right and bottom right children should have same maxX coordinate.");
        assert!(tr.rect.maxY() == br.rect.minY(), "Top right and bottom right children should have same maxY and minY coordinates, respectively.");

        assert!(nodeRect.minX() == tl.rect.minX(), "Tree node's minX should match its top left child's minX coordinate.");
        assert!(nodeRect.maxX() == tr.rect.maxX(), "Tree node's maxX should match its top right child's maxX coordinate.");
        assert!(nodeRect.minY() == tl.rect.minY(), "Tree node's minY should match its top left child's minY coordinate.");
        assert!(nodeRect.maxY() == bl.rect.maxY(), "Tree node's maxY should match its top left child's maxY coordinate.");

        let tree = QuadTree { rect: nodeRect, elements: Children(tl, tr, br, bl) };

        tree
    }

    /**
     Create a quadtree with a root node with the given origin, size, and member rectangle.
     */
    fn newWithMember(origin: Point, size: Size, insertRect: Rect) -> QuadTree {
        let node = QuadTree::newWithSize(origin, size);

        let (success, tree) = node.insertRect(insertRect);
        assert!(success, "Failed inserting a node into an empty quadtree.");

        tree
    }

    /**
     Create a quadtree with only a specified size and position.
     */
    fn newWithSize(origin: Point, size: Size) -> QuadTree {
        let nodeRect = Rect::new(origin, size);
        let tree = QuadTree { rect: nodeRect, elements: NoElements };

        tree
    }

    /**
     Insert a rectangle into the quadtree. If `toInsert` overlaps another rectangle
     already in the tree, the return value will be (false, self).
     If the root node is zero-sized, the resulting tree will have a square root node
     large enough to hold `toInsert`.
     */
    pub fn insertRect(self, toInsert: Rect) -> (bool, QuadTree) {
        if self.rect.width() == 0.0 {
            return (true, QuadTree::newAutosized(toInsert))
        }

        let rectsInChildren = self.rectsInChildNodesIntersectedByRect(&toInsert);
        if rectsInChildren.len() > 0 {
            return (false, self)
        }

        let mut node = self;
        let mut needBigger = node.rect.contains(&toInsert);

        while needBigger {
            let width = node.rect.width();
            let height = node.rect.height();
            let origin = node.rect.origin;
            let size = node.rect.size;

            let wPoint = Point::new(width, 0.);
            let hPoint = Point::new(0., height);

            // Check if the rect to insert extends to the left or "above" our origin,
            // i.e. has a lower x or y coordinate in its origin.
            // Use this information to determine if we must grow the tree left, up, right, or down.
            let left = node.rect.minX() < toInsert.minX();
            let top = node.rect.minX() < toInsert.minY();

            let (tl, tr, bl, br) =
            match (left, top) {
                (true, true) => (QuadTree::newWithSize(origin.subtract(wPoint).add(hPoint), size),
                                 QuadTree::newWithSize(origin.subtract(hPoint), size),
                                 QuadTree::newWithSize(origin.subtract(wPoint), size),
                                 node),
                (true, false) => (QuadTree::newWithSize(origin.subtract(wPoint), size),
                                  node,
                                  QuadTree::newWithSize(origin.subtract(wPoint).subtract(hPoint), size),
                                  QuadTree::newWithSize(origin.subtract(hPoint), size)),
                (false, true) => (QuadTree::newWithSize(origin.add(hPoint), size),
                                  QuadTree::newWithSize(origin.add(hPoint).add(wPoint), size),
                                  node,
                                  QuadTree::newWithSize(origin.add(wPoint), size)),
                (false, false) => (node,
                                   QuadTree::newWithSize(origin.add(wPoint), size),
                                   QuadTree::newWithSize(origin.add(hPoint), size),
                                   QuadTree::newWithSize(origin.add(wPoint).add(hPoint), size)),
            };

            let (tl, tr, bl, br) = (tl.insertRectIfIntersects(toInsert),
                                    tr.insertRectIfIntersects(toInsert),
                                    bl.insertRectIfIntersects(toInsert),
                                    br.insertRectIfIntersects(toInsert),);

            node = QuadTree::newWithChildren(tl.rect.origin,
                Size::new(width * 2., height * 2.),
                ~tl, ~tr, ~br, ~bl);

            needBigger = node.rect.contains(&toInsert);
        }

        (true, node)
    }

    /**
     Insert a rectangle into the node IFF the rectangle intersects the node.
     Does nothing if `toInsert` intersects our existing member rect.
     */
    fn insertRectIfIntersects(self, toInsert: Rect) -> QuadTree {
        if self.rect.intersects(&toInsert) {
            let origin = self.rect.origin;
            let size = self.rect.size;
            match self.elements {
                Children(~tl, ~tr, ~br, ~bl) => {
                    let (tl, tr, br, bl) = (tl.insertRectIfIntersects(toInsert),
                                            tr.insertRectIfIntersects(toInsert),
                                            br.insertRectIfIntersects(toInsert),
                                            bl.insertRectIfIntersects(toInsert),);
                    QuadTree::newWithChildren(origin, size, ~tl, ~tr, ~br, ~bl)
                },
                Member(rect) => {
                    if rect.intersects(&toInsert) {
                        self
                    } else {
                        let (tl, tr, br, bl) = QuadTree::makeChildrenForRect(&self.rect);

                        let (tl, tr, br, bl) = (tl.insertRectIfIntersects(rect),
                                                tr.insertRectIfIntersects(rect),
                                                br.insertRectIfIntersects(rect),
                                                bl.insertRectIfIntersects(rect),);
                        let (tl, tr, br, bl) = (tl.insertRectIfIntersects(toInsert),
                                                tr.insertRectIfIntersects(toInsert),
                                                br.insertRectIfIntersects(toInsert),
                                                bl.insertRectIfIntersects(toInsert),);

                        QuadTree::newWithChildren(origin, size, ~tl, ~tr, ~br, ~bl)
                    }
                },
                NoElements => QuadTree::newWithMember(origin, size, toInsert),
            }
        } else {
            self
        }
    }

    /**
     Create four nodes suitable for use as children, covering the passed in rect.
     */
    fn makeChildrenForRect(rect: &Rect) -> (~QuadTree, ~QuadTree, ~QuadTree, ~QuadTree,) {
        let origin = rect.origin;
        let size = rect.size;

        let newSize = Size::new(size.width / 2., size.height / 2.);
        let wPoint = Point::new(newSize.width, 0.);
        let hPoint = Point::new(0., newSize.height);

        let (tl, tr, br, bl) = (QuadTree::newWithSize(origin, newSize),
                                QuadTree::newWithSize(origin.add(wPoint), newSize),
                                QuadTree::newWithSize(origin.add(wPoint).add(hPoint), newSize),
                                QuadTree::newWithSize(origin.add(hPoint), newSize),);

        (~tl, ~tr, ~br, ~bl)
    }

    /**
     Find all of the rects in `self`, or its children, that are in nodes
     intersected by the given rect.
     */
    pub fn rectsInChildNodesIntersectedByRect(&self, testRect: &Rect) -> ~[Rect] {
        // If the test rect doesn't intersect us, then it can't intersect
        // any rects that we have.
        match self.rect.intersect(testRect) {
            Some(intersection) => {
                let mut rects = ~[];
                let mut nodesToCheck = ~[self];

                while nodesToCheck.len() > 0 {
                    let mut newNodesToCheck = ~[];

                    for node in nodesToCheck.iter() {
                        match node.elements {
                            Children(~ref tl, ~ref tr, ~ref br, ~ref bl) => {
                                let mut check = ~[];
                                let intersection = &intersection;
                                if tl.rect.intersects(intersection) {
                                    check.push(tl);
                                }
                                if tr.rect.intersects(intersection) {
                                    check.push(tr);
                                }
                                if br.rect.intersects(intersection) {
                                    check.push(br);
                                }
                                if bl.rect.intersects(intersection) {
                                    check.push(bl);
                                }
                                newNodesToCheck.push_all(check);
                            }
                            Member(memberRect) => rects.push(memberRect),
                            NoElements => ()
                        };
                    }

                    nodesToCheck = newNodesToCheck;
                }

                rects
            },
            None => ~[],
        }
    }
}
<|endoftext|>


<commit_before>//! Contains types related to vertex data, which are used for [`VertexBuffers`]
//! (../vertex_buffer/struct.VertexBuffer.html).

use std::mem;
use std::slice;
use types::DataType;

/// A type that has vertex data.
///
/// # Safety
/// Implementors must properly implement the [`visit_attributes`]
/// (trait.VertexData.html#tymethod.visit_attributes) method. Implementing
/// this method incorrectly will lead to memory unsafety in some safe
/// API's in glitter.
///
/// # Example
/// ```
/// #[macro_use] extern crate glitter;
/// use glitter::prelude::*;
///
/// #[derive(Clone, Copy)] // `VertexData` types must implement `Copy`
/// #[repr(C)] // Use a predictable data layout (for our field offsets)
/// struct MyVertex {
///     position: [f32; 3],
///     color: [f32; 3]
/// }
///
/// // Manually implement the `VertexData` trait
/// unsafe impl glitter::VertexData for MyVertex {
///     fn visit_attributes<F>(mut f: F)
///         where F: FnMut(glitter::VertexAttribute)
///     {
///         use std::mem;
///         use glitter::{VertexAttribute, VertexAttributeType, VertexDatum};
///
///         // The vertex attribute type for an `[f32; 3]`, or `vec3`
///         let vec3 = <[f32; 3] as VertexDatum>::attrib_type();
///
///         // let vec3 = VertexAttributeType {
///         //     data: glitter::FLOAT,
///         //     components: 3,
///         //     normalize: false
///         // };
///
///         let stride = mem::size_of::<MyVertex>();
///         let position_offset = 0;
///         let position_size = mem::size_of::<[f32; 3]>();
///         let color_offset = position_offset + position_size;
///
///         let position = VertexAttribute {
///             ty: vec3.clone(),
///             name: "position".into(),
///             offset: position_offset,
///             stride: stride
///         };
///         let color = VertexAttribute {
///             ty: vec3,
///             name: "color".into(),
///             offset: color_offset,
///             stride: stride
///         };
///
///         // Call the function with the "position" and "color" attributes
///         f(position);
///         f(color);
///     }
/// }
/// # fn main() {
/// #     // TODO: Add `VertexData` implementation test
/// # }
/// ```
///
/// # See also
/// [`impl_vertx_data!`](../macro.impl_vertex_data!.html): A macro that
/// automatically implements `VertexData` for structs.
pub unsafe trait VertexData: Copy {
    /// Call the given function with each attribute that this
    /// vertex data is composed of.
    ///
    /// # Safety
    /// The function must only be called once per attribute, and
    /// the provided values of the [`VertexAttribute`]
    /// (struct.VertexAttribute.html) passed to the function *must*
    /// be correct. See the [`VertexAttribute`](struct.VertexAttribute.html)
    /// docs for more details on what each field means.
    fn visit_attributes<F>(&f: F) where F: FnMut(VertexAttribute);
}

/// A single value that can be treated as a part of a vertex. Implementors
/// should map to a GLSL primitive that can be used as a vertex attribute.
/// For example, `[f32; 2]` corresponds to `vec2` in memory layout
/// and structure.
///
/// # Safety
/// This type will be transmuted to a slice according to the value returned
/// by the [`attrib_type`](trait.VertexDatum.html#tymethod.attrib_type) method.
/// Implementing this method incorrectly will lead to memory unsafety.
pub unsafe trait VertexDatum: Copy {
    /// Return the data type this datum corresponds to.
    ///
    /// # Safety
    /// An instance of this type must match the size and memory layout
    /// specified by the returned [`VertexAttributeType`]
    /// (struct.VertexAttributeType.html).
    fn attrib_type() -> VertexAttributeType;
}

/// A single, basic value that can be composed to make a [`VertexDatum`]
/// (trait.VertexDatum.html). Scalar values are an example of a
/// `VertexPrimitive`.
///
/// # Safety
/// This type will be transmuted to a slice according to the value returned
/// by the [`data_type`](trait.VertexPrimitive.html#tymethod.data_type) method.
/// Implementing this method incorrectly will lead to memory unsafety.
pub unsafe trait VertexPrimitive: Copy {
    /// Return the data type this primitive corresponds to.
    ///
    /// # Safety
    /// An instance of this type must be the size of the [`DataType`]
    /// (../types/enum.DataType.html) returned by this function.
    fn data_type() -> DataType;
}

/// Specifies the type, name, and memory layout of a vertex attribute.
/// Generally, a "vertex attribute" corresponds to a field in a [`VertexData`]
/// (trait.VertexData.html) struct.
#[derive(Clone)]
pub struct VertexAttribute {
    /// The type of the vertex attribute. This also specifies the number
    /// of bytes that make up a vertex attribute.
    pub ty: VertexAttributeType,

    /// The name of the vertex attribute. This value is used
    /// as the `$field_name` when binding vertex attribute
    /// pointers with the [`attrib_pointers!`](macro.attrib_pointers!.html)
    /// macro.
    pub name: String,

    /// The number of bytes to "move" from the start of the vertex data
    /// to reach this vertex attribute.
    pub offset: usize,

    /// The number of bytes between consecutive vertex attributes. 0 indicates
    /// that the vertex data is tightly packed.
    pub stride: usize
}

/// Used to specify type of a vertex attribute. The size of the vertex
/// attribute is `size_of(data) * components`.
#[derive(Clone)]
pub struct VertexAttributeType {
    /// The type of data that makes up this vertex attribute.
    pub data: DataType,

    /// The number of `data` components that make up this vertex attribute.
    pub components: i8,

    /// If the `data` type is fixed-point data, indicates if the data
    /// should be normalized when being accessed. `true` indicates
    /// that the vertex attribute **should** be normalized when being
    /// accessed.
    pub normalize: bool
}

unsafe impl VertexPrimitive for i8 {
    fn data_type() -> DataType { DataType::Byte }
}

unsafe impl VertexPrimitive for u8 {
    fn data_type() -> DataType { DataType::UnsignedByte }
}

unsafe impl VertexPrimitive for i16 {
    fn data_type() -> DataType { DataType::Short }
}

unsafe impl VertexPrimitive for u16 {
    fn data_type() -> DataType { DataType::UnsignedShort }
}

unsafe impl VertexPrimitive for f32 {
    fn data_type() -> DataType { DataType::Float }
}

unsafe impl<T: VertexPrimitive> VertexDatum for T {
    fn attrib_type() -> VertexAttributeType {
        VertexAttributeType {
            data: T::data_type(),
            components: 1,
            normalize: false
        }
    }
}

unsafe impl<T: VertexPrimitive> VertexDatum for [T; 1] {
    fn attrib_type() -> VertexAttributeType {
        VertexAttributeType {
            data: T::data_type(),
            components: 1,
            normalize: false
        }
    }
}

unsafe impl<T: VertexPrimitive> VertexDatum for [T; 2] {
    fn attrib_type() -> VertexAttributeType {
        VertexAttributeType {
            data: T::data_type(),
            components: 2,
            normalize: false
        }
    }
}

unsafe impl<T: VertexPrimitive> VertexDatum for [T; 3] {
    fn attrib_type() -> VertexAttributeType {
        VertexAttributeType {
            data: T::data_type(),
            components: 3,
            normalize: false
        }
    }
}

unsafe impl<T: VertexPrimitive> VertexDatum for [T; 4] {
    fn attrib_type() -> VertexAttributeType {
        VertexAttributeType {
            data: T::data_type(),
            components: 4,
            normalize: false
        }
    }
}

/// Indicates that a type can be coerced to a `u8` slice that can
/// then be treated as a stream of vertex data.
pub trait VertexBytes {
    /// Create a byte slice of vertex data from `self`.
    fn vertex_bytes(&self) -> &[u8];
}

impl<T> VertexBytes for T where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(mem::transmute(self), mem::size_of::<Self>())
        }
    }
}

impl<T> VertexBytes for [T] where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        let size = mem::size_of::<T>() * self.len();
        unsafe {
            slice::from_raw_parts(mem::transmute(&self[0]), size)
        }
    }
}

// TODO: Use a proper compiler intrinsic/macro (when available)
// see: https://github.com/rust-lang/rust/issues/24111
/// Compute the offset of a field within a struct type.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate glitter;
/// # fn main() {
/// #[repr(C, packed)]
/// struct MyStruct {
///     foo: u32,
///     bar: u32,
///     baz: u32
/// }
///
/// assert_eq!(offset_of!(MyStruct, foo), 0);
/// assert_eq!(offset_of!(MyStruct, bar), 4);
/// assert_eq!(offset_of!(MyStruct, baz), 8);
/// # }
/// ```
#[macro_export]
macro_rules! offset_of {
    ($T:ty, $field:ident) => {
        unsafe {
            let obj: $T = ::std::mem::uninitialized();
            let obj_ptr: *const u8 = ::std::mem::transmute(&obj);
            let member_ptr: *const u8 = ::std::mem::transmute(&obj.$field);

            ::std::mem::forget(obj);

            (member_ptr as usize) - (obj_ptr as usize)
        }
    }
}

/// Implement the [`VertexData`](vertex_data/trait.VertexData.html) trait
/// for a struct. Each field of the struct must that is part of the
/// `VertexData` implementation must be a type that implements [`VertexDatum`]
/// (vertex_data/trait.VertexDatum.html).
///
/// # Examples
///
/// ```
/// #[macro_use] extern crate glitter;
///
/// # fn main() {
/// // A type must implement `Copy` to implement `VertexData`
/// #[derive(Clone, Copy)]
/// struct MyVertex {
///     position: [f32; 3],
///     color: [f32; 3]
/// }
///
/// // Implement `VertexData`, using the "position" and "color" fields
/// // as vertex attributes.
/// impl_vertex_data!(MyVertex, position, color);
/// # }
/// ```
#[macro_export]
macro_rules! impl_vertex_data {
    ($name:ty, $($field_name:ident),*) => {
        unsafe impl $crate::VertexData for $name {
            fn visit_attributes<F>(mut f: F)
                where F: FnMut($crate::VertexAttribute)
            {
                // TODO: A better way of iterating over field types
                let _data: $name = unsafe { ::std::mem::uninitialized() };
                fn get_attribute_type<T: $crate::VertexDatum>(_: &T)
                    -> $crate::VertexAttributeType
                {
                    T::attrib_type()
                }
                $(
                    f($crate::VertexAttribute {
                        ty: get_attribute_type(&_data.$field_name),
                        name: stringify!($field_name).into(),
                        stride: ::std::mem::size_of::<$name>(),
                        offset: offset_of!($name, $field_name)
                    });
                )*

                ::std::mem::forget(_data);
            }
        }
    };
}
<commit_msg>Docs: add note about panicking for `impl_vertex_data!` and `VertexDatum::attrib_type()`<commit_after>//! Contains types related to vertex data, which are used for [`VertexBuffers`]
//! (../vertex_buffer/struct.VertexBuffer.html).

use std::mem;
use std::slice;
use types::DataType;

/// A type that has vertex data.
///
/// # Safety
/// Implementors must properly implement the [`visit_attributes`]
/// (trait.VertexData.html#tymethod.visit_attributes) method. Implementing
/// this method incorrectly will lead to memory unsafety in some safe
/// API's in glitter.
///
/// # Example
/// ```
/// #[macro_use] extern crate glitter;
/// use glitter::prelude::*;
///
/// #[derive(Clone, Copy)] // `VertexData` types must implement `Copy`
/// #[repr(C)] // Use a predictable data layout (for our field offsets)
/// struct MyVertex {
///     position: [f32; 3],
///     color: [f32; 3]
/// }
///
/// // Manually implement the `VertexData` trait
/// unsafe impl glitter::VertexData for MyVertex {
///     fn visit_attributes<F>(mut f: F)
///         where F: FnMut(glitter::VertexAttribute)
///     {
///         use std::mem;
///         use glitter::{VertexAttribute, VertexAttributeType, VertexDatum};
///
///         // The vertex attribute type for an `[f32; 3]`, or `vec3`
///         let vec3 = <[f32; 3] as VertexDatum>::attrib_type();
///
///         // let vec3 = VertexAttributeType {
///         //     data: glitter::FLOAT,
///         //     components: 3,
///         //     normalize: false
///         // };
///
///         let stride = mem::size_of::<MyVertex>();
///         let position_offset = 0;
///         let position_size = mem::size_of::<[f32; 3]>();
///         let color_offset = position_offset + position_size;
///
///         let position = VertexAttribute {
///             ty: vec3.clone(),
///             name: "position".into(),
///             offset: position_offset,
///             stride: stride
///         };
///         let color = VertexAttribute {
///             ty: vec3,
///             name: "color".into(),
///             offset: color_offset,
///             stride: stride
///         };
///
///         // Call the function with the "position" and "color" attributes
///         f(position);
///         f(color);
///     }
/// }
/// # fn main() {
/// #     // TODO: Add `VertexData` implementation test
/// # }
/// ```
///
/// # See also
/// [`impl_vertx_data!`](../macro.impl_vertex_data!.html): A macro that
/// automatically implements `VertexData` for structs.
pub unsafe trait VertexData: Copy {
    /// Call the given function with each attribute that this
    /// vertex data is composed of.
    ///
    /// # Safety
    /// The function must only be called once per attribute, and
    /// the provided values of the [`VertexAttribute`]
    /// (struct.VertexAttribute.html) passed to the function *must*
    /// be correct. See the [`VertexAttribute`](struct.VertexAttribute.html)
    /// docs for more details on what each field means.
    fn visit_attributes<F>(&f: F) where F: FnMut(VertexAttribute);
}

/// A single value that can be treated as a part of a vertex. Implementors
/// should map to a GLSL primitive that can be used as a vertex attribute.
/// For example, `[f32; 2]` corresponds to `vec2` in memory layout
/// and structure.
///
/// # Safety
/// This type will be transmuted to a slice according to the value returned
/// by the [`attrib_type`](trait.VertexDatum.html#tymethod.attrib_type) method.
/// Implementing this method incorrectly will lead to memory unsafety.
pub unsafe trait VertexDatum: Copy {
    /// Return the data type this datum corresponds to.
    ///
    /// # Safety
    /// An instance of this type must match the size and memory layout
    /// specified by the returned [`VertexAttributeType`]
    /// (struct.VertexAttributeType.html). Additionally **this function
    /// must not painc**. Safe code must be able to rely on this property.
    fn attrib_type() -> VertexAttributeType;
}

/// A single, basic value that can be composed to make a [`VertexDatum`]
/// (trait.VertexDatum.html). Scalar values are an example of a
/// `VertexPrimitive`.
///
/// # Safety
/// This type will be transmuted to a slice according to the value returned
/// by the [`data_type`](trait.VertexPrimitive.html#tymethod.data_type) method.
/// Implementing this method incorrectly will lead to memory unsafety.
pub unsafe trait VertexPrimitive: Copy {
    /// Return the data type this primitive corresponds to.
    ///
    /// # Safety
    /// An instance of this type must be the size of the [`DataType`]
    /// (../types/enum.DataType.html) returned by this function.
    fn data_type() -> DataType;
}

/// Specifies the type, name, and memory layout of a vertex attribute.
/// Generally, a "vertex attribute" corresponds to a field in a [`VertexData`]
/// (trait.VertexData.html) struct.
#[derive(Clone)]
pub struct VertexAttribute {
    /// The type of the vertex attribute. This also specifies the number
    /// of bytes that make up a vertex attribute.
    pub ty: VertexAttributeType,

    /// The name of the vertex attribute. This value is used
    /// as the `$field_name` when binding vertex attribute
    /// pointers with the [`attrib_pointers!`](macro.attrib_pointers!.html)
    /// macro.
    pub name: String,

    /// The number of bytes to "move" from the start of the vertex data
    /// to reach this vertex attribute.
    pub offset: usize,

    /// The number of bytes between consecutive vertex attributes. 0 indicates
    /// that the vertex data is tightly packed.
    pub stride: usize
}

/// Used to specify type of a vertex attribute. The size of the vertex
/// attribute is `size_of(data) * components`.
#[derive(Clone)]
pub struct VertexAttributeType {
    /// The type of data that makes up this vertex attribute.
    pub data: DataType,

    /// The number of `data` components that make up this vertex attribute.
    pub components: i8,

    /// If the `data` type is fixed-point data, indicates if the data
    /// should be normalized when being accessed. `true` indicates
    /// that the vertex attribute **should** be normalized when being
    /// accessed.
    pub normalize: bool
}

unsafe impl VertexPrimitive for i8 {
    fn data_type() -> DataType { DataType::Byte }
}

unsafe impl VertexPrimitive for u8 {
    fn data_type() -> DataType { DataType::UnsignedByte }
}

unsafe impl VertexPrimitive for i16 {
    fn data_type() -> DataType { DataType::Short }
}

unsafe impl VertexPrimitive for u16 {
    fn data_type() -> DataType { DataType::UnsignedShort }
}

unsafe impl VertexPrimitive for f32 {
    fn data_type() -> DataType { DataType::Float }
}

unsafe impl<T: VertexPrimitive> VertexDatum for T {
    fn attrib_type() -> VertexAttributeType {
        VertexAttributeType {
            data: T::data_type(),
            components: 1,
            normalize: false
        }
    }
}

unsafe impl<T: VertexPrimitive> VertexDatum for [T; 1] {
    fn attrib_type() -> VertexAttributeType {
        VertexAttributeType {
            data: T::data_type(),
            components: 1,
            normalize: false
        }
    }
}

unsafe impl<T: VertexPrimitive> VertexDatum for [T; 2] {
    fn attrib_type() -> VertexAttributeType {
        VertexAttributeType {
            data: T::data_type(),
            components: 2,
            normalize: false
        }
    }
}

unsafe impl<T: VertexPrimitive> VertexDatum for [T; 3] {
    fn attrib_type() -> VertexAttributeType {
        VertexAttributeType {
            data: T::data_type(),
            components: 3,
            normalize: false
        }
    }
}

unsafe impl<T: VertexPrimitive> VertexDatum for [T; 4] {
    fn attrib_type() -> VertexAttributeType {
        VertexAttributeType {
            data: T::data_type(),
            components: 4,
            normalize: false
        }
    }
}

/// Indicates that a type can be coerced to a `u8` slice that can
/// then be treated as a stream of vertex data.
pub trait VertexBytes {
    /// Create a byte slice of vertex data from `self`.
    fn vertex_bytes(&self) -> &[u8];
}

impl<T> VertexBytes for T where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(mem::transmute(self), mem::size_of::<Self>())
        }
    }
}

impl<T> VertexBytes for [T] where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        let size = mem::size_of::<T>() * self.len();
        unsafe {
            slice::from_raw_parts(mem::transmute(&self[0]), size)
        }
    }
}

// TODO: Use a proper compiler intrinsic/macro (when available)
// see: https://github.com/rust-lang/rust/issues/24111
/// Compute the offset of a field within a struct type.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate glitter;
/// # fn main() {
/// #[repr(C, packed)]
/// struct MyStruct {
///     foo: u32,
///     bar: u32,
///     baz: u32
/// }
///
/// assert_eq!(offset_of!(MyStruct, foo), 0);
/// assert_eq!(offset_of!(MyStruct, bar), 4);
/// assert_eq!(offset_of!(MyStruct, baz), 8);
/// # }
/// ```
#[macro_export]
macro_rules! offset_of {
    ($T:ty, $field:ident) => {
        unsafe {
            let obj: $T = ::std::mem::uninitialized();
            let obj_ptr: *const u8 = ::std::mem::transmute(&obj);
            let member_ptr: *const u8 = ::std::mem::transmute(&obj.$field);

            ::std::mem::forget(obj);

            (member_ptr as usize) - (obj_ptr as usize)
        }
    }
}

/// Implement the [`VertexData`](vertex_data/trait.VertexData.html) trait
/// for a struct. Each field of the struct must that is part of the
/// `VertexData` implementation must be a type that implements [`VertexDatum`]
/// (vertex_data/trait.VertexDatum.html).
///
/// # Note
/// The generated implementation will **not** be panic safe with regards
/// to the [`VertexDatum::attrib_type`]
/// (trait.VertexDatum.html#tymethod.attrib_type) method of the vertex
/// attribute fields. However, as the documenation of
// [`VertexDatum::attrib_type`](trait.VertexDatum.html#tymethod.attrib_type)
/// notes, implementors should be aware of this already.
///
/// # Examples
///
/// ```
/// #[macro_use] extern crate glitter;
///
/// # fn main() {
/// // A type must implement `Copy` to implement `VertexData`
/// #[derive(Clone, Copy)]
/// struct MyVertex {
///     position: [f32; 3],
///     color: [f32; 3]
/// }
///
/// // Implement `VertexData`, using the "position" and "color" fields
/// // as vertex attributes.
/// impl_vertex_data!(MyVertex, position, color);
/// # }
/// ```
#[macro_export]
macro_rules! impl_vertex_data {
    ($name:ty, $($field_name:ident),*) => {
        unsafe impl $crate::VertexData for $name {
            fn visit_attributes<F>(mut f: F)
                where F: FnMut($crate::VertexAttribute)
            {
                // TODO: A better way of iterating over field types
                // TODO: Panic safety (using `catch_panic`/`recover`)
                let _data: $name = unsafe { ::std::mem::uninitialized() };
                fn get_attribute_type<T: $crate::VertexDatum>(_: &T)
                    -> $crate::VertexAttributeType
                {
                    T::attrib_type()
                }
                $(
                    f($crate::VertexAttribute {
                        ty: get_attribute_type(&_data.$field_name),
                        name: stringify!($field_name).into(),
                        stride: ::std::mem::size_of::<$name>(),
                        offset: offset_of!($name, $field_name)
                    });
                )*

                ::std::mem::forget(_data);
            }
        }
    };
}
<|endoftext|>


<commit_before>//! rustdoc handler

use super::pool::Pool;
use super::file::File;
use super::redirect_base;
use super::crate_details::CrateDetails;
use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::{match_version, MatchVersion};
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
use postgres::Connection;
use time;
use iron::Handler;
use utils;

#[derive(Debug)]
struct RustdocPage {
    pub head: String,
    pub body: String,
    pub body_class: String,
    pub name: String,
    pub full: String,
    pub version: String,
    pub description: Option<String>,
    pub crate_details: Option<CrateDetails>,
}

impl Default for RustdocPage {
    fn default() -> RustdocPage {
        RustdocPage {
            head: String::new(),
            body: String::new(),
            body_class: String::new(),
            name: String::new(),
            full: String::new(),
            version: String::new(),
            description: None,
            crate_details: None,
        }
    }
}

impl ToJson for RustdocPage {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("rustdoc_head".to_string(), self.head.to_json());
        m.insert("rustdoc_body".to_string(), self.body.to_json());
        m.insert("rustdoc_body_class".to_string(), self.body_class.to_json());
        m.insert("rustdoc_full".to_string(), self.full.to_json());
        m.insert("rustdoc_status".to_string(), true.to_json());
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("crate_details".to_string(), self.crate_details.to_json());
        m.to_json()
    }
}

#[derive(Clone)]
pub struct RustLangRedirector {
    url: Url,
}

impl RustLangRedirector {
    pub fn new(target: &'static str) -> Self {
        let url = url::Url::parse("https://doc.rust-lang.org/stable/")
            .expect("failed to parse rust-lang.org base URL")
            .join(target)
            .expect("failed to append crate name to rust-lang.org base URL");
        let url = Url::from_generic_url(url)
            .expect("failed to convert url::Url to iron::Url");
        Self { url }
    }
}

impl iron::Handler for RustLangRedirector {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Found, Redirect(self.url.clone()))))
    }
}

/// Handler called for `/:crate` and `/:crate/:version` URLs. Automatically redirects to the docs
/// or crate details page based on whether the given crate version was successfully built.
pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

    fn redirect_to_doc(req: &Request,
                       name: &str,
                       vers: &str,
                       target_name: &str)
                       -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/{}/{}/{}/",
                                            redirect_base(req),
                                            name,
                                            vers,
                                            target_name)[..]));
        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    fn redirect_to_crate(req: &Request,
                         name: &str,
                         vers: &str)
                         -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/crate/{}/{}",
                                            redirect_base(req),
                                            name,
                                            vers)[..]));

        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    // this unwrap is safe because iron urls are always able to use `path_segments`
    // i'm using this instead of `req.url.path()` to avoid allocating the Vec, and also to avoid
    // keeping the borrow alive into the return statement
    if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".js")) {
        // javascript files should be handled by the file server instead of erroneously
        // redirecting to the crate root page
        if req.url.as_ref().path_segments().unwrap().count() > 2 {
            // this URL is actually from a crate-internal path, serve it there instead
            return rustdoc_html_server_handler(req);
        } else {
            let path = req.url.path();
            let path = path.join("/");
            let conn = extension!(req, Pool).get();
            match File::from_path(&conn, &path) {
                Some(f) => return Ok(f.serve()),
                None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
            }
        }
    } else if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".ico")) {
        // route .ico files into their dedicated handler so that docs.rs's favicon is always
        // displayed
        return super::ico_handler(req);
    }

    let router = extension!(req, Router);
    // this handler should never called without crate pattern
    let crate_name = cexpect!(router.find("crate"));
    let req_version = router.find("version");

    let conn = extension!(req, Pool).get();

    // it doesn't matter if the version that was given was exact or not, since we're redirecting
    // anyway
    let version = match match_version(&conn, &crate_name, req_version).into_option() {
        Some(v) => v,
        None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
    };

    // get target name and whether it has docs
    // FIXME: This is a bit inefficient but allowing us to use less code in general
    let (target_name, has_docs): (String, bool) = {
        let rows = ctry!(conn.query("SELECT target_name, rustdoc_status
                                     FROM releases
                                     INNER JOIN crates ON crates.id = releases.crate_id
                                     WHERE crates.name = $1 AND releases.version = $2",
                                    &[&crate_name, &version]));

        (rows.get(0).get(0), rows.get(0).get(1))
    };

    if has_docs {
        redirect_to_doc(req, &crate_name, &version, &target_name)
    } else {
        redirect_to_crate(req, &crate_name, &version)
    }
}

/// Serves documentation generated by rustdoc.
///
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
/// also crate-specific.
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

    let router = extension!(req, Router);
    let name = router.find("crate").unwrap_or("").to_string();
    let url_version = router.find("version");
    let version; // pre-declaring it to enforce drop order relative to `req_path`
    let conn = extension!(req, Pool).get();

    let mut req_path = req.url.path();

    // remove name and version from path
    for _ in 0..2 {
        req_path.remove(0);
    }

    version = match match_version(&conn, &name, url_version) {
        MatchVersion::Exact(v) => v,
        MatchVersion::Semver(v) => {
            // to prevent cloudfront caching the wrong artifacts on URLs with loose semver
            // versions, redirect the browser to the returned version instead of loading it
            // immediately
            let url = ctry!(Url::parse(&format!("{}/{}/{}/{}",
                                                redirect_base(req),
                                                name,
                                                v,
                                                req_path.join("/"))[..]));
            return Ok(super::redirect(url));
        }
        MatchVersion::None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // docs have "rustdoc" prefix in database
    req_path.insert(0, "rustdoc");

    // add crate name and version
    req_path.insert(1, &name);
    req_path.insert(2, &version);

    let path = {
        let mut path = req_path.join("/");
        if path.ends_with('/') {
            req_path.pop(); // get rid of empty string
            path.push_str("index.html");
            req_path.push("index.html");
        }
        path
    };

    let file = match File::from_path(&conn, &path) {
        Some(f) => f,
        None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // serve file directly if it's not html
    if !path.ends_with(".html") {
        return Ok(file.serve());
    }

    let mut content = RustdocPage::default();

    let file_content = ctry!(String::from_utf8(file.0.content));

    let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
    content.head = head;
    content.body = body;

    if body_class.is_empty() {
        body_class = "rustdoc container-rustdoc".to_string();
    } else {
        // rustdoc adds its own "rustdoc" class to the body
        body_class.push_str(" container-rustdoc");
    }
    content.body_class = body_class;

    content.full = file_content;
    let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));

    let latest_version = crate_details.latest_version().to_owned();
    let is_latest_version = latest_version == version;

    let path = if !is_latest_version {
        req_path[2] = &latest_version;
        path_for_version(&req_path, &crate_details.target_name, &conn)
    } else {
        Default::default()
    };

    content.crate_details = Some(crate_details);

    Page::new(content)
        .set_true("show_package_navigation")
        .set_true("package_navigation_documentation_tab")
        .set_true("package_navigation_show_platforms_tab")
        .set_bool("is_latest_version", is_latest_version)
        .set("path_in_latest", &path)
        .set("latest_version", &latest_version)
        .to_resp("rustdoc")
}

/// Checks whether the given path exists.
/// The crate's `target_name` is used to confirm whether a platform triple is part of the path.
///
/// Note that path is overloaded in this context to mean both the path of a URL
/// and the file path of a static file in the DB.
///
/// `req_path` is assumed to have the following format:
/// `rustdoc/crate/version[/platform]/module/[kind.name.html|index.html]`
///
/// Returns a path that can be appended to `/crate/version/` to create a complete URL.
fn path_for_version(req_path: &[&str], target_name: &str, conn: &Connection) -> String {
    // Simple case: page exists in the latest version, so just change the version number
    if File::from_path(&conn, &req_path.join("/")).is_some() {
        // NOTE: this adds 'index.html' if it wasn't there before
        return req_path[3..].join("/");
    }
    // this page doesn't exist in the latest version
    let search_item = if *req_path.last().unwrap() == "index.html" {
        // this is a module
        req_path[req_path.len() - 2]
    } else {
        // this is an item
        req_path.last().unwrap().split('.').nth(1)
            .expect("paths should be of the form <kind>.<name>.html")
    };
    // check if req_path[3] is the platform choice or the name of the crate
    let concat_path;
    let crate_root = if req_path[3] != target_name {
        concat_path = format!("{}/{}", req_path[3], req_path[4]);
        &concat_path
    } else {
        req_path[3]
    };
    format!("{}/?search={}", crate_root, search_item)
}

pub fn badge_handler(req: &mut Request) -> IronResult<Response> {
    use iron::headers::ContentType;
    use params::{Params, Value};
    use badge::{Badge, BadgeOptions};

    let version = {
        let params = ctry!(req.get_ref::<Params>());
        match params.find(&["version"]) {
            Some(&Value::String(ref version)) => version.clone(),
            _ => "*".to_owned(),
        }
    };

    let name = cexpect!(extension!(req, Router).find("crate"));
    let conn = extension!(req, Pool).get();

    let options = match match_version(&conn, &name, Some(&version)) {
        MatchVersion::Exact(version) => {
            let rows = ctry!(conn.query("SELECT rustdoc_status
                                         FROM releases
                                         INNER JOIN crates ON crates.id = releases.crate_id
                                         WHERE crates.name = $1 AND releases.version = $2",
                                        &[&name, &version]));
            if rows.len() > 0 && rows.get(0).get(0) {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#4d76ae".to_owned(),
                }
            } else {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#e05d44".to_owned(),
                }
            }
        }
        MatchVersion::Semver(version) => {
            let url = ctry!(Url::parse(&format!("{}/{}/badge.svg?version={}",
                                                redirect_base(req),
                                                name,
                                                version)[..]));

            return Ok(super::redirect(url));
        }
        MatchVersion::None => {
            BadgeOptions {
                subject: "docs".to_owned(),
                status: "no builds".to_owned(),
                color: "#e05d44".to_owned(),
            }
        }
    };

    let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg()));
    resp.headers.set(ContentType("image/svg+xml".parse().unwrap()));
    resp.headers.set(Expires(HttpDate(time::now())));
    resp.headers.set(CacheControl(vec![CacheDirective::NoCache,
                                       CacheDirective::NoStore,
                                       CacheDirective::MustRevalidate]));
    Ok(resp)
}

/// Serves shared web resources used by rustdoc-generated documentation.
///
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
/// deduplicate them and save space.
pub struct SharedResourceHandler;

impl Handler for SharedResourceHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let filename = path.last().unwrap();  // unwrap is fine: vector is non-empty
        let suffix = filename.split('.').last().unwrap();  // unwrap is fine: split always works
        if ["js", "css", "woff", "svg"].contains(&suffix) {
            let conn = extension!(req, Pool).get();

            if let Some(file) = File::from_path(&conn, filename) {
                return Ok(file.serve());
            }
        }

        // Just always return a 404 here - the main handler will then try the other handlers
        Err(IronError::new(Nope::ResourceNotFound, status::NotFound))
    }
}
<commit_msg>Fix occasional panic when visiting settings.html<commit_after>//! rustdoc handler

use super::pool::Pool;
use super::file::File;
use super::redirect_base;
use super::crate_details::CrateDetails;
use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::{match_version, MatchVersion};
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
use postgres::Connection;
use time;
use iron::Handler;
use utils;

#[derive(Debug)]
struct RustdocPage {
    pub head: String,
    pub body: String,
    pub body_class: String,
    pub name: String,
    pub full: String,
    pub version: String,
    pub description: Option<String>,
    pub crate_details: Option<CrateDetails>,
}

impl Default for RustdocPage {
    fn default() -> RustdocPage {
        RustdocPage {
            head: String::new(),
            body: String::new(),
            body_class: String::new(),
            name: String::new(),
            full: String::new(),
            version: String::new(),
            description: None,
            crate_details: None,
        }
    }
}

impl ToJson for RustdocPage {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("rustdoc_head".to_string(), self.head.to_json());
        m.insert("rustdoc_body".to_string(), self.body.to_json());
        m.insert("rustdoc_body_class".to_string(), self.body_class.to_json());
        m.insert("rustdoc_full".to_string(), self.full.to_json());
        m.insert("rustdoc_status".to_string(), true.to_json());
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("crate_details".to_string(), self.crate_details.to_json());
        m.to_json()
    }
}

#[derive(Clone)]
pub struct RustLangRedirector {
    url: Url,
}

impl RustLangRedirector {
    pub fn new(target: &'static str) -> Self {
        let url = url::Url::parse("https://doc.rust-lang.org/stable/")
            .expect("failed to parse rust-lang.org base URL")
            .join(target)
            .expect("failed to append crate name to rust-lang.org base URL");
        let url = Url::from_generic_url(url)
            .expect("failed to convert url::Url to iron::Url");
        Self { url }
    }
}

impl iron::Handler for RustLangRedirector {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Found, Redirect(self.url.clone()))))
    }
}

/// Handler called for `/:crate` and `/:crate/:version` URLs. Automatically redirects to the docs
/// or crate details page based on whether the given crate version was successfully built.
pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

    fn redirect_to_doc(req: &Request,
                       name: &str,
                       vers: &str,
                       target_name: &str)
                       -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/{}/{}/{}/",
                                            redirect_base(req),
                                            name,
                                            vers,
                                            target_name)[..]));
        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    fn redirect_to_crate(req: &Request,
                         name: &str,
                         vers: &str)
                         -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/crate/{}/{}",
                                            redirect_base(req),
                                            name,
                                            vers)[..]));

        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    // this unwrap is safe because iron urls are always able to use `path_segments`
    // i'm using this instead of `req.url.path()` to avoid allocating the Vec, and also to avoid
    // keeping the borrow alive into the return statement
    if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".js")) {
        // javascript files should be handled by the file server instead of erroneously
        // redirecting to the crate root page
        if req.url.as_ref().path_segments().unwrap().count() > 2 {
            // this URL is actually from a crate-internal path, serve it there instead
            return rustdoc_html_server_handler(req);
        } else {
            let path = req.url.path();
            let path = path.join("/");
            let conn = extension!(req, Pool).get();
            match File::from_path(&conn, &path) {
                Some(f) => return Ok(f.serve()),
                None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
            }
        }
    } else if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".ico")) {
        // route .ico files into their dedicated handler so that docs.rs's favicon is always
        // displayed
        return super::ico_handler(req);
    }

    let router = extension!(req, Router);
    // this handler should never called without crate pattern
    let crate_name = cexpect!(router.find("crate"));
    let req_version = router.find("version");

    let conn = extension!(req, Pool).get();

    // it doesn't matter if the version that was given was exact or not, since we're redirecting
    // anyway
    let version = match match_version(&conn, &crate_name, req_version).into_option() {
        Some(v) => v,
        None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
    };

    // get target name and whether it has docs
    // FIXME: This is a bit inefficient but allowing us to use less code in general
    let (target_name, has_docs): (String, bool) = {
        let rows = ctry!(conn.query("SELECT target_name, rustdoc_status
                                     FROM releases
                                     INNER JOIN crates ON crates.id = releases.crate_id
                                     WHERE crates.name = $1 AND releases.version = $2",
                                    &[&crate_name, &version]));

        (rows.get(0).get(0), rows.get(0).get(1))
    };

    if has_docs {
        redirect_to_doc(req, &crate_name, &version, &target_name)
    } else {
        redirect_to_crate(req, &crate_name, &version)
    }
}

/// Serves documentation generated by rustdoc.
///
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
/// also crate-specific.
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

    let router = extension!(req, Router);
    let name = router.find("crate").unwrap_or("").to_string();
    let url_version = router.find("version");
    let version; // pre-declaring it to enforce drop order relative to `req_path`
    let conn = extension!(req, Pool).get();

    let mut req_path = req.url.path();

    // remove name and version from path
    for _ in 0..2 {
        req_path.remove(0);
    }

    version = match match_version(&conn, &name, url_version) {
        MatchVersion::Exact(v) => v,
        MatchVersion::Semver(v) => {
            // to prevent cloudfront caching the wrong artifacts on URLs with loose semver
            // versions, redirect the browser to the returned version instead of loading it
            // immediately
            let url = ctry!(Url::parse(&format!("{}/{}/{}/{}",
                                                redirect_base(req),
                                                name,
                                                v,
                                                req_path.join("/"))[..]));
            return Ok(super::redirect(url));
        }
        MatchVersion::None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // docs have "rustdoc" prefix in database
    req_path.insert(0, "rustdoc");

    // add crate name and version
    req_path.insert(1, &name);
    req_path.insert(2, &version);

    let path = {
        let mut path = req_path.join("/");
        if path.ends_with('/') {
            req_path.pop(); // get rid of empty string
            path.push_str("index.html");
            req_path.push("index.html");
        }
        path
    };

    let file = match File::from_path(&conn, &path) {
        Some(f) => f,
        None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // serve file directly if it's not html
    if !path.ends_with(".html") {
        return Ok(file.serve());
    }

    let mut content = RustdocPage::default();

    let file_content = ctry!(String::from_utf8(file.0.content));

    let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
    content.head = head;
    content.body = body;

    if body_class.is_empty() {
        body_class = "rustdoc container-rustdoc".to_string();
    } else {
        // rustdoc adds its own "rustdoc" class to the body
        body_class.push_str(" container-rustdoc");
    }
    content.body_class = body_class;

    content.full = file_content;
    let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));

    let latest_version = crate_details.latest_version().to_owned();
    let is_latest_version = latest_version == version;

    let path = if !is_latest_version {
        req_path[2] = &latest_version;
        path_for_version(&req_path, &crate_details.target_name, &conn)
    } else {
        Default::default()
    };

    content.crate_details = Some(crate_details);

    Page::new(content)
        .set_true("show_package_navigation")
        .set_true("package_navigation_documentation_tab")
        .set_true("package_navigation_show_platforms_tab")
        .set_bool("is_latest_version", is_latest_version)
        .set("path_in_latest", &path)
        .set("latest_version", &latest_version)
        .to_resp("rustdoc")
}

/// Checks whether the given path exists.
/// The crate's `target_name` is used to confirm whether a platform triple is part of the path.
///
/// Note that path is overloaded in this context to mean both the path of a URL
/// and the file path of a static file in the DB.
///
/// `req_path` is assumed to have the following format:
/// `rustdoc/crate/version[/platform]/module/[kind.name.html|index.html]`
///
/// Returns a path that can be appended to `/crate/version/` to create a complete URL.
fn path_for_version(req_path: &[&str], target_name: &str, conn: &Connection) -> String {
    // Simple case: page exists in the latest version, so just change the version number
    if File::from_path(&conn, &req_path.join("/")).is_some() {
        // NOTE: this adds 'index.html' if it wasn't there before
        return req_path[3..].join("/");
    }
    // this page doesn't exist in the latest version
    let search_item = if *req_path.last().unwrap() == "index.html" {
        // this is a module
        req_path[req_path.len() - 2]
    } else {
        // this is an item
        req_path.last().unwrap().split('.').nth(1)
            .expect("paths should be of the form <kind>.<name>.html")
    };
    // check if req_path[3] is the platform choice or the name of the crate
    // rustdoc generates a ../settings.html page;
    // if we get this far and we're on settings.html, there is no module.
    // additionally, if settings.html doesn't exist on the most recent page,
    // the build must have failed, so we just redirect to the root page.
    let concat_path;
    let crate_root = if req_path[3] != target_name && req_path[3] != "settings.html" {
        assert!(req_path.len() >= 5, "{:?}", req_path);
        concat_path = format!("{}/{}", req_path[3], req_path[4]);
        &concat_path
    } else {
        req_path[3]
    };
    format!("{}/?search={}", crate_root, search_item)
}

pub fn badge_handler(req: &mut Request) -> IronResult<Response> {
    use iron::headers::ContentType;
    use params::{Params, Value};
    use badge::{Badge, BadgeOptions};

    let version = {
        let params = ctry!(req.get_ref::<Params>());
        match params.find(&["version"]) {
            Some(&Value::String(ref version)) => version.clone(),
            _ => "*".to_owned(),
        }
    };

    let name = cexpect!(extension!(req, Router).find("crate"));
    let conn = extension!(req, Pool).get();

    let options = match match_version(&conn, &name, Some(&version)) {
        MatchVersion::Exact(version) => {
            let rows = ctry!(conn.query("SELECT rustdoc_status
                                         FROM releases
                                         INNER JOIN crates ON crates.id = releases.crate_id
                                         WHERE crates.name = $1 AND releases.version = $2",
                                        &[&name, &version]));
            if rows.len() > 0 && rows.get(0).get(0) {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#4d76ae".to_owned(),
                }
            } else {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#e05d44".to_owned(),
                }
            }
        }
        MatchVersion::Semver(version) => {
            let url = ctry!(Url::parse(&format!("{}/{}/badge.svg?version={}",
                                                redirect_base(req),
                                                name,
                                                version)[..]));

            return Ok(super::redirect(url));
        }
        MatchVersion::None => {
            BadgeOptions {
                subject: "docs".to_owned(),
                status: "no builds".to_owned(),
                color: "#e05d44".to_owned(),
            }
        }
    };

    let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg()));
    resp.headers.set(ContentType("image/svg+xml".parse().unwrap()));
    resp.headers.set(Expires(HttpDate(time::now())));
    resp.headers.set(CacheControl(vec![CacheDirective::NoCache,
                                       CacheDirective::NoStore,
                                       CacheDirective::MustRevalidate]));
    Ok(resp)
}

/// Serves shared web resources used by rustdoc-generated documentation.
///
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
/// deduplicate them and save space.
pub struct SharedResourceHandler;

impl Handler for SharedResourceHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let filename = path.last().unwrap();  // unwrap is fine: vector is non-empty
        let suffix = filename.split('.').last().unwrap();  // unwrap is fine: split always works
        if ["js", "css", "woff", "svg"].contains(&suffix) {
            let conn = extension!(req, Pool).get();

            if let Some(file) = File::from_path(&conn, filename) {
                return Ok(file.serve());
            }
        }

        // Just always return a 404 here - the main handler will then try the other handlers
        Err(IronError::new(Nope::ResourceNotFound, status::NotFound))
    }
}
<|endoftext|>


<commit_before>//! This module provides the ability to simulate a mutli table independent chip tournament.
//! It does this via simulation. Different heros and villans go to all in show downs. Then
//! the resulting placements are computed as each player busts.
//!
//! This method does not require a recursive dive N! so it makes simulating
//! tournaments with many different people and different payments feasible. However it comes with
//! some downsides.
//!
//! - The results are not repeatable.
//! - Small SNG's would be faster to compute with full ICM rather than simulations
//!
//! However it does have some other nice properties
//!
//! - It's parrallelizable. This can be farmed out to many different cores to speed
//! this up. Since each tournament is indepent there's little coordination oeverhead needed.
//! - We can change the players skill easily. Since ICM just looks at the percentage or outstanding chips
use fixedbitset::FixedBitSet;
use rand::seq::IteratorRandom;
use rand::{thread_rng, Rng};

const DEFAULT_PAYMENT: i32 = 0;

#[inline]
fn award_payments(
    remaining_stacks: &[i32],
    payments: &[i32],
    idx: usize,
    other_idx: usize,
    winnings: &mut Vec<i32>,
    next_place: &mut usize,
) -> bool {
    if remaining_stacks[idx] == 0 {
        winnings[idx] += payments.get(*next_place).unwrap_or(&DEFAULT_PAYMENT);
        *next_place -= 1;
        if *next_place == 0 {
            winnings[other_idx] += payments.get(*next_place).unwrap_or(&DEFAULT_PAYMENT);
        }
        true
    } else {
        false
    }
}

pub fn simulate_icm_tournament(chip_stacks: &[i32], payments: &[i32]) -> Vec<i32> {
    // We're going to mutate in place so move the chip stacks into a mutable vector.
    let mut remaining_stacks: Vec<i32> = chip_stacks.into();
    // Thread local rng.
    let mut rng = thread_rng();
    // Which place in the next player to bust will get.
    let mut next_place = remaining_stacks.len() - 1;

    // The results.
    let mut winnings = vec![0; remaining_stacks.len()];
    let mut remaining_players = FixedBitSet::with_capacity(remaining_stacks.len());

    // set all the players as still having chips remaining.
    remaining_players.insert_range(..);

    while next_place > 0 {
        // Perform a choose multiple. We do this random choice rather than iterating because
        // we really don't want order to be the deciding factor. I am assuming the when
        // ICM is important that most players will make push/fold decisions based upon
        // their hole cards.
        if let [hero, villan] = remaining_players
            .ones()
            .choose_multiple(&mut rng, 2)
            .as_slice()
        {
            // For now assume that each each player has the same skill.
            // TODO: Check to see if adding in a skill(running avg of win %) array for each player is needed.
            let hero_won: bool = rng.gen_bool(0.5);

            // can't bet chips that can't be called.
            let effective_stacks =
                std::cmp::min(remaining_stacks[*hero], remaining_stacks[*villan]);
            let hero_change: i32 = if hero_won {
                effective_stacks
            } else {
                -effective_stacks
            };
            remaining_stacks[*hero] += hero_change;
            remaining_stacks[*villan] -= hero_change;

            // Check if hero was eliminated.
            if award_payments(
                &remaining_stacks,
                payments,
                *hero,
                *villan,
                &mut winnings,
                &mut next_place,
            ) {
                remaining_players.set(*hero, false);
            }

            // Now check if the villan was eliminated.
            if award_payments(
                &remaining_stacks,
                payments,
                *villan,
                *hero,
                &mut winnings,
                &mut next_place,
            ) {
                remaining_players.set(*villan, false);
            }
        }
    }
    winnings
}

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

    #[test]
    fn test_huge_lead_wins() {
        let stacks = vec![1000, 2, 1];
        let payments = vec![100, 30, 10];

        let mut total_winnings = vec![0; 3];
        let num_trials = 1000;

        for _i in 0..num_trials {
            let single_wins = simulate_icm_tournament(&stacks, &payments);
            total_winnings = total_winnings
                .iter()
                .zip(single_wins.iter())
                .map(|(a, b)| a + b)
                .collect()
        }

        let final_share: Vec<f64> = total_winnings
            .iter()
            .map(|v| (*v as f64) / (num_trials as f64))
            .collect();

        assert!(
            final_share[0] > final_share[1],
            "The total winnings of a player with most of the chips should be above the rest."
        );
        dbg!(final_share);
    }

    #[test]
    fn about_same() {
        let stacks = vec![1000, 1000, 999];
        let payments = vec![100, 30, 10];

        let mut total_winnings = vec![0; 3];
        let num_trials = 1000;

        for _i in 0..num_trials {
            let single_wins = simulate_icm_tournament(&stacks, &payments);
            total_winnings = total_winnings
                .iter()
                .zip(single_wins.iter())
                .map(|(a, b)| a + b)
                .collect()
        }

        let final_share: Vec<f64> = total_winnings
            .iter()
            .map(|v| (*v as f64) / (num_trials as f64))
            .collect();

        let sum: f64 = final_share.iter().sum();
        let avg = sum / (final_share.len() as f64);

        for &share in final_share.iter() {
            assert!(share < 1.1 * avg);
            assert!(1.1 * share > avg);
        }

        dbg!(final_share);
    }
}
<commit_msg>Better ICM clippy<commit_after>//! This module provides the ability to simulate a mutli table independent chip tournament.
//! It does this via simulation. Different heros and villans go to all in show downs. Then
//! the resulting placements are computed as each player busts.
//!
//! This method does not require a recursive dive N! so it makes simulating
//! tournaments with many different people and different payments feasible. However it comes with
//! some downsides.
//!
//! - The results are not repeatable.
//! - Small SNG's would be faster to compute with full ICM rather than simulations
//!
//! However it does have some other nice properties
//!
//! - It's parrallelizable. This can be farmed out to many different cores to speed
//! this up. Since each tournament is indepent there's little coordination oeverhead needed.
//! - We can change the players skill easily. Since ICM just looks at the percentage or outstanding chips
use fixedbitset::FixedBitSet;
use rand::seq::IteratorRandom;
use rand::{thread_rng, Rng};

const DEFAULT_PAYMENT: i32 = 0;

#[inline]
fn award_payments(
    remaining_stacks: &[i32],
    payments: &[i32],
    idx: usize,
    other_idx: usize,
    winnings: &mut [i32],
    next_place: &mut usize,
) -> bool {
    if remaining_stacks[idx] == 0 {
        winnings[idx] += payments.get(*next_place).unwrap_or(&DEFAULT_PAYMENT);
        *next_place -= 1;
        if *next_place == 0 {
            winnings[other_idx] += payments.get(*next_place).unwrap_or(&DEFAULT_PAYMENT);
        }
        true
    } else {
        false
    }
}

pub fn simulate_icm_tournament(chip_stacks: &[i32], payments: &[i32]) -> Vec<i32> {
    // We're going to mutate in place so move the chip stacks into a mutable vector.
    let mut remaining_stacks: Vec<i32> = chip_stacks.into();
    // Thread local rng.
    let mut rng = thread_rng();
    // Which place in the next player to bust will get.
    let mut next_place = remaining_stacks.len() - 1;

    // The results.
    let mut winnings = vec![0; remaining_stacks.len()];
    let mut remaining_players = FixedBitSet::with_capacity(remaining_stacks.len());

    // set all the players as still having chips remaining.
    remaining_players.insert_range(..);

    while next_place > 0 {
        // Perform a choose multiple. We do this random choice rather than iterating because
        // we really don't want order to be the deciding factor. I am assuming the when
        // ICM is important that most players will make push/fold decisions based upon
        // their hole cards.
        if let [hero, villan] = remaining_players
            .ones()
            .choose_multiple(&mut rng, 2)
            .as_slice()
        {
            // For now assume that each each player has the same skill.
            // TODO: Check to see if adding in a skill(running avg of win %) array for each player is needed.
            let hero_won: bool = rng.gen_bool(0.5);

            // can't bet chips that can't be called.
            let effective_stacks =
                std::cmp::min(remaining_stacks[*hero], remaining_stacks[*villan]);
            let hero_change: i32 = if hero_won {
                effective_stacks
            } else {
                -effective_stacks
            };
            remaining_stacks[*hero] += hero_change;
            remaining_stacks[*villan] -= hero_change;

            // Check if hero was eliminated.
            if award_payments(
                &remaining_stacks,
                payments,
                *hero,
                *villan,
                &mut winnings,
                &mut next_place,
            ) {
                remaining_players.set(*hero, false);
            }

            // Now check if the villan was eliminated.
            if award_payments(
                &remaining_stacks,
                payments,
                *villan,
                *hero,
                &mut winnings,
                &mut next_place,
            ) {
                remaining_players.set(*villan, false);
            }
        }
    }
    winnings
}

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

    #[test]
    fn test_huge_lead_wins() {
        let stacks = vec![1000, 2, 1];
        let payments = vec![100, 30, 10];

        let mut total_winnings = vec![0; 3];
        let num_trials = 1000;

        for _i in 0..num_trials {
            let single_wins = simulate_icm_tournament(&stacks, &payments);
            total_winnings = total_winnings
                .iter()
                .zip(single_wins.iter())
                .map(|(a, b)| a + b)
                .collect()
        }

        let final_share: Vec<f64> = total_winnings
            .iter()
            .map(|v| (*v as f64) / (num_trials as f64))
            .collect();

        assert!(
            final_share[0] > final_share[1],
            "The total winnings of a player with most of the chips should be above the rest."
        );
        dbg!(final_share);
    }

    #[test]
    fn about_same() {
        let stacks = vec![1000, 1000, 999];
        let payments = vec![100, 30, 10];

        let mut total_winnings = vec![0; 3];
        let num_trials = 1000;

        for _i in 0..num_trials {
            let single_wins = simulate_icm_tournament(&stacks, &payments);
            total_winnings = total_winnings
                .iter()
                .zip(single_wins.iter())
                .map(|(a, b)| a + b)
                .collect()
        }

        let final_share: Vec<f64> = total_winnings
            .iter()
            .map(|v| (*v as f64) / (num_trials as f64))
            .collect();

        let sum: f64 = final_share.iter().sum();
        let avg = sum / (final_share.len() as f64);

        for &share in final_share.iter() {
            assert!(share < 1.1 * avg);
            assert!(1.1 * share > avg);
        }

        dbg!(final_share);
    }
}
<|endoftext|>