<commit_before>use Icon;
use backend::MagogContext;
use brush::Frame;
use cache;
use calx_alg::timing;
use calx_color::color;
use calx_grid::{Dir6, FovValue, HexFov};
use euclid::{Point2D, point2, Vector2D, vec2, Rect};
use render::{self, Layer};
use sprite::Sprite;
use std::collections::HashMap;
use std::iter::FromIterator;
use std::rc::Rc;
use world::{self, FovStatus, Location, Query, TerrainQuery, World};

/// Useful general constant for cell dimension ops.
pub static PIXEL_UNIT: f32 = 16.0;

pub struct WorldView {
    pub cursor_loc: Option<Location>,
    pub show_cursor: bool,
    camera_loc: Location,
    screen_area: Rect<f32>,
    fov: Option<HashMap<Vector2D<i32>, Vec<Location>>>,

    /// Mostly used in mapedit
    pub highlight_offscreen_tiles: bool,
}

impl WorldView {
    pub fn new(camera_loc: Location, screen_area: Rect<f32>) -> WorldView {
        WorldView {
            cursor_loc: None,
            show_cursor: false,
            camera_loc: camera_loc,
            screen_area: screen_area,
            fov: None,
            highlight_offscreen_tiles: false,
        }
    }

    pub fn set_camera(&mut self, loc: Location) {
        if loc != self.camera_loc {
            self.camera_loc = loc;
            self.fov = None;
        }
    }

    /// Recompute the cached screen view if the cache has been invalidated.
    fn ensure_fov(&mut self, world: &World) {
        if self.fov.is_none() {
            // Chart area, center in origin, inflated by tile width in every direction to get the cells
            // partially on screen included.
            let center = (self.screen_area.origin + self.screen_area.size / 2.0 -
                              vec2(PIXEL_UNIT / 2.0, 0.0)).to_vector();
            let bounds = self.screen_area
                .translate(&-(self.screen_area.origin + center).to_vector())
                .inflate(PIXEL_UNIT * 2.0, PIXEL_UNIT * 2.0);

            self.fov = Some(screen_fov(world, self.camera_loc, bounds));
        }
    }

    pub fn draw<C: MagogContext>(&mut self, world: &World, context: &mut C) {
        self.ensure_fov(world);

        let center = (self.screen_area.origin + self.screen_area.size / 2.0 -
                          vec2(PIXEL_UNIT / 2.0, 0.0)).to_vector();
        let chart = self.fov.as_ref().unwrap();
        let mut sprites = Vec::new();
        let cursor_pos = view_to_chart(context.mouse_pos() - center);

        for (&chart_pos, origins) in chart.iter() {
            assert!(!origins.is_empty());

            let mut loc = origins[0] + chart_pos;

            let in_map_memory;

            // If the chart position is in live FOV, we want to show the deepest stack coordinate.
            // If it's not, we want to start looking for the map memory one from the top of the
            // stack.
            if get_fov(world, loc) == Some(FovStatus::Seen) {
                in_map_memory = false;
            } else {
                in_map_memory = true;
                if let Some(&remembered) =
                    origins.iter().rev().find(|&&orig| {
                        get_fov(world, orig + chart_pos) == Some(FovStatus::Remembered)
                    })
                {
                    loc = remembered + chart_pos;
                } else {
                    // Got nothing, bail out.
                    continue;
                }
            }

            let screen_pos = chart_to_view(chart_pos.to_point()) + center;

            // TODO: Set up dynamic lighting, shade sprites based on angle and local light.
            render::draw_terrain_sprites(world, loc, |layer, _angle, brush, frame_idx| {
                sprites.push(Sprite {
                    layer: layer,
                    offset: [screen_pos.x as i32, screen_pos.y as i32],
                    brush: if in_map_memory {
                        map_memory_colorize(brush.clone())
                    } else {
                        brush.clone()
                    },
                    frame_idx: frame_idx,
                })
            });

            if !in_map_memory {
                for &i in &world.entities_at(loc) {
                    if let Some(desc) = world.ecs().desc.get(i) {
                        let layer = if world.is_mob(i) {
                            Layer::Object
                        } else {
                            Layer::Items
                        };
                        let frame_idx = if world.is_bobbing(i) {
                            timing::cycle_anim(1.0 / 3.0, 2)
                        } else {
                            0
                        };
                        sprites.push(Sprite {
                            layer: layer,
                            offset: [screen_pos.x as i32, screen_pos.y as i32],
                            brush: cache::entity(desc.icon),
                            frame_idx: frame_idx,
                        });
                    }
                }
            }

            if self.highlight_offscreen_tiles {
                if let Some(loc) = Location::origin().v2_at(loc) {
                    if !world::on_screen(loc) {
                        if Dir6::iter().any(|d| world::on_screen(loc + d.to_v2())) {
                            sprites.push(Sprite {
                                layer: Layer::Effect,
                                offset: [screen_pos.x as i32, screen_pos.y as i32],
                                brush: cache::misc(Icon::Portal),
                                frame_idx: 0,
                            });
                        } else {
                            sprites.push(Sprite {
                                layer: Layer::Effect,
                                offset: [screen_pos.x as i32, screen_pos.y as i32],
                                brush: cache::misc(Icon::CursorBottom),
                                frame_idx: 0,
                            });
                        }
                    }
                }
            }
        }

        // Draw cursor.
        if let Some(origins) = chart.get(&cursor_pos.to_vector()) {
            let screen_pos = chart_to_view(cursor_pos) + center;
            let loc = origins[0] + cursor_pos.to_vector();
            self.cursor_loc = Some(loc);

            if self.show_cursor {
                // TODO: Need a LOT less verbose API to add stuff to the sprite set.
                sprites.push(Sprite {
                    layer: Layer::Decal,
                    offset: [screen_pos.x as i32, screen_pos.y as i32],
                    brush: cache::misc(Icon::CursorBottom),
                    frame_idx: 0,
                });
                sprites.push(Sprite {
                    layer: Layer::Effect,
                    offset: [screen_pos.x as i32, screen_pos.y as i32],
                    brush: cache::misc(Icon::CursorTop),
                    frame_idx: 0,
                });
            }
        } else {
            self.cursor_loc = None;
        }

        sprites.sort();

        for i in &sprites {
            i.draw(context)
        }

        fn get_fov(world: &World, loc: Location) -> Option<FovStatus> {
            if let Some(player) = world.player() {
                world.ecs().map_memory.get(player).map_or(
                    Some(FovStatus::Seen),
                    |fov| fov.status(loc),
                )
            } else {
                Some(FovStatus::Seen)
            }
        }

        fn map_memory_colorize(brush: Rc<Vec<Frame>>) -> Rc<Vec<Frame>> {
            // XXX: This is horribly wasteful memory churning.
            use std::ops::Deref;

            let mut ret: Vec<Frame> = brush.deref().clone();
            for frame in ret.iter_mut() {
                for splat in frame.iter_mut() {
                    splat.color = color::BLACK.into_array();
                    splat.back_color = color::BROWN.into_array();
                }
            }

            Rc::new(ret)
        }
    }
}

/// Transform from chart space (unit is one map cell) to view space (unit is
/// one pixel).
pub fn chart_to_view(chart_pos: Point2D<i32>) -> Point2D<f32> {
    point2(
        (chart_pos.x as f32 * PIXEL_UNIT - chart_pos.y as f32 * PIXEL_UNIT),
        (chart_pos.x as f32 * PIXEL_UNIT / 2.0 + chart_pos.y as f32 * PIXEL_UNIT / 2.0),
    )
}

/// Transform from view space (unit is one pixel) to chart space (unit is one
/// map cell).
pub fn view_to_chart(view_pos: Point2D<f32>) -> Point2D<i32> {
    let c = PIXEL_UNIT / 2.0;
    let column = ((view_pos.x + c) / (c * 2.0)).floor();
    let row = ((view_pos.y - column * c) / (c * 2.0)).floor();
    point2((column + row) as i32, row as i32)
}

#[derive(Clone)]
struct ScreenFov<'a> {
    w: &'a World,
    screen_area: Rect<f32>,
    origins: Vec<Location>,
}

impl<'a> PartialEq for ScreenFov<'a> {
    fn eq(&self, other: &Self) -> bool {
        self.w as *const World == other.w as *const World &&
            self.screen_area == other.screen_area && self.origins == other.origins
    }
}

impl<'a> Eq for ScreenFov<'a> {}

impl<'a> FovValue for ScreenFov<'a> {
    fn advance(&self, offset: Vector2D<i32>) -> Option<Self> {
        if !self.screen_area.contains(&chart_to_view(offset.to_point())) {
            return None;
        }

        let loc = self.origins[0] + offset;

        let mut ret = self.clone();
        // Go through a portal if terrain on our side of the portal is a void cell.
        //
        // With non-void terrain on top of the portal, just show our side and stay on the current
        // frame as far as FOV is concerned.
        if let Some(dest) = self.w.visible_portal(loc) {
            ret.origins.insert(0, dest - offset);
        }

        Some(ret)
    }
}

/// Return the field of view chart for drawing a screen.
///
/// The stack of locations in the return value lists origins for coordinate frames that have been
/// passed through when traversing portals, in reverse order. The first value is the origin of the
/// coordinate space you probably want to show for that point.
pub fn screen_fov(
    w: &World,
    origin: Location,
    screen_area: Rect<f32>,
) -> HashMap<Vector2D<i32>, Vec<Location>> {
    let init = ScreenFov {
        w: w,
        screen_area: screen_area,
        origins: vec![origin],
    };

    HashMap::from_iter(HexFov::new(init).map(|(pos, a)| (pos, a.origins)))
}

