<commit_before>use linked_hash_map::LinkedHashMap;

use crate::generation::value::{pretty_print_value, Value};
use crate::options::Options;
use crate::shape::{self, Shape};
use crate::to_singular::to_singular;
use crate::util::string_hashmap;

#[allow(dead_code)]
pub struct Ctxt {
    options: Options,
}

pub type Code = String;

pub fn shape_string(name: &str, shape: &Shape, options: Options) -> Code {
    let mut ctxt = Ctxt { options };

    let value = type_from_shape(&mut ctxt, name, shape);

    pretty_print_value(0, &value)
}

fn type_from_shape(ctxt: &mut Ctxt, path: &str, shape: &Shape) -> Value {
    use crate::shape::Shape::*;
    match shape {
        Null => Value::Null,
        Any => Value::Str("any"),
        Bottom => Value::Str("bottom"),
        Bool => Value::Str("bool"),
        StringT => Value::Str("string"),
        Integer => Value::Str("integer"),
        Floating => Value::Str("floating"),
        Tuple(shapes, _n) => {
            let folded = shape::fold_shapes(shapes.clone());
            if folded == Any && shapes.iter().any(|s| s != &Any) {
                generate_tuple_type(ctxt, path, shapes)
            } else {
                generate_vec_type(ctxt, path, &folded)
            }
        }
        VecT { elem_type: e } => generate_vec_type(ctxt, path, e),
        Struct { fields } => generate_struct_from_field_shapes(ctxt, path, fields),
        MapT { val_type: v } => generate_map_type(ctxt, path, v),
        Opaque(t) => Value::String(t.to_string()),
        Optional(e) => Value::Object(string_hashmap! {
            "__type__" => Value::Str("optional"),
            "item" => type_from_shape(ctxt, path, e),
        }),
    }
}

fn generate_vec_type(ctxt: &mut Ctxt, path: &str, shape: &Shape) -> Value {
    let singular = to_singular(path);
    let inner = type_from_shape(ctxt, &singular, shape);
    Value::Array(vec![inner])
}

fn generate_map_type(ctxt: &mut Ctxt, path: &str, shape: &Shape) -> Value {
    let singular = to_singular(path);
    let inner = type_from_shape(ctxt, &singular, shape);
    Value::Object(string_hashmap! {
        "__type__" => Value::Str("map"),
        "values" => inner
    })
}

fn generate_tuple_type(ctxt: &mut Ctxt, path: &str, shapes: &[Shape]) -> Value {
    let mut types = Vec::new();

    for shape in shapes {
        let typ = type_from_shape(ctxt, path, shape);
        types.push(typ);
    }

    Value::Object(string_hashmap! {
        "__type__" => Value::Str("tuple"),
        "items" => Value::Array(types),
    })
}

fn collapse_option(typ: &Shape) -> (bool, &Shape) {
    if let Shape::Optional(inner) = typ {
        return (true, &**inner);
    }
    (false, typ)
}

fn generate_struct_from_field_shapes(
    ctxt: &mut Ctxt,
    _path: &str,
    map: &LinkedHashMap<String, Shape>,
) -> Value {
    let mut properties = LinkedHashMap::new();

    for (name, typ) in map.iter() {
        let (was_optional, collapsed) = collapse_option(typ);

        let annotated_name = if was_optional {
            name.to_owned() + "?"
        } else {
            name.to_owned()
        };

        let field_code = type_from_shape(ctxt, name, collapsed);

        properties.insert(annotated_name, field_code);
    }

    Value::Object(properties)
}
<commit_msg>shared: Remove unused path arg from shape gen<commit_after>use linked_hash_map::LinkedHashMap;

use crate::generation::value::{pretty_print_value, Value};
use crate::options::Options;
use crate::shape::{self, Shape};
use crate::util::string_hashmap;

#[allow(dead_code)]
pub struct Ctxt {
    options: Options,
}

pub type Code = String;

pub fn shape_string(_name: &str, shape: &Shape, options: Options) -> Code {
    let mut ctxt = Ctxt { options };

    let value = type_from_shape(&mut ctxt, shape);

    pretty_print_value(0, &value)
}

fn type_from_shape(ctxt: &mut Ctxt, shape: &Shape) -> Value {
    use crate::shape::Shape::*;
    match shape {
        Null => Value::Null,
        Any => Value::Str("any"),
        Bottom => Value::Str("bottom"),
        Bool => Value::Str("bool"),
        StringT => Value::Str("string"),
        Integer => Value::Str("integer"),
        Floating => Value::Str("floating"),
        Tuple(shapes, _n) => {
            let folded = shape::fold_shapes(shapes.clone());
            if folded == Any && shapes.iter().any(|s| s != &Any) {
                generate_tuple_type(ctxt, shapes)
            } else {
                generate_vec_type(ctxt, &folded)
            }
        }
        VecT { elem_type: e } => generate_vec_type(ctxt, e),
        Struct { fields } => generate_struct_from_field_shapes(ctxt, fields),
        MapT { val_type: v } => generate_map_type(ctxt, v),
        Opaque(t) => Value::String(t.to_string()),
        Optional(e) => Value::Object(string_hashmap! {
            "__type__" => Value::Str("optional"),
            "item" => type_from_shape(ctxt, e),
        }),
    }
}

fn generate_vec_type(ctxt: &mut Ctxt, shape: &Shape) -> Value {
    let inner = type_from_shape(ctxt, shape);
    Value::Array(vec![inner])
}

fn generate_map_type(ctxt: &mut Ctxt, shape: &Shape) -> Value {
    let inner = type_from_shape(ctxt, shape);
    Value::Object(string_hashmap! {
        "__type__" => Value::Str("map"),
        "values" => inner
    })
}

fn generate_tuple_type(ctxt: &mut Ctxt, shapes: &[Shape]) -> Value {
    let mut types = Vec::new();

    for shape in shapes {
        let typ = type_from_shape(ctxt, shape);
        types.push(typ);
    }

    Value::Object(string_hashmap! {
        "__type__" => Value::Str("tuple"),
        "items" => Value::Array(types),
    })
}

fn collapse_option(typ: &Shape) -> (bool, &Shape) {
    if let Shape::Optional(inner) = typ {
        return (true, &**inner);
    }
    (false, typ)
}

fn generate_struct_from_field_shapes(ctxt: &mut Ctxt, map: &LinkedHashMap<String, Shape>) -> Value {
    let mut properties = LinkedHashMap::new();

    for (name, typ) in map.iter() {
        let (was_optional, collapsed) = collapse_option(typ);

        let annotated_name = if was_optional {
            name.to_owned() + "?"
        } else {
            name.to_owned()
        };

        let field_code = type_from_shape(ctxt, collapsed);

        properties.insert(annotated_name, field_code);
    }

    Value::Object(properties)
}
<|endoftext|>


<commit_before>extern crate cgmath;

use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use cgmath::*;

use types::*;
use polyomino::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ShapeId(u32);

#[derive(Debug)]
pub struct Shape {
    // Gameplay:
    id: ShapeId,

    //TODO: use a faster hash table or just a vec https://github.com/servo/rust-fnv
    parent_ids: HashMap<ShapeId, IVec2>,

    pub polyomino: Polyomino,
    pub zoom_scale: i32,

    // Drawing:
    pub fill_color: [f32; 3],
    pub outline_color: [f32; 3],
}

impl Shape {
    pub fn has_position(&self, p: IVec2) -> bool {
        self.polyomino.has_position(p)
    }

    pub fn has_parent(&self, parent: &Shape) -> bool {
        self.parent_ids.contains_key(&parent.id)
    }

    pub fn position_on(&self, parent: &Shape) -> IVec2 {
        self.parent_ids[&parent.id]
    }
}

fn build_fill_mesh() -> () {}

pub struct Universe {
    pub shapes: HashMap<ShapeId, Shape>, // Should probably just be a Vec
}

impl Universe {
    pub fn minimal() -> Universe {
        let id1 = ShapeId(1);
        let id2 = ShapeId(2);
        let shape1 = Shape {
            id: id1,
            parent_ids: hashmap!{ id2 => Vector2::new(0, 0) },
            polyomino: Polyomino::monomino(),
            zoom_scale: 2,
            fill_color: [1.0, 1.0, 1.0],
            outline_color: [0.5, 0.5, 0.5],
        };
        let shape2 = Shape {
            id: id2,
            parent_ids: hashmap!{ id1 => Vector2::new(0, 0) },
            polyomino: Polyomino::monomino(),
            zoom_scale: 2,
            fill_color: [1.0, 0.5, 0.5],
            outline_color: [0.5, 0.25, 0.25],
        };

        let mut shapes = HashMap::new();
        shapes.insert(id1, shape1);
        shapes.insert(id2, shape2);

        Universe { shapes: shapes }
    }

    pub fn parents_of<'a>(&'a self, shape: &'a Shape) -> impl Iterator<Item = &'a Shape> + 'a {
        shape.parent_ids.keys().map(move |id| &self.shapes[id])
    }

    pub fn parents_of_id<'a>(&'a self, shape_id: ShapeId) -> impl Iterator<Item = &'a Shape> {
        self.parents_of(&self.shapes[&shape_id])
    }

    pub fn children_of<'a>(&'a self, parent: &'a Shape) -> impl Iterator<Item = &'a Shape> {
        self.shapes.values().filter(move |s| s.has_parent(parent))
    }
    pub fn children_of_id<'a>(&'a self, parent_id: ShapeId) -> impl Iterator<Item = &'a Shape> {
        self.shapes.values().filter(move |s| {
            s.parent_ids.contains_key(&parent_id)
        })
    }

    pub fn parents_with_position_of(&self, shape: &Shape) -> Vec<(&Shape, IVec2)> {
        shape
            .parent_ids
            .iter()
            .map(|(id, pos)| (&self.shapes[id], *pos))
            .collect()
    }
}

pub struct Square<'a> {
    pub universe: &'a Universe,
    pub shape: &'a Shape,
    pub position: IVec2,
}

impl<'a> Square<'a> {
    fn location_on(&self, parent_id: ShapeId) -> Option<Location> {
        let pos_on = self.shape.parent_ids.get(&parent_id)?;
        let new_shape = &self.universe.shapes[&parent_id];
        let new_pos = (self.position + pos_on) / new_shape.zoom_scale;
        let new_subp = (self.position + pos_on) % new_shape.zoom_scale;

        Some(Location {
            square: Square {
                universe: self.universe,
                shape: new_shape,
                position: new_pos,
            },
            subposition: new_subp,
        })
    }

    fn location(&self) -> Location {
        // TODO: This sort of sanity checking is slower, probably doesn't matter
        let mut locations: Vec<Location> = self.shape
            .parent_ids
            .keys()
            .filter_map(|s| self.location_on(*s))
            .collect();

        match locations.len() {
            0 => panic!("A square is not sitting on a location!"),
            1 => locations.pop().unwrap(),
            _ => panic!("A square is sitting on multiple locations!"),
        }
    }
}

pub struct Location<'a> {
    pub square: Square<'a>,
    pub subposition: IVec2,
}

impl<'a> Location<'a> {
    pub fn inhabitant(&self) -> Option<Square> {
        let c = self.to_coordinate();

        let mut inhabitants: Vec<Square> = self.square
            .universe
            .parents_with_position_of(self.square.shape)
            .into_iter()
            .filter(|&(s, pos)| s.has_position(c - pos))
            .map(|(s, pos)| {
                Square {
                    universe: self.square.universe,
                    shape: s,
                    position: c - pos,
                }
            })
            .collect();

        if inhabitants.len() > 1 {
            // TODO: This sort of sanity checking is probably a bit slower
            panic!("A location has multiple inhabitants!");
        } else {
            inhabitants.pop()
        }
    }

    fn to_coordinate(&self) -> IVec2 {
        (self.square.position * self.square.shape.zoom_scale) + self.subposition
    }
}

// This stores offsets of each shape in the chunk

// TODO: these offsets may be too small, need a vec of offsets, one
// for each level (that can be converted to a normal form, if we want)
#[derive(Clone)]
pub struct Chunk {
    pub origin_id: ShapeId,
    pub top_shape_ids: HashSet<(ShapeId, IVec2)>,
    pub lower_shape_ids: HashSet<(ShapeId, IVec2)>,
}

impl Chunk {
}

impl Universe {
    type ExploreResult = HashMap<ShapeId, u16>;
    type ExploreQueue = HashMap<ShapeId, IVec2, u16>;
    fn explore_step(&self, result: &mut ExploreResult, queue: &mut ExploreQueue) -> () {
        while !queue.is_empty() {
            let (s, i) = queue.pop_front().unwrap();

            let needs_update: bool = match result.get(&s) {
                None => true,
                Some(i2) => i < *i2,
            };

            if !needs_update {
                continue;
            }

            result.insert(s, i);

            if i > 0 {
                for p in self.parents_of_id(s) {
                    queue.push_front((p.id, i - 1));
                }
            }

            for p in self.children_of_id(s) {
                queue.push_back((p.id, i + 1));
            }
        }
    }

    fn explore(&self, shape_ids: impl Iterator<Item = ShapeId>) -> Chunk {
        let mut result = HashMap::new();
        let mut queue = VecDeque::new();

        for sid in shape_ids {
            queue.push_back((sid, 0));
        }

        self.explore_step(&mut result, &mut queue);

        let top = result.iter().filter_map(
            |(s, d)| if *d == 0 { Some(*s) } else { None },
        ).collect();
        let lower = result.iter().filter_map(
            |(s, d)| if *d > 0 { Some(*s) } else { None },
        ).collect();

        Chunk {
            top_shape_ids: top,
            lower_shape_ids: lower
        }
    }

    pub fn chunk_of(&self, shape: &Shape) -> Chunk {
        self.explore(Some(shape.id).into_iter())
    }

    pub fn parent_of(&self, chunk: &Chunk) -> Chunk {
        self.explore(chunk.top_shape_ids.clone().into_iter())
    }
}

pub struct GameState {
    pub universe: Universe,
    pub player_chunk: Chunk,
}

impl GameState {
    pub fn minimal() -> GameState {
        let u = Universe::minimal();

        GameState {
            universe: u,
            player_chunk: Chunk {
                origin_id: ShapeId(1),
                top_shape_ids: hashset![ShapeId(1)],
                lower_shape_ids: hashset![],
            },
        }
    }
}
<commit_msg>Eq for Shape<commit_after>extern crate cgmath;

use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use cgmath::*;

use types::*;
use polyomino::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ShapeId(u32);

#[derive(Debug)]
pub struct Shape {
    // Gameplay:
    id: ShapeId,

    //TODO: use a faster hash table or just a vec https://github.com/servo/rust-fnv
    parent_ids: HashMap<ShapeId, IVec2>,

    pub polyomino: Polyomino,
    pub zoom_scale: i32,

    // Drawing:
    pub fill_color: [f32; 3],
    pub outline_color: [f32; 3],
}

impl Shape {
    pub fn has_position(&self, p: IVec2) -> bool {
        self.polyomino.has_position(p)
    }

    pub fn has_parent(&self, parent: &Shape) -> bool {
        self.parent_ids.contains_key(&parent.id)
    }

    pub fn position_on(&self, parent: &Shape) -> IVec2 {
        self.parent_ids[&parent.id]
    }
}
impl PartialEq for Shape {
    fn eq(&self, other: &Shape) -> bool {
        self.id == other.id
    }
}

impl Eq for Shape { }

fn build_fill_mesh() -> () {}

pub struct Universe {
    pub shapes: HashMap<ShapeId, Shape>, // Should probably just be a Vec
}

impl Universe {
    pub fn minimal() -> Universe {
        let id1 = ShapeId(1);
        let id2 = ShapeId(2);
        let shape1 = Shape {
            id: id1,
            parent_ids: hashmap!{ id2 => Vector2::new(0, 0) },
            polyomino: Polyomino::monomino(),
            zoom_scale: 2,
            fill_color: [1.0, 1.0, 1.0],
            outline_color: [0.5, 0.5, 0.5],
        };
        let shape2 = Shape {
            id: id2,
            parent_ids: hashmap!{ id1 => Vector2::new(0, 0) },
            polyomino: Polyomino::monomino(),
            zoom_scale: 2,
            fill_color: [1.0, 0.5, 0.5],
            outline_color: [0.5, 0.25, 0.25],
        };

        let mut shapes = HashMap::new();
        shapes.insert(id1, shape1);
        shapes.insert(id2, shape2);

        Universe { shapes: shapes }
    }

    pub fn parents_of<'a>(&'a self, shape: &'a Shape) -> impl Iterator<Item = &'a Shape> + 'a {
        shape.parent_ids.keys().map(move |id| &self.shapes[id])
    }

    pub fn parents_of_id<'a>(&'a self, shape_id: ShapeId) -> impl Iterator<Item = &'a Shape> {
        self.parents_of(&self.shapes[&shape_id])
    }

    pub fn children_of<'a>(&'a self, parent: &'a Shape) -> impl Iterator<Item = &'a Shape> {
        self.shapes.values().filter(move |s| s.has_parent(parent))
    }
    pub fn children_of_id<'a>(&'a self, parent_id: ShapeId) -> impl Iterator<Item = &'a Shape> {
        self.shapes.values().filter(move |s| {
            s.parent_ids.contains_key(&parent_id)
        })
    }

    pub fn parents_with_position_of(&self, shape: &Shape) -> Vec<(&Shape, IVec2)> {
        shape
            .parent_ids
            .iter()
            .map(|(id, pos)| (&self.shapes[id], *pos))
            .collect()
    }
}

pub struct Square<'a> {
    pub universe: &'a Universe,
    pub shape: &'a Shape,
    pub position: IVec2,
}

impl<'a> Square<'a> {
    fn location_on(&self, parent_id: ShapeId) -> Option<Location> {
        let pos_on = self.shape.parent_ids.get(&parent_id)?;
        let new_shape = &self.universe.shapes[&parent_id];
        let new_pos = (self.position + pos_on) / new_shape.zoom_scale;
        let new_subp = (self.position + pos_on) % new_shape.zoom_scale;

        Some(Location {
            square: Square {
                universe: self.universe,
                shape: new_shape,
                position: new_pos,
            },
            subposition: new_subp,
        })
    }

    fn location(&self) -> Location {
        // TODO: This sort of sanity checking is slower, probably doesn't matter
        let mut locations: Vec<Location> = self.shape
            .parent_ids
            .keys()
            .filter_map(|s| self.location_on(*s))
            .collect();

        match locations.len() {
            0 => panic!("A square is not sitting on a location!"),
            1 => locations.pop().unwrap(),
            _ => panic!("A square is sitting on multiple locations!"),
        }
    }
}

pub struct Location<'a> {
    pub square: Square<'a>,
    pub subposition: IVec2,
}

impl<'a> Location<'a> {
    pub fn inhabitant(&self) -> Option<Square> {
        let c = self.to_coordinate();

        let mut inhabitants: Vec<Square> = self.square
            .universe
            .parents_with_position_of(self.square.shape)
            .into_iter()
            .filter(|&(s, pos)| s.has_position(c - pos))
            .map(|(s, pos)| {
                Square {
                    universe: self.square.universe,
                    shape: s,
                    position: c - pos,
                }
            })
            .collect();

        if inhabitants.len() > 1 {
            // TODO: This sort of sanity checking is probably a bit slower
            panic!("A location has multiple inhabitants!");
        } else {
            inhabitants.pop()
        }
    }

    fn to_coordinate(&self) -> IVec2 {
        (self.square.position * self.square.shape.zoom_scale) + self.subposition
    }
}

// This stores offsets of each shape in the chunk

// TODO: these offsets may be too small, need a vec of offsets, one
// for each level (that can be converted to a normal form, if we want)
#[derive(Clone)]
pub struct Chunk {
    pub origin_id: ShapeId,
    pub top_shape_ids: HashSet<(ShapeId, IVec2)>,
    pub lower_shape_ids: HashSet<(ShapeId, IVec2)>,
}

impl Chunk {
}

impl Universe {
    type ExploreResult = HashMap<ShapeId, u16>;
    type ExploreQueue = HashMap<ShapeId, IVec2, u16>;
    fn explore_step(&self, result: &mut ExploreResult, queue: &mut ExploreQueue) -> () {
        while !queue.is_empty() {
            let (s, i) = queue.pop_front().unwrap();

            let needs_update: bool = match result.get(&s) {
                None => true,
                Some(i2) => i < *i2,
            };

            if !needs_update {
                continue;
            }

            result.insert(s, i);

            if i > 0 {
                for p in self.parents_of_id(s) {
                    queue.push_front((p.id, i - 1));
                }
            }

            for p in self.children_of_id(s) {
                queue.push_back((p.id, i + 1));
            }
        }
    }

    fn explore(&self, shape_ids: impl Iterator<Item = ShapeId>) -> Chunk {
        let mut result = HashMap::new();
        let mut queue = VecDeque::new();

        for sid in shape_ids {
            queue.push_back((sid, 0));
        }

        self.explore_step(&mut result, &mut queue);

        let top = result.iter().filter_map(
            |(s, d)| if *d == 0 { Some(*s) } else { None },
        ).collect();
        let lower = result.iter().filter_map(
            |(s, d)| if *d > 0 { Some(*s) } else { None },
        ).collect();

        Chunk {
            top_shape_ids: top,
            lower_shape_ids: lower
        }
    }

    pub fn chunk_of(&self, shape: &Shape) -> Chunk {
        self.explore(Some(shape.id).into_iter())
    }

    pub fn parent_of(&self, chunk: &Chunk) -> Chunk {
        self.explore(chunk.top_shape_ids.clone().into_iter())
    }
}

pub struct GameState {
    pub universe: Universe,
    pub player_chunk: Chunk,
}

impl GameState {
    pub fn minimal() -> GameState {
        let u = Universe::minimal();

        GameState {
            universe: u,
            player_chunk: Chunk {
                origin_id: ShapeId(1),
                top_shape_ids: hashset![ShapeId(1)],
                lower_shape_ids: hashset![],
            },
        }
    }
}
<|endoftext|>


<commit_before>use crate::StrError;

/// Defines the class of geometric shape
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum GeoClass {
    /// Lines (segments) class
    Lin,

    /// Triangles class
    Tri,

    /// Quadrilaterals class
    Qua,

    /// Tetrahedra class
    Tet,

    /// Hexahedra class
    Hex,
}

/// Defines the kind of geometric shape
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum GeoKind {
    /// Line (segment) with 2 nodes (linear functions)
    Lin2 = 1_002,

    /// Line (segment) with 3 nodes (quadratic functions)
    Lin3 = 1_003,

    /// Line (segment) with 4 nodes (cubic functions)
    Lin4 = 1_004,

    /// Line (segment) with 5 nodes (quartic functions)
    Lin5 = 1_005,

    /// Triangle with 3 nodes (linear edges)
    Tri3 = 2_003,

    /// Triangle with 6 nodes (quadratic edges)
    Tri6 = 2_006,

    /// Triangle with 10 nodes (cubic edges; interior node)
    Tri10 = 2_010,

    /// Triangle with 15 nodes (quartic edges; interior nodes)
    Tri15 = 2_015,

    /// Quadrilateral with 4 nodes (linear edges)
    Qua4 = 2_004,

    /// Quadrilateral with 8 nodes (quadratic edges)
    Qua8 = 2_008,

    /// Quadrilateral with 9 nodes (quadratic edges; interior node)
    Qua9 = 2_009,

    /// Quadrilateral with 12 nodes (cubic edges)
    Qua12 = 2_012,

    /// Quadrilateral with 16 nodes (cubic edges; interior nodes)
    Qua16 = 2_016,

    /// Quadrilateral with 17 nodes (quartic edges; interior node)
    Qua17 = 2_017,

    /// Tetrahedron with 4 nodes (linear faces)
    Tet4 = 3_004,

    /// Tetrahedron with 10 nodes (quadratic faces)
    Tet10 = 3_010,

    /// Hexahedron with 8 nodes (bilinear faces)
    Hex8 = 3_008,

    /// Hexahedron with 20 nodes (quadratic faces)
    Hex20 = 3_020,
}