#[cfg(test)]
mod test {
    // FIXME: Allow constructing World instances without resource dependencies to allow lightweight
    // unit tests.
/*
    use euclid::{Point2D, Vector2D, Rect, Size2D};
    use world::{Location, Portal, World, Terraform};
    use super::{screen_fov, view_to_chart};

    fn test_world() -> World {
        use world::terrain::{Form, Kind, Tile};
        use calx_resource::ResourceStore;
        use world::Brush;
        use content;

        Brush::insert_resource("dummy".to_string(), Brush::new(Vec::new()));
        Brush::insert_resource("player".to_string(), Brush::new(Vec::new()));

        Tile::insert_resource(0, Tile::new("dummy", Kind::Block, Form::Void));
        Tile::insert_resource(1, Tile::new("dummy", Kind::Ground, Form::Gate));
        Tile::insert_resource(2, Tile::new("dummy", Kind::Ground, Form::Floor));
        Tile::insert_resource(3, Tile::new("dummy", Kind::Ground, Form::Floor));

        let mut ret = World::new(1);

        ret.set_terrain(Location::new(10, 10, 0), 2);
        ret.set_terrain(Location::new(11, 11, 0), 2);
        ret.set_terrain(Location::new(9, 9, 0), 2);
        ret.set_terrain(Location::new(10, 11, 0), 2);
        ret.set_terrain(Location::new(9, 10, 0), 2);
        ret.set_terrain(Location::new(10, 9, 0), 2);

        // Void for the see-through portal.
        ret.set_terrain(Location::new(11, 10, 0), 0);
        ret.set_portal(Location::new(11, 10, 0),
                       Portal::new(Location::new(11, 10, 0), Location::new(31, 10, 0)));
        ret.set_terrain(Location::new(31, 10, 0), 3);

        ret
    }

    #[test]
    fn test_portaling_fov() {
        let world = test_world();
        let fov = screen_fov(&world,
                             Location::new(10, 10, 0),
                             Rect::new(Point2D::new(-48.0, -48.0), Size2D::new(96.0, 96.0)));
        assert_eq!(fov.get(&vec2(0, 0)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&vec2(0, 1)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&vec2(1, 1)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&vec2(-1, -1)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&vec2(1, 0)),
                   Some(&vec![Location::new(30, 10, 0), Location::new(10, 10, 0)]));
    }

    #[test]
    fn test_corner_visibility() {
        let world = test_world();
        let screen_rect = Rect::new(Point2D::new(-200.0, -200.0), Size2D::new(400.0, 400.0));
        let fov = screen_fov(&world, Location::new(10, 10, 0), screen_rect);

        // Check that the fov is bounded close to the given rectangle.

        let inside_screen = screen_rect.inflate(-40.0, -40.0);
        assert!(fov.get(&view_to_chart(inside_screen.origin)).is_some());
        assert!(fov.get(&view_to_chart(inside_screen.bottom_left())).is_some());
        assert!(fov.get(&view_to_chart(inside_screen.top_right())).is_some());
        assert!(fov.get(&view_to_chart(inside_screen.bottom_right())).is_some());

        let outside_screen = screen_rect.inflate(40.0, 40.0);
        assert!(fov.get(&view_to_chart(outside_screen.origin)).is_none());
        assert!(fov.get(&view_to_chart(outside_screen.bottom_left())).is_none());
        assert!(fov.get(&view_to_chart(outside_screen.top_right())).is_none());
        assert!(fov.get(&view_to_chart(outside_screen.bottom_right())).is_none());
    }
*/

}
<commit_msg>Use only local zone terrain for map memory<commit_after>use Icon;
use backend::MagogContext;
use brush::Frame;
use cache;
use calx_alg::timing;
use calx_color::color;
use calx_grid::{Dir6, FovValue, HexFov};
use euclid::{Point2D, point2, Vector2D, vec2, Rect};
use render::{self, Layer};
use sprite::Sprite;
use std::collections::HashMap;
use std::iter::FromIterator;
use std::rc::Rc;
use world::{self, FovStatus, Location, Query, TerrainQuery, World};

/// Useful general constant for cell dimension ops.
pub static PIXEL_UNIT: f32 = 16.0;

pub struct WorldView {
    pub cursor_loc: Option<Location>,
    pub show_cursor: bool,
    camera_loc: Location,
    screen_area: Rect<f32>,
    fov: Option<HashMap<Vector2D<i32>, Vec<Location>>>,

    /// Mostly used in mapedit
    pub highlight_offscreen_tiles: bool,
}

impl WorldView {
    pub fn new(camera_loc: Location, screen_area: Rect<f32>) -> WorldView {
        WorldView {
            cursor_loc: None,
            show_cursor: false,
            camera_loc: camera_loc,
            screen_area: screen_area,
            fov: None,
            highlight_offscreen_tiles: false,
        }
    }

    pub fn set_camera(&mut self, loc: Location) {
        if loc != self.camera_loc {
            self.camera_loc = loc;
            self.fov = None;
        }
    }

    /// Recompute the cached screen view if the cache has been invalidated.
    fn ensure_fov(&mut self, world: &World) {
        if self.fov.is_none() {
            // Chart area, center in origin, inflated by tile width in every direction to get the cells
            // partially on screen included.
            let center = (self.screen_area.origin + self.screen_area.size / 2.0 -
                              vec2(PIXEL_UNIT / 2.0, 0.0)).to_vector();
            let bounds = self.screen_area
                .translate(&-(self.screen_area.origin + center).to_vector())
                .inflate(PIXEL_UNIT * 2.0, PIXEL_UNIT * 2.0);

            self.fov = Some(screen_fov(world, self.camera_loc, bounds));
        }
    }

    pub fn draw<C: MagogContext>(&mut self, world: &World, context: &mut C) {
        self.ensure_fov(world);

        let center = (self.screen_area.origin + self.screen_area.size / 2.0 -
                          vec2(PIXEL_UNIT / 2.0, 0.0)).to_vector();
        let chart = self.fov.as_ref().unwrap();
        let mut sprites = Vec::new();
        let cursor_pos = view_to_chart(context.mouse_pos() - center);

        for (&chart_pos, origins) in chart.iter() {
            assert!(!origins.is_empty());

            let mut loc = origins[0] + chart_pos;

            let in_map_memory;

            // If the chart position is in live FOV, we want to show the deepest stack coordinate.
            // If it's not, we want to start looking for the map memory one from the top of the
            // stack.
            if get_fov(world, loc) == Some(FovStatus::Seen) {
                in_map_memory = false;
            } else {
                in_map_memory = true;
                // Only accept map memory from the base layer (top of origins stack)
                loc = origins[origins.len() - 1] + chart_pos;
                if get_fov(world, loc) != Some(FovStatus::Remembered) {
                    // Bail out if there's no memory
                    continue;
                }
            }

            let screen_pos = chart_to_view(chart_pos.to_point()) + center;

            // TODO: Set up dynamic lighting, shade sprites based on angle and local light.
            render::draw_terrain_sprites(world, loc, |layer, _angle, brush, frame_idx| {
                sprites.push(Sprite {
                    layer: layer,
                    offset: [screen_pos.x as i32, screen_pos.y as i32],
                    brush: if in_map_memory {
                        map_memory_colorize(brush.clone())
                    } else {
                        brush.clone()
                    },
                    frame_idx: frame_idx,
                })
            });

            if !in_map_memory {
                for &i in &world.entities_at(loc) {
                    if let Some(desc) = world.ecs().desc.get(i) {
                        let layer = if world.is_mob(i) {
                            Layer::Object
                        } else {
                            Layer::Items
                        };
                        let frame_idx = if world.is_bobbing(i) {
                            timing::cycle_anim(1.0 / 3.0, 2)
                        } else {
                            0
                        };
                        sprites.push(Sprite {
                            layer: layer,
                            offset: [screen_pos.x as i32, screen_pos.y as i32],
                            brush: cache::entity(desc.icon),
                            frame_idx: frame_idx,
                        });
                    }
                }
            }

            if self.highlight_offscreen_tiles {
                if let Some(loc) = Location::origin().v2_at(loc) {
                    if !world::on_screen(loc) {
                        if Dir6::iter().any(|d| world::on_screen(loc + d.to_v2())) {
                            sprites.push(Sprite {
                                layer: Layer::Effect,
                                offset: [screen_pos.x as i32, screen_pos.y as i32],
                                brush: cache::misc(Icon::Portal),
                                frame_idx: 0,
                            });
                        } else {
                            sprites.push(Sprite {
                                layer: Layer::Effect,
                                offset: [screen_pos.x as i32, screen_pos.y as i32],
                                brush: cache::misc(Icon::CursorBottom),
                                frame_idx: 0,
                            });
                        }
                    }
                }
            }
        }

        // Draw cursor.
        if let Some(origins) = chart.get(&cursor_pos.to_vector()) {
            let screen_pos = chart_to_view(cursor_pos) + center;
            let loc = origins[0] + cursor_pos.to_vector();
            self.cursor_loc = Some(loc);

            if self.show_cursor {
                // TODO: Need a LOT less verbose API to add stuff to the sprite set.
                sprites.push(Sprite {
                    layer: Layer::Decal,
                    offset: [screen_pos.x as i32, screen_pos.y as i32],
                    brush: cache::misc(Icon::CursorBottom),
                    frame_idx: 0,
                });
                sprites.push(Sprite {
                    layer: Layer::Effect,
                    offset: [screen_pos.x as i32, screen_pos.y as i32],
                    brush: cache::misc(Icon::CursorTop),
                    frame_idx: 0,
                });
            }
        } else {
            self.cursor_loc = None;
        }

        sprites.sort();

        for i in &sprites {
            i.draw(context)
        }

        fn get_fov(world: &World, loc: Location) -> Option<FovStatus> {
            if let Some(player) = world.player() {
                world.ecs().map_memory.get(player).map_or(
                    Some(FovStatus::Seen),
                    |fov| fov.status(loc),
                )
            } else {
                Some(FovStatus::Seen)
            }
        }

        fn map_memory_colorize(brush: Rc<Vec<Frame>>) -> Rc<Vec<Frame>> {
            // XXX: This is horribly wasteful memory churning.
            use std::ops::Deref;

            let mut ret: Vec<Frame> = brush.deref().clone();
            for frame in ret.iter_mut() {
                for splat in frame.iter_mut() {
                    splat.color = color::BLACK.into_array();
                    splat.back_color = color::BROWN.into_array();
                }
            }

            Rc::new(ret)
        }
    }
}

/// Transform from chart space (unit is one map cell) to view space (unit is
/// one pixel).
pub fn chart_to_view(chart_pos: Point2D<i32>) -> Point2D<f32> {
    point2(
        (chart_pos.x as f32 * PIXEL_UNIT - chart_pos.y as f32 * PIXEL_UNIT),
        (chart_pos.x as f32 * PIXEL_UNIT / 2.0 + chart_pos.y as f32 * PIXEL_UNIT / 2.0),
    )
}

/// Transform from view space (unit is one pixel) to chart space (unit is one
/// map cell).
pub fn view_to_chart(view_pos: Point2D<f32>) -> Point2D<i32> {
    let c = PIXEL_UNIT / 2.0;
    let column = ((view_pos.x + c) / (c * 2.0)).floor();
    let row = ((view_pos.y - column * c) / (c * 2.0)).floor();
    point2((column + row) as i32, row as i32)
}

#[derive(Clone)]
struct ScreenFov<'a> {
    w: &'a World,
    screen_area: Rect<f32>,
    origins: Vec<Location>,
}

impl<'a> PartialEq for ScreenFov<'a> {
    fn eq(&self, other: &Self) -> bool {
        self.w as *const World == other.w as *const World &&
            self.screen_area == other.screen_area && self.origins == other.origins
    }
}

impl<'a> Eq for ScreenFov<'a> {}

impl<'a> FovValue for ScreenFov<'a> {
    fn advance(&self, offset: Vector2D<i32>) -> Option<Self> {
        if !self.screen_area.contains(&chart_to_view(offset.to_point())) {
            return None;
        }

        let loc = self.origins[0] + offset;

        let mut ret = self.clone();
        // Go through a portal if terrain on our side of the portal is a void cell.
        //
        // With non-void terrain on top of the portal, just show our side and stay on the current
        // frame as far as FOV is concerned.
        if let Some(dest) = self.w.visible_portal(loc) {
            ret.origins.insert(0, dest - offset);
        }

        Some(ret)
    }
}

/// Return the field of view chart for drawing a screen.
///
/// The stack of locations in the return value lists origins for coordinate frames that have been
/// passed through when traversing portals, in reverse order. The first value is the origin of the
/// coordinate space you probably want to show for that point.
pub fn screen_fov(
    w: &World,
    origin: Location,
    screen_area: Rect<f32>,
) -> HashMap<Vector2D<i32>, Vec<Location>> {
    let init = ScreenFov {
        w: w,
        screen_area: screen_area,
        origins: vec![origin],
    };

    HashMap::from_iter(HexFov::new(init).map(|(pos, a)| (pos, a.origins)))
}

#[cfg(test)]
mod test {
    // FIXME: Allow constructing World instances without resource dependencies to allow lightweight
    // unit tests.
/*
    use euclid::{Point2D, Vector2D, Rect, Size2D};
    use world::{Location, Portal, World, Terraform};
    use super::{screen_fov, view_to_chart};

    fn test_world() -> World {
        use world::terrain::{Form, Kind, Tile};
        use calx_resource::ResourceStore;
        use world::Brush;
        use content;

        Brush::insert_resource("dummy".to_string(), Brush::new(Vec::new()));
        Brush::insert_resource("player".to_string(), Brush::new(Vec::new()));

        Tile::insert_resource(0, Tile::new("dummy", Kind::Block, Form::Void));
        Tile::insert_resource(1, Tile::new("dummy", Kind::Ground, Form::Gate));
        Tile::insert_resource(2, Tile::new("dummy", Kind::Ground, Form::Floor));
        Tile::insert_resource(3, Tile::new("dummy", Kind::Ground, Form::Floor));

        let mut ret = World::new(1);

        ret.set_terrain(Location::new(10, 10, 0), 2);
        ret.set_terrain(Location::new(11, 11, 0), 2);
        ret.set_terrain(Location::new(9, 9, 0), 2);
        ret.set_terrain(Location::new(10, 11, 0), 2);
        ret.set_terrain(Location::new(9, 10, 0), 2);
        ret.set_terrain(Location::new(10, 9, 0), 2);

        // Void for the see-through portal.
        ret.set_terrain(Location::new(11, 10, 0), 0);
        ret.set_portal(Location::new(11, 10, 0),
                       Portal::new(Location::new(11, 10, 0), Location::new(31, 10, 0)));
        ret.set_terrain(Location::new(31, 10, 0), 3);

        ret
    }

    #[test]
    fn test_portaling_fov() {
        let world = test_world();
        let fov = screen_fov(&world,
                             Location::new(10, 10, 0),
                             Rect::new(Point2D::new(-48.0, -48.0), Size2D::new(96.0, 96.0)));
        assert_eq!(fov.get(&vec2(0, 0)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&vec2(0, 1)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&vec2(1, 1)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&vec2(-1, -1)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&vec2(1, 0)),
                   Some(&vec![Location::new(30, 10, 0), Location::new(10, 10, 0)]));
    }

    #[test]
    fn test_corner_visibility() {
        let world = test_world();
        let screen_rect = Rect::new(Point2D::new(-200.0, -200.0), Size2D::new(400.0, 400.0));
        let fov = screen_fov(&world, Location::new(10, 10, 0), screen_rect);

        // Check that the fov is bounded close to the given rectangle.

        let inside_screen = screen_rect.inflate(-40.0, -40.0);
        assert!(fov.get(&view_to_chart(inside_screen.origin)).is_some());
        assert!(fov.get(&view_to_chart(inside_screen.bottom_left())).is_some());
        assert!(fov.get(&view_to_chart(inside_screen.top_right())).is_some());
        assert!(fov.get(&view_to_chart(inside_screen.bottom_right())).is_some());

        let outside_screen = screen_rect.inflate(40.0, 40.0);
        assert!(fov.get(&view_to_chart(outside_screen.origin)).is_none());
        assert!(fov.get(&view_to_chart(outside_screen.bottom_left())).is_none());
        assert!(fov.get(&view_to_chart(outside_screen.top_right())).is_none());
        assert!(fov.get(&view_to_chart(outside_screen.bottom_right())).is_none());
    }
*/

}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use eutil::slice_to_str;
use libc::{c_int};
use std::collections::TreeMap;
use std::mem;
use std::string::String;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_multimap_t,cef_string_t};

fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> {
    smm as *mut TreeMap<String, Vec<*mut cef_string_t>>
}

//cef_string_multimap

#[no_mangle]
pub extern "C" fn cef_string_multimap_alloc() -> *mut cef_string_multimap_t {
    unsafe {
         let smm: Box<TreeMap<String, Vec<*mut cef_string_t>>> = box TreeMap::new();
         mem::transmute(smm)
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_size(smm: *mut cef_string_multimap_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let mut c: c_int = 0;
        let v = string_multimap_to_treemap(smm);
        for (_, val) in (*v).iter() {
            c = c + (*val).len() as c_int;
        }
        c
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_find_count(smm: *mut cef_string_multimap_t, key: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    s.len() as c_int
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_append(smm: *mut cef_string_multimap_t, key: *const cef_string_t, value: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            let s = String::from_str(result);
            let csv = cef_string_userfree_utf8_alloc();
            cef_string_utf8_set((*value).str as *const u8, (*value).length, csv, 1);
            match (*v).find_mut(&s) {
                Some(vc) => {
                    (*vc).push(csv);
                    1
                }
                None => {
                    let vc = vec!(csv);
                    (*v).insert(s, vc);
                    1
                }
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_enumerate(smm: *mut cef_string_multimap_t, key: *const cef_string_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    if (*s).len() <= index as uint {
                        return 0;
                    }
                    let cs = (*s)[index as uint];
                    cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1)
                }
                None => 0
            }
        })
    }
}
<commit_msg>embedding: cef_string_multimap_key()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use eutil::slice_to_str;
use libc::{c_int};
use std::collections::TreeMap;
use std::mem;
use std::string::String;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_multimap_t,cef_string_t};

fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> {
    smm as *mut TreeMap<String, Vec<*mut cef_string_t>>
}

//cef_string_multimap