/// GeoNdim is the (local) space dimension of the geometric feature
pub type GeoNdim = usize;

/// GeoNnode is the number of nodes associated with a geometric feature
pub type GeoNnode = usize;

impl GeoKind {
    /// Holds all (geo_ndim,nnode) pairs
    pub const PAIRS: [(usize, usize); 18] = [
        // Lin
        (1, 2),
        (1, 3),
        (1, 4),
        (1, 5),
        // Tri
        (2, 3),
        (2, 6),
        (2, 10),
        (2, 15),
        // Qua
        (2, 4),
        (2, 8),
        (2, 9),
        (2, 12),
        (2, 16),
        (2, 17),
        // Tet
        (3, 4),
        (3, 10),
        // Hex
        (3, 8),
        (3, 20),
    ];

    /// Holds all enum values
    pub const VALUES: [Self; 18] = [
        // Lin
        Self::Lin2,
        Self::Lin3,
        Self::Lin4,
        Self::Lin5,
        // Tri
        Self::Tri3,
        Self::Tri6,
        Self::Tri10,
        Self::Tri15,
        // Qua
        Self::Qua4,
        Self::Qua8,
        Self::Qua9,
        Self::Qua12,
        Self::Qua16,
        Self::Qua17,
        // Tet
        Self::Tet4,
        Self::Tet10,
        // Hex
        Self::Hex8,
        Self::Hex20,
    ];
}

/// Returns the GeoClass and GeoKind for given geo_ndim and nnode
pub fn geo_class_and_kind(geo_ndim: usize, nnode: usize) -> Result<(GeoClass, GeoKind), StrError> {
    match (geo_ndim, nnode) {
        // Lin
        (1, 2) => Ok((GeoClass::Lin, GeoKind::Lin2)),
        (1, 3) => Ok((GeoClass::Lin, GeoKind::Lin3)),
        (1, 4) => Ok((GeoClass::Lin, GeoKind::Lin4)),
        (1, 5) => Ok((GeoClass::Lin, GeoKind::Lin5)),

        // Tri
        (2, 3) => Ok((GeoClass::Tri, GeoKind::Tri3)),
        (2, 6) => Ok((GeoClass::Tri, GeoKind::Tri6)),
        (2, 10) => Ok((GeoClass::Tri, GeoKind::Tri10)),
        (2, 15) => Ok((GeoClass::Tri, GeoKind::Tri15)),

        // Qua
        (2, 4) => Ok((GeoClass::Qua, GeoKind::Qua4)),
        (2, 8) => Ok((GeoClass::Qua, GeoKind::Qua8)),
        (2, 9) => Ok((GeoClass::Qua, GeoKind::Qua9)),
        (2, 12) => Ok((GeoClass::Qua, GeoKind::Qua12)),
        (2, 16) => Ok((GeoClass::Qua, GeoKind::Qua16)),
        (2, 17) => Ok((GeoClass::Qua, GeoKind::Qua17)),

        // Tet
        (3, 4) => Ok((GeoClass::Tet, GeoKind::Tet4)),
        (3, 10) => Ok((GeoClass::Tet, GeoKind::Tet10)),

        // Hex
        (3, 8) => Ok((GeoClass::Hex, GeoKind::Hex8)),
        (3, 20) => Ok((GeoClass::Hex, GeoKind::Hex20)),
        _ => Err("(geo_ndim,nnode) combination is invalid"),
    }
}