#[no_mangle]
pub extern "C" fn cef_string_multimap_alloc() -> *mut cef_string_multimap_t {
    unsafe {
         let smm: Box<TreeMap<String, Vec<*mut cef_string_t>>> = box TreeMap::new();
         mem::transmute(smm)
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_size(smm: *mut cef_string_multimap_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let mut c: c_int = 0;
        let v = string_multimap_to_treemap(smm);
        for (_, val) in (*v).iter() {
            c = c + (*val).len() as c_int;
        }
        c
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_find_count(smm: *mut cef_string_multimap_t, key: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    s.len() as c_int
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_append(smm: *mut cef_string_multimap_t, key: *const cef_string_t, value: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            let s = String::from_str(result);
            let csv = cef_string_userfree_utf8_alloc();
            cef_string_utf8_set((*value).str as *const u8, (*value).length, csv, 1);
            match (*v).find_mut(&s) {
                Some(vc) => {
                    (*vc).push(csv);
                    1
                }
                None => {
                    let vc = vec!(csv);
                    (*v).insert(s, vc);
                    1
                }
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_enumerate(smm: *mut cef_string_multimap_t, key: *const cef_string_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    if (*s).len() <= index as uint {
                        return 0;
                    }
                    let cs = (*s)[index as uint];
                    cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1)
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_key(smm: *mut cef_string_multimap_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        let mut rem = index as uint;

        for (key, val) in (*v).iter() {
            if rem < (*val).len() {
                return cef_string_utf8_set((*key).as_bytes().as_ptr(), (*key).len() as u64, value, 1);
            } else {
                rem = rem - (*val).len();
            }
        }
    }
    0
}
<|endoftext|>


<commit_before>#![feature(core)]

extern crate nix;
extern crate rand;

#[cfg(test)]
mod test {
    use nix::unistd::{writev, readv, Iovec, pipe, close, read, write};
    use std::cmp::min;
    use std::iter::repeat;
    use rand::{thread_rng, Rng};

    use nix::unistd::{fork};
    use nix::sys::wait::{waitpid, WaitStatus};
    use nix::unistd::Fork::{Parent, Child};

    #[test]
    fn test_writev() {
        let mut to_write = Vec::with_capacity(16 * 128);
        for _ in 0..16 {
            let s: String = thread_rng().gen_ascii_chars().take(128).collect();
            let b = s.as_bytes();
            to_write.extend(b.iter().map(|x| x.clone()));
        }
        // Allocate and fill iovecs
        let mut iovecs = Vec::new();
        let mut consumed = 0;
        while consumed < to_write.len() {
            let left = to_write.len() - consumed;
            let slice_len = if left < 64 { left } else { thread_rng().gen_range(64, min(256, left)) };
            let b = &to_write[consumed..consumed+slice_len];
            iovecs.push(Iovec::from_slice(b));
            consumed += slice_len;
        }
        let pipe_res = pipe();
        assert!(pipe_res.is_ok());
        let (reader, writer) = pipe_res.ok().unwrap();
        // FileDesc will close its filedesc (reader).
        let mut read_buf: Vec<u8> = repeat(0u8).take(128 * 16).collect();
        // Blocking io, should write all data.
        let write_res = writev(writer, iovecs.as_slice());
        // Successful write
        assert!(write_res.is_ok());
        let written = write_res.ok().unwrap();
        // Check whether we written all data
        assert_eq!(to_write.len(), written);
        let read_res = read(reader, read_buf.as_mut_slice());
        // Successful read
        assert!(read_res.is_ok());
        let read = read_res.ok().unwrap() as usize;
        // Check we have read as much as we written
        assert_eq!(read, written);
        // Check equality of written and read data
        assert_eq!(to_write.as_slice(), read_buf.as_slice());
        let close_res = close(writer);
        assert!(close_res.is_ok());
        let close_res = close(reader);
        assert!(close_res.is_ok());
    }

    #[test]
    fn test_readv() {
        let s:String = thread_rng().gen_ascii_chars().take(128).collect();
        let to_write = s.as_bytes().to_vec();
        let mut storage = Vec::new();
        let mut allocated = 0;
        while allocated < to_write.len() {
            let left = to_write.len() - allocated;
            let vec_len = if left < 64 { left } else { thread_rng().gen_range(64, min(256, left)) };
            let v: Vec<u8> = repeat(0u8).take(vec_len).collect();
            storage.push(v);
            allocated += vec_len;
        }
        let mut iovecs = Vec::with_capacity(storage.len());
        for v in storage.iter_mut() {
            iovecs.push(Iovec::from_mut_slice(v.as_mut_slice()));
        }
        let pipe_res = pipe();
        assert!(pipe_res.is_ok());
        let (reader, writer) = pipe_res.ok().unwrap();
        // Blocking io, should write all data.
        let write_res = write(writer, to_write.as_slice());
        // Successful write
        assert!(write_res.is_ok());
        let read_res = readv(reader, iovecs.as_mut_slice());
        assert!(read_res.is_ok());
        let read = read_res.ok().unwrap();
        // Check whether we've read all data
        assert_eq!(to_write.len(), read);
        // Cccumulate data from iovecs
        let mut read_buf = Vec::with_capacity(to_write.len());
        for iovec in iovecs.iter() {
            read_buf.extend(iovec.as_slice().iter().map(|x| x.clone()));
        }
        // Check whether iovecs contain all written data
        assert_eq!(read_buf.len(), to_write.len());
        // Check equality of written and read data
        assert_eq!(read_buf.as_slice(), to_write.as_slice());
        let close_res = close(reader);
        assert!(close_res.is_ok());
        let close_res = close(writer);
        assert!(close_res.is_ok());
    }

    #[test]
    fn test_fork_and_waitpid() {
        let pid = fork();
        match pid {
          Ok(Child) => {} // ignore child here
          Ok(Parent(child_pid)) => {
              // assert that child was created and pid > 0
              assert!(child_pid > 0);
              let wait_status = waitpid(child_pid, None);
              match wait_status {
                  // assert that waitpid returned correct status and the pid is the one of the child
                  Ok(WaitStatus::Exited(pid_t)) =>  assert!(pid_t == child_pid),

                  // panic, must never happen
                  Ok(WaitStatus::StillAlive) => panic!("Child still alive, should never happen"),

                  // panic, waitpid should never fail
                  Err(_) => panic!("Error: waitpid Failed")
              }

          },
          // panic, fork should never fail unless there is a serious problem with the OS
          Err(_) => panic!("Error: Fork Failed")
        }
    }
}
<commit_msg>Add tests for `nix::unistd::execve()`.<commit_after>#![feature(core, std_misc)]

extern crate nix;
extern crate rand;

#[cfg(test)]
mod test {
    use nix::unistd::{writev, readv, Iovec, pipe, close, read, write, dup,
                      execve};
    use std::cmp::min;
    use std::ffi::CString;
    use std::iter::repeat;
    use rand::{thread_rng, Rng};

    use nix::unistd::{fork};
    use nix::sys::wait::{waitpid, WaitStatus};
    use nix::unistd::Fork::{Parent, Child};

    #[test]
    fn test_writev() {
        let mut to_write = Vec::with_capacity(16 * 128);
        for _ in 0..16 {
            let s: String = thread_rng().gen_ascii_chars().take(128).collect();
            let b = s.as_bytes();
            to_write.extend(b.iter().map(|x| x.clone()));
        }
        // Allocate and fill iovecs
        let mut iovecs = Vec::new();
        let mut consumed = 0;
        while consumed < to_write.len() {
            let left = to_write.len() - consumed;
            let slice_len = if left < 64 { left } else { thread_rng().gen_range(64, min(256, left)) };
            let b = &to_write[consumed..consumed+slice_len];
            iovecs.push(Iovec::from_slice(b));
            consumed += slice_len;
        }
        let pipe_res = pipe();
        assert!(pipe_res.is_ok());
        let (reader, writer) = pipe_res.ok().unwrap();
        // FileDesc will close its filedesc (reader).
        let mut read_buf: Vec<u8> = repeat(0u8).take(128 * 16).collect();
        // Blocking io, should write all data.
        let write_res = writev(writer, iovecs.as_slice());
        // Successful write
        assert!(write_res.is_ok());
        let written = write_res.ok().unwrap();
        // Check whether we written all data
        assert_eq!(to_write.len(), written);
        let read_res = read(reader, read_buf.as_mut_slice());
        // Successful read
        assert!(read_res.is_ok());
        let read = read_res.ok().unwrap() as usize;
        // Check we have read as much as we written
        assert_eq!(read, written);
        // Check equality of written and read data
        assert_eq!(to_write.as_slice(), read_buf.as_slice());
        let close_res = close(writer);
        assert!(close_res.is_ok());
        let close_res = close(reader);
        assert!(close_res.is_ok());
    }

    #[test]
    fn test_readv() {
        let s:String = thread_rng().gen_ascii_chars().take(128).collect();
        let to_write = s.as_bytes().to_vec();
        let mut storage = Vec::new();
        let mut allocated = 0;
        while allocated < to_write.len() {
            let left = to_write.len() - allocated;
            let vec_len = if left < 64 { left } else { thread_rng().gen_range(64, min(256, left)) };
            let v: Vec<u8> = repeat(0u8).take(vec_len).collect();
            storage.push(v);
            allocated += vec_len;
        }
        let mut iovecs = Vec::with_capacity(storage.len());
        for v in storage.iter_mut() {
            iovecs.push(Iovec::from_mut_slice(v.as_mut_slice()));
        }
        let pipe_res = pipe();
        assert!(pipe_res.is_ok());
        let (reader, writer) = pipe_res.ok().unwrap();
        // Blocking io, should write all data.
        let write_res = write(writer, to_write.as_slice());
        // Successful write
        assert!(write_res.is_ok());
        let read_res = readv(reader, iovecs.as_mut_slice());
        assert!(read_res.is_ok());
        let read = read_res.ok().unwrap();
        // Check whether we've read all data
        assert_eq!(to_write.len(), read);
        // Cccumulate data from iovecs
        let mut read_buf = Vec::with_capacity(to_write.len());
        for iovec in iovecs.iter() {
            read_buf.extend(iovec.as_slice().iter().map(|x| x.clone()));
        }
        // Check whether iovecs contain all written data
        assert_eq!(read_buf.len(), to_write.len());
        // Check equality of written and read data
        assert_eq!(read_buf.as_slice(), to_write.as_slice());
        let close_res = close(reader);
        assert!(close_res.is_ok());
        let close_res = close(writer);
        assert!(close_res.is_ok());
    }

    #[test]
    fn test_fork_and_waitpid() {
        let pid = fork();
        match pid {
          Ok(Child) => {} // ignore child here
          Ok(Parent(child_pid)) => {
              // assert that child was created and pid > 0
              assert!(child_pid > 0);
              let wait_status = waitpid(child_pid, None);
              match wait_status {
                  // assert that waitpid returned correct status and the pid is the one of the child
                  Ok(WaitStatus::Exited(pid_t)) =>  assert!(pid_t == child_pid),

                  // panic, must never happen
                  Ok(WaitStatus::StillAlive) => panic!("Child still alive, should never happen"),

                  // panic, waitpid should never fail
                  Err(_) => panic!("Error: waitpid Failed")
              }

          },
          // panic, fork should never fail unless there is a serious problem with the OS
          Err(_) => panic!("Error: Fork Failed")
        }
    }

    #[test]
    fn test_execve() {
        // The `exec`d process will write to `writer`, and we'll read that
        // data from `reader`.
        let (reader, writer) = pipe().unwrap();

        match fork().unwrap() {
            Child => {
                // Close stdout.
                close(1).unwrap();
                // Make `writer` be the stdout of the new process.
                dup(writer).unwrap();
                // exec!
                execve(&CString::from_slice(b"/bin/sh"),
                       &[CString::from_slice(b""),
                         CString::from_slice(b"-c"),
                         CString::from_slice(b"echo nix!!! && env")],
                       &[CString::from_slice(b"foo=bar"),
                         CString::from_slice(b"baz=quux")]).unwrap();
            },
            Parent(child_pid) => {
                // Wait for the child to exit.
                waitpid(child_pid, None).unwrap();
                // Read 1024 bytes.
                let mut buf = [0u8; 1024];
                read(reader, &mut buf).unwrap();
                // It should contain the things we printed using `/bin/sh`.
                let string = String::from_utf8_lossy(&buf);
                assert!(string.contains("nix!!!"));
                assert!(string.contains("foo=bar"));
                assert!(string.contains("baz=quux"));
            }
        }
    }
}
<|endoftext|>


<commit_before>use common::types::Types;
use common::conn::Conn;
use common::stream::HttpStreamCommon;
use common::stream::HttpStreamData;
use solicit::connection::HttpFrame;
use solicit::StreamId;

use data_or_headers_with_flag::DataOrHeadersWithFlag;

use error;
use ErrorCode;
use solicit::frame::RstStreamFrame;
use solicit::frame::GoawayFrame;
use solicit::frame::SettingsFrame;
use result;
use futures::Poll;
use futures::Async;
use common::conn_read::ConnReadSideCustom;
use common::conn_command::ConnCommandSideCustom;
use common::stream::HttpStreamCommand;
use solicit::frame::FrameBuilder;
use std::cmp;
use solicit::frame::HeadersFrame;
use solicit::connection::EndStream;
use solicit::frame::HeadersFlag;
use solicit::frame::ContinuationFrame;
use solicit::frame::continuation::ContinuationFlag;
use solicit::frame::DataFrame;
use solicit::frame::DataFlag;
use solicit::frame::FrameIR;
use std::mem;
use common::goaway_state::GoAwayState;
use futures::task;

pub trait ConnWriteSideCustom {
    type Types : Types;

    fn process_message(&mut self, message: <Self::Types as Types>::ToWriteMessage) -> result::Result<()>;
}

impl<T> Conn<T>
    where
        T : Types,
        Self : ConnReadSideCustom<Types=T>,
        Self : ConnWriteSideCustom<Types=T>,
        Self : ConnCommandSideCustom<Types=T>,
        HttpStreamCommon<T> : HttpStreamData<Types=T>,
{
    fn poll_flush(&mut self) -> Poll<(), error::Error> {
        self.framed_write.poll_flush()
    }

    fn write_part(&mut self, target: &mut FrameBuilder, stream_id: StreamId, part: HttpStreamCommand) {
        let max_frame_size = self.peer_settings.max_frame_size as usize;

        match part {
            HttpStreamCommand::Data(data, end_stream) => {
                // if client requested end of stream,
                // we must send at least one frame with end stream flag
                if end_stream == EndStream::Yes && data.len() == 0 {
                    // probably should send RST_STREAM
                    let mut frame = DataFrame::with_data(stream_id, Vec::new());
                    frame.set_flag(DataFlag::EndStream);

                    debug!("sending frame {:?}", frame);

                    frame.serialize_into(target);
                    return;
                }

                let mut pos = 0;
                while pos < data.len() {
                    let end = cmp::min(data.len(), pos + max_frame_size);

                    let end_stream_in_frame =
                        if end == data.len() && end_stream == EndStream::Yes {
                            EndStream::Yes
                        } else {
                            EndStream::No
                        };

                    let mut frame = DataFrame::with_data(stream_id, data.slice(pos, end));
                    if end_stream_in_frame == EndStream::Yes {
                        frame.set_flag(DataFlag::EndStream);
                    }

                    debug!("sending frame {:?}", frame);

                    frame.serialize_into(target);

                    pos = end;
                }
            }
            HttpStreamCommand::Headers(headers, end_stream) => {
                let headers_fragment = self
                    .encoder.encode(headers.0.iter().map(|h| (h.name(), h.value())));

                let mut pos = 0;
                while pos < headers_fragment.len() || pos == 0 {
                    let end = cmp::min(headers_fragment.len(), pos + max_frame_size);

                    let chunk = &headers_fragment[pos..end];

                    if pos == 0 {
                        let mut frame = HeadersFrame::new(chunk, stream_id);
                        if end_stream == EndStream::Yes {
                            frame.set_flag(HeadersFlag::EndStream);
                        }

                        if end == headers_fragment.len() {
                            frame.set_flag(HeadersFlag::EndHeaders);
                        }

                        debug!("sending frame {:?}", frame);

                        frame.serialize_into(target);
                    } else {
                        let mut frame = ContinuationFrame::new(chunk, stream_id);

                        if end == headers_fragment.len() {
                            frame.set_flag(ContinuationFlag::EndHeaders);
                        }

                        debug!("sending frame {:?}", frame);

                        frame.serialize_into(target);
                    }

                    pos = end;
                }
            }
            HttpStreamCommand::Rst(error_code) => {
                let frame = RstStreamFrame::new(stream_id, error_code);

                debug!("sending frame {:?}", frame);

                frame.serialize_into(target);
            }
        }
    }

    fn pop_outg_all_for_stream_bytes(&mut self, stream_id: StreamId) -> Vec<u8> {
        let mut send = FrameBuilder::new();
        for part in self.pop_outg_all_for_stream(stream_id) {
            self.write_part(&mut send, stream_id, part);
        }
        send.0
    }

    fn pop_outg_all_for_conn_bytes(&mut self) -> Vec<u8> {
        // TODO: maintain own limits of out window
        let mut send = FrameBuilder::new();
        for (stream_id, part) in self.pop_outg_all_for_conn() {
            self.write_part(&mut send, stream_id, part);
        }
        send.0
    }

    fn pop_outg_all_for_stream(&mut self, stream_id: StreamId) -> Vec<HttpStreamCommand> {
        if let Some(stream) = self.streams.get_mut(stream_id) {
            stream.pop_outg_all_maybe_remove(&mut self.out_window_size)
        } else {
            Vec::new()
        }
    }

    pub fn pop_outg_all_for_conn(&mut self) -> Vec<(StreamId, HttpStreamCommand)> {
        let mut r = Vec::new();

        // TODO: keep list of streams with data
        for stream_id in self.streams.stream_ids() {
            r.extend(self.pop_outg_all_for_stream(stream_id).into_iter().map(|s| (stream_id, s)));
        }

        r
    }

    pub fn buffer_outg_stream(&mut self, stream_id: StreamId) -> result::Result<()> {
        let bytes = self.pop_outg_all_for_stream_bytes(stream_id);

        self.framed_write.buffer(bytes.into());

        Ok(())
    }

    fn buffer_outg_conn(&mut self) -> result::Result<()> {
        let bytes = self.pop_outg_all_for_conn_bytes();

        self.framed_write.buffer(bytes.into());

        Ok(())
    }

    pub fn send_frame_and_notify<F : Into<HttpFrame>>(&mut self, frame: F) {
        // TODO: some of frames should not be in front of GOAWAY
        self.framed_write.buffer_frame(frame);
        // Notify the task to make sure write loop is called again
        // to flush the buffer
        task::current().notify();
    }

    /// Sends an SETTINGS Frame with ack set to acknowledge seeing a SETTINGS frame from the peer.
    pub fn send_ack_settings(&mut self) -> result::Result<()> {
        let settings = SettingsFrame::new_ack();
        self.send_frame_and_notify(settings);
        Ok(())
    }

    fn process_stream_end(&mut self, stream_id: StreamId, error_code: ErrorCode) -> result::Result<()> {
        let stream_id = {
            let stream = self.streams.get_mut(stream_id);
            if let Some(mut stream) = stream {
                stream.stream().outgoing.close(error_code);
                Some(stream_id)
            } else {
                None
            }
        };
        if let Some(stream_id) = stream_id {
            self.buffer_outg_stream(stream_id)?;
        }
        Ok(())
    }

    fn process_stream_enqueue(&mut self, stream_id: StreamId, part: DataOrHeadersWithFlag) -> result::Result<()> {
        let stream_id = {
            let stream = self.streams.get_mut(stream_id);
            if let Some(mut stream) = stream {
                stream.stream().outgoing.push_back_part(part);
                Some(stream_id)
            } else {
                None
            }
        };
        if let Some(stream_id) = stream_id {
            self.buffer_outg_stream(stream_id)?;
        }
        Ok(())
    }

    pub fn process_common_message(&mut self, common: CommonToWriteMessage) -> result::Result<()> {
        match common {
            CommonToWriteMessage::StreamEnd(stream_id, error_code) => {
                self.process_stream_end(stream_id, error_code)?;
            },
            CommonToWriteMessage::StreamEnqueue(stream_id, part) => {
                self.process_stream_enqueue(stream_id, part)?;
            },
            CommonToWriteMessage::IncreaseInWindow(stream_id, increase) => {
                self.increase_in_window(stream_id, increase)?;
            },
        }
        Ok(())
    }

    fn process_flush_xxx_fields(&mut self) -> result::Result<()> {
        if mem::replace(&mut self.flush_conn, false) {
            self.buffer_outg_conn()?;
        }

        let stream_ids: Vec<StreamId> = self.flush_streams.iter().cloned().collect();
        self.flush_streams.clear();
        for stream_id in stream_ids {
            self.buffer_outg_stream(stream_id)?;
        }

        Ok(())
    }

    fn process_goaway_state(&mut self) -> result::Result<()> {
        loop {
            match self.goaway_state {
                GoAwayState::None => return Ok(()),
                GoAwayState::NeedToSend(error_code) => {
                    let frame = GoawayFrame::new(self.last_peer_stream_id, error_code);
                    self.framed_write.buffer_frame(HttpFrame::Goaway(frame));
                    self.goaway_state = GoAwayState::Sending;
                    continue;
                }
                GoAwayState::Sending => {
                    match self.poll_flush()? {
                        Async::Ready(()) => {
                            self.goaway_state = GoAwayState::Sent;
                        },
                        Async::NotReady => {}
                    }
                    return Ok(());
                }
                GoAwayState::Sent => return Ok(()),
            }
        }
    }

    pub fn poll_write(&mut self) -> Poll<(), error::Error> {
        loop {
            self.process_goaway_state()?;

            match self.goaway_state {
                GoAwayState::None => {}
                GoAwayState::NeedToSend(..) => {
                    unreachable!();
                }
                GoAwayState::Sending => {
                    assert!(self.framed_write.remaining() != 0);
                    return Ok(Async::NotReady);
                }
                GoAwayState::Sent => {
                    info!("GOAWAY sent, exiting loop");
                    assert!(self.framed_write.remaining() == 0);
                    return Ok(Async::Ready(()));
                }
            }

            self.process_flush_xxx_fields()?;

            if let Async::NotReady = self.poll_flush()? {
                return Ok(Async::NotReady);
            }

            let message = match self.write_rx.poll()? {
                Async::NotReady => return Ok(Async::NotReady),
                Async::Ready(Some(message)) => message,
                Async::Ready(None) => return Ok(Async::Ready(())), // Add some diagnostics maybe?
            };

            self.process_message(message)?;
        }
    }
}

// Message sent to write loop.
// Processed while write loop is not handling network I/O.
pub enum CommonToWriteMessage {
    IncreaseInWindow(StreamId, u32),
    StreamEnqueue(StreamId, DataOrHeadersWithFlag),
    StreamEnd(StreamId, ErrorCode),   // send when user provided handler completed the stream
}
<commit_msg>Refactor/simplify<commit_after>use common::types::Types;
use common::conn::Conn;
use common::stream::HttpStreamCommon;
use common::stream::HttpStreamData;
use solicit::connection::HttpFrame;
use solicit::StreamId;

use data_or_headers_with_flag::DataOrHeadersWithFlag;

use error;
use ErrorCode;
use solicit::frame::RstStreamFrame;
use solicit::frame::GoawayFrame;
use solicit::frame::SettingsFrame;
use result;
use futures::Poll;
use futures::Async;
use common::conn_read::ConnReadSideCustom;
use common::conn_command::ConnCommandSideCustom;
use common::stream::HttpStreamCommand;
use solicit::frame::FrameBuilder;
use std::cmp;
use solicit::frame::HeadersFrame;
use solicit::connection::EndStream;
use solicit::frame::HeadersFlag;
use solicit::frame::ContinuationFrame;
use solicit::frame::continuation::ContinuationFlag;
use solicit::frame::DataFrame;
use solicit::frame::DataFlag;
use solicit::frame::FrameIR;
use std::mem;
use common::goaway_state::GoAwayState;
use futures::task;

pub trait ConnWriteSideCustom {
    type Types : Types;

    fn process_message(&mut self, message: <Self::Types as Types>::ToWriteMessage) -> result::Result<()>;
}

impl<T> Conn<T>
    where
        T : Types,
        Self : ConnReadSideCustom<Types=T>,
        Self : ConnWriteSideCustom<Types=T>,
        Self : ConnCommandSideCustom<Types=T>,
        HttpStreamCommon<T> : HttpStreamData<Types=T>,
{
    fn poll_flush(&mut self) -> Poll<(), error::Error> {
        self.framed_write.poll_flush()
    }

    fn write_part(&mut self, target: &mut FrameBuilder, stream_id: StreamId, part: HttpStreamCommand) {
        let max_frame_size = self.peer_settings.max_frame_size as usize;

        match part {
            HttpStreamCommand::Data(data, end_stream) => {
                // if client requested end of stream,
                // we must send at least one frame with end stream flag
                if end_stream == EndStream::Yes && data.len() == 0 {
                    // probably should send RST_STREAM
                    let mut frame = DataFrame::with_data(stream_id, Vec::new());
                    frame.set_flag(DataFlag::EndStream);

                    debug!("sending frame {:?}", frame);

                    frame.serialize_into(target);
                    return;
                }

                let mut pos = 0;
                while pos < data.len() {
                    let end = cmp::min(data.len(), pos + max_frame_size);

                    let end_stream_in_frame =
                        if end == data.len() && end_stream == EndStream::Yes {
                            EndStream::Yes
                        } else {
                            EndStream::No
                        };

                    let mut frame = DataFrame::with_data(stream_id, data.slice(pos, end));
                    if end_stream_in_frame == EndStream::Yes {
                        frame.set_flag(DataFlag::EndStream);
                    }

                    debug!("sending frame {:?}", frame);

                    frame.serialize_into(target);

                    pos = end;
                }
            }
            HttpStreamCommand::Headers(headers, end_stream) => {
                let headers_fragment = self
                    .encoder.encode(headers.0.iter().map(|h| (h.name(), h.value())));

                let mut pos = 0;
                while pos < headers_fragment.len() || pos == 0 {
                    let end = cmp::min(headers_fragment.len(), pos + max_frame_size);

                    let chunk = &headers_fragment[pos..end];

                    if pos == 0 {
                        let mut frame = HeadersFrame::new(chunk, stream_id);
                        if end_stream == EndStream::Yes {
                            frame.set_flag(HeadersFlag::EndStream);
                        }

                        if end == headers_fragment.len() {
                            frame.set_flag(HeadersFlag::EndHeaders);
                        }

                        debug!("sending frame {:?}", frame);

                        frame.serialize_into(target);
                    } else {
                        let mut frame = ContinuationFrame::new(chunk, stream_id);

                        if end == headers_fragment.len() {
                            frame.set_flag(ContinuationFlag::EndHeaders);
                        }

                        debug!("sending frame {:?}", frame);

                        frame.serialize_into(target);
                    }

                    pos = end;
                }
            }
            HttpStreamCommand::Rst(error_code) => {
                let frame = RstStreamFrame::new(stream_id, error_code);

                debug!("sending frame {:?}", frame);

                frame.serialize_into(target);
            }
        }
    }

    fn pop_outg_all_for_stream_bytes(&mut self, stream_id: StreamId) -> Vec<u8> {
        let mut send = FrameBuilder::new();
        for part in self.pop_outg_all_for_stream(stream_id) {
            self.write_part(&mut send, stream_id, part);
        }
        send.0
    }

    fn pop_outg_all_for_conn_bytes(&mut self) -> Vec<u8> {
        // TODO: maintain own limits of out window
        let mut send = FrameBuilder::new();
        for (stream_id, part) in self.pop_outg_all_for_conn() {
            self.write_part(&mut send, stream_id, part);
        }
        send.0
    }

    fn pop_outg_all_for_stream(&mut self, stream_id: StreamId) -> Vec<HttpStreamCommand> {
        if let Some(stream) = self.streams.get_mut(stream_id) {
            stream.pop_outg_all_maybe_remove(&mut self.out_window_size)
        } else {
            Vec::new()
        }
    }

    pub fn pop_outg_all_for_conn(&mut self) -> Vec<(StreamId, HttpStreamCommand)> {
        let mut r = Vec::new();

        // TODO: keep list of streams with data
        for stream_id in self.streams.stream_ids() {
            r.extend(self.pop_outg_all_for_stream(stream_id).into_iter().map(|s| (stream_id, s)));
        }

        r
    }

    pub fn buffer_outg_stream(&mut self, stream_id: StreamId) -> result::Result<()> {
        let bytes = self.pop_outg_all_for_stream_bytes(stream_id);

        self.framed_write.buffer(bytes.into());

        Ok(())
    }

    fn buffer_outg_conn(&mut self) -> result::Result<()> {
        let bytes = self.pop_outg_all_for_conn_bytes();

        self.framed_write.buffer(bytes.into());

        Ok(())
    }

    pub fn send_frame_and_notify<F : Into<HttpFrame>>(&mut self, frame: F) {
        // TODO: some of frames should not be in front of GOAWAY
        self.framed_write.buffer_frame(frame);
        // Notify the task to make sure write loop is called again
        // to flush the buffer
        task::current().notify();
    }

    /// Sends an SETTINGS Frame with ack set to acknowledge seeing a SETTINGS frame from the peer.
    pub fn send_ack_settings(&mut self) -> result::Result<()> {
        let settings = SettingsFrame::new_ack();
        self.send_frame_and_notify(settings);
        Ok(())
    }

    fn process_stream_end(&mut self, stream_id: StreamId, error_code: ErrorCode) -> result::Result<()> {
        let stream_id = {
            let stream = self.streams.get_mut(stream_id);
            if let Some(mut stream) = stream {
                stream.stream().outgoing.close(error_code);
                Some(stream_id)
            } else {
                None
            }
        };
        if let Some(stream_id) = stream_id {
            self.buffer_outg_stream(stream_id)?;
        }
        Ok(())
    }

    fn process_stream_enqueue(&mut self, stream_id: StreamId, part: DataOrHeadersWithFlag) -> result::Result<()> {
        let stream_id = {
            let stream = self.streams.get_mut(stream_id);
            if let Some(mut stream) = stream {
                stream.stream().outgoing.push_back_part(part);
                Some(stream_id)
            } else {
                None
            }
        };
        if let Some(stream_id) = stream_id {
            self.buffer_outg_stream(stream_id)?;
        }
        Ok(())
    }

    pub fn process_common_message(&mut self, common: CommonToWriteMessage) -> result::Result<()> {
        match common {
            CommonToWriteMessage::StreamEnd(stream_id, error_code) => {
                self.process_stream_end(stream_id, error_code)?;
            },
            CommonToWriteMessage::StreamEnqueue(stream_id, part) => {
                self.process_stream_enqueue(stream_id, part)?;
            },
            CommonToWriteMessage::IncreaseInWindow(stream_id, increase) => {
                self.increase_in_window(stream_id, increase)?;
            },
        }
        Ok(())
    }

    fn process_flush_xxx_fields(&mut self) -> result::Result<()> {
        if mem::replace(&mut self.flush_conn, false) {
            self.buffer_outg_conn()?;
        }

        let stream_ids: Vec<StreamId> = self.flush_streams.iter().cloned().collect();
        self.flush_streams.clear();
        for stream_id in stream_ids {
            self.buffer_outg_stream(stream_id)?;
        }

        Ok(())
    }

    fn process_goaway_state(&mut self) -> result::Result<()> {
        loop {
            match self.goaway_state {
                GoAwayState::None => return Ok(()),
                GoAwayState::NeedToSend(error_code) => {
                    let frame = GoawayFrame::new(self.last_peer_stream_id, error_code);
                    self.framed_write.buffer_frame(HttpFrame::Goaway(frame));
                    self.goaway_state = GoAwayState::Sending;
                    continue;
                }
                GoAwayState::Sending => {
                    match self.poll_flush()? {
                        Async::Ready(()) => {
                            self.goaway_state = GoAwayState::Sent;
                        },
                        Async::NotReady => {}
                    }
                    return Ok(());
                }
                GoAwayState::Sent => return Ok(()),
            }
        }
    }

    fn process_write_queue(&mut self) -> Poll<(), error::Error> {
        loop {
            let message = match self.write_rx.poll()? {
                Async::NotReady => return Ok(Async::NotReady),
                Async::Ready(Some(message)) => message,
                Async::Ready(None) => return Ok(Async::Ready(())), // Add some diagnostics maybe?
            };

            self.process_message(message)?;
        }
    }

    pub fn poll_write(&mut self) -> Poll<(), error::Error> {
        self.process_goaway_state()?;

        match self.goaway_state {
            GoAwayState::None => {}
            GoAwayState::NeedToSend(..) => {
                unreachable!();
            }
            GoAwayState::Sending => {
                assert!(self.framed_write.remaining() != 0);
                return Ok(Async::NotReady);
            }
            GoAwayState::Sent => {
                info!("GOAWAY sent, exiting loop");
                assert!(self.framed_write.remaining() == 0);
                return Ok(Async::Ready(()));
            }
        }

        self.process_flush_xxx_fields()?;

        if let Async::Ready(()) = self.process_write_queue()? {
            return Ok(Async::Ready(()));
        }

        self.poll_flush()?;
        Ok(Async::NotReady)
    }
}

// Message sent to write loop.
// Processed while write loop is not handling network I/O.
pub enum CommonToWriteMessage {
    IncreaseInWindow(StreamId, u32),
    StreamEnqueue(StreamId, DataOrHeadersWithFlag),
    StreamEnd(StreamId, ErrorCode),   // send when user provided handler completed the stream
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use smallvec::SmallVec;

use crate::crlf;
use crate::rope::Rope;
use crate::tree::{Node, NodeChildren, NodeText, MAX_BYTES, MAX_CHILDREN};

/// An efficient incremental `Rope` builder.
///
/// This is used to efficiently build ropes from sequences of text
/// chunks.  It is useful for creating ropes from:
///
/// - ...large text files, without pre-loading their entire contents into
///   memory (but see [`from_reader()`](Rope::from_reader) for a convenience
///   function that does this for casual use-cases).
/// - ...streaming data sources.
/// - ...non-utf8 text data, doing the encoding conversion incrementally
///   as you go.
///
/// Unlike repeatedly calling `Rope::insert()` on the end of a rope,
/// this API runs in time linear to the amount of data fed to it, and
/// is overall much faster.
///
/// # Example
/// ```
/// # use ropey::RopeBuilder;
/// #
/// let mut builder = RopeBuilder::new();
///
/// builder.append("Hello ");
/// builder.append("world!\n");
/// builder.append("How's ");
/// builder.append("it goin");
/// builder.append("g?");
///
/// let rope = builder.finish();
///
/// assert_eq!(rope, "Hello world!\nHow's it going?");
/// ```
#[derive(Debug, Clone, Default)]
pub struct RopeBuilder {
    stack: SmallVec<[Arc<Node>; 4]>,
    buffer: String,
}

impl RopeBuilder {
    /// Creates a new RopeBuilder, ready for input.
    pub fn new() -> Self {
        RopeBuilder {
            stack: {
                let mut stack = SmallVec::new();
                stack.push(Arc::new(Node::new()));
                stack
            },
            buffer: String::new(),
        }
    }

    /// Appends `chunk` to the end of the in-progress `Rope`.
    ///
    /// Call this method repeatedly to incrementally build up a
    /// `Rope`.  The passed text chunk can be as large or small as
    /// desired, but larger chunks are more efficient.
    ///
    /// `chunk` must be valid utf8 text.
    pub fn append(&mut self, chunk: &str) {
        self.append_internal(chunk, false);
    }

    /// Finishes the build, and returns the `Rope`.
    ///
    /// Note: this method consumes the builder.  If you want to continue
    /// building other ropes with the same prefix, you can clone the builder
    /// before calling `finish()`.
    pub fn finish(mut self) -> Rope {
        // Append the last leaf
        self.append_internal("", true);
        self.finish_internal()
    }

    /// Builds a rope all at once from a single string slice.
    ///
    /// This avoids the creation and use of the internal buffer.  This is
    /// for internal use only, because the public-facing API has
    /// Rope::from_str(), which actually uses this for its implementation.
    pub(crate) fn build_at_once(mut self, chunk: &str) -> Rope {
        self.append_internal(chunk, true);
        self.finish_internal()
    }

    //-----------------------------------------------------------------

    // Internal workings of `append()`.
    fn append_internal(&mut self, chunk: &str, is_last_chunk: bool) {
        let mut chunk = chunk;

        // Repeatedly chop text off the end of the input, creating
        // leaf nodes out of them and appending them to the tree.
        while !chunk.is_empty() || (!self.buffer.is_empty() && is_last_chunk) {
            // Get the text for the next leaf
            let (leaf_text, remainder) = self.get_next_leaf_text(chunk, is_last_chunk);
            chunk = remainder;

            // Append the leaf to the rope
            match leaf_text {
                NextText::None => break,
                NextText::UseBuffer => {
                    let leaf_text = NodeText::from_str(&self.buffer);
                    self.append_leaf_node(Arc::new(Node::Leaf(leaf_text)));
                    self.buffer.clear();
                }
                NextText::String(s) => {
                    self.append_leaf_node(Arc::new(Node::Leaf(NodeText::from_str(s))));
                }
            }
        }
    }

    // Internal workings of `finish()`.
    fn finish_internal(mut self) -> Rope {
        // Zip up all the remaining nodes on the stack
        let mut stack_idx = self.stack.len() - 1;
        while stack_idx >= 1 {
            let node = self.stack.pop().unwrap();
            if let Node::Internal(ref mut children) = *Arc::make_mut(&mut self.stack[stack_idx - 1])
            {
                children.push((node.text_info(), node));
            } else {
                unreachable!();
            }
            stack_idx -= 1;
        }

        // Get root and fix any right-side nodes with too few children.
        let mut root = self.stack.pop().unwrap();
        Arc::make_mut(&mut root).zip_fix_right();

        // Create the rope, make sure it's well-formed, and return it.
        let mut rope = Rope { root: root };
        rope.pull_up_singular_nodes();
        return rope;
    }

    // Returns (next_leaf_text, remaining_text)
    #[inline(always)]
    fn get_next_leaf_text<'a>(
        &mut self,
        text: &'a str,
        is_last_chunk: bool,
    ) -> (NextText<'a>, &'a str) {
        assert!(
            self.buffer.len() < MAX_BYTES,
            "RopeBuilder: buffer is already full when receiving a chunk! \
             This should never happen!",
        );

        // Simplest case: empty buffer and enough in `text` for a full
        // chunk, so just chop a chunk off from `text` and use that.
        if self.buffer.is_empty() && text.len() >= MAX_BYTES {
            let split_idx = crlf::find_good_split(
                MAX_BYTES.min(text.len() - 1), // - 1 to avoid CRLF split.
                text.as_bytes(),
                true,
            );
            return (NextText::String(&text[..split_idx]), &text[split_idx..]);
        }
        // If the buffer + `text` is enough for a full chunk, push enough
        // of `text` onto the buffer to fill it and use that.
        else if (text.len() + self.buffer.len()) >= MAX_BYTES {
            let mut split_idx =
                crlf::find_good_split(MAX_BYTES - self.buffer.len(), text.as_bytes(), true);
            if split_idx == text.len() && text.as_bytes()[text.len() - 1] == 0x0D {
                // Avoid CRLF split.
                split_idx -= 1;
            };
            self.buffer.push_str(&text[..split_idx]);
            return (NextText::UseBuffer, &text[split_idx..]);
        }
        // If we don't have enough text for a full chunk.
        else {
            // If it's our last chunk, wrap it all up!
            if is_last_chunk {
                if self.buffer.is_empty() {
                    return if text.is_empty() {
                        (NextText::None, "")
                    } else {
                        (NextText::String(text), "")
                    };
                } else {
                    self.buffer.push_str(text);
                    return (NextText::UseBuffer, "");
                }
            }
            // Otherwise, just push to the buffer.
            else {
                self.buffer.push_str(text);
                return (NextText::None, "");
            }
        }
    }

    fn append_leaf_node(&mut self, leaf: Arc<Node>) {
        let last = self.stack.pop().unwrap();
        match *last {
            Node::Leaf(_) => {
                if last.leaf_text().is_empty() {
                    self.stack.push(leaf);
                } else {
                    let mut children = NodeChildren::new();
                    children.push((last.text_info(), last));
                    children.push((leaf.text_info(), leaf));
                    self.stack.push(Arc::new(Node::Internal(children)));
                }
            }

            Node::Internal(_) => {
                self.stack.push(last);
                let mut left = leaf;
                let mut stack_idx = (self.stack.len() - 1) as isize;
                loop {
                    if stack_idx < 0 {
                        // We're above the root, so do a root split.
                        let mut children = NodeChildren::new();
                        children.push((left.text_info(), left));
                        self.stack.insert(0, Arc::new(Node::Internal(children)));
                        break;
                    } else if self.stack[stack_idx as usize].child_count() < (MAX_CHILDREN - 1) {
                        // There's room to add a child, so do that.
                        Arc::make_mut(&mut self.stack[stack_idx as usize])
                            .children_mut()
                            .push((left.text_info(), left));
                        break;
                    } else {
                        // Not enough room to fit a child, so split.
                        left = Arc::new(Node::Internal(
                            Arc::make_mut(&mut self.stack[stack_idx as usize])
                                .children_mut()
                                .push_split((left.text_info(), left)),
                        ));
                        std::mem::swap(&mut left, &mut self.stack[stack_idx as usize]);
                        stack_idx -= 1;
                    }
                }
            }
        }
    }
}

enum NextText<'a> {
    None,
    UseBuffer,
    String(&'a str),
}

//===========================================================================

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

    // 127 bytes, 103 chars, 4 lines
    const TEXT: &str = "Hello there!  How're you doing?\r\nIt's \
                        a fine day, isn't it?\r\nAren't you glad \
                        we're alive?\r\nこんにちは、みんなさん！";

    #[test]
    fn rope_builder_01() {
        let mut b = RopeBuilder::new();

        b.append("Hello there!  How're you doing?\r");
        b.append("\nIt's a fine ");
        b.append("d");
        b.append("a");
        b.append("y,");
        b.append(" ");
        b.append("isn't it?");
        b.append("\r");
        b.append("\nAren't you ");
        b.append("glad we're alive?\r");
        b.append("\n");
        b.append("こんにち");
        b.append("は、みんなさ");
        b.append("ん！");

        let r = b.finish();

        assert_eq!(r, TEXT);

        r.assert_integrity();
        r.assert_invariants();
    }
}
<commit_msg>Clean up too-small final chunks in RopeBuilder::finish().<commit_after>use std::sync::Arc;

use smallvec::SmallVec;

use crate::crlf;
use crate::rope::Rope;
use crate::tree::{Node, NodeChildren, NodeText, MAX_BYTES, MAX_CHILDREN, MIN_BYTES};

/// An efficient incremental `Rope` builder.
///
/// This is used to efficiently build ropes from sequences of text
/// chunks.  It is useful for creating ropes from:
///
/// - ...large text files, without pre-loading their entire contents into
///   memory (but see [`from_reader()`](Rope::from_reader) for a convenience
///   function that does this for casual use-cases).
/// - ...streaming data sources.
/// - ...non-utf8 text data, doing the encoding conversion incrementally
///   as you go.
///
/// Unlike repeatedly calling `Rope::insert()` on the end of a rope,
/// this API runs in time linear to the amount of data fed to it, and
/// is overall much faster.
///
/// # Example
/// ```
/// # use ropey::RopeBuilder;
/// #
/// let mut builder = RopeBuilder::new();
///
/// builder.append("Hello ");
/// builder.append("world!\n");
/// builder.append("How's ");
/// builder.append("it goin");
/// builder.append("g?");
///
/// let rope = builder.finish();
///
/// assert_eq!(rope, "Hello world!\nHow's it going?");
/// ```
#[derive(Debug, Clone, Default)]
pub struct RopeBuilder {
    stack: SmallVec<[Arc<Node>; 4]>,
    buffer: String,
    last_chunk_len_bytes: usize,
}

impl RopeBuilder {
    /// Creates a new RopeBuilder, ready for input.
    pub fn new() -> Self {
        RopeBuilder {
            stack: {
                let mut stack = SmallVec::new();
                stack.push(Arc::new(Node::new()));
                stack
            },
            buffer: String::new(),
            last_chunk_len_bytes: 0,
        }
    }

    /// Appends `chunk` to the end of the in-progress `Rope`.
    ///
    /// Call this method repeatedly to incrementally build up a
    /// `Rope`.  The passed text chunk can be as large or small as
    /// desired, but larger chunks are more efficient.
    ///
    /// `chunk` must be valid utf8 text.
    pub fn append(&mut self, chunk: &str) {
        self.append_internal(chunk, false);
    }

    /// Finishes the build, and returns the `Rope`.
    ///
    /// Note: this method consumes the builder.  If you want to continue
    /// building other ropes with the same prefix, you can clone the builder
    /// before calling `finish()`.
    pub fn finish(mut self) -> Rope {
        // Append the last leaf
        self.append_internal("", true);
        self.finish_internal()
    }

    /// Builds a rope all at once from a single string slice.
    ///
    /// This avoids the creation and use of the internal buffer.  This is
    /// for internal use only, because the public-facing API has
    /// Rope::from_str(), which actually uses this for its implementation.
    pub(crate) fn build_at_once(mut self, chunk: &str) -> Rope {
        self.append_internal(chunk, true);
        self.finish_internal()
    }

    //-----------------------------------------------------------------

    // Internal workings of `append()`.
    fn append_internal(&mut self, chunk: &str, is_last_chunk: bool) {
        let mut chunk = chunk;

        // Repeatedly chop text off the end of the input, creating
        // leaf nodes out of them and appending them to the tree.
        while !chunk.is_empty() || (!self.buffer.is_empty() && is_last_chunk) {
            // Get the text for the next leaf
            let (leaf_text, remainder) = self.get_next_leaf_text(chunk, is_last_chunk);
            chunk = remainder;

            self.last_chunk_len_bytes = chunk.len();

            // Append the leaf to the rope
            match leaf_text {
                NextText::None => break,
                NextText::UseBuffer => {
                    let leaf_text = NodeText::from_str(&self.buffer);
                    self.append_leaf_node(Arc::new(Node::Leaf(leaf_text)));
                    self.buffer.clear();
                }
                NextText::String(s) => {
                    self.append_leaf_node(Arc::new(Node::Leaf(NodeText::from_str(s))));
                }
            }
        }
    }

    // Internal workings of `finish()`.
    fn finish_internal(mut self) -> Rope {
        // Zip up all the remaining nodes on the stack
        let mut stack_idx = self.stack.len() - 1;
        while stack_idx >= 1 {
            let node = self.stack.pop().unwrap();
            if let Node::Internal(ref mut children) = *Arc::make_mut(&mut self.stack[stack_idx - 1])
            {
                children.push((node.text_info(), node));
            } else {
                unreachable!();
            }
            stack_idx -= 1;
        }

        // Get root and fix any right-side nodes with too few children or.
        let mut root = self.stack.pop().unwrap();
        Arc::make_mut(&mut root).zip_fix_right();

        // Create the rope, make sure it's well-formed, and return it.
        let mut rope = Rope { root: root };
        if self.last_chunk_len_bytes < MIN_BYTES && self.last_chunk_len_bytes != rope.len_bytes() {
            // Merge the last chunk if it was too small.
            let idx =
                rope.len_chars() - rope.byte_to_char(rope.len_bytes() - self.last_chunk_len_bytes);
            Arc::make_mut(&mut rope.root).fix_tree_seam(idx);
        }
        rope.pull_up_singular_nodes();
        return rope;
    }

    // Returns (next_leaf_text, remaining_text)
    #[inline(always)]
    fn get_next_leaf_text<'a>(
        &mut self,
        text: &'a str,
        is_last_chunk: bool,
    ) -> (NextText<'a>, &'a str) {
        assert!(
            self.buffer.len() < MAX_BYTES,
            "RopeBuilder: buffer is already full when receiving a chunk! \
             This should never happen!",
        );

        // Simplest case: empty buffer and enough in `text` for a full
        // chunk, so just chop a chunk off from `text` and use that.
        if self.buffer.is_empty() && text.len() >= MAX_BYTES {
            let split_idx = crlf::find_good_split(
                MAX_BYTES.min(text.len() - 1), // - 1 to avoid CRLF split.
                text.as_bytes(),
                true,
            );
            return (NextText::String(&text[..split_idx]), &text[split_idx..]);
        }
        // If the buffer + `text` is enough for a full chunk, push enough
        // of `text` onto the buffer to fill it and use that.
        else if (text.len() + self.buffer.len()) >= MAX_BYTES {
            let mut split_idx =
                crlf::find_good_split(MAX_BYTES - self.buffer.len(), text.as_bytes(), true);
            if split_idx == text.len() && text.as_bytes()[text.len() - 1] == 0x0D {
                // Avoid CRLF split.
                split_idx -= 1;
            };
            self.buffer.push_str(&text[..split_idx]);
            return (NextText::UseBuffer, &text[split_idx..]);
        }
        // If we don't have enough text for a full chunk.
        else {
            // If it's our last chunk, wrap it all up!
            if is_last_chunk {
                if self.buffer.is_empty() {
                    return if text.is_empty() {
                        (NextText::None, "")
                    } else {
                        (NextText::String(text), "")
                    };
                } else {
                    self.buffer.push_str(text);
                    return (NextText::UseBuffer, "");
                }
            }
            // Otherwise, just push to the buffer.
            else {
                self.buffer.push_str(text);
                return (NextText::None, "");
            }
        }
    }

    fn append_leaf_node(&mut self, leaf: Arc<Node>) {
        let last = self.stack.pop().unwrap();
        match *last {
            Node::Leaf(_) => {
                if last.leaf_text().is_empty() {
                    self.stack.push(leaf);
                } else {
                    let mut children = NodeChildren::new();
                    children.push((last.text_info(), last));
                    children.push((leaf.text_info(), leaf));
                    self.stack.push(Arc::new(Node::Internal(children)));
                }
            }

            Node::Internal(_) => {
                self.stack.push(last);
                let mut left = leaf;
                let mut stack_idx = (self.stack.len() - 1) as isize;
                loop {
                    if stack_idx < 0 {
                        // We're above the root, so do a root split.
                        let mut children = NodeChildren::new();
                        children.push((left.text_info(), left));
                        self.stack.insert(0, Arc::new(Node::Internal(children)));
                        break;
                    } else if self.stack[stack_idx as usize].child_count() < (MAX_CHILDREN - 1) {
                        // There's room to add a child, so do that.
                        Arc::make_mut(&mut self.stack[stack_idx as usize])
                            .children_mut()
                            .push((left.text_info(), left));
                        break;
                    } else {
                        // Not enough room to fit a child, so split.
                        left = Arc::new(Node::Internal(
                            Arc::make_mut(&mut self.stack[stack_idx as usize])
                                .children_mut()
                                .push_split((left.text_info(), left)),
                        ));
                        std::mem::swap(&mut left, &mut self.stack[stack_idx as usize]);
                        stack_idx -= 1;
                    }
                }
            }
        }
    }
}

enum NextText<'a> {
    None,
    UseBuffer,
    String(&'a str),
}

//===========================================================================

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

    // 127 bytes, 103 chars, 4 lines
    const TEXT: &str = "Hello there!  How're you doing?\r\nIt's \
                        a fine day, isn't it?\r\nAren't you glad \
                        we're alive?\r\nこんにちは、みんなさん！";

    #[test]
    fn rope_builder_01() {
        let mut b = RopeBuilder::new();

        b.append("Hello there!  How're you doing?\r");
        b.append("\nIt's a fine ");
        b.append("d");
        b.append("a");
        b.append("y,");
        b.append(" ");
        b.append("isn't it?");
        b.append("\r");
        b.append("\nAren't you ");
        b.append("glad we're alive?\r");
        b.append("\n");
        b.append("こんにち");
        b.append("は、みんなさ");
        b.append("ん！");

        let r = b.finish();

        assert_eq!(r, TEXT);

        r.assert_integrity();
        r.assert_invariants();
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::error::Error;
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::io::BufWriter;
use std::path::{Path, PathBuf};
use std::thread;
use std::time::Duration;
use time;

use config;
use futures::future::Shared;
use futures::sync::oneshot;
use lib;
use router::RouterConfig;
use std::sync::{Arc, Mutex};

pub fn route_thread(
    config: &RouterConfig,
    todo: &Arc<Mutex<VecDeque<PathBuf>>>,
    sigint: &Shared<oneshot::Receiver<()>>,
    id: u64,
) {
    loop {
        match todo.lock().unwrap().pop_front() {
            Some(path) => {
                if let Err(err) = route(&path, &config, id) {
                    warn!("{}", err);
                }
            }
            None => {
                thread::sleep(Duration::from_millis(config::REST_TIME));
            }
        }

        if sigint.peek().is_some() {
            return;
        }
    }
}

fn route(path: &PathBuf, config: &RouterConfig, id: u64) -> Result<(), Box<Error>> {
    let start = time::now_utc().to_timespec();
    let run_id = format!("{}#{}", start.sec, start.nsec);

    // Load metrics
    debug!("open {}", format!("{:?}", path));
    let mut content = String::new();
    File::open(&path)?.read_to_string(&mut content)?;

    let mut metrics: Vec<String> = Vec::new();
    for line in content.lines() {
        metrics.push(lib::add_labels(&line, &config.labels)?);
    }

    // Nothing to do
    if metrics.is_empty() {
        // Delete source file
        debug!("delete  {}", format!("{:?}", path));
        fs::remove_file(&path)?;

        return Ok(());
    }

    // Setup sinks files
    let dir = Path::new(&config.sink_dir);

    // Open tmp files
    for sink in &config.sinks {
        let sink_file_name = dir.join(format!("{}-{}.tmp", sink.name, id));
        debug!("open tmp sink file {}", format!("{:?}", sink_file_name));
        let mut sink_file = BufWriter::new(File::create(&sink_file_name)?);

        // Write metrics
        for line in &metrics {
            if line.is_empty() {
                continue;
            }

            if sink.selector.is_some() {
                let selector = sink.selector.as_ref().unwrap();
                if !line
                    .split_whitespace()
                    .nth(1)
                    .map_or(false, |class| selector.is_match(class))
                {
                    continue;
                }
            }
            sink_file.write_all(line.as_bytes())?;
            sink_file.write_all(b"\n")?;
        }

        // Write buffered datas
        sink_file.flush()?;

        // Rotate
        let dest_file = dir.join(format!("{}-{}-{}.metrics", sink.name, id, run_id));
        debug!("rename {:?} to {:?}", sink_file_name, dest_file);
        fs::rename(sink_file_name, dest_file)?;

        // Delete source file
        debug!("delete  {}", format!("{:?}", path));
        fs::remove_file(&path)?;
    }

    Ok(())
}
<commit_msg>fix(router): src file is removed multiple time<commit_after>use std::collections::VecDeque;
use std::error::Error;
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::io::BufWriter;
use std::path::{Path, PathBuf};
use std::thread;
use std::time::Duration;
use time;

use config;
use futures::future::Shared;
use futures::sync::oneshot;
use lib;
use router::RouterConfig;
use std::sync::{Arc, Mutex};

pub fn route_thread(
    config: &RouterConfig,
    todo: &Arc<Mutex<VecDeque<PathBuf>>>,
    sigint: &Shared<oneshot::Receiver<()>>,
    id: u64,
) {
    loop {
        match todo.lock().unwrap().pop_front() {
            Some(path) => {
                debug!("Processing: {:?}", path);
                if let Err(err) = route(&path, &config, id) {
                    warn!("Fail to process:{:?} - {}", path, err);
                }
            }
            None => {
                thread::sleep(Duration::from_millis(config::REST_TIME));
            }
        }

        if sigint.peek().is_some() {
            return;
        }
    }
}

fn route(path: &PathBuf, config: &RouterConfig, id: u64) -> Result<(), Box<Error>> {
    let start = time::now_utc().to_timespec();
    let run_id = format!("{}#{}", start.sec, start.nsec);

    // Load metrics
    debug!("open {}", format!("{:?}", path));
    let mut content = String::new();
    File::open(&path)?.read_to_string(&mut content)?;

    let mut metrics: Vec<String> = Vec::new();
    for line in content.lines() {
        metrics.push(lib::add_labels(&line, &config.labels)?);
    }

    // Nothing to do
    if metrics.is_empty() {
        // Delete source file
        debug!("delete  {}", format!("{:?}", path));
        fs::remove_file(&path)?;

        return Ok(());
    }

    // Setup sinks files
    let dir = Path::new(&config.sink_dir);

    // Open tmp files
    for sink in &config.sinks {
        let sink_file_name = dir.join(format!("{}-{}.tmp", sink.name, id));
        debug!("open tmp sink file {}", format!("{:?}", sink_file_name));
        let mut sink_file = BufWriter::new(File::create(&sink_file_name)?);

        // Write metrics
        for line in &metrics {
            if line.is_empty() {
                continue;
            }

            if sink.selector.is_some() {
                let selector = sink.selector.as_ref().unwrap();
                if !line
                    .split_whitespace()
                    .nth(1)
                    .map_or(false, |class| selector.is_match(class))
                {
                    continue;
                }
            }
            sink_file.write_all(line.as_bytes())?;
            sink_file.write_all(b"\n")?;
        }

        // Write buffered datas
        sink_file.flush()?;

        // Rotate
        let dest_file = dir.join(format!("{}-{}-{}.metrics", sink.name, id, run_id));
        debug!("rename {:?} to {:?}", sink_file_name, dest_file);
        fs::rename(sink_file_name, dest_file)?;
    }

    // Delete source file
    debug!("delete  {}", format!("{:?}", path));
    fs::remove_file(&path)?;

    Ok(())
}
<|endoftext|>