/// Returns the (min,max,delta) limits on the reference domain
///
/// # Tri and Tet
///
/// * `ξ_min` = 0.0
/// * `ξ_max` = 1.0
/// * `Δξ` = 1.0
///
/// # Lin, Qua, Hex
///
/// * `ξ_min` = -1.0
/// * `ξ_max` = +1.0
/// * `Δξ` = 2.0
#[inline]
pub fn ref_domain_limits(class: GeoClass) -> (f64, f64, f64) {
    if class == GeoClass::Tri || class == GeoClass::Tet {
        (0.0, 1.0, 1.0)
    } else {
        (-1.0, 1.0, 2.0)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::{
        shapes::{geo_class_and_kind, GeoClass, GeoKind},
        StrError,
    };
    use std::collections::HashSet;

    #[test]
    fn derive_works() {
        let class = GeoClass::Tri.clone();
        let kind = GeoKind::Tri6.clone();
        let classes = HashSet::from([GeoClass::Tri, GeoClass::Qua]);
        let kinds = HashSet::from([GeoKind::Tri3, GeoKind::Qua4]);
        assert_eq!(class, GeoClass::Tri);
        assert_eq!(kind, GeoKind::Tri6);
        assert_eq!(format!("{:?}", class), "Tri");
        assert_eq!(format!("{:?}", kind), "Tri6");
        assert_eq!(classes.contains(&GeoClass::Tri), true);
        assert_eq!(kinds.contains(&GeoKind::Tri3), true);
    }

    #[test]
    fn data_is_consistent() -> Result<(), StrError> {
        for kind in GeoKind::VALUES {
            match kind {
                // Lin
                GeoKind::Lin2 => {
                    assert_eq!(geo_class_and_kind(1, 2)?, (GeoClass::Lin, kind));
                }
                GeoKind::Lin3 => {
                    assert_eq!(geo_class_and_kind(1, 3)?, (GeoClass::Lin, kind));
                }
                GeoKind::Lin4 => {
                    assert_eq!(geo_class_and_kind(1, 4)?, (GeoClass::Lin, kind));
                }
                GeoKind::Lin5 => {
                    assert_eq!(geo_class_and_kind(1, 5)?, (GeoClass::Lin, kind));
                }

                // Tri
                GeoKind::Tri3 => {
                    assert_eq!(geo_class_and_kind(2, 3)?, (GeoClass::Tri, kind));
                }
                GeoKind::Tri6 => {
                    assert_eq!(geo_class_and_kind(2, 6)?, (GeoClass::Tri, kind));
                }
                GeoKind::Tri10 => {
                    assert_eq!(geo_class_and_kind(2, 10)?, (GeoClass::Tri, kind));
                }
                GeoKind::Tri15 => {
                    assert_eq!(geo_class_and_kind(2, 15)?, (GeoClass::Tri, kind));
                }

                // Qua
                GeoKind::Qua4 => {
                    assert_eq!(geo_class_and_kind(2, 4)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua8 => {
                    assert_eq!(geo_class_and_kind(2, 8)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua9 => {
                    assert_eq!(geo_class_and_kind(2, 9)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua12 => {
                    assert_eq!(geo_class_and_kind(2, 12)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua16 => {
                    assert_eq!(geo_class_and_kind(2, 16)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua17 => {
                    assert_eq!(geo_class_and_kind(2, 17)?, (GeoClass::Qua, kind));
                }

                // Tet
                GeoKind::Tet4 => {
                    assert_eq!(geo_class_and_kind(3, 4)?, (GeoClass::Tet, kind));
                }
                GeoKind::Tet10 => {
                    assert_eq!(geo_class_and_kind(3, 10)?, (GeoClass::Tet, kind));
                }

                // Hex
                GeoKind::Hex8 => {
                    assert_eq!(geo_class_and_kind(3, 8)?, (GeoClass::Hex, kind));
                }
                GeoKind::Hex20 => {
                    assert_eq!(geo_class_and_kind(3, 20)?, (GeoClass::Hex, kind));
                }
            }
        }
        Ok(())
    }
}
<commit_msg>Remove unnecessary values for GeoKind enums<commit_after>use crate::StrError;

/// Defines the class of geometric shape
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum GeoClass {
    /// Lines (segments) class
    Lin,

    /// Triangles class
    Tri,

    /// Quadrilaterals class
    Qua,

    /// Tetrahedra class
    Tet,

    /// Hexahedra class
    Hex,
}

/// Defines the kind of geometric shape
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum GeoKind {
    /// Line (segment) with 2 nodes (linear functions)
    Lin2,

    /// Line (segment) with 3 nodes (quadratic functions)
    Lin3,

    /// Line (segment) with 4 nodes (cubic functions)
    Lin4,

    /// Line (segment) with 5 nodes (quartic functions)
    Lin5,

    /// Triangle with 3 nodes (linear edges)
    Tri3,

    /// Triangle with 6 nodes (quadratic edges)
    Tri6,

    /// Triangle with 10 nodes (cubic edges; interior node)
    Tri10,

    /// Triangle with 15 nodes (quartic edges; interior nodes)
    Tri15,

    /// Quadrilateral with 4 nodes (linear edges)
    Qua4,

    /// Quadrilateral with 8 nodes (quadratic edges)
    Qua8,

    /// Quadrilateral with 9 nodes (quadratic edges; interior node)
    Qua9,

    /// Quadrilateral with 12 nodes (cubic edges)
    Qua12,

    /// Quadrilateral with 16 nodes (cubic edges; interior nodes)
    Qua16,

    /// Quadrilateral with 17 nodes (quartic edges; interior node)
    Qua17,

    /// Tetrahedron with 4 nodes (linear faces)
    Tet4,

    /// Tetrahedron with 10 nodes (quadratic faces)
    Tet10,

    /// Hexahedron with 8 nodes (bilinear faces)
    Hex8,

    /// Hexahedron with 20 nodes (quadratic faces)
    Hex20,
}

/// GeoNdim is the (local) space dimension of the geometric feature
pub type GeoNdim = usize;

/// GeoNnode is the number of nodes associated with a geometric feature
pub type GeoNnode = usize;

impl GeoKind {
    /// Holds all (geo_ndim,nnode) pairs
    pub const PAIRS: [(usize, usize); 18] = [
        // Lin
        (1, 2),
        (1, 3),
        (1, 4),
        (1, 5),
        // Tri
        (2, 3),
        (2, 6),
        (2, 10),
        (2, 15),
        // Qua
        (2, 4),
        (2, 8),
        (2, 9),
        (2, 12),
        (2, 16),
        (2, 17),
        // Tet
        (3, 4),
        (3, 10),
        // Hex
        (3, 8),
        (3, 20),
    ];

    /// Holds all enum values
    pub const VALUES: [Self; 18] = [
        // Lin
        Self::Lin2,
        Self::Lin3,
        Self::Lin4,
        Self::Lin5,
        // Tri
        Self::Tri3,
        Self::Tri6,
        Self::Tri10,
        Self::Tri15,
        // Qua
        Self::Qua4,
        Self::Qua8,
        Self::Qua9,
        Self::Qua12,
        Self::Qua16,
        Self::Qua17,
        // Tet
        Self::Tet4,
        Self::Tet10,
        // Hex
        Self::Hex8,
        Self::Hex20,
    ];
}

/// Returns the GeoClass and GeoKind for given geo_ndim and nnode
pub fn geo_class_and_kind(geo_ndim: usize, nnode: usize) -> Result<(GeoClass, GeoKind), StrError> {
    match (geo_ndim, nnode) {
        // Lin
        (1, 2) => Ok((GeoClass::Lin, GeoKind::Lin2)),
        (1, 3) => Ok((GeoClass::Lin, GeoKind::Lin3)),
        (1, 4) => Ok((GeoClass::Lin, GeoKind::Lin4)),
        (1, 5) => Ok((GeoClass::Lin, GeoKind::Lin5)),

        // Tri
        (2, 3) => Ok((GeoClass::Tri, GeoKind::Tri3)),
        (2, 6) => Ok((GeoClass::Tri, GeoKind::Tri6)),
        (2, 10) => Ok((GeoClass::Tri, GeoKind::Tri10)),
        (2, 15) => Ok((GeoClass::Tri, GeoKind::Tri15)),

        // Qua
        (2, 4) => Ok((GeoClass::Qua, GeoKind::Qua4)),
        (2, 8) => Ok((GeoClass::Qua, GeoKind::Qua8)),
        (2, 9) => Ok((GeoClass::Qua, GeoKind::Qua9)),
        (2, 12) => Ok((GeoClass::Qua, GeoKind::Qua12)),
        (2, 16) => Ok((GeoClass::Qua, GeoKind::Qua16)),
        (2, 17) => Ok((GeoClass::Qua, GeoKind::Qua17)),

        // Tet
        (3, 4) => Ok((GeoClass::Tet, GeoKind::Tet4)),
        (3, 10) => Ok((GeoClass::Tet, GeoKind::Tet10)),

        // Hex
        (3, 8) => Ok((GeoClass::Hex, GeoKind::Hex8)),
        (3, 20) => Ok((GeoClass::Hex, GeoKind::Hex20)),
        _ => Err("(geo_ndim,nnode) combination is invalid"),
    }
}

/// Returns the (min,max,delta) limits on the reference domain
///
/// # Tri and Tet
///
/// * `ξ_min` = 0.0
/// * `ξ_max` = 1.0
/// * `Δξ` = 1.0
///
/// # Lin, Qua, Hex
///
/// * `ξ_min` = -1.0
/// * `ξ_max` = +1.0
/// * `Δξ` = 2.0
#[inline]
pub fn ref_domain_limits(class: GeoClass) -> (f64, f64, f64) {
    if class == GeoClass::Tri || class == GeoClass::Tet {
        (0.0, 1.0, 1.0)
    } else {
        (-1.0, 1.0, 2.0)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::{
        shapes::{geo_class_and_kind, GeoClass, GeoKind},
        StrError,
    };
    use std::collections::HashSet;

    #[test]
    fn derive_works() {
        let class = GeoClass::Tri.clone();
        let kind = GeoKind::Tri6.clone();
        let classes = HashSet::from([GeoClass::Tri, GeoClass::Qua]);
        let kinds = HashSet::from([GeoKind::Tri3, GeoKind::Qua4]);
        assert_eq!(class, GeoClass::Tri);
        assert_eq!(kind, GeoKind::Tri6);
        assert_eq!(format!("{:?}", class), "Tri");
        assert_eq!(format!("{:?}", kind), "Tri6");
        assert_eq!(classes.contains(&GeoClass::Tri), true);
        assert_eq!(kinds.contains(&GeoKind::Tri3), true);
    }

    #[test]
    fn data_is_consistent() -> Result<(), StrError> {
        for kind in GeoKind::VALUES {
            match kind {
                // Lin
                GeoKind::Lin2 => {
                    assert_eq!(geo_class_and_kind(1, 2)?, (GeoClass::Lin, kind));
                }
                GeoKind::Lin3 => {
                    assert_eq!(geo_class_and_kind(1, 3)?, (GeoClass::Lin, kind));
                }
                GeoKind::Lin4 => {
                    assert_eq!(geo_class_and_kind(1, 4)?, (GeoClass::Lin, kind));
                }
                GeoKind::Lin5 => {
                    assert_eq!(geo_class_and_kind(1, 5)?, (GeoClass::Lin, kind));
                }

                // Tri
                GeoKind::Tri3 => {
                    assert_eq!(geo_class_and_kind(2, 3)?, (GeoClass::Tri, kind));
                }
                GeoKind::Tri6 => {
                    assert_eq!(geo_class_and_kind(2, 6)?, (GeoClass::Tri, kind));
                }
                GeoKind::Tri10 => {
                    assert_eq!(geo_class_and_kind(2, 10)?, (GeoClass::Tri, kind));
                }
                GeoKind::Tri15 => {
                    assert_eq!(geo_class_and_kind(2, 15)?, (GeoClass::Tri, kind));
                }

                // Qua
                GeoKind::Qua4 => {
                    assert_eq!(geo_class_and_kind(2, 4)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua8 => {
                    assert_eq!(geo_class_and_kind(2, 8)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua9 => {
                    assert_eq!(geo_class_and_kind(2, 9)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua12 => {
                    assert_eq!(geo_class_and_kind(2, 12)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua16 => {
                    assert_eq!(geo_class_and_kind(2, 16)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua17 => {
                    assert_eq!(geo_class_and_kind(2, 17)?, (GeoClass::Qua, kind));
                }

                // Tet
                GeoKind::Tet4 => {
                    assert_eq!(geo_class_and_kind(3, 4)?, (GeoClass::Tet, kind));
                }
                GeoKind::Tet10 => {
                    assert_eq!(geo_class_and_kind(3, 10)?, (GeoClass::Tet, kind));
                }

                // Hex
                GeoKind::Hex8 => {
                    assert_eq!(geo_class_and_kind(3, 8)?, (GeoClass::Hex, kind));
                }
                GeoKind::Hex20 => {
                    assert_eq!(geo_class_and_kind(3, 20)?, (GeoClass::Hex, kind));
                }
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::collections::Bound::Included;
use std::collections::BTreeMap;
use std::u64;

pub struct Store<'a> {
  max_offset: u64,
  data: Box<BTreeMap<&'a str, Box<BTreeMap<u64, &'a [u8]>>>>
}

impl<'a> Store<'a> {
  pub fn new<'b>() -> Store<'b> {
    Store {
      max_offset: 0,
      data: Box::new(BTreeMap::new())
    }
  }

  pub fn add(&'a mut self, key: &'a str, value: &'a [u8]) {
    self.max_offset += 1;
    if self.data.get_mut(&key).is_none() {
      if self.data.insert(key, Box::new(BTreeMap::new())).is_some() {
        panic!("Invariant violation; duplicate version tree detected");
      }
    }

    if self.data.get_mut(&key).unwrap().insert(self.max_offset, value).is_some() {
      panic!("Invariant violation; duplicate offset detected");
    }
  }

  pub fn get(&'a mut self, key: &'a str) -> Option<&'a [u8]> {
    self.data.get(&key).map( |version_tree| {
      version_tree.range(Included(&u64::MAX), Included(&u64::MAX)).last().unwrap()
    })
  }
}

#[test]
fn add_something() {
  let mut store = Store::new();
  store.add("yo", b"ok");
}

#[test]
fn get_something() {
  let mut store = Store::new();
  store.add("spaghetti", b"I'm");
  store.add("spaghetti", b"James");
  store.add("spaghetti", b"Quall");
  store.add("spaghetti", b"spaghetti");
  store.add("spaghetti", b"and");
  store.add("spaghetti", b"meatballs");
  assert!(store.get("spaghetti") == Some(b"meatballs"));
}
<commit_msg>Using match<commit_after>use std::collections::Bound::Included;
use std::collections::BTreeMap;
use std::u64;

pub struct Store<'a> {
  max_offset: u64,
  data: Box<BTreeMap<&'a str, Box<BTreeMap<u64, &'a [u8]>>>>
}

impl<'a> Store<'a> {
  pub fn new<'b>() -> Store<'b> {
    Store {
      max_offset: 0,
      data: Box::new(BTreeMap::new())
    }
  }

  pub fn add(&'a mut self, key: &'a str, value: &'a [u8]) {
    self.max_offset += 1;
    if self.data.get_mut(&key).is_none() {
      if self.data.insert(key, Box::new(BTreeMap::new())).is_some() {
        panic!("Invariant violation; duplicate version tree detected");
      }
    }

    if self.data.get_mut(&key).unwrap().insert(self.max_offset, value).is_some() {
      panic!("Invariant violation; duplicate offset detected");
    }
  }

  pub fn get(&'a mut self, key: &'a str) -> Option<&'a [u8]> {
    self.data.get(&key).map( |version_tree| {
      match version_tree.range(Included(&u64::MAX), Included(&u64::MAX)).last() {
        Some((_, value)) => value
      }
    })
  }
}

#[test]
fn add_something() {
  let mut store = Store::new();
  store.add("yo", b"ok");
}

#[test]
fn get_something() {
  let mut store = Store::new();
  store.add("spaghetti", b"I'm");
  store.add("spaghetti", b"James");
  store.add("spaghetti", b"Quall");
  store.add("spaghetti", b"spaghetti");
  store.add("spaghetti", b"and");
  store.add("spaghetti", b"meatballs");
  assert!(store.get("spaghetti") == Some(b"meatballs"));
}
<|endoftext|>


<commit_before>use circle::Circle;
use fx32::Fx32;
use ray2::Ray2;
use vec2::Vec2;

#[derive (Clone, Copy)]
pub enum Ray2TraceResult {
	Hit (Fx32, Vec2, Vec2),
	Miss,
}

pub fn fold_closer_result (a: Ray2TraceResult, b: Ray2TraceResult) -> Ray2TraceResult {
	match a {
		Ray2TraceResult::Miss => {
			return b;
		},
		Ray2TraceResult::Hit (a_t, ..) => {
			match b {
				Ray2TraceResult::Miss => {
					return a;
				},
				Ray2TraceResult::Hit (b_t, ..) => {
					if a_t < b_t {
						return a;
					}
					else {
						return b;
					}
				}
			}
		},
	}
}

pub fn ray_trace_circle (ray: &Ray2, circle: &Circle) -> Ray2TraceResult {
	let toward_circle = circle.center - ray.start;

	if toward_circle * ray.dir < Fx32::from_int (0) {
		// Ray is heading out of the circle's space or is already out
		return Ray2TraceResult::Miss;
	}

	// TODO: Handle ray starting inside circle

	// The following is derived from the quadratic formula and my Lua code
	let a = ray.dir.length_sq ();

	if a == Fx32::from_int (0) {
		return Ray2TraceResult::Miss;
	}

	// This part is different from the canonical quadratic formula
	// I negated it because it will save a negation later on
	let b = (ray.dir * toward_circle) * Fx32::from_int (2);

	let c = toward_circle.length_sq () - circle.radius.square_64 ();

	let determinant = b * b - Fx32::from_int (4) * a * c;
	if determinant < Fx32::from_int (0) {
		return Ray2TraceResult::Miss;
	}

	let t = (b - determinant.sqrt_64 ()) / (Fx32::from_int (2) * a);

	if t >= Fx32::from_int (0) && t <= Fx32::from_int (1) {
		let ccd_pos = ray.at (t);

		let normal = (ccd_pos - circle.center).normalized ();

		return Ray2TraceResult::Hit (t, ccd_pos, normal);
	}

	Ray2TraceResult::Miss
}
<commit_msg>Further refactoring.<commit_after>use circle::Circle;
use fx32::Fx32;
use ray2::Ray2;
use vec2::Vec2;

#[derive (Clone, Copy)]
pub enum Ray2TraceResult {
	Hit (Fx32, Vec2, Vec2),
	Miss,
}

pub fn fold_closer_result (a: Ray2TraceResult, b: Ray2TraceResult) -> Ray2TraceResult {
	match a {
		Ray2TraceResult::Miss => {
			return b;
		},
		Ray2TraceResult::Hit (a_t, ..) => {
			match b {
				Ray2TraceResult::Miss => {
					return a;
				},
				Ray2TraceResult::Hit (b_t, ..) => {
					if a_t < b_t {
						return a;
					}
					else {
						return b;
					}
				}
			}
		},
	}
}

pub fn ray_trace_circle (ray: &Ray2, circle: &Circle) -> Ray2TraceResult {
	let toward_circle = circle.center - ray.start;

	let ray_dot_circle = toward_circle * ray.dir;

	if ray_dot_circle < Fx32::from_int (0) {
		// Ray is heading out of the circle's space or is already out
		return Ray2TraceResult::Miss;
	}

	// TODO: Handle ray starting inside circle

	// The following is derived from the quadratic formula and my Lua code
	let a = ray.dir.length_sq ();

	if a == Fx32::from_int (0) {
		return Ray2TraceResult::Miss;
	}

	// This part is different from the canonical quadratic formula
	// I negated it because it will save a negation later on
	// Then I also halved it
	let half_b = ray_dot_circle;

	let c = toward_circle.length_sq () - circle.radius.square_64 ();

	let determinant = Fx32::from_int (4) * (half_b.square_64 () - a * c);
	if determinant < Fx32::from_int (0) {
		return Ray2TraceResult::Miss;
	}

	let t = (half_b * Fx32::from_int (2) - determinant.sqrt_64 ()) / (Fx32::from_int (2) * a);

	if t >= Fx32::from_int (0) && t <= Fx32::from_int (1) {
		let ccd_pos = ray.at (t);

		let normal = (ccd_pos - circle.center).normalized ();

		return Ray2TraceResult::Hit (t, ccd_pos, normal);
	}

	Ray2TraceResult::Miss
}
<|endoftext|>


<commit_before>use circle::Circle;
use fx32::Fx32;
use fx32::Fx32Small;
use ray2::Ray2;
use vec2::Vec2;
use wide_line::WideLine;

use std::cmp;

use std::io::Error;
use std::io::prelude::*;
use std::io::BufWriter;
use std::fs::File;

#[derive (Clone, Copy)]
pub enum Ray2TraceResult {
	Hit (Fx32, Vec2 <Fx32>, Vec2 <Fx32Small>),
	Miss,
}

pub fn fold_closer_result (a: Ray2TraceResult, b: Ray2TraceResult) -> Ray2TraceResult {
	match a {
		Ray2TraceResult::Miss => {
			return b;
		},
		Ray2TraceResult::Hit (a_t, ..) => {
			match b {
				Ray2TraceResult::Miss => {
					return a;
				},
				Ray2TraceResult::Hit (b_t, ..) => {
					if a_t < b_t {
						return a;
					}
					else {
						return b;
					}
				}
			}
		},
	}
}

pub fn test_ray_trace () -> Result <(), Error> {
	let scale = 1;
	//let scale_fx = Fx32::from_int (scale);

	let obstacle = vec! [
	Circle {
		center: Vec2 {x: Fx32::from_q (133, scale), y: Fx32::from_q (512 - 34, scale)},
		radius: Fx32::from_q (20, scale),
	},
	Circle {
		center: Vec2 {x: Fx32::from_q (256, scale), y: Fx32::from_q (501, scale)},
		radius: Fx32::from_q (20, scale),
	},
	Circle {
		center: Vec2 {x: Fx32::from_q (404, scale), y: Fx32::from_q (512 - 41, scale)},
		radius: Fx32::from_q (20, scale),
	},
	];

	let lines = vec! [
	WideLine {
		start: obstacle [0].center,
		end: obstacle [1].center,
	},
	];

	let mut num_bounces = 0;
	let mut num_ticks = 0;

	let inv_dt = 64;
	let gravity = Vec2::<Fx32> {
		x: Fx32::from_q (0, 1),
		y: Fx32::from_q (2, 1),
	};

	let obj_file = try!(File::create("lines.obj"));
	let mut writer = BufWriter::new (obj_file);

	let mut vertex_i = 1;
	let mut polyline_start = vertex_i;

	for x in 0..256 {
		let x = x * 2;
		let mut particle = Ray2 {
			start: Vec2 {
				x: Fx32::from_q (x * 2 + 1, scale * 2),
				y: Fx32::from_q (0, scale)
			},
			dir: Vec2 {
				x: Fx32::from_q (0, scale),
				y: Fx32::from_q (0, scale),
			},
		};

		try! (write! (writer, "v {} {} 0\n", particle.start.x.to_f64 (), particle.start.y.to_f64 ()));
		vertex_i += 1;

		for _ in 0..4000 {
			let trace_result = obstacle.iter ().map(|obstacle: &Circle| ray_trace_circle_2 (&particle, obstacle)).fold ( Ray2TraceResult::Miss, fold_closer_result);

			let dt = Fx32::from_q (1, inv_dt).to_small ();

			match trace_result {
				Ray2TraceResult::Miss => {
					let air_drag = Fx32 { x: particle.dir.length_sq ().x / -16384 };
					let air_force = particle.dir * air_drag;
					let new_dir = particle.dir + gravity * dt + Vec2::<Fx32>::from (air_force * dt);
					let sum_dir = particle.dir + new_dir;
					let average_dir = Vec2::<Fx32> {
						x: Fx32 { x: sum_dir.x.x / 2 },
						y: Fx32 { x: sum_dir.y.x / 2 },
					};

					particle.start = particle.start + (average_dir * dt);
					particle.dir = new_dir;
				},
				Ray2TraceResult::Hit (_, ccd_pos, normal) => {
					particle.start = ccd_pos;
					particle.dir = particle.dir.reflect (normal) * Fx32::from_q (1023, 1024);
					//particle.dir = normal;
					num_bounces += 1;
				},
			};

			try! (write! (writer, "v {} {} 0\n", particle.start.x.to_f64 (), particle.start.y.to_f64 ()));
			vertex_i += 1;

			num_ticks += 1;

			if particle.start.y > 768 {
				break;
			}
		}

		for i in polyline_start..vertex_i - 1 {
			try! (write! (writer, "f {} {}\n", i, i + 1));
		}
		polyline_start = vertex_i
	}

	println! ("num_bounces: {}", num_bounces);
	println! ("num_ticks: {}", num_ticks);

	Ok (())
}

pub fn ray_trace_circle_2 (ray: &Ray2, circle: &Circle) -> Ray2TraceResult {
	let ray_length = ray.dir.length ();

	let basis_x_big = if ray_length == 0 {
		ray.dir
	}
	else {
		ray.dir / ray_length
	};

	let basis_x = basis_x_big.to_small ();
	let basis_y = basis_x_big.cross ().to_small ();

	let to_circle = circle.center - ray.start;

	let center_in_ray_space = Vec2::<Fx32> {
		x: to_circle * basis_x,
		y: to_circle * basis_y,
	};

	if center_in_ray_space.x < 0 {
		return Ray2TraceResult::Miss;
	}

	if center_in_ray_space.x > ray_length + circle.radius {
		return Ray2TraceResult::Miss;
	}

	if center_in_ray_space.y.abs () >= circle.radius {
		// Prevents a negative root later on
		return Ray2TraceResult::Miss;
	}

	let ray_space_x = center_in_ray_space.x - (circle.radius.square () - center_in_ray_space.y.square ()).sqrt ();

	if ray_space_x > ray_length || ray_length == 0 {
		return Ray2TraceResult::Miss;
	}

	let t = ray_space_x / ray_length;
	let ccd_pos = ray.start + ray.dir * t;

	if t <= 1 {
		return Ray2TraceResult::Hit (
			Fx32 { x: cmp::max (t.x, Fx32::from_int (0).x) },
			ccd_pos,
			((ccd_pos - circle.center) / circle.radius).to_small (),
		);
	}
	else {
		return Ray2TraceResult::Miss;
	}
}
<commit_msg>Making space in the collision code for lines<commit_after>use circle::Circle;
use fx32::Fx32;
use fx32::Fx32Small;
use ray2::Ray2;
use vec2::Vec2;
use wide_line::WideLine;

use std::cmp;

use std::io::Error;
use std::io::prelude::*;
use std::io::BufWriter;
use std::fs::File;

#[derive (Clone, Copy)]
pub enum Ray2TraceResult {
	Hit (Fx32, Vec2 <Fx32>, Vec2 <Fx32Small>),
	Miss,
}

pub fn fold_closer_result (a: Ray2TraceResult, b: Ray2TraceResult) -> Ray2TraceResult {
	match a {
		Ray2TraceResult::Miss => {
			return b;
		},
		Ray2TraceResult::Hit (a_t, ..) => {
			match b {
				Ray2TraceResult::Miss => {
					return a;
				},
				Ray2TraceResult::Hit (b_t, ..) => {
					if a_t < b_t {
						return a;
					}
					else {
						return b;
					}
				}
			}
		},
	}
}

pub fn test_ray_trace () -> Result <(), Error> {
	let scale = 1;
	//let scale_fx = Fx32::from_int (scale);

	let obstacle = vec! [
	Circle {
		center: Vec2 {x: Fx32::from_q (133, scale), y: Fx32::from_q (512 - 34, scale)},
		radius: Fx32::from_q (20, scale),
	},
	Circle {
		center: Vec2 {x: Fx32::from_q (256, scale), y: Fx32::from_q (501, scale)},
		radius: Fx32::from_q (20, scale),
	},
	Circle {
		center: Vec2 {x: Fx32::from_q (404, scale), y: Fx32::from_q (512 - 41, scale)},
		radius: Fx32::from_q (20, scale),
	},
	];

	let lines = vec! [
	WideLine {
		start: obstacle [0].center,
		end: obstacle [1].center,
	},
	];

	let mut num_bounces = 0;
	let mut num_ticks = 0;

	let inv_dt = 64;
	let gravity = Vec2::<Fx32> {
		x: Fx32::from_q (0, 1),
		y: Fx32::from_q (2, 1),
	};

	let obj_file = try!(File::create("lines.obj"));
	let mut writer = BufWriter::new (obj_file);

	let mut vertex_i = 1;
	let mut polyline_start = vertex_i;

	for x in 0..256 {
		let x = x * 2;
		let mut particle = Ray2 {
			start: Vec2 {
				x: Fx32::from_q (x * 2 + 1, scale * 2),
				y: Fx32::from_q (0, scale)
			},
			dir: Vec2 {
				x: Fx32::from_q (0, scale),
				y: Fx32::from_q (0, scale),
			},
		};

		try! (write! (writer, "v {} {} 0\n", particle.start.x.to_f64 (), particle.start.y.to_f64 ()));
		vertex_i += 1;

		for _ in 0..4000 {
			let trace_result = {
				let point_results = obstacle.iter ().map(|obstacle: &Circle| ray_trace_circle_2 (&particle, obstacle));

				point_results.fold ( Ray2TraceResult::Miss, fold_closer_result)
			};

			let dt = Fx32::from_q (1, inv_dt).to_small ();

			match trace_result {
				Ray2TraceResult::Miss => {
					let air_drag = Fx32 { x: particle.dir.length_sq ().x / -16384 };
					let air_force = particle.dir * air_drag;
					let new_dir = particle.dir + gravity * dt + Vec2::<Fx32>::from (air_force * dt);
					let sum_dir = particle.dir + new_dir;
					let average_dir = Vec2::<Fx32> {
						x: Fx32 { x: sum_dir.x.x / 2 },
						y: Fx32 { x: sum_dir.y.x / 2 },
					};

					particle.start = particle.start + (average_dir * dt);
					particle.dir = new_dir;
				},
				Ray2TraceResult::Hit (_, ccd_pos, normal) => {
					particle.start = ccd_pos;
					particle.dir = particle.dir.reflect (normal) * Fx32::from_q (1023, 1024);
					//particle.dir = normal;
					num_bounces += 1;
				},
			};

			try! (write! (writer, "v {} {} 0\n", particle.start.x.to_f64 (), particle.start.y.to_f64 ()));
			vertex_i += 1;

			num_ticks += 1;

			if particle.start.y > 768 {
				break;
			}
		}

		for i in polyline_start..vertex_i - 1 {
			try! (write! (writer, "f {} {}\n", i, i + 1));
		}
		polyline_start = vertex_i
	}

	println! ("num_bounces: {}", num_bounces);
	println! ("num_ticks: {}", num_ticks);

	Ok (())
}

pub fn ray_trace_circle_2 (ray: &Ray2, circle: &Circle) -> Ray2TraceResult {
	let ray_length = ray.dir.length ();

	let basis_x_big = if ray_length == 0 {
		ray.dir
	}
	else {
		ray.dir / ray_length
	};

	let basis_x = basis_x_big.to_small ();
	let basis_y = basis_x_big.cross ().to_small ();

	let to_circle = circle.center - ray.start;

	let center_in_ray_space = Vec2::<Fx32> {
		x: to_circle * basis_x,
		y: to_circle * basis_y,
	};

	if center_in_ray_space.x < 0 {
		return Ray2TraceResult::Miss;
	}

	if center_in_ray_space.x > ray_length + circle.radius {
		return Ray2TraceResult::Miss;
	}

	if center_in_ray_space.y.abs () >= circle.radius {
		// Prevents a negative root later on
		return Ray2TraceResult::Miss;
	}

	let ray_space_x = center_in_ray_space.x - (circle.radius.square () - center_in_ray_space.y.square ()).sqrt ();

	if ray_space_x > ray_length || ray_length == 0 {
		return Ray2TraceResult::Miss;
	}

	let t = ray_space_x / ray_length;
	let ccd_pos = ray.start + ray.dir * t;

	if t <= 1 {
		return Ray2TraceResult::Hit (
			Fx32 { x: cmp::max (t.x, Fx32::from_int (0).x) },
			ccd_pos,
			((ccd_pos - circle.center) / circle.radius).to_small (),
		);
	}
	else {
		return Ray2TraceResult::Miss;
	}
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use actix_net::codec::Framed;
use actix_net::service::{NewService, Service};
use futures::future::{ok, Either, FutureResult};
use futures::{Async, AsyncSink, Future, Poll, Sink};
use tokio_io::{AsyncRead, AsyncWrite};

use body::Body;
use error::{Error, ResponseError};
use h1::{Codec, Message};
use response::Response;

pub struct SendError<T, R, E>(PhantomData<(T, R, E)>);

impl<T, R, E> Default for SendError<T, R, E>
where
    T: AsyncWrite,
    E: ResponseError,
{
    fn default() -> Self {
        SendError(PhantomData)
    }
}

impl<T, R, E> NewService for SendError<T, R, E>
where
    T: AsyncWrite,
    E: ResponseError,
{
    type Request = Result<R, (E, Framed<T, Codec>)>;
    type Response = R;
    type Error = (E, Framed<T, Codec>);
    type InitError = ();
    type Service = SendError<T, R, E>;
    type Future = FutureResult<Self::Service, Self::InitError>;

    fn new_service(&self) -> Self::Future {
        ok(SendError(PhantomData))
    }
}

impl<T, R, E> Service for SendError<T, R, E>
where
    T: AsyncWrite,
    E: ResponseError,
{
    type Request = Result<R, (E, Framed<T, Codec>)>;
    type Response = R;
    type Error = (E, Framed<T, Codec>);
    type Future = Either<FutureResult<R, (E, Framed<T, Codec>)>, SendErrorFut<T, R, E>>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        Ok(Async::Ready(()))
    }

    fn call(&mut self, req: Self::Request) -> Self::Future {
        match req {
            Ok(r) => Either::A(ok(r)),
            Err((e, framed)) => {
                let mut resp = e.error_response();
                resp.set_body(format!("{}", e));
                Either::B(SendErrorFut {
                    framed: Some(framed),
                    res: Some(resp.into()),
                    err: Some(e),
                    _t: PhantomData,
                })
            }
        }
    }
}

pub struct SendErrorFut<T, R, E> {
    res: Option<Message<Response>>,
    framed: Option<Framed<T, Codec>>,
    err: Option<E>,
    _t: PhantomData<R>,
}

impl<T, R, E> Future for SendErrorFut<T, R, E>
where
    E: ResponseError,
    T: AsyncWrite,
{
    type Item = R;
    type Error = (E, Framed<T, Codec>);

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if let Some(res) = self.res.take() {
            match self.framed.as_mut().unwrap().start_send(res) {
                Ok(AsyncSink::Ready) => (),
                Ok(AsyncSink::NotReady(res)) => {
                    self.res = Some(res);
                    return Ok(Async::NotReady);
                }
                Err(_) => {
                    return Err((self.err.take().unwrap(), self.framed.take().unwrap()))
                }
            }
        }
        match self.framed.as_mut().unwrap().poll_complete() {
            Ok(Async::Ready(_)) => {
                Err((self.err.take().unwrap(), self.framed.take().unwrap()))
            }
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(_) => Err((self.err.take().unwrap(), self.framed.take().unwrap())),
        }
    }
}

pub struct SendResponse<T>(PhantomData<(T,)>);

impl<T> Default for SendResponse<T>
where
    T: AsyncRead + AsyncWrite,
{
    fn default() -> Self {
        SendResponse(PhantomData)
    }
}

impl<T> SendResponse<T>
where
    T: AsyncRead + AsyncWrite,
{
    pub fn send(
        mut framed: Framed<T, Codec>,
        mut res: Response,
    ) -> impl Future<Item = Framed<T, Codec>, Error = Error> {
        // init codec
        framed.get_codec_mut().prepare_te(&mut res);

        // extract body from response
        let body = res.replace_body(Body::Empty);

        // write response
        SendResponseFut {
            res: Some(Message::Item(res)),
            body: Some(body),
            framed: Some(framed),
        }
    }
}

impl<T> NewService for SendResponse<T>
where
    T: AsyncRead + AsyncWrite,
{
    type Request = (Response, Framed<T, Codec>);
    type Response = Framed<T, Codec>;
    type Error = Error;
    type InitError = ();
    type Service = SendResponse<T>;
    type Future = FutureResult<Self::Service, Self::InitError>;

    fn new_service(&self) -> Self::Future {
        ok(SendResponse(PhantomData))
    }
}

impl<T> Service for SendResponse<T>
where
    T: AsyncRead + AsyncWrite,
{
    type Request = (Response, Framed<T, Codec>);
    type Response = Framed<T, Codec>;
    type Error = Error;
    type Future = SendResponseFut<T>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        Ok(Async::Ready(()))
    }

    fn call(&mut self, (mut res, mut framed): Self::Request) -> Self::Future {
        framed.get_codec_mut().prepare_te(&mut res);
        let body = res.replace_body(Body::Empty);
        SendResponseFut {
            res: Some(Message::Item(res)),
            body: Some(body),
            framed: Some(framed),
        }
    }
}

pub struct SendResponseFut<T> {
    res: Option<Message<Response>>,
    body: Option<Body>,
    framed: Option<Framed<T, Codec>>,
}

impl<T> Future for SendResponseFut<T>
where
    T: AsyncRead + AsyncWrite,
{
    type Item = Framed<T, Codec>;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        // send response
        if self.res.is_some() {
            let framed = self.framed.as_mut().unwrap();
            if !framed.is_write_buf_full() {
                if let Some(res) = self.res.take() {
                    println!("SEND RESP: {:?}", res);
                    framed.force_send(res)?;
                }
            }
        }

        // send body
        if self.res.is_none() && self.body.is_some() {
            let framed = self.framed.as_mut().unwrap();
            if !framed.is_write_buf_full() {
                let body = self.body.take().unwrap();
                match body {
                    Body::Empty => (),
                    Body::Streaming(mut stream) => loop {
                        match stream.poll()? {
                            Async::Ready(item) => {
                                let done = item.is_none();
                                framed.force_send(Message::Chunk(item.into()))?;
                                if !done {
                                    if !framed.is_write_buf_full() {
                                        continue;
                                    } else {
                                        self.body = Some(Body::Streaming(stream));
                                        break;
                                    }
                                }
                            }
                            Async::NotReady => {
                                self.body = Some(Body::Streaming(stream));
                                break;
                            }
                        }
                    },
                    Body::Binary(mut bin) => {
                        framed.force_send(Message::Chunk(Some(bin.take())))?;
                        framed.force_send(Message::Chunk(None))?;
                    }
                }
            }
        }

        // flush
        match self.framed.as_mut().unwrap().poll_complete()? {
            Async::Ready(_) => if self.res.is_some() || self.body.is_some() {
                return self.poll();
            },
            Async::NotReady => return Ok(Async::NotReady),
        }

        Ok(Async::Ready(self.framed.take().unwrap()))
    }
}
<commit_msg>remove debug print<commit_after>use std::marker::PhantomData;

use actix_net::codec::Framed;
use actix_net::service::{NewService, Service};
use futures::future::{ok, Either, FutureResult};
use futures::{Async, AsyncSink, Future, Poll, Sink};
use tokio_io::{AsyncRead, AsyncWrite};

use body::Body;
use error::{Error, ResponseError};
use h1::{Codec, Message};
use response::Response;

pub struct SendError<T, R, E>(PhantomData<(T, R, E)>);

impl<T, R, E> Default for SendError<T, R, E>
where
    T: AsyncWrite,
    E: ResponseError,
{
    fn default() -> Self {
        SendError(PhantomData)
    }
}

impl<T, R, E> NewService for SendError<T, R, E>
where
    T: AsyncWrite,
    E: ResponseError,
{
    type Request = Result<R, (E, Framed<T, Codec>)>;
    type Response = R;
    type Error = (E, Framed<T, Codec>);
    type InitError = ();
    type Service = SendError<T, R, E>;
    type Future = FutureResult<Self::Service, Self::InitError>;

    fn new_service(&self) -> Self::Future {
        ok(SendError(PhantomData))
    }
}

impl<T, R, E> Service for SendError<T, R, E>
where
    T: AsyncWrite,
    E: ResponseError,
{
    type Request = Result<R, (E, Framed<T, Codec>)>;
    type Response = R;
    type Error = (E, Framed<T, Codec>);
    type Future = Either<FutureResult<R, (E, Framed<T, Codec>)>, SendErrorFut<T, R, E>>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        Ok(Async::Ready(()))
    }

    fn call(&mut self, req: Self::Request) -> Self::Future {
        match req {
            Ok(r) => Either::A(ok(r)),
            Err((e, framed)) => {
                let mut resp = e.error_response();
                resp.set_body(format!("{}", e));
                Either::B(SendErrorFut {
                    framed: Some(framed),
                    res: Some(resp.into()),
                    err: Some(e),
                    _t: PhantomData,
                })
            }
        }
    }
}

pub struct SendErrorFut<T, R, E> {
    res: Option<Message<Response>>,
    framed: Option<Framed<T, Codec>>,
    err: Option<E>,
    _t: PhantomData<R>,
}

impl<T, R, E> Future for SendErrorFut<T, R, E>
where
    E: ResponseError,
    T: AsyncWrite,
{
    type Item = R;
    type Error = (E, Framed<T, Codec>);

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if let Some(res) = self.res.take() {
            match self.framed.as_mut().unwrap().start_send(res) {
                Ok(AsyncSink::Ready) => (),
                Ok(AsyncSink::NotReady(res)) => {
                    self.res = Some(res);
                    return Ok(Async::NotReady);
                }
                Err(_) => {
                    return Err((self.err.take().unwrap(), self.framed.take().unwrap()))
                }
            }
        }
        match self.framed.as_mut().unwrap().poll_complete() {
            Ok(Async::Ready(_)) => {
                Err((self.err.take().unwrap(), self.framed.take().unwrap()))
            }
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(_) => Err((self.err.take().unwrap(), self.framed.take().unwrap())),
        }
    }
}

pub struct SendResponse<T>(PhantomData<(T,)>);

impl<T> Default for SendResponse<T>
where
    T: AsyncRead + AsyncWrite,
{
    fn default() -> Self {
        SendResponse(PhantomData)
    }
}

impl<T> SendResponse<T>
where
    T: AsyncRead + AsyncWrite,
{
    pub fn send(
        mut framed: Framed<T, Codec>,
        mut res: Response,
    ) -> impl Future<Item = Framed<T, Codec>, Error = Error> {
        // init codec
        framed.get_codec_mut().prepare_te(&mut res);

        // extract body from response
        let body = res.replace_body(Body::Empty);

        // write response
        SendResponseFut {
            res: Some(Message::Item(res)),
            body: Some(body),
            framed: Some(framed),
        }
    }
}

impl<T> NewService for SendResponse<T>
where
    T: AsyncRead + AsyncWrite,
{
    type Request = (Response, Framed<T, Codec>);
    type Response = Framed<T, Codec>;
    type Error = Error;
    type InitError = ();
    type Service = SendResponse<T>;
    type Future = FutureResult<Self::Service, Self::InitError>;

    fn new_service(&self) -> Self::Future {
        ok(SendResponse(PhantomData))
    }
}

impl<T> Service for SendResponse<T>
where
    T: AsyncRead + AsyncWrite,
{
    type Request = (Response, Framed<T, Codec>);
    type Response = Framed<T, Codec>;
    type Error = Error;
    type Future = SendResponseFut<T>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        Ok(Async::Ready(()))
    }

    fn call(&mut self, (mut res, mut framed): Self::Request) -> Self::Future {
        framed.get_codec_mut().prepare_te(&mut res);
        let body = res.replace_body(Body::Empty);
        SendResponseFut {
            res: Some(Message::Item(res)),
            body: Some(body),
            framed: Some(framed),
        }
    }
}

pub struct SendResponseFut<T> {
    res: Option<Message<Response>>,
    body: Option<Body>,
    framed: Option<Framed<T, Codec>>,
}

impl<T> Future for SendResponseFut<T>
where
    T: AsyncRead + AsyncWrite,
{
    type Item = Framed<T, Codec>;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        // send response
        if self.res.is_some() {
            let framed = self.framed.as_mut().unwrap();
            if !framed.is_write_buf_full() {
                if let Some(res) = self.res.take() {
                    framed.force_send(res)?;
                }
            }
        }

        // send body
        if self.res.is_none() && self.body.is_some() {
            let framed = self.framed.as_mut().unwrap();
            if !framed.is_write_buf_full() {
                let body = self.body.take().unwrap();
                match body {
                    Body::Empty => (),
                    Body::Streaming(mut stream) => loop {
                        match stream.poll()? {
                            Async::Ready(item) => {
                                let done = item.is_none();
                                framed.force_send(Message::Chunk(item.into()))?;
                                if !done {
                                    if !framed.is_write_buf_full() {
                                        continue;
                                    } else {
                                        self.body = Some(Body::Streaming(stream));
                                        break;
                                    }
                                }
                            }
                            Async::NotReady => {
                                self.body = Some(Body::Streaming(stream));
                                break;
                            }
                        }
                    },
                    Body::Binary(mut bin) => {
                        framed.force_send(Message::Chunk(Some(bin.take())))?;
                        framed.force_send(Message::Chunk(None))?;
                    }
                }
            }
        }

        // flush
        match self.framed.as_mut().unwrap().poll_complete()? {
            Async::Ready(_) => if self.res.is_some() || self.body.is_some() {
                return self.poll();
            },
            Async::NotReady => return Ok(Async::NotReady),
        }

        Ok(Async::Ready(self.framed.take().unwrap()))
    }
}
<|endoftext|>


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

//!
//! # Symbol range
//!
//! It's quite common to want to match ranges of symbols (most particularly, 'all' symbols but also things like all upper-case
//! characters). It would be inefficient to store all of the transitions represented by one of these transitions on a per-symbol
//! basis, and impossible for some symbol sets (consider a state machine working on u32s). Instead, transitions are stored as
//! symbol ranges.
//!

use std::cmp::*;

///
/// Represents a range of symbols
///
/// Symbols must be ordered in order to use them with a range-based state machine. Symbol ranges are inclusive unlike standard
/// Rust ranges - this allows them to represent the entire range of symbols instead of having a maximum coverage of 'all symbols
/// except the last one'.
///
#[derive(Clone, Eq, PartialEq)]
pub struct SymbolRange<Symbol: PartialOrd> {
    ///
    /// Lowest symbol in the range
    ///
    pub lowest: Symbol,

    ///
    /// Highest symbol in the range
    ///
    /// This is inclusive, so the highest symbol is always included in the range (this makes it differ from Rust's
    /// built-in Range struct, and is important for supporting uncountable symbols)
    ///
    pub highest: Symbol
}

impl<Symbol: PartialOrd> PartialOrd for SymbolRange<Symbol> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        let lower = self.lowest.partial_cmp(&other.lowest);

        if lower == Some(Ordering::Equal) {
            self.highest.partial_cmp(&other.highest)
        } else {
            lower
        }
    }
}

impl<Symbol: PartialOrd> SymbolRange<Symbol> {
    ///
    /// Creates a new range covering everything between the specified two symbols
    ///
    #[inline]
    pub fn new(lowest: Symbol, highest: Symbol) -> SymbolRange<Symbol> {
        if lowest > highest {
            SymbolRange { lowest: highest, highest: lowest }
        } else {
            SymbolRange { lowest: lowest, highest: highest }
        }
    }

    ///
    /// True if this range overlaps another
    ///
    #[inline]
    pub fn overlaps(&self, with: &SymbolRange<Symbol>) -> bool {
        if self.highest < with.lowest {
            false
        } else if self.lowest > with.highest {
            false
        } else {
            true
        }
    }
}

impl<Symbol: PartialOrd+Clone> SymbolRange<Symbol> {
    ///
    /// Joins this range with another
    ///
    /// This creates a new range that covers all the symbols of both. If `overlaps()` is false for these two ranges, then
    /// the new range may cover additional symbols that are not in either range.
    ///
    pub fn join(&self, with: &SymbolRange<Symbol>) -> SymbolRange<Symbol> {
        SymbolRange {
            lowest:  if with.lowest<self.lowest   { with.lowest.clone()  } else { self.lowest.clone()  },
            highest: if with.highest<self.highest { self.highest.clone() } else { with.highest.clone() }
        }
    }
}

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

    #[test]
    fn can_create_range() {
        let range = SymbolRange::new(1, 2);

        assert!(range.lowest == 1);
        assert!(range.highest == 2);
    }

    #[test]
    fn can_create_range_reversed() {
        let range = SymbolRange::new(5, 1);

        assert!(range.lowest == 1);
        assert!(range.highest == 5);
    }

    #[test]
    fn overlaps_when_within() {
        assert!(SymbolRange::new(1, 4).overlaps(&SymbolRange::new(2, 3)));
    }

    #[test]
    fn overlaps_when_within_float() {
        assert!(SymbolRange::new(1.0, 4.0).overlaps(&SymbolRange::new(2.0, 3.0)));
    }

    #[test]
    fn overlaps_when_without() {
        assert!(SymbolRange::new(2, 3).overlaps(&SymbolRange::new(1, 4)));
    }

    #[test]
    fn overlaps_when_lower() {
        assert!(SymbolRange::new(1, 3).overlaps(&SymbolRange::new(2, 4)));
    }

    #[test]
    fn overlaps_when_higher() {
        assert!(SymbolRange::new(2, 4).overlaps(&SymbolRange::new(1, 3)));
    }

    #[test]
    fn overlaps_when_same() {
        assert!(SymbolRange::new(1, 4).overlaps(&SymbolRange::new(1, 4)));
    }

    #[test]
    fn does_not_overlap_lower() {
        assert!(!SymbolRange::new(1, 2).overlaps(&SymbolRange::new(4, 5)));
    }

    #[test]
    fn does_not_overlap_higher() {
        assert!(!SymbolRange::new(4, 5).overlaps(&SymbolRange::new(1, 2)));
    }

    #[test]
    fn join_left() {
        let joined = SymbolRange::new(1, 3).join(&SymbolRange::new(3, 4));

        assert!(joined.lowest == 1);
        assert!(joined.highest == 4);
    }

    #[test]
    fn join_right() {
        let joined = SymbolRange::new(3, 4).join(&SymbolRange::new(1, 3));

        assert!(joined.lowest == 1);
        assert!(joined.highest == 4);
    }

    #[test]
    fn join_overlap() {
        let joined = SymbolRange::new(1, 4).join(&SymbolRange::new(2, 3));

        assert!(joined.lowest == 1);
        assert!(joined.highest == 4);
    }
}
<commit_msg>Add a way to detect if a symbol is in the range<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Symbol range
//!
//! It's quite common to want to match ranges of symbols (most particularly, 'all' symbols but also things like all upper-case
//! characters). It would be inefficient to store all of the transitions represented by one of these transitions on a per-symbol
//! basis, and impossible for some symbol sets (consider a state machine working on u32s). Instead, transitions are stored as
//! symbol ranges.
//!

use std::cmp::*;

///
/// Represents a range of symbols
///
/// Symbols must be ordered in order to use them with a range-based state machine. Symbol ranges are inclusive unlike standard
/// Rust ranges - this allows them to represent the entire range of symbols instead of having a maximum coverage of 'all symbols
/// except the last one'.
///
#[derive(Clone, Eq, PartialEq)]
pub struct SymbolRange<Symbol: PartialOrd> {
    ///
    /// Lowest symbol in the range
    ///
    pub lowest: Symbol,

    ///
    /// Highest symbol in the range
    ///
    /// This is inclusive, so the highest symbol is always included in the range (this makes it differ from Rust's
    /// built-in Range struct, and is important for supporting uncountable symbols)
    ///
    pub highest: Symbol
}

impl<Symbol: PartialOrd> PartialOrd for SymbolRange<Symbol> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        let lower = self.lowest.partial_cmp(&other.lowest);

        if lower == Some(Ordering::Equal) {
            self.highest.partial_cmp(&other.highest)
        } else {
            lower
        }
    }
}

impl<Symbol: PartialOrd> SymbolRange<Symbol> {
    ///
    /// Creates a new range covering everything between the specified two symbols
    ///
    #[inline]
    pub fn new(lowest: Symbol, highest: Symbol) -> SymbolRange<Symbol> {
        if lowest > highest {
            SymbolRange { lowest: highest, highest: lowest }
        } else {
            SymbolRange { lowest: lowest, highest: highest }
        }
    }

    ///
    /// True if this range overlaps another
    ///
    #[inline]
    pub fn overlaps(&self, with: &SymbolRange<Symbol>) -> bool {
        if self.highest < with.lowest {
            false
        } else if self.lowest > with.highest {
            false
        } else {
            true
        }
    }

    ///
    /// True if this range contains a symbol
    ///
    #[inline]
    pub fn includes(&self, symbol: Symbol) -> bool {
        self.lowest < symbol && symbol <= self.highest
    }
}

impl<Symbol: PartialOrd+Clone> SymbolRange<Symbol> {
    ///
    /// Joins this range with another
    ///
    /// This creates a new range that covers all the symbols of both. If `overlaps()` is false for these two ranges, then
    /// the new range may cover additional symbols that are not in either range.
    ///
    pub fn join(&self, with: &SymbolRange<Symbol>) -> SymbolRange<Symbol> {
        SymbolRange {
            lowest:  if with.lowest<self.lowest   { with.lowest.clone()  } else { self.lowest.clone()  },
            highest: if with.highest<self.highest { self.highest.clone() } else { with.highest.clone() }
        }
    }
}

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

    #[test]
    fn can_create_range() {
        let range = SymbolRange::new(1, 2);

        assert!(range.lowest == 1);
        assert!(range.highest == 2);
    }

    #[test]
    fn can_create_range_reversed() {
        let range = SymbolRange::new(5, 1);

        assert!(range.lowest == 1);
        assert!(range.highest == 5);
    }

    #[test]
    fn overlaps_when_within() {
        assert!(SymbolRange::new(1, 4).overlaps(&SymbolRange::new(2, 3)));
    }

    #[test]
    fn overlaps_when_within_float() {
        assert!(SymbolRange::new(1.0, 4.0).overlaps(&SymbolRange::new(2.0, 3.0)));
    }

    #[test]
    fn overlaps_when_without() {
        assert!(SymbolRange::new(2, 3).overlaps(&SymbolRange::new(1, 4)));
    }

    #[test]
    fn overlaps_when_lower() {
        assert!(SymbolRange::new(1, 3).overlaps(&SymbolRange::new(2, 4)));
    }

    #[test]
    fn overlaps_when_higher() {
        assert!(SymbolRange::new(2, 4).overlaps(&SymbolRange::new(1, 3)));
    }

    #[test]
    fn overlaps_when_same() {
        assert!(SymbolRange::new(1, 4).overlaps(&SymbolRange::new(1, 4)));
    }

    #[test]
    fn does_not_overlap_lower() {
        assert!(!SymbolRange::new(1, 2).overlaps(&SymbolRange::new(4, 5)));
    }

    #[test]
    fn does_not_overlap_higher() {
        assert!(!SymbolRange::new(4, 5).overlaps(&SymbolRange::new(1, 2)));
    }

    #[test]
    fn join_left() {
        let joined = SymbolRange::new(1, 3).join(&SymbolRange::new(3, 4));

        assert!(joined.lowest == 1);
        assert!(joined.highest == 4);
    }

    #[test]
    fn join_right() {
        let joined = SymbolRange::new(3, 4).join(&SymbolRange::new(1, 3));

        assert!(joined.lowest == 1);
        assert!(joined.highest == 4);
    }

    #[test]
    fn join_overlap() {
        let joined = SymbolRange::new(1, 4).join(&SymbolRange::new(2, 3));

        assert!(joined.lowest == 1);
        assert!(joined.highest == 4);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::error::Error;
use std::str;
use rustc_serialize::base64::{FromBase64, ToBase64, STANDARD};

use conduit::{Request, Response};
use conduit_middleware;
use cookie::Cookie;

use super::RequestCookies;

pub struct SessionMiddleware {
    cookie_name: String,
    secure: bool,
}

pub struct Session {
    pub data: HashMap<String, String>,
}

impl SessionMiddleware {
    pub fn new(cookie: &str, secure: bool) -> SessionMiddleware {
        SessionMiddleware {
            cookie_name: cookie.to_string(),
            secure: secure,
        }
    }

    pub fn decode(&self, cookie: Cookie) -> HashMap<String, String> {
        let mut ret = HashMap::new();
        let bytes = cookie.value.from_base64().unwrap_or(Vec::new());
        let mut parts = bytes.split(|&a| a == 0xff);
        loop {
            match (parts.next(), parts.next()) {
                (Some(key), Some(value)) => {
                    if key.len() == 0 { break }
                    match (str::from_utf8(key), str::from_utf8(value)) {
                        (Ok(key), Ok(value)) => {
                            ret.insert(key.to_string(), value.to_string());
                        }
                        _ => {}
                    }
                }
                _ => break
            }
        }
        return ret;
    }

    pub fn encode(&self, h: &HashMap<String, String>) -> String {
        let mut ret = Vec::new();
        for (i, (k, v)) in h.iter().enumerate() {
            if i != 0 { ret.push(0xff) }
            ret.extend(k.bytes());
            ret.push(0xff);
            ret.extend(v.bytes());
        }
        while ret.len() * 8 % 6 != 0 {
            ret.push(0xff);
        }
        ret.to_base64(STANDARD)
    }
}

impl conduit_middleware::Middleware for SessionMiddleware {
    fn before(&self, req: &mut Request) -> Result<(), Box<Error+Send>> {
        let session = {
            let jar = req.cookies().signed();
            jar.find(&self.cookie_name).map(|cookie| {
                self.decode(cookie)
            }).unwrap_or_else(|| HashMap::new())
        };
        req.mut_extensions().insert(Session { data: session });
        Ok(())
    }

    fn after(&self, req: &mut Request, res: Result<Response, Box<Error+Send>>)
        -> Result<Response, Box<Error+Send>>
    {
        let mut cookie = {
            let session = req.mut_extensions().find::<Session>();
            let session = session.expect("session must be present after request");
            let encoded = self.encode(&session.data);
            Cookie::new(self.cookie_name.to_string(), encoded)
        };
        cookie.httponly = true;
        cookie.secure = self.secure;
        req.cookies().signed().add(cookie);
        return res;
    }
}

pub trait RequestSession {
    fn session(&mut self) -> &mut HashMap<String, String>;
}

impl<'a> RequestSession for Request+'a {
    fn session(&mut self) -> &mut HashMap<String, String> {
        &mut self.mut_extensions().find_mut::<Session>()
                 .expect("missing cookie session").data
    }
}

#[cfg(test)]
mod test {

    use std::collections::HashMap;
    use std::io::{self, Cursor};

    use conduit::{Request, Response, Handler, Method};
    use conduit_middleware::MiddlewareBuilder;
    use cookie::Cookie;
    use conduit_test::MockRequest;

    use {RequestSession, Middleware, SessionMiddleware};

    #[test]
    fn simple() {
        let mut req = MockRequest::new(Method::Post, "/articles");

        // Set the session cookie
        let mut app = MiddlewareBuilder::new(set_session);
        app.add(Middleware::new(b"foo"));
        app.add(SessionMiddleware::new("lol", false));
        let response = app.call(&mut req).ok().unwrap();

        let v = &response.headers["Set-Cookie"];
        assert!(v[0].starts_with("lol"));

        // Use the session cookie
        req.header("Cookie", &v[0]);
        let mut app = MiddlewareBuilder::new(use_session);
        app.add(Middleware::new(b"foo"));
        app.add(SessionMiddleware::new("lol", false));
        assert!(app.call(&mut req).is_ok());

        fn set_session(req: &mut Request) -> io::Result<Response> {
            assert!(req.session().insert("foo".to_string(), "bar".to_string())
                                 .is_none());
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: Box::new(Cursor::new(Vec::new())),
            })
        }
        fn use_session(req: &mut Request) -> io::Result<Response> {
            assert_eq!(*req.session().get("foo").unwrap(), "bar");
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: Box::new(Cursor::new(Vec::new())),
            })
        }
    }

    #[test]
    fn no_equals() {
        let m = SessionMiddleware::new("test", false);
        let e = {
            let mut map = HashMap::new();
            map.insert("a".to_string(), "bc".to_string());
            m.encode(&map)
        };
        assert!(!e.ends_with("="));
        let m = m.decode(Cookie::new("foo".to_string(), e));
        assert_eq!(*m.get("a").unwrap(), "bc");
    }
}
<commit_msg>Continue to set `path` for new cookies<commit_after>use std::collections::HashMap;
use std::error::Error;
use std::str;
use rustc_serialize::base64::{FromBase64, ToBase64, STANDARD};

use conduit::{Request, Response};
use conduit_middleware;
use cookie::Cookie;

use super::RequestCookies;

pub struct SessionMiddleware {
    cookie_name: String,
    secure: bool,
}

pub struct Session {
    pub data: HashMap<String, String>,
}

impl SessionMiddleware {
    pub fn new(cookie: &str, secure: bool) -> SessionMiddleware {
        SessionMiddleware {
            cookie_name: cookie.to_string(),
            secure: secure,
        }
    }

    pub fn decode(&self, cookie: Cookie) -> HashMap<String, String> {
        let mut ret = HashMap::new();
        let bytes = cookie.value.from_base64().unwrap_or(Vec::new());
        let mut parts = bytes.split(|&a| a == 0xff);
        loop {
            match (parts.next(), parts.next()) {
                (Some(key), Some(value)) => {
                    if key.len() == 0 { break }
                    match (str::from_utf8(key), str::from_utf8(value)) {
                        (Ok(key), Ok(value)) => {
                            ret.insert(key.to_string(), value.to_string());
                        }
                        _ => {}
                    }
                }
                _ => break
            }
        }
        return ret;
    }

    pub fn encode(&self, h: &HashMap<String, String>) -> String {
        let mut ret = Vec::new();
        for (i, (k, v)) in h.iter().enumerate() {
            if i != 0 { ret.push(0xff) }
            ret.extend(k.bytes());
            ret.push(0xff);
            ret.extend(v.bytes());
        }
        while ret.len() * 8 % 6 != 0 {
            ret.push(0xff);
        }
        ret.to_base64(STANDARD)
    }
}

impl conduit_middleware::Middleware for SessionMiddleware {
    fn before(&self, req: &mut Request) -> Result<(), Box<Error+Send>> {
        let session = {
            let jar = req.cookies().signed();
            jar.find(&self.cookie_name).map(|cookie| {
                self.decode(cookie)
            }).unwrap_or_else(|| HashMap::new())
        };
        req.mut_extensions().insert(Session { data: session });
        Ok(())
    }

    fn after(&self, req: &mut Request, res: Result<Response, Box<Error+Send>>)
        -> Result<Response, Box<Error+Send>>
    {
        let mut cookie = {
            let session = req.mut_extensions().find::<Session>();
            let session = session.expect("session must be present after request");
            let encoded = self.encode(&session.data);
            Cookie::new(self.cookie_name.to_string(), encoded)
        };
        cookie.httponly = true;
        cookie.secure = self.secure;
        cookie.path = Some("/".to_string());
        req.cookies().signed().add(cookie);
        return res;
    }
}

pub trait RequestSession {
    fn session(&mut self) -> &mut HashMap<String, String>;
}

impl<'a> RequestSession for Request+'a {
    fn session(&mut self) -> &mut HashMap<String, String> {
        &mut self.mut_extensions().find_mut::<Session>()
                 .expect("missing cookie session").data
    }
}

#[cfg(test)]
mod test {

    use std::collections::HashMap;
    use std::io::{self, Cursor};

    use conduit::{Request, Response, Handler, Method};
    use conduit_middleware::MiddlewareBuilder;
    use cookie::Cookie;
    use conduit_test::MockRequest;

    use {RequestSession, Middleware, SessionMiddleware};

    #[test]
    fn simple() {
        let mut req = MockRequest::new(Method::Post, "/articles");

        // Set the session cookie
        let mut app = MiddlewareBuilder::new(set_session);
        app.add(Middleware::new(b"foo"));
        app.add(SessionMiddleware::new("lol", false));
        let response = app.call(&mut req).ok().unwrap();

        let v = &response.headers["Set-Cookie"];
        assert!(v[0].starts_with("lol"));

        // Use the session cookie
        req.header("Cookie", &v[0]);
        let mut app = MiddlewareBuilder::new(use_session);
        app.add(Middleware::new(b"foo"));
        app.add(SessionMiddleware::new("lol", false));
        assert!(app.call(&mut req).is_ok());

        fn set_session(req: &mut Request) -> io::Result<Response> {
            assert!(req.session().insert("foo".to_string(), "bar".to_string())
                                 .is_none());
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: Box::new(Cursor::new(Vec::new())),
            })
        }
        fn use_session(req: &mut Request) -> io::Result<Response> {
            assert_eq!(*req.session().get("foo").unwrap(), "bar");
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: Box::new(Cursor::new(Vec::new())),
            })
        }
    }

    #[test]
    fn no_equals() {
        let m = SessionMiddleware::new("test", false);
        let e = {
            let mut map = HashMap::new();
            map.insert("a".to_string(), "bc".to_string());
            m.encode(&map)
        };
        assert!(!e.ends_with("="));
        let m = m.decode(Cookie::new("foo".to_string(), e));
        assert_eq!(*m.get("a").unwrap(), "bc");
    }
}
<|endoftext|>