<commit_before>// See LICENSE file for copyright and license details.

use std::f32::consts::{PI};
use rand::{thread_rng, Rng};
use cgmath::{Vector3, Vector, rad};
use common::types::{MapPos, ZFloat, UnitId};
use core::game_state::GameState;
use core::core;
use core::unit::{UnitTypeId};
use core::pathfinder::{MapPath};
use zgl::mesh::{MeshId};
use zgl::font_stash::{FontStash};
use zgl::zgl::{Zgl};
use zgl::types::{Time, WorldPos};
use geom;
use scene::{
    Scene,
    SceneNode,
    NodeId,
    MIN_MARKER_NODE_ID,
    SHELL_NODE_ID,
};
use unit_type_visual_info::{UnitTypeVisualInfo};
use move_helper::{MoveHelper};
use map_text::{MapTextManager};

fn unit_id_to_node_id(unit_id: &UnitId) -> NodeId {
    NodeId{id: unit_id.id}
}

fn marker_id(unit_id: &UnitId) -> NodeId {
    NodeId{id: MIN_MARKER_NODE_ID.id + unit_id.id}
}

pub trait EventVisualizer {
    fn is_finished(&self) -> bool;
    // fn draw(&mut self, scene: &mut Scene, dtime: &Time, map_text: &MapTextManager);
    fn draw(&mut self, scene: &mut Scene, dtime: &Time);
    fn end(&mut self, scene: &mut Scene, state: &GameState);
}

// TODO: store CoreEvent
pub struct EventMoveVisualizer {
    unit_id: UnitId,
    path: Vec<WorldPos>,
    move_helper: MoveHelper,
    speed: ZFloat,
}

impl EventVisualizer for EventMoveVisualizer {
    fn is_finished(&self) -> bool {
        self.path.len() == 1
    }

    fn draw(&mut self, scene: &mut Scene, dtime: &Time) {
        let pos = self.move_helper.step(dtime);
        {
            let marker_node = scene.node(&marker_id(&self.unit_id));
            marker_node.pos.v = pos.v.add_v(&vec3_z(geom::HEX_EX_RADIUS / 2.0));
        }
        let node_id = unit_id_to_node_id(&self.unit_id);
        let node = scene.node(&node_id);
        node.pos = pos;
        if self.move_helper.is_finished() {
            let _ = self.path.remove(0);
            if self.path.len() > 1 {
                self.update_waypoint(node);
            }
            node.pos = self.current_waypoint().clone();
        }
    }

    fn end(&mut self, scene: &mut Scene, _: &GameState) {
        assert!(self.path.len() == 1);
        let node_id = unit_id_to_node_id(&self.unit_id);
        let node = scene.node(&node_id);
        node.pos = self.current_waypoint().clone();
    }
}

impl EventMoveVisualizer {
    pub fn new(
        scene: &mut Scene,
        _: &GameState,
        unit_id: UnitId,
        unit_type_visual_info: &UnitTypeVisualInfo,
        path: MapPath,
    ) -> Box<EventVisualizer> {
        let mut world_path = Vec::new();
        for path_node in path.nodes().iter() {
            let world_pos = geom::map_pos_to_world_pos(&path_node.pos);
            world_path.push(world_pos);
        }
        let speed = unit_type_visual_info.move_speed;
        let node_id = unit_id_to_node_id(&unit_id);
        let node = scene.node(&node_id);
        node.rot = geom::get_rot_angle(
            &world_path[0], &world_path[1]);
        let move_helper = MoveHelper::new(
            &world_path[0], &world_path[1], speed);
        let mut vis = box EventMoveVisualizer {
            unit_id: unit_id.clone(),
            path: world_path,
            move_helper: move_helper,
            speed: speed,
        };
        vis.update_waypoint(node);
        vis as Box<EventVisualizer>
    }

    fn update_waypoint(&mut self, node: &mut SceneNode) {
        self.move_helper = MoveHelper::new(
            self.current_waypoint(),
            self.next_waypoint(),
            self.speed,
        );
        node.rot = geom::get_rot_angle(
            self.current_waypoint(),
            self.next_waypoint()
        );
    }

    fn current_waypoint(&self) -> &WorldPos {
        assert!(self.path.len() >= 1);
        &self.path[0]
    }

    fn next_waypoint(&self) -> &WorldPos {
        assert!(self.path.len() >= 2);
        &self.path[1]
    }
}

pub struct EventEndTurnVisualizer;

impl EventEndTurnVisualizer {
    pub fn new() -> Box<EventVisualizer> {
        box EventEndTurnVisualizer as Box<EventVisualizer>
    }
}

impl EventVisualizer for EventEndTurnVisualizer {
    fn is_finished(&self) -> bool {
        true
    }

    fn draw(&mut self, _: &mut Scene, _: &Time) {}

    fn end(&mut self, _: &mut Scene, _: &GameState) {}
}

fn show_unit_at(
    core: &core::Core,
    scene: &mut Scene,
    id: &UnitId,
    type_id: &UnitTypeId,
    pos: &MapPos,
    mesh_id: &MeshId,
    marker_mesh_id: &MeshId,
) {
    let node_id = unit_id_to_node_id(id);
    let world_pos = geom::map_pos_to_world_pos(pos);
    let to = world_pos;
    let rot = rad(thread_rng().gen_range(0.0, PI * 2.0));
    scene.nodes.insert(node_id, SceneNode {
        pos: to.clone(),
        rot: rot,
        mesh_id: None,
        children: get_unit_scene_nodes(core, type_id, mesh_id),
    });
    scene.nodes.insert(marker_id(id), SceneNode {
        pos: WorldPos{v: to.v.add_v(&vec3_z(geom::HEX_EX_RADIUS / 2.0))},
        rot: rad(0.0),
        mesh_id: Some(marker_mesh_id.clone()),
        children: Vec::new(),
    });
}

pub struct EventCreateUnitVisualizer {
    id: UnitId,
    move_helper: MoveHelper,
}

fn get_unit_scene_nodes(
    core: &core::Core,
    type_id: &UnitTypeId,
    mesh_id: &MeshId,
) -> Vec<SceneNode> {
    let count = core.object_types().get_unit_type(type_id).count;
    let mut vec = Vec::new();
    if count == 1 {
        vec![SceneNode {
            pos: WorldPos{v: Vector3{x: 0.0, y: 0.0, z: 0.0}},
            rot: rad(0.0),
            mesh_id: Some(mesh_id.clone()),
            children: vec![],
        }]
    } else {
        for i in 0 .. count {
            let pos = geom::index_to_circle_vertex(count, i).v.mul_s(0.3f32);
            vec.push(SceneNode {
                pos: WorldPos{v: pos},
                rot: rad(0.0),
                mesh_id: Some(mesh_id.clone()),
                children: vec![],
            });
        }
        vec
    }
}

impl EventCreateUnitVisualizer {
    pub fn new(
        core: &core::Core,
        scene: &mut Scene,
        _: &GameState,
        id: UnitId,
        type_id: &UnitTypeId,
        pos: &MapPos,
        mesh_id: &MeshId,
        marker_mesh_id: &MeshId,
    ) -> Box<EventVisualizer> {
        let node_id = unit_id_to_node_id(&id);
        let to = geom::map_pos_to_world_pos(pos);
        let from = WorldPos{v: to.v.sub_v(&vec3_z(geom::HEX_EX_RADIUS / 2.0))};
        show_unit_at(core, scene, &id, type_id, pos, mesh_id, marker_mesh_id);
        let move_helper = MoveHelper::new(&from, &to, 1.0);
        scene.nodes.get_mut(&node_id).unwrap().pos = from.clone();
        box EventCreateUnitVisualizer {
            id: id,
            move_helper: move_helper,
        } as Box<EventVisualizer>
    }
}

impl EventVisualizer for EventCreateUnitVisualizer {
    fn is_finished(&self) -> bool {
        self.move_helper.is_finished()
    }

    fn draw(&mut self, scene: &mut Scene, dtime: &Time) {
        let node_id = unit_id_to_node_id(&self.id);
        let node = scene.node(&node_id);
        node.pos = self.move_helper.step(dtime);
    }

    fn end(&mut self, _: &mut Scene, _: &GameState) {}
}

fn vec3_z(z: ZFloat) -> Vector3<ZFloat> {
    Vector3{x: 0.0, y: 0.0, z: z}
}

pub struct EventAttackUnitVisualizer {
    defender_id: UnitId,
    killed: bool,
    move_helper: MoveHelper,
    shell_move: MoveHelper,
}

impl EventAttackUnitVisualizer {
    pub fn new(
        zgl: &Zgl,
        scene: &mut Scene,
        _: &GameState,
        attacker_id: UnitId,
        defender_id: UnitId,
        killed: bool,
        mode: core::FireMode,
        shell_mesh_id: MeshId,
        map_text: &mut MapTextManager,
        font_stash: &mut FontStash,
    ) -> Box<EventVisualizer> {
        let node_id = unit_id_to_node_id(&defender_id);
        // TODO: from <-> to
        let from = scene.nodes.get(&node_id)
            .expect("Can not find defender scene node")
            .pos.clone();
        let to = WorldPos{v: from.v.sub_v(&vec3_z(geom::HEX_EX_RADIUS / 2.0))};
        let move_helper = MoveHelper::new(&from, &to, 1.0);
        let attacker_pos = scene.nodes.get(&unit_id_to_node_id(&attacker_id))
            .expect("Can not find attacker").pos.clone();
        let defender_pos = scene.nodes.get(&unit_id_to_node_id(&defender_id))
            .expect("Can not find defender").pos.clone();
        let shell_move = {
            scene.nodes.insert(SHELL_NODE_ID, SceneNode {
                pos: from.clone(),
                rot: rad(0.0),
                mesh_id: Some(shell_mesh_id),
                children: Vec::new(),
            });
            MoveHelper::new(&attacker_pos, &defender_pos, 10.0)
        };
        if killed {
            map_text.add_text_to_world_pos(zgl, font_stash, "-1", &defender_pos);
        } else {
            map_text.add_text_to_world_pos(zgl, font_stash, "miss", &defender_pos);
        }
        match mode {
            core::FireMode::Reactive => {
                map_text.add_text_to_world_pos(zgl, font_stash, "reaction fire", &attacker_pos);
            },
            core::FireMode::Active => {},
        }
        box EventAttackUnitVisualizer {
            defender_id: defender_id,
            killed: killed,
            move_helper: move_helper,
            shell_move: shell_move,
        } as Box<EventVisualizer>
    }
}

impl EventVisualizer for EventAttackUnitVisualizer {
    fn is_finished(&self) -> bool {
        if self.killed {
            self.move_helper.is_finished()
        } else {
            self.shell_move.is_finished()
        }
    }

    fn draw(&mut self, scene: &mut Scene, dtime: &Time) {
        scene.node(&SHELL_NODE_ID).pos = self.shell_move.step(dtime);
        if self.killed {
            if self.shell_move.is_finished() {
                let node_id = unit_id_to_node_id(&self.defender_id);
                scene.node(&node_id).pos = self.move_helper.step(dtime);
            }
        }
    }

    fn end(&mut self, scene: &mut Scene, _: &GameState) {
        if self.killed {
            let node_id = unit_id_to_node_id(&self.defender_id);
            scene.nodes.remove(&node_id);
            scene.nodes.remove(&marker_id(&self.defender_id));
        }
        scene.nodes.remove(&SHELL_NODE_ID);
    }
}

pub struct EventShowUnitVisualizer;

impl EventShowUnitVisualizer {
    pub fn new(
        core: &core::Core,
        scene: &mut Scene,
        _: &GameState,
        id: UnitId,
        type_id: &UnitTypeId,
        pos: &MapPos,
        mesh_id: &MeshId,
        marker_mesh_id: &MeshId,
    ) -> Box<EventVisualizer> {
        show_unit_at(core, scene, &id, type_id, pos, mesh_id, marker_mesh_id);
        box EventShowUnitVisualizer as Box<EventVisualizer>
    }
}

impl EventVisualizer for EventShowUnitVisualizer {
    fn is_finished(&self) -> bool {
        true
    }

    fn draw(&mut self, _: &mut Scene, _: &Time) {}

    fn end(&mut self, _: &mut Scene, _: &GameState) {}
}

pub struct EventHideUnitVisualizer;

impl EventHideUnitVisualizer {
    pub fn new(scene: &mut Scene, unit_id: &UnitId) -> Box<EventVisualizer> {
        scene.nodes.remove(&unit_id_to_node_id(&unit_id));
        scene.nodes.remove(&marker_id(&unit_id));
        box EventHideUnitVisualizer as Box<EventVisualizer>
    }
}

impl EventVisualizer for EventHideUnitVisualizer {
    fn is_finished(&self) -> bool {
        true
    }

    fn draw(&mut self, _: &mut Scene, _: &Time) {}

    fn end(&mut self, _: &mut Scene, _: &GameState) {}
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>event_visualizer.rs: EventAttackVisualizer: Removed outdated todo-comment<commit_after>// See LICENSE file for copyright and license details.

use std::f32::consts::{PI};
use rand::{thread_rng, Rng};
use cgmath::{Vector3, Vector, rad};
use common::types::{MapPos, ZFloat, UnitId};
use core::game_state::GameState;
use core::core;
use core::unit::{UnitTypeId};
use core::pathfinder::{MapPath};
use zgl::mesh::{MeshId};
use zgl::font_stash::{FontStash};
use zgl::zgl::{Zgl};
use zgl::types::{Time, WorldPos};
use geom;
use scene::{
    Scene,
    SceneNode,
    NodeId,
    MIN_MARKER_NODE_ID,
    SHELL_NODE_ID,
};
use unit_type_visual_info::{UnitTypeVisualInfo};
use move_helper::{MoveHelper};
use map_text::{MapTextManager};

fn unit_id_to_node_id(unit_id: &UnitId) -> NodeId {
    NodeId{id: unit_id.id}
}

fn marker_id(unit_id: &UnitId) -> NodeId {
    NodeId{id: MIN_MARKER_NODE_ID.id + unit_id.id}
}

pub trait EventVisualizer {
    fn is_finished(&self) -> bool;
    // fn draw(&mut self, scene: &mut Scene, dtime: &Time, map_text: &MapTextManager);
    fn draw(&mut self, scene: &mut Scene, dtime: &Time);
    fn end(&mut self, scene: &mut Scene, state: &GameState);
}

// TODO: store CoreEvent
pub struct EventMoveVisualizer {
    unit_id: UnitId,
    path: Vec<WorldPos>,
    move_helper: MoveHelper,
    speed: ZFloat,
}

impl EventVisualizer for EventMoveVisualizer {
    fn is_finished(&self) -> bool {
        self.path.len() == 1
    }

    fn draw(&mut self, scene: &mut Scene, dtime: &Time) {
        let pos = self.move_helper.step(dtime);
        {
            let marker_node = scene.node(&marker_id(&self.unit_id));
            marker_node.pos.v = pos.v.add_v(&vec3_z(geom::HEX_EX_RADIUS / 2.0));
        }
        let node_id = unit_id_to_node_id(&self.unit_id);
        let node = scene.node(&node_id);
        node.pos = pos;
        if self.move_helper.is_finished() {
            let _ = self.path.remove(0);
            if self.path.len() > 1 {
                self.update_waypoint(node);
            }
            node.pos = self.current_waypoint().clone();
        }
    }

    fn end(&mut self, scene: &mut Scene, _: &GameState) {
        assert!(self.path.len() == 1);
        let node_id = unit_id_to_node_id(&self.unit_id);
        let node = scene.node(&node_id);
        node.pos = self.current_waypoint().clone();
    }
}

impl EventMoveVisualizer {
    pub fn new(
        scene: &mut Scene,
        _: &GameState,
        unit_id: UnitId,
        unit_type_visual_info: &UnitTypeVisualInfo,
        path: MapPath,
    ) -> Box<EventVisualizer> {
        let mut world_path = Vec::new();
        for path_node in path.nodes().iter() {
            let world_pos = geom::map_pos_to_world_pos(&path_node.pos);
            world_path.push(world_pos);
        }
        let speed = unit_type_visual_info.move_speed;
        let node_id = unit_id_to_node_id(&unit_id);
        let node = scene.node(&node_id);
        node.rot = geom::get_rot_angle(
            &world_path[0], &world_path[1]);
        let move_helper = MoveHelper::new(
            &world_path[0], &world_path[1], speed);
        let mut vis = box EventMoveVisualizer {
            unit_id: unit_id.clone(),
            path: world_path,
            move_helper: move_helper,
            speed: speed,
        };
        vis.update_waypoint(node);
        vis as Box<EventVisualizer>
    }

    fn update_waypoint(&mut self, node: &mut SceneNode) {
        self.move_helper = MoveHelper::new(
            self.current_waypoint(),
            self.next_waypoint(),
            self.speed,
        );
        node.rot = geom::get_rot_angle(
            self.current_waypoint(),
            self.next_waypoint()
        );
    }

    fn current_waypoint(&self) -> &WorldPos {
        assert!(self.path.len() >= 1);
        &self.path[0]
    }

    fn next_waypoint(&self) -> &WorldPos {
        assert!(self.path.len() >= 2);
        &self.path[1]
    }
}

pub struct EventEndTurnVisualizer;

impl EventEndTurnVisualizer {
    pub fn new() -> Box<EventVisualizer> {
        box EventEndTurnVisualizer as Box<EventVisualizer>
    }
}

impl EventVisualizer for EventEndTurnVisualizer {
    fn is_finished(&self) -> bool {
        true
    }

    fn draw(&mut self, _: &mut Scene, _: &Time) {}

    fn end(&mut self, _: &mut Scene, _: &GameState) {}
}

fn show_unit_at(
    core: &core::Core,
    scene: &mut Scene,
    id: &UnitId,
    type_id: &UnitTypeId,
    pos: &MapPos,
    mesh_id: &MeshId,
    marker_mesh_id: &MeshId,
) {
    let node_id = unit_id_to_node_id(id);
    let world_pos = geom::map_pos_to_world_pos(pos);
    let to = world_pos;
    let rot = rad(thread_rng().gen_range(0.0, PI * 2.0));
    scene.nodes.insert(node_id, SceneNode {
        pos: to.clone(),
        rot: rot,
        mesh_id: None,
        children: get_unit_scene_nodes(core, type_id, mesh_id),
    });
    scene.nodes.insert(marker_id(id), SceneNode {
        pos: WorldPos{v: to.v.add_v(&vec3_z(geom::HEX_EX_RADIUS / 2.0))},
        rot: rad(0.0),
        mesh_id: Some(marker_mesh_id.clone()),
        children: Vec::new(),
    });
}

pub struct EventCreateUnitVisualizer {
    id: UnitId,
    move_helper: MoveHelper,
}

fn get_unit_scene_nodes(
    core: &core::Core,
    type_id: &UnitTypeId,
    mesh_id: &MeshId,
) -> Vec<SceneNode> {
    let count = core.object_types().get_unit_type(type_id).count;
    let mut vec = Vec::new();
    if count == 1 {
        vec![SceneNode {
            pos: WorldPos{v: Vector3{x: 0.0, y: 0.0, z: 0.0}},
            rot: rad(0.0),
            mesh_id: Some(mesh_id.clone()),
            children: vec![],
        }]
    } else {
        for i in 0 .. count {
            let pos = geom::index_to_circle_vertex(count, i).v.mul_s(0.3f32);
            vec.push(SceneNode {
                pos: WorldPos{v: pos},
                rot: rad(0.0),
                mesh_id: Some(mesh_id.clone()),
                children: vec![],
            });
        }
        vec
    }
}

impl EventCreateUnitVisualizer {
    pub fn new(
        core: &core::Core,
        scene: &mut Scene,
        _: &GameState,
        id: UnitId,
        type_id: &UnitTypeId,
        pos: &MapPos,
        mesh_id: &MeshId,
        marker_mesh_id: &MeshId,
    ) -> Box<EventVisualizer> {
        let node_id = unit_id_to_node_id(&id);
        let to = geom::map_pos_to_world_pos(pos);
        let from = WorldPos{v: to.v.sub_v(&vec3_z(geom::HEX_EX_RADIUS / 2.0))};
        show_unit_at(core, scene, &id, type_id, pos, mesh_id, marker_mesh_id);
        let move_helper = MoveHelper::new(&from, &to, 1.0);
        scene.nodes.get_mut(&node_id).unwrap().pos = from.clone();
        box EventCreateUnitVisualizer {
            id: id,
            move_helper: move_helper,
        } as Box<EventVisualizer>
    }
}

impl EventVisualizer for EventCreateUnitVisualizer {
    fn is_finished(&self) -> bool {
        self.move_helper.is_finished()
    }

    fn draw(&mut self, scene: &mut Scene, dtime: &Time) {
        let node_id = unit_id_to_node_id(&self.id);
        let node = scene.node(&node_id);
        node.pos = self.move_helper.step(dtime);
    }

    fn end(&mut self, _: &mut Scene, _: &GameState) {}
}

fn vec3_z(z: ZFloat) -> Vector3<ZFloat> {
    Vector3{x: 0.0, y: 0.0, z: z}
}

pub struct EventAttackUnitVisualizer {
    defender_id: UnitId,
    killed: bool,
    move_helper: MoveHelper,
    shell_move: MoveHelper,
}

impl EventAttackUnitVisualizer {
    pub fn new(
        zgl: &Zgl,
        scene: &mut Scene,
        _: &GameState,
        attacker_id: UnitId,
        defender_id: UnitId,
        killed: bool,
        mode: core::FireMode,
        shell_mesh_id: MeshId,
        map_text: &mut MapTextManager,
        font_stash: &mut FontStash,
    ) -> Box<EventVisualizer> {
        let node_id = unit_id_to_node_id(&defender_id);
        let from = scene.nodes.get(&node_id)
            .expect("Can not find defender scene node")
            .pos.clone();
        let to = WorldPos{v: from.v.sub_v(&vec3_z(geom::HEX_EX_RADIUS / 2.0))};
        let move_helper = MoveHelper::new(&from, &to, 1.0);
        let attacker_pos = scene.nodes.get(&unit_id_to_node_id(&attacker_id))
            .expect("Can not find attacker").pos.clone();
        let defender_pos = scene.nodes.get(&unit_id_to_node_id(&defender_id))
            .expect("Can not find defender").pos.clone();
        let shell_move = {
            scene.nodes.insert(SHELL_NODE_ID, SceneNode {
                pos: from.clone(),
                rot: rad(0.0),
                mesh_id: Some(shell_mesh_id),
                children: Vec::new(),
            });
            MoveHelper::new(&attacker_pos, &defender_pos, 10.0)
        };
        if killed {
            map_text.add_text_to_world_pos(zgl, font_stash, "-1", &defender_pos);
        } else {
            map_text.add_text_to_world_pos(zgl, font_stash, "miss", &defender_pos);
        }
        match mode {
            core::FireMode::Reactive => {
                map_text.add_text_to_world_pos(zgl, font_stash, "reaction fire", &attacker_pos);
            },
            core::FireMode::Active => {},
        }
        box EventAttackUnitVisualizer {
            defender_id: defender_id,
            killed: killed,
            move_helper: move_helper,
            shell_move: shell_move,
        } as Box<EventVisualizer>
    }
}

impl EventVisualizer for EventAttackUnitVisualizer {
    fn is_finished(&self) -> bool {
        if self.killed {
            self.move_helper.is_finished()
        } else {
            self.shell_move.is_finished()
        }
    }

    fn draw(&mut self, scene: &mut Scene, dtime: &Time) {
        scene.node(&SHELL_NODE_ID).pos = self.shell_move.step(dtime);
        if self.killed {
            if self.shell_move.is_finished() {
                let node_id = unit_id_to_node_id(&self.defender_id);
                scene.node(&node_id).pos = self.move_helper.step(dtime);
            }
        }
    }

    fn end(&mut self, scene: &mut Scene, _: &GameState) {
        if self.killed {
            let node_id = unit_id_to_node_id(&self.defender_id);
            scene.nodes.remove(&node_id);
            scene.nodes.remove(&marker_id(&self.defender_id));
        }
        scene.nodes.remove(&SHELL_NODE_ID);
    }
}

pub struct EventShowUnitVisualizer;

impl EventShowUnitVisualizer {
    pub fn new(
        core: &core::Core,
        scene: &mut Scene,
        _: &GameState,
        id: UnitId,
        type_id: &UnitTypeId,
        pos: &MapPos,
        mesh_id: &MeshId,
        marker_mesh_id: &MeshId,
    ) -> Box<EventVisualizer> {
        show_unit_at(core, scene, &id, type_id, pos, mesh_id, marker_mesh_id);
        box EventShowUnitVisualizer as Box<EventVisualizer>
    }
}

impl EventVisualizer for EventShowUnitVisualizer {
    fn is_finished(&self) -> bool {
        true
    }

    fn draw(&mut self, _: &mut Scene, _: &Time) {}

    fn end(&mut self, _: &mut Scene, _: &GameState) {}
}

pub struct EventHideUnitVisualizer;

impl EventHideUnitVisualizer {
    pub fn new(scene: &mut Scene, unit_id: &UnitId) -> Box<EventVisualizer> {
        scene.nodes.remove(&unit_id_to_node_id(&unit_id));
        scene.nodes.remove(&marker_id(&unit_id));
        box EventHideUnitVisualizer as Box<EventVisualizer>
    }
}

impl EventVisualizer for EventHideUnitVisualizer {
    fn is_finished(&self) -> bool {
        true
    }

    fn draw(&mut self, _: &mut Scene, _: &Time) {}

    fn end(&mut self, _: &mut Scene, _: &GameState) {}
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use nom::{
    branch::alt,
    bytes::streaming::{tag, tag_no_case, take, take_while, take_while1},
    character::streaming::{char, digit1},
    combinator::{map, map_res},
    multi::{separated_list, separated_nonempty_list},
    sequence::{delimited, tuple},
    IResult,
};

use std::str::{from_utf8, FromStr};

// ----- number -----

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
pub fn number(i: &[u8]) -> IResult<&[u8], u32> {
    let (i, bytes) = digit1(i)?;
    match from_utf8(bytes).ok().and_then(|s| u32::from_str(s).ok()) {
        Some(v) => Ok((i, v)),
        None => Err(nom::Err::Error(nom::error::make_error(
            i,
            nom::error::ErrorKind::ParseTo,
        ))),
    }
}

// same as `number` but 64-bit
pub fn number_64(i: &[u8]) -> IResult<&[u8], u64> {
    let (i, bytes) = digit1(i)?;
    match from_utf8(bytes).ok().and_then(|s| u64::from_str(s).ok()) {
        Some(v) => Ok((i, v)),
        None => Err(nom::Err::Error(nom::error::make_error(
            i,
            nom::error::ErrorKind::ParseTo,
        ))),
    }
}

// ----- string -----

// string = quoted / literal
pub fn string(i: &[u8]) -> IResult<&[u8], &[u8]> {
    alt((quoted, literal))(i)
}

// string bytes as utf8
pub fn string_utf8(i: &[u8]) -> IResult<&[u8], &str> {
    map_res(string, from_utf8)(i)
}

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
pub fn quoted(i: &[u8]) -> IResult<&[u8], &[u8]> {
    delimited(char('"'), quoted_data, char('"'))(i)
}

// quoted bytes as utf8
pub fn quoted_utf8(i: &[u8]) -> IResult<&[u8], &str> {
    map_res(quoted, from_utf8)(i)
}

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted-specials = DQUOTE / "\"
pub fn is_quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let parser = tuple((tag(b"{"), number, tag(b"}"), tag("\r\n")));

    let (remaining, (_, count, _, _)) = parser(input)?;

    let (remaining, data) = take(count)(remaining)?;

    if !data.iter().all(|byte| is_char8(*byte)) {
        // FIXME: what ErrorKind should this have?
        return Err(nom::Err::Error((remaining, nom::error::ErrorKind::Verify)));
    }

    Ok((remaining, data))
}

/// CHAR8 = %x01-ff ; any OCTET except NUL, %x00
pub fn is_char8(i: u8) -> bool {
    i != 0
}

// ----- astring ----- atom (roughly) or string

// astring = 1*ASTRING-CHAR / string
pub fn astring(i: &[u8]) -> IResult<&[u8], &[u8]> {
    alt((take_while1(is_astring_char), string))(i)
}

// astring bytes as utf8
pub fn astring_utf8(i: &[u8]) -> IResult<&[u8], &str> {
    map_res(astring, from_utf8)(i)
}

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn is_astring_char(c: u8) -> bool {
    is_atom_char(c) || is_resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn is_atom_char(c: u8) -> bool {
    is_char(c) && !is_atom_specials(c)
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn is_atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || is_list_wildcards(c)
        || is_quoted_specials(c)
        || is_resp_specials(c)
}

// resp-specials = "]"
pub fn is_resp_specials(c: u8) -> bool {
    c == b']'
}

// atom = 1*ATOM-CHAR
pub fn atom(i: &[u8]) -> IResult<&[u8], &str> {
    map_res(take_while1(is_atom_char), from_utf8)(i)
}

// ----- nstring ----- nil or string

// nstring = string / nil
pub fn nstring(i: &[u8]) -> IResult<&[u8], Option<&[u8]>> {
    alt((map(nil, |_| None), map(string, Some)))(i)
}

// nstring bytes as utf8
pub fn nstring_utf8(i: &[u8]) -> IResult<&[u8], Option<&str>> {
    alt((map(nil, |_| None), map(string_utf8, Some)))(i)
}

// nil = "NIL"
pub fn nil(i: &[u8]) -> IResult<&[u8], &[u8]> {
    tag_no_case("NIL")(i)
}

// ----- text -----

// text = 1*TEXT-CHAR
pub fn text(i: &[u8]) -> IResult<&[u8], &str> {
    map_res(take_while(is_text_char), from_utf8)(i)
}

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn is_text_char(c: u8) -> bool {
    is_char(c) && c != b'\r' && c != b'\n'
}

// CHAR = %x01-7F
//          ; any 7-bit US-ASCII character,
//          ;  excluding NUL
// From RFC5234
pub fn is_char(c: u8) -> bool {
    match c {
        0x01..=0x7F => true,
        _ => false,
    }
}

// ----- others -----

// list-wildcards = "%" / "*"
pub fn is_list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

pub fn paren_delimited<'a, F, O, E>(f: F) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O, E>
where
    F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,
    E: nom::error::ParseError<&'a [u8]>,
{
    delimited(char('('), f, char(')'))
}

pub fn parenthesized_nonempty_list<'a, F, O, E>(
    f: F,
) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec<O>, E>
where
    F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,
    E: nom::error::ParseError<&'a [u8]>,
{
    delimited(char('('), separated_nonempty_list(char(' '), f), char(')'))
}

pub fn parenthesized_list<'a, F, O, E>(f: F) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec<O>, E>
where
    F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,
    E: nom::error::ParseError<&'a [u8]>,
{
    delimited(char('('), separated_list(char(' '), f), char(')'))
}

pub fn opt_opt<'a, F, O, E>(f: F) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Option<O>, E>
where
    F: Fn(&'a [u8]) -> IResult<&'a [u8], Option<O>, E>,
{
    move |i: &[u8]| match f(i) {
        Ok((i, o)) => Ok((i, o)),
        Err(nom::Err::Error(_)) => Ok((i, None)),
        Err(e) => Err(e),
    }
}

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

    #[test]
    fn test_quoted() {
        let (rem, val) = quoted(br#""Hello"???"#).unwrap();
        assert_eq!(rem, b"???");
        assert_eq!(val, b"Hello");

        // Allowed escapes...
        assert!(quoted(br#""Hello \" "???"#).is_ok());
        assert!(quoted(br#""Hello \\ "???"#).is_ok());

        // Not allowed escapes...
        //assert!(quoted(br#""Hello \a "???"#).is_err()); // fails
        //assert!(quoted(br#""Hello \z "???"#).is_err()); // fails
        //assert!(quoted(br#""Hello \? "???"#).is_err()); // fails

        let (rem, val) = quoted(br#""Hello \"World\""???"#).unwrap();
        assert_eq!(rem, br#"???"#);
        // Should it be this (Hello \"World\") ...
        assert_eq!(val, br#"Hello \"World\""#);
        // ... or this (Hello "World")?
        //assert_eq!(val, br#"Hello "World""#); // fails

        // Test Incomplete
        assert_matches!(quoted(br#""#), Err(nom::Err::Incomplete(_)));
        assert_matches!(quoted(br#""\"#), Err(nom::Err::Incomplete(_)));
        assert_matches!(quoted(br#""Hello "#), Err(nom::Err::Incomplete(_)));

        // Test Error
        assert_matches!(quoted(br#"\"#), Err(nom::Err::Error(_)));
    }

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<commit_msg>Fixed quoted, removed QUOTED-CHAR<commit_after>use nom::{
    branch::alt,
    bytes::streaming::{escaped, tag, tag_no_case, take, take_while, take_while1},
    character::streaming::{char, digit1, one_of},
    combinator::{map, map_res},
    multi::{separated_list, separated_nonempty_list},
    sequence::{delimited, tuple},
    IResult,
};

use std::str::{from_utf8, FromStr};

// ----- number -----

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
pub fn number(i: &[u8]) -> IResult<&[u8], u32> {
    let (i, bytes) = digit1(i)?;
    match from_utf8(bytes).ok().and_then(|s| u32::from_str(s).ok()) {
        Some(v) => Ok((i, v)),
        None => Err(nom::Err::Error(nom::error::make_error(
            i,
            nom::error::ErrorKind::ParseTo,
        ))),
    }
}

// same as `number` but 64-bit
pub fn number_64(i: &[u8]) -> IResult<&[u8], u64> {
    let (i, bytes) = digit1(i)?;
    match from_utf8(bytes).ok().and_then(|s| u64::from_str(s).ok()) {
        Some(v) => Ok((i, v)),
        None => Err(nom::Err::Error(nom::error::make_error(
            i,
            nom::error::ErrorKind::ParseTo,
        ))),
    }
}

// ----- string -----

// string = quoted / literal
pub fn string(i: &[u8]) -> IResult<&[u8], &[u8]> {
    alt((quoted, literal))(i)
}

// string bytes as utf8
pub fn string_utf8(i: &[u8]) -> IResult<&[u8], &str> {
    map_res(string, from_utf8)(i)
}

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
pub fn quoted(i: &[u8]) -> IResult<&[u8], &[u8]> {
    delimited(
        char('"'),
        escaped(
            take_while1(|byte| is_text_char(byte) && !is_quoted_specials(byte)),
            '\\',
            one_of("\\\""),
        ),
        char('"'),
    )(i)
}

// quoted bytes as utf8
pub fn quoted_utf8(i: &[u8]) -> IResult<&[u8], &str> {
    map_res(quoted, from_utf8)(i)
}

// quoted-specials = DQUOTE / "\"
pub fn is_quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let parser = tuple((tag(b"{"), number, tag(b"}"), tag("\r\n")));

    let (remaining, (_, count, _, _)) = parser(input)?;

    let (remaining, data) = take(count)(remaining)?;

    if !data.iter().all(|byte| is_char8(*byte)) {
        // FIXME: what ErrorKind should this have?
        return Err(nom::Err::Error((remaining, nom::error::ErrorKind::Verify)));
    }

    Ok((remaining, data))
}

/// CHAR8 = %x01-ff ; any OCTET except NUL, %x00
pub fn is_char8(i: u8) -> bool {
    i != 0
}

// ----- astring ----- atom (roughly) or string

// astring = 1*ASTRING-CHAR / string
pub fn astring(i: &[u8]) -> IResult<&[u8], &[u8]> {
    alt((take_while1(is_astring_char), string))(i)
}

// astring bytes as utf8
pub fn astring_utf8(i: &[u8]) -> IResult<&[u8], &str> {
    map_res(astring, from_utf8)(i)
}

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn is_astring_char(c: u8) -> bool {
    is_atom_char(c) || is_resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn is_atom_char(c: u8) -> bool {
    is_char(c) && !is_atom_specials(c)
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn is_atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || is_list_wildcards(c)
        || is_quoted_specials(c)
        || is_resp_specials(c)
}

// resp-specials = "]"
pub fn is_resp_specials(c: u8) -> bool {
    c == b']'
}

// atom = 1*ATOM-CHAR
pub fn atom(i: &[u8]) -> IResult<&[u8], &str> {
    map_res(take_while1(is_atom_char), from_utf8)(i)
}

// ----- nstring ----- nil or string

// nstring = string / nil
pub fn nstring(i: &[u8]) -> IResult<&[u8], Option<&[u8]>> {
    alt((map(nil, |_| None), map(string, Some)))(i)
}

// nstring bytes as utf8
pub fn nstring_utf8(i: &[u8]) -> IResult<&[u8], Option<&str>> {
    alt((map(nil, |_| None), map(string_utf8, Some)))(i)
}

// nil = "NIL"
pub fn nil(i: &[u8]) -> IResult<&[u8], &[u8]> {
    tag_no_case("NIL")(i)
}

// ----- text -----

// text = 1*TEXT-CHAR
pub fn text(i: &[u8]) -> IResult<&[u8], &str> {
    map_res(take_while(is_text_char), from_utf8)(i)
}

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn is_text_char(c: u8) -> bool {
    is_char(c) && c != b'\r' && c != b'\n'
}

// CHAR = %x01-7F
//          ; any 7-bit US-ASCII character,
//          ;  excluding NUL
// From RFC5234
pub fn is_char(c: u8) -> bool {
    match c {
        0x01..=0x7F => true,
        _ => false,
    }
}

// ----- others -----

// list-wildcards = "%" / "*"
pub fn is_list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

pub fn paren_delimited<'a, F, O, E>(f: F) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O, E>
where
    F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,
    E: nom::error::ParseError<&'a [u8]>,
{
    delimited(char('('), f, char(')'))
}

pub fn parenthesized_nonempty_list<'a, F, O, E>(
    f: F,
) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec<O>, E>
where
    F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,
    E: nom::error::ParseError<&'a [u8]>,
{
    delimited(char('('), separated_nonempty_list(char(' '), f), char(')'))
}

pub fn parenthesized_list<'a, F, O, E>(f: F) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec<O>, E>
where
    F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,
    E: nom::error::ParseError<&'a [u8]>,
{
    delimited(char('('), separated_list(char(' '), f), char(')'))
}

pub fn opt_opt<'a, F, O, E>(f: F) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Option<O>, E>
where
    F: Fn(&'a [u8]) -> IResult<&'a [u8], Option<O>, E>,
{
    move |i: &[u8]| match f(i) {
        Ok((i, o)) => Ok((i, o)),
        Err(nom::Err::Error(_)) => Ok((i, None)),
        Err(e) => Err(e),
    }
}

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

    #[test]
    fn test_quoted() {
        let (rem, val) = quoted(br#""Hello"???"#).unwrap();
        assert_eq!(rem, b"???");
        assert_eq!(val, b"Hello");

        // Allowed escapes...
        assert!(quoted(br#""Hello \" "???"#).is_ok());
        assert!(quoted(br#""Hello \\ "???"#).is_ok());

        // Not allowed escapes...
        assert!(quoted(br#""Hello \a "???"#).is_err());
        assert!(quoted(br#""Hello \z "???"#).is_err());
        assert!(quoted(br#""Hello \? "???"#).is_err());

        let (rem, val) = quoted(br#""Hello \"World\""???"#).unwrap();
        assert_eq!(rem, br#"???"#);
        // Should it be this (Hello \"World\") ...
        assert_eq!(val, br#"Hello \"World\""#);
        // ... or this (Hello "World")?
        //assert_eq!(val, br#"Hello "World""#); // fails

        // Test Incomplete
        assert_matches!(quoted(br#""#), Err(nom::Err::Incomplete(_)));
        assert_matches!(quoted(br#""\"#), Err(nom::Err::Incomplete(_)));
        assert_matches!(quoted(br#""Hello "#), Err(nom::Err::Incomplete(_)));

        // Test Error
        assert_matches!(quoted(br#"\"#), Err(nom::Err::Error(_)));
    }

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<|endoftext|>


<commit_before>use std::any::{Any, TypeId};

use dces::prelude::Entity;

use super::{Event, EventStrategy};

#[derive(Debug)]
pub enum EventError {
    WrongType(TypeId),
}

#[derive(Debug)]
pub struct EventBox {
    event: Box<dyn Any>,
    event_type: TypeId,
    pub source: Entity,
    pub strategy: EventStrategy,
}

impl EventBox {
    pub fn new<E: Event>(event: E, strategy: EventStrategy, source: Entity) -> Self {
        EventBox {
            event: Box::new(event),
            source,
            event_type: TypeId::of::<E>(),
            strategy,
        }
    }

    pub fn is_type<E: Event>(&self) -> bool {
        self.event_type == TypeId::of::<E>()
    }

    pub fn event_type(&self) -> TypeId {
        self.event_type
    }

    pub fn downcast<E: Event>(self) -> Result<E, EventError> {
        if self.event_type == TypeId::of::<E>() {
            return Ok(*self.event.downcast::<E>().unwrap());
        }

        Err(EventError::WrongType(TypeId::of::<E>()))
    }

    pub fn downcast_ref<E: Any>(&self) -> Result<&E, EventError> {
        if self.event_type == TypeId::of::<E>() {
            return Ok(&*self.event.downcast_ref::<E>().unwrap());
        }

        Err(EventError::WrongType(TypeId::of::<E>()))
    }
}

#[derive(Default, Debug)]
pub struct EventQueue {
    event_queue: Vec<EventBox>,
}

impl EventQueue {
    pub fn append(&mut self, other: &mut Vec<EventBox>) {
        self.event_queue.append(other);
    }

    pub fn register_event_with_strategy<E: Event>(
        &mut self,
        event: E,
        strategy: EventStrategy,
        source: Entity,
    ) {
        self.event_queue
            .push(EventBox::new::<E>(event, strategy, source));
    }

    // todo rename to enqueue event
    pub fn register_event<E: Event>(&mut self, event: E, source: Entity) {
        self.event_queue
            .push(EventBox::new::<E>(event, EventStrategy::BottomUp, source));
    }

    pub fn dequeue(&mut self) -> Option<EventBox> {
        if !self.event_queue.is_empty() {
            return Some(self.event_queue.remove(0));
        }

        None
    }

    pub fn len(&self) -> usize {
        self.event_queue.len()
    }

    pub fn is_empty(&self) -> bool {
        self.event_queue.is_empty()
    }
}

impl<'a> IntoIterator for &'a mut EventQueue {
    type Item = EventBox;
    type IntoIter = EventQeueIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        EventQeueIterator { event_queue: self }
    }
}

pub struct EventQeueIterator<'a> {
    event_queue: &'a mut EventQueue,
}

impl<'a> Iterator for EventQeueIterator<'a> {
    type Item = EventBox;

    fn next(&mut self) -> Option<EventBox> {
        self.event_queue.dequeue()
    }
}
<commit_msg>Fix typo on EventQueueIterator<commit_after>use std::any::{Any, TypeId};

use dces::prelude::Entity;

use super::{Event, EventStrategy};

#[derive(Debug)]
pub enum EventError {
    WrongType(TypeId),
}

#[derive(Debug)]
pub struct EventBox {
    event: Box<dyn Any>,
    event_type: TypeId,
    pub source: Entity,
    pub strategy: EventStrategy,
}

impl EventBox {
    pub fn new<E: Event>(event: E, strategy: EventStrategy, source: Entity) -> Self {
        EventBox {
            event: Box::new(event),
            source,
            event_type: TypeId::of::<E>(),
            strategy,
        }
    }

    pub fn is_type<E: Event>(&self) -> bool {
        self.event_type == TypeId::of::<E>()
    }

    pub fn event_type(&self) -> TypeId {
        self.event_type
    }

    pub fn downcast<E: Event>(self) -> Result<E, EventError> {
        if self.event_type == TypeId::of::<E>() {
            return Ok(*self.event.downcast::<E>().unwrap());
        }

        Err(EventError::WrongType(TypeId::of::<E>()))
    }

    pub fn downcast_ref<E: Any>(&self) -> Result<&E, EventError> {
        if self.event_type == TypeId::of::<E>() {
            return Ok(&*self.event.downcast_ref::<E>().unwrap());
        }

        Err(EventError::WrongType(TypeId::of::<E>()))
    }
}

#[derive(Default, Debug)]
pub struct EventQueue {
    event_queue: Vec<EventBox>,
}

impl EventQueue {
    pub fn append(&mut self, other: &mut Vec<EventBox>) {
        self.event_queue.append(other);
    }

    pub fn register_event_with_strategy<E: Event>(
        &mut self,
        event: E,
        strategy: EventStrategy,
        source: Entity,
    ) {
        self.event_queue
            .push(EventBox::new::<E>(event, strategy, source));
    }

    // todo rename to enqueue event
    pub fn register_event<E: Event>(&mut self, event: E, source: Entity) {
        self.event_queue
            .push(EventBox::new::<E>(event, EventStrategy::BottomUp, source));
    }

    pub fn dequeue(&mut self) -> Option<EventBox> {
        if !self.event_queue.is_empty() {
            return Some(self.event_queue.remove(0));
        }

        None
    }

    pub fn len(&self) -> usize {
        self.event_queue.len()
    }

    pub fn is_empty(&self) -> bool {
        self.event_queue.is_empty()
    }
}

impl<'a> IntoIterator for &'a mut EventQueue {
    type Item = EventBox;
    type IntoIter = EventQueueIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        EventQueueIterator { event_queue: self }
    }
}

pub struct EventQueueIterator<'a> {
    event_queue: &'a mut EventQueue,
}

impl<'a> Iterator for EventQueueIterator<'a> {
    type Item = EventBox;

    fn next(&mut self) -> Option<EventBox> {
        self.event_queue.dequeue()
    }
}
<|endoftext|>


<commit_before>use itertools::Itertools;

use ra_syntax::{
    ast::{self, AstNode},
    Location,
    SourceFileNode,
    SyntaxKind,
    TextRange,
};
use ra_text_edit::{
    TextEdit,
    TextEditBuilder,
};

use crate::{
    Diagnostic,
    LocalEdit,
    Severity,
};

pub fn diagnostics(file: &SourceFileNode) -> Vec<Diagnostic> {
    fn location_to_range(location: Location) -> TextRange {
        match location {
            Location::Offset(offset) => TextRange::offset_len(offset, 1.into()),
            Location::Range(range) => range,
        }
    }

    let mut errors: Vec<Diagnostic> = file
        .errors()
        .into_iter()
        .map(|err| Diagnostic {
            range: location_to_range(err.location()),
            msg: format!("Syntax Error: {}", err),
            severity: Severity::Error,
            fix: None,
        })
        .collect();

    errors.extend(check_unnecessary_braces_in_use_statement(file));
    errors.extend(check_struct_shorthand_initialization(file));
    errors
}

fn check_unnecessary_braces_in_use_statement(file: &SourceFileNode) -> Vec<Diagnostic> {
    let mut diagnostics = Vec::new();
    for use_tree_list in file
        .syntax()
        .descendants()
        .filter_map(ast::UseTreeList::cast)
    {
        if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
            let range = use_tree_list.syntax().range();
            let edit =
                text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(single_use_tree)
                    .unwrap_or_else(|| {
                        let to_replace = single_use_tree.syntax().text().to_string();
                        let mut edit_builder = TextEditBuilder::new();
                        edit_builder.delete(range);
                        edit_builder.insert(range.start(), to_replace);
                        edit_builder.finish()
                    });

            diagnostics.push(Diagnostic {
                range,
                msg: format!("Unnecessary braces in use statement"),
                severity: Severity::WeakWarning,
                fix: Some(LocalEdit {
                    label: "Remove unnecessary braces".to_string(),
                    edit,
                    cursor_position: None,
                }),
            })
        }
    }

    diagnostics
}

fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
    single_use_tree: ast::UseTree,
) -> Option<TextEdit> {
    let use_tree_list_node = single_use_tree.syntax().parent()?;
    if single_use_tree
        .path()?
        .segment()?
        .syntax()
        .first_child()?
        .kind()
        == SyntaxKind::SELF_KW
    {
        let start = use_tree_list_node.prev_sibling()?.range().start();
        let end = use_tree_list_node.range().end();
        let range = TextRange::from_to(start, end);
        let mut edit_builder = TextEditBuilder::new();
        edit_builder.delete(range);
        return Some(edit_builder.finish());
    }
    None
}

fn check_struct_shorthand_initialization(file: &SourceFileNode) -> Vec<Diagnostic> {
    let mut diagnostics = Vec::new();
    for struct_lit in file.syntax().descendants().filter_map(ast::StructLit::cast) {
        if let Some(named_field_list) = struct_lit.named_field_list() {
            for named_field in named_field_list.fields() {
                if let (Some(name_ref), Some(expr)) = (named_field.name_ref(), named_field.expr()) {
                    let field_name = name_ref.syntax().text().to_string();
                    let field_expr = expr.syntax().text().to_string();
                    if field_name == field_expr {
                        let mut edit_builder = TextEditBuilder::new();
                        edit_builder.delete(named_field.syntax().range());
                        edit_builder.insert(named_field.syntax().range().start(), field_name);
                        let edit = edit_builder.finish();

                        diagnostics.push(Diagnostic {
                            range: named_field.syntax().range(),
                            msg: format!("Shorthand struct initialization"),
                            severity: Severity::WeakWarning,
                            fix: Some(LocalEdit {
                                label: "use struct shorthand initialization".to_string(),
                                edit,
                                cursor_position: None,
                            }),
                        });
                    }
                }
            }
        }
    }
    diagnostics
}

#[cfg(test)]
mod tests {
    use crate::test_utils::assert_eq_text;

    use super::*;

    fn check_not_applicable(code: &str, func: fn(file: &SourceFileNode) -> Vec<Diagnostic>) {
        let file = SourceFileNode::parse(code);
        let diagnostics = func(&file);
        assert!(diagnostics.is_empty());
    }

    fn check_apply(before: &str, after: &str, func: fn(file: &SourceFileNode) -> Vec<Diagnostic>) {
        let file = SourceFileNode::parse(before);
        let diagnostic = func(&file)
            .pop()
            .unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before));
        let fix = diagnostic.fix.unwrap();
        let actual = fix.edit.apply(&before);
        assert_eq_text!(after, &actual);
    }

    #[test]
    fn test_check_unnecessary_braces_in_use_statement() {
        check_not_applicable(
            "
            use a;
            use a::{c, d::e};
        ",
            check_unnecessary_braces_in_use_statement,
        );
        check_apply(
            "use {b};",
            "use b;",
            check_unnecessary_braces_in_use_statement,
        );
        check_apply(
            "use a::{c};",
            "use a::c;",
            check_unnecessary_braces_in_use_statement,
        );
        check_apply(
            "use a::{self};",
            "use a;",
            check_unnecessary_braces_in_use_statement,
        );
        check_apply(
            "use a::{c, d::{e}};",
            "use a::{c, d::e};",
            check_unnecessary_braces_in_use_statement,
        );
    }

    #[test]
    fn test_check_struct_shorthand_initialization() {
        check_not_applicable(
            r#"
            struct A {
                a: &'static str
            }

            fn main() {
                A {
                    a: "hello"
                }
            }
        "#,
            check_struct_shorthand_initialization,
        );

        check_apply(
            r#"
struct A {
    a: &'static str
}

fn main() {
    let a = "haha";
    A {
        a: a
    }
}
        "#,
            r#"
struct A {
    a: &'static str
}

fn main() {
    let a = "haha";
    A {
        a
    }
}
        "#,
            check_struct_shorthand_initialization,
        );

        check_apply(
            r#"
struct A {
    a: &'static str,
    b: &'static str
}

fn main() {
    let a = "haha";
    let b = "bb";
    A {
        a: a,
        b
    }
}
        "#,
            r#"
struct A {
    a: &'static str,
    b: &'static str
}

fn main() {
    let a = "haha";
    let b = "bb";
    A {
        a,
        b
    }
}
        "#,
            check_struct_shorthand_initialization,
        );
    }
}
<commit_msg>avoid allocating an unnecessary intermediate vector & not traverse multiple times<commit_after>use itertools::Itertools;

use ra_syntax::{
    ast::{self, AstNode},
    Location,
    SourceFileNode,
    SyntaxKind,
    TextRange,
};
use ra_syntax::SyntaxNodeRef;
use ra_text_edit::{
    TextEdit,
    TextEditBuilder,
};

use crate::{
    Diagnostic,
    LocalEdit,
    Severity,
};

pub fn diagnostics(file: &SourceFileNode) -> Vec<Diagnostic> {
    fn location_to_range(location: Location) -> TextRange {
        match location {
            Location::Offset(offset) => TextRange::offset_len(offset, 1.into()),
            Location::Range(range) => range,
        }
    }

    let mut errors: Vec<Diagnostic> = file
        .errors()
        .into_iter()
        .map(|err| Diagnostic {
            range: location_to_range(err.location()),
            msg: format!("Syntax Error: {}", err),
            severity: Severity::Error,
            fix: None,
        })
        .collect();

    for node in file.syntax().descendants() {
        check_unnecessary_braces_in_use_statement(&mut errors, node);
        check_struct_shorthand_initialization(&mut errors, node);
    }

    errors
}

fn check_unnecessary_braces_in_use_statement(
    acc: &mut Vec<Diagnostic>,
    node: SyntaxNodeRef,
) -> Option<()> {
    let use_tree_list = ast::UseTreeList::cast(node)?;
    if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
        let range = use_tree_list.syntax().range();
        let edit =
            text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(single_use_tree)
                .unwrap_or_else(|| {
                    let to_replace = single_use_tree.syntax().text().to_string();
                    let mut edit_builder = TextEditBuilder::new();
                    edit_builder.delete(range);
                    edit_builder.insert(range.start(), to_replace);
                    edit_builder.finish()
                });

        acc.push(Diagnostic {
            range,
            msg: format!("Unnecessary braces in use statement"),
            severity: Severity::WeakWarning,
            fix: Some(LocalEdit {
                label: "Remove unnecessary braces".to_string(),
                edit,
                cursor_position: None,
            }),
        });
    }

    Some(())
}

fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
    single_use_tree: ast::UseTree,
) -> Option<TextEdit> {
    let use_tree_list_node = single_use_tree.syntax().parent()?;
    if single_use_tree
        .path()?
        .segment()?
        .syntax()
        .first_child()?
        .kind()
        == SyntaxKind::SELF_KW
    {
        let start = use_tree_list_node.prev_sibling()?.range().start();
        let end = use_tree_list_node.range().end();
        let range = TextRange::from_to(start, end);
        let mut edit_builder = TextEditBuilder::new();
        edit_builder.delete(range);
        return Some(edit_builder.finish());
    }
    None
}

fn check_struct_shorthand_initialization(
    acc: &mut Vec<Diagnostic>,
    node: SyntaxNodeRef,
) -> Option<()> {
    let struct_lit = ast::StructLit::cast(node)?;
    let named_field_list = struct_lit.named_field_list()?;
    for named_field in named_field_list.fields() {
        if let (Some(name_ref), Some(expr)) = (named_field.name_ref(), named_field.expr()) {
            let field_name = name_ref.syntax().text().to_string();
            let field_expr = expr.syntax().text().to_string();
            if field_name == field_expr {
                let mut edit_builder = TextEditBuilder::new();
                edit_builder.delete(named_field.syntax().range());
                edit_builder.insert(named_field.syntax().range().start(), field_name);
                let edit = edit_builder.finish();

                acc.push(Diagnostic {
                    range: named_field.syntax().range(),
                    msg: format!("Shorthand struct initialization"),
                    severity: Severity::WeakWarning,
                    fix: Some(LocalEdit {
                        label: "use struct shorthand initialization".to_string(),
                        edit,
                        cursor_position: None,
                    }),
                });
            }
        }
    }
    Some(())
}

#[cfg(test)]
mod tests {
    use crate::test_utils::assert_eq_text;

    use super::*;

    type DiagnosticChecker = fn(&mut Vec<Diagnostic>, SyntaxNodeRef) -> Option<()>;

    fn check_not_applicable(code: &str, func: DiagnosticChecker) {
        let file = SourceFileNode::parse(code);
        let mut diagnostics = Vec::new();
        for node in file.syntax().descendants() {
            func(&mut diagnostics, node);
        }
        assert!(diagnostics.is_empty());
    }

    fn check_apply(before: &str, after: &str, func: DiagnosticChecker) {
        let file = SourceFileNode::parse(before);
        let mut diagnostics = Vec::new();
        for node in file.syntax().descendants() {
            func(&mut diagnostics, node);
        }
        let diagnostic = diagnostics
            .pop()
            .unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before));
        let fix = diagnostic.fix.unwrap();
        let actual = fix.edit.apply(&before);
        assert_eq_text!(after, &actual);
    }

    #[test]
    fn test_check_unnecessary_braces_in_use_statement() {
        check_not_applicable(
            "
            use a;
            use a::{c, d::e};
        ",
            check_unnecessary_braces_in_use_statement,
        );
        check_apply(
            "use {b};",
            "use b;",
            check_unnecessary_braces_in_use_statement,
        );
        check_apply(
            "use a::{c};",
            "use a::c;",
            check_unnecessary_braces_in_use_statement,
        );
        check_apply(
            "use a::{self};",
            "use a;",
            check_unnecessary_braces_in_use_statement,
        );
        check_apply(
            "use a::{c, d::{e}};",
            "use a::{c, d::e};",
            check_unnecessary_braces_in_use_statement,
        );
    }

    #[test]
    fn test_check_struct_shorthand_initialization() {
        check_not_applicable(
            r#"
            struct A {
                a: &'static str
            }

            fn main() {
                A {
                    a: "hello"
                }
            }
        "#,
            check_struct_shorthand_initialization,
        );

        check_apply(
            r#"
struct A {
    a: &'static str
}

fn main() {
    let a = "haha";
    A {
        a: a
    }
}
        "#,
            r#"
struct A {
    a: &'static str
}

fn main() {
    let a = "haha";
    A {
        a
    }
}
        "#,
            check_struct_shorthand_initialization,
        );

        check_apply(
            r#"
struct A {
    a: &'static str,
    b: &'static str
}

fn main() {
    let a = "haha";
    let b = "bb";
    A {
        a: a,
        b
    }
}
        "#,
            r#"
struct A {
    a: &'static str,
    b: &'static str
}

fn main() {
    let a = "haha";
    let b = "bb";
    A {
        a,
        b
    }
}
        "#,
            check_struct_shorthand_initialization,
        );
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix whitespace<commit_after><|endoftext|>


<commit_before>use std::{io, iter};
use std::io::Stdout;
use std::io::prelude::*;
use term::{self, color, Terminal, StdoutTerminal};
use term::color::Color;
use slsr_core::puzzle::{Puzzle, Edge, Side};
use slsr_core::geom::{Geom, Point, Move};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Mode {
    Color,
    Ascii,
}

#[derive(Copy, Clone, Debug)]
pub struct Config {
    pub mode: Mode,
    pub cell_width: usize,
    pub cell_height: usize,
}

struct Style {
    fg: Color,
    bg: Color,
}

fn side_to_style(ty: Option<Side>) -> Style {
    match ty {
        Some(Side::In) => Style { fg: color::BLACK, bg: color::YELLOW },
        Some(Side::Out) => Style { fg: color::WHITE, bg: color::BLACK },
        None => Style { fg: color::BLACK, bg: color::WHITE },
    }
}

#[cfg(unix)]
fn isatty_stdout() -> bool {
    extern crate libc;
    unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
}
#[cfg(windows)]
fn isatty_stdout() -> bool {
    extern crate kernel32;
    extern crate winapi;
    unsafe {
        let handle = winapi::winbase::STD_OUTPUT_HANDLE as *mut winapi::c_void;
        let mut out = 0;
        kernel32::GetConsoleMode(handle, &mut out) != 0
    }
}

pub fn is_pprintable() -> bool {
    isatty_stdout()
}

trait Printer {
    fn write_pretty(&mut self, side: Option<Side>, s: &str) -> io::Result<()>;
    fn write_plain(&mut self, s: &str) -> io::Result<()>;
}

impl Printer for Stdout {
    fn write_pretty(&mut self, _side: Option<Side>, s: &str) -> io::Result<()> {
        self.write_all(s.as_bytes())
    }
    fn write_plain(&mut self, s: &str) -> io::Result<()> {
        self.write_all(s.as_bytes())
    }
}

impl Printer for Box<StdoutTerminal> {
    fn write_pretty(&mut self, side: Option<Side>, s: &str) -> io::Result<()> {
        let style = side_to_style(side);
        try!(self.reset());
        try!(self.fg(style.fg));
        try!(self.bg(style.bg));
        self.write_all(s.as_bytes())
    }
    fn write_plain(&mut self, s: &str) -> io::Result<()> {
        try!(self.reset());
        self.write_all(s.as_bytes())
    }
}

enum StdoutPrinter {
    Pretty(Box<StdoutTerminal>),
    Raw(Stdout),
}

impl StdoutPrinter {
    fn new(is_color: bool) -> StdoutPrinter {
        if !is_color {
            return StdoutPrinter::Raw(io::stdout());
        }

        match term::stdout() {
            Some(t) => StdoutPrinter::Pretty(t),
            None => StdoutPrinter::Raw(io::stdout())
        }
    }
}

struct Table {
    label_row: LabelRow,
    edge_row: EdgeRow,
    cell_row: CellRow,
}

impl Table {
    fn new(conf: &Config) -> Table {
        Table {
            label_row: LabelRow::new(conf),
            edge_row: EdgeRow::new(conf),
            cell_row: CellRow::new(conf),
        }
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle) -> io::Result<()>
        where P: Printer
    {
        let row = puzzle.row();
        try!(self.label_row.pprint(printer, puzzle));
        for y in 0..row {
            try!(self.edge_row.pprint(printer, puzzle, y));
            try!(self.cell_row.pprint(printer, puzzle, y));
        }
        try!(self.edge_row.pprint(printer, puzzle, row));
        try!(self.label_row.pprint(printer, puzzle));
        Ok(())
    }
}

struct LabelRow {
    space_left: String,
    space_cross: String,
    label: Label,
}

impl LabelRow {
    fn new(conf: &Config) -> LabelRow {
        LabelRow {
            space_left: format!("{:1$}", "", conf.cell_width),
            space_cross: format!("{:1$}", "", 1),
            label: Label::new(conf),
        }
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle) -> io::Result<()>
        where P: Printer
     {
        try!(printer.write_plain(&self.space_left));
        for x in 0..puzzle.column() {
            try!(printer.write_plain(&self.space_cross));
            try!(self.label.pprint(printer, x, true));
        }
        try!(printer.write_plain("\n"));
        Ok(())
    }
}

struct EdgeRow {
    space_left: String,
    corner: Corner,
    edge_h: EdgeH,
}

impl EdgeRow {
    fn new(conf: &Config) -> EdgeRow {
        EdgeRow {
            space_left: format!("{:1$}", "", conf.cell_width),
            corner: Corner::new(conf),
            edge_h: EdgeH::new(conf),
        }
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle, y: i32) -> io::Result<()>
        where P: Printer
    {
        let col = puzzle.column();
        try!(printer.write_plain(&self.space_left));
        for x in 0..col {
            try!(self.corner.pprint(printer, puzzle, Point(y, x)));
            try!(self.edge_h.pprint(printer, puzzle, Point(y, x)));
        }
        try!(self.corner.pprint(printer, puzzle, Point(y, col)));
        try!(printer.write_plain("\n"));
        Ok(())
    }
}

struct CellRow {
    cell_height: usize,
    edge_v: EdgeV,
    label: Label,
    cell: Cell,
}

impl CellRow {
    fn new(conf: &Config) -> CellRow {
        CellRow {
            cell_height: conf.cell_height,
            edge_v: EdgeV::new(conf),
            label: Label::new(conf),
            cell: Cell::new(conf),
        }
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle, y: i32) -> io::Result<()>
        where P: Printer
     {
        let col = puzzle.column();
        for i in 0..self.cell_height {
            let num_line = (self.cell_height - 1) / 2 == i;
            try!(self.label.pprint(printer, y, num_line));
            for x in 0..col {
                try!(self.edge_v.pprint(printer, puzzle, Point(y, x)));
                try!(self.cell.pprint(printer, puzzle, Point(y, x), num_line));
            }
            try!(self.edge_v.pprint(printer, puzzle, Point(y, col)));
            try!(self.label.pprint(printer, y, num_line));
            try!(printer.write_plain("\n"));
        }
        Ok(())
    }
}

struct Corner;
impl Corner {
    fn new(_conf: &Config) -> Corner {
        Corner
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle, p: Point) -> io::Result<()>
        where P: Printer
     {
        let l = p + Move::LEFT;
        let u = p + Move::UP;
        let eh_p = puzzle.edge_h(p);
        let eh_l = puzzle.edge_h(l);
        let ev_p = puzzle.edge_v(p);
        let ev_u = puzzle.edge_v(u);

        let is_same_all = (eh_p == Some(Edge::Cross)) && (eh_l == Some(Edge::Cross)) &&
                          (ev_p == Some((Edge::Cross))) &&
                          (ev_u == Some((Edge::Cross)));

        let side = if is_same_all {
            puzzle.side(p)
        } else {
            None
        };
        let is_h = eh_p == Some(Edge::Line) && eh_l == Some(Edge::Line);
        let is_v = ev_p == Some(Edge::Line) && ev_u == Some(Edge::Line);

        if is_same_all {
            try!(printer.write_pretty(side, "."));
        } else if is_h {
            try!(printer.write_pretty(side, "-"));
        } else if is_v {
            try!(printer.write_pretty(side, "|"));
        } else {
            try!(printer.write_pretty(side, "+"));
        }
        Ok(())
    }
}

struct EdgeH {
    str_cross: String,
    str_line: String,
    str_unknown: String,
}

impl EdgeH {
    fn new(conf: &Config) -> EdgeH {
        EdgeH {
            str_cross: iter::repeat(' ').take(conf.cell_width).collect(),
            str_line: iter::repeat('-').take(conf.cell_width).collect(),
            str_unknown: iter::repeat('~').take(conf.cell_width).collect(),
        }
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle, p: Point) -> io::Result<()>
        where P: Printer
     {
        let (s, side) = match puzzle.edge_h(p) {
            Some(Edge::Cross) => (&self.str_cross, puzzle.side(p)),
            Some(Edge::Line) => (&self.str_line, None),
            None => (&self.str_unknown, None),
        };
        try!(printer.write_pretty(side, s));
        Ok(())
    }
}

struct Label {
    width: usize,
    order: i32,
    space: String,
}

impl Label {
    fn new(conf: &Config) -> Label {
        Label {
            width: conf.cell_width,
            order: 10i32.pow(conf.cell_width as u32),
            space: format!("{:1$}", "", conf.cell_width),
        }
    }

    fn pprint<P>(&self, printer: &mut P, n: i32, num_line: bool) -> io::Result<()>
        where P: Printer
     {
        if num_line {
            try!(printer.write_plain(&format!("{:^1$}", n % self.order, self.width)));
        } else {
            try!(printer.write_plain(&self.space));
        }
        Ok(())
    }
}

struct EdgeV;

impl EdgeV {
    fn new(_conf: &Config) -> EdgeV {
        EdgeV
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle, p: Point) -> io::Result<()>
        where P: Printer
     {
        let (s, side) = match puzzle.edge_v(p) {
            Some(Edge::Cross) => (" ", puzzle.side(p)),
            Some(Edge::Line) => ("|", None),
            None => ("?", None),
        };
        try!(printer.write_pretty(side, s));
        Ok(())
    }
}

struct Cell {
    nums: [String; 5],
    space: String,
}

impl Cell {
    fn new(conf: &Config) -> Cell {
        Cell {
            nums: [format!("{:^1$}", 0, conf.cell_width),
                   format!("{:^1$}", 1, conf.cell_width),
                   format!("{:^1$}", 2, conf.cell_width),
                   format!("{:^1$}", 3, conf.cell_width),
                   format!("{:^1$}", 4, conf.cell_width)],
            space: format!("{:^1$}", "", conf.cell_width),
        }
    }

    fn pprint<P>(&self,
              printer: &mut P,
              puzzle: &Puzzle,
              p: Point,
              num_line: bool)
              -> io::Result<()>
        where P: Printer
    {
        let side = puzzle.side(p);
        match puzzle.hint(p) {
            Some(x) if num_line => {
                try!(printer.write_pretty(side, &self.nums[x as usize]))
            }
            _ => {
                try!(printer.write_pretty(side, &self.space))
            }
        }
        Ok(())
    }
}

pub fn print(conf: &Config, puzzle: &Puzzle) -> io::Result<()> {
    let is_color = conf.mode == Mode::Color;

    let table = Table::new(conf);
    match StdoutPrinter::new(is_color) {
        StdoutPrinter::Pretty(mut p) => table.pprint(&mut p, puzzle),
        StdoutPrinter::Raw(mut p) => table.pprint(&mut p, puzzle),
    }
}
<commit_msg>Run rustfmt<commit_after>use std::{io, iter};
use std::io::Stdout;
use std::io::prelude::*;
use term::{self, color, Terminal, StdoutTerminal};
use term::color::Color;
use slsr_core::puzzle::{Puzzle, Edge, Side};
use slsr_core::geom::{Geom, Point, Move};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Mode {
    Color,
    Ascii,
}

#[derive(Copy, Clone, Debug)]
pub struct Config {
    pub mode: Mode,
    pub cell_width: usize,
    pub cell_height: usize,
}

struct Style {
    fg: Color,
    bg: Color,
}

fn side_to_style(ty: Option<Side>) -> Style {
    match ty {
        Some(Side::In) => Style {
            fg: color::BLACK,
            bg: color::YELLOW,
        },
        Some(Side::Out) => Style {
            fg: color::WHITE,
            bg: color::BLACK,
        },
        None => Style {
            fg: color::BLACK,
            bg: color::WHITE,
        },
    }
}

#[cfg(unix)]
fn isatty_stdout() -> bool {
    extern crate libc;
    unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
}
#[cfg(windows)]
fn isatty_stdout() -> bool {
    extern crate kernel32;
    extern crate winapi;
    unsafe {
        let handle = winapi::winbase::STD_OUTPUT_HANDLE as *mut winapi::c_void;
        let mut out = 0;
        kernel32::GetConsoleMode(handle, &mut out) != 0
    }
}

pub fn is_pprintable() -> bool {
    isatty_stdout()
}

trait Printer {
    fn write_pretty(&mut self, side: Option<Side>, s: &str) -> io::Result<()>;
    fn write_plain(&mut self, s: &str) -> io::Result<()>;
}

impl Printer for Stdout {
    fn write_pretty(&mut self, _side: Option<Side>, s: &str) -> io::Result<()> {
        self.write_all(s.as_bytes())
    }
    fn write_plain(&mut self, s: &str) -> io::Result<()> {
        self.write_all(s.as_bytes())
    }
}

impl Printer for Box<StdoutTerminal> {
    fn write_pretty(&mut self, side: Option<Side>, s: &str) -> io::Result<()> {
        let style = side_to_style(side);
        try!(self.reset());
        try!(self.fg(style.fg));
        try!(self.bg(style.bg));
        self.write_all(s.as_bytes())
    }
    fn write_plain(&mut self, s: &str) -> io::Result<()> {
        try!(self.reset());
        self.write_all(s.as_bytes())
    }
}

enum StdoutPrinter {
    Pretty(Box<StdoutTerminal>),
    Raw(Stdout),
}

impl StdoutPrinter {
    fn new(is_color: bool) -> StdoutPrinter {
        if !is_color {
            return StdoutPrinter::Raw(io::stdout());
        }

        match term::stdout() {
            Some(t) => StdoutPrinter::Pretty(t),
            None => StdoutPrinter::Raw(io::stdout()),
        }
    }
}

struct Table {
    label_row: LabelRow,
    edge_row: EdgeRow,
    cell_row: CellRow,
}

impl Table {
    fn new(conf: &Config) -> Table {
        Table {
            label_row: LabelRow::new(conf),
            edge_row: EdgeRow::new(conf),
            cell_row: CellRow::new(conf),
        }
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle) -> io::Result<()>
        where P: Printer
    {
        let row = puzzle.row();
        try!(self.label_row.pprint(printer, puzzle));
        for y in 0..row {
            try!(self.edge_row.pprint(printer, puzzle, y));
            try!(self.cell_row.pprint(printer, puzzle, y));
        }
        try!(self.edge_row.pprint(printer, puzzle, row));
        try!(self.label_row.pprint(printer, puzzle));
        Ok(())
    }
}

struct LabelRow {
    space_left: String,
    space_cross: String,
    label: Label,
}

impl LabelRow {
    fn new(conf: &Config) -> LabelRow {
        LabelRow {
            space_left: format!("{:1$}", "", conf.cell_width),
            space_cross: format!("{:1$}", "", 1),
            label: Label::new(conf),
        }
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle) -> io::Result<()>
        where P: Printer
    {
        try!(printer.write_plain(&self.space_left));
        for x in 0..puzzle.column() {
            try!(printer.write_plain(&self.space_cross));
            try!(self.label.pprint(printer, x, true));
        }
        try!(printer.write_plain("\n"));
        Ok(())
    }
}

struct EdgeRow {
    space_left: String,
    corner: Corner,
    edge_h: EdgeH,
}

impl EdgeRow {
    fn new(conf: &Config) -> EdgeRow {
        EdgeRow {
            space_left: format!("{:1$}", "", conf.cell_width),
            corner: Corner::new(conf),
            edge_h: EdgeH::new(conf),
        }
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle, y: i32) -> io::Result<()>
        where P: Printer
    {
        let col = puzzle.column();
        try!(printer.write_plain(&self.space_left));
        for x in 0..col {
            try!(self.corner.pprint(printer, puzzle, Point(y, x)));
            try!(self.edge_h.pprint(printer, puzzle, Point(y, x)));
        }
        try!(self.corner.pprint(printer, puzzle, Point(y, col)));
        try!(printer.write_plain("\n"));
        Ok(())
    }
}

struct CellRow {
    cell_height: usize,
    edge_v: EdgeV,
    label: Label,
    cell: Cell,
}

impl CellRow {
    fn new(conf: &Config) -> CellRow {
        CellRow {
            cell_height: conf.cell_height,
            edge_v: EdgeV::new(conf),
            label: Label::new(conf),
            cell: Cell::new(conf),
        }
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle, y: i32) -> io::Result<()>
        where P: Printer
    {
        let col = puzzle.column();
        for i in 0..self.cell_height {
            let num_line = (self.cell_height - 1) / 2 == i;
            try!(self.label.pprint(printer, y, num_line));
            for x in 0..col {
                try!(self.edge_v.pprint(printer, puzzle, Point(y, x)));
                try!(self.cell.pprint(printer, puzzle, Point(y, x), num_line));
            }
            try!(self.edge_v.pprint(printer, puzzle, Point(y, col)));
            try!(self.label.pprint(printer, y, num_line));
            try!(printer.write_plain("\n"));
        }
        Ok(())
    }
}

struct Corner;
impl Corner {
    fn new(_conf: &Config) -> Corner {
        Corner
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle, p: Point) -> io::Result<()>
        where P: Printer
    {
        let l = p + Move::LEFT;
        let u = p + Move::UP;
        let eh_p = puzzle.edge_h(p);
        let eh_l = puzzle.edge_h(l);
        let ev_p = puzzle.edge_v(p);
        let ev_u = puzzle.edge_v(u);

        let is_same_all = (eh_p == Some(Edge::Cross)) && (eh_l == Some(Edge::Cross)) &&
                          (ev_p == Some((Edge::Cross))) &&
                          (ev_u == Some((Edge::Cross)));

        let side = if is_same_all {
            puzzle.side(p)
        } else {
            None
        };
        let is_h = eh_p == Some(Edge::Line) && eh_l == Some(Edge::Line);
        let is_v = ev_p == Some(Edge::Line) && ev_u == Some(Edge::Line);

        if is_same_all {
            try!(printer.write_pretty(side, "."));
        } else if is_h {
            try!(printer.write_pretty(side, "-"));
        } else if is_v {
            try!(printer.write_pretty(side, "|"));
        } else {
            try!(printer.write_pretty(side, "+"));
        }
        Ok(())
    }
}

struct EdgeH {
    str_cross: String,
    str_line: String,
    str_unknown: String,
}

impl EdgeH {
    fn new(conf: &Config) -> EdgeH {
        EdgeH {
            str_cross: iter::repeat(' ').take(conf.cell_width).collect(),
            str_line: iter::repeat('-').take(conf.cell_width).collect(),
            str_unknown: iter::repeat('~').take(conf.cell_width).collect(),
        }
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle, p: Point) -> io::Result<()>
        where P: Printer
    {
        let (s, side) = match puzzle.edge_h(p) {
            Some(Edge::Cross) => (&self.str_cross, puzzle.side(p)),
            Some(Edge::Line) => (&self.str_line, None),
            None => (&self.str_unknown, None),
        };
        try!(printer.write_pretty(side, s));
        Ok(())
    }
}

struct Label {
    width: usize,
    order: i32,
    space: String,
}

impl Label {
    fn new(conf: &Config) -> Label {
        Label {
            width: conf.cell_width,
            order: 10i32.pow(conf.cell_width as u32),
            space: format!("{:1$}", "", conf.cell_width),
        }
    }

    fn pprint<P>(&self, printer: &mut P, n: i32, num_line: bool) -> io::Result<()>
        where P: Printer
    {
        if num_line {
            try!(printer.write_plain(&format!("{:^1$}", n % self.order, self.width)));
        } else {
            try!(printer.write_plain(&self.space));
        }
        Ok(())
    }
}

struct EdgeV;

impl EdgeV {
    fn new(_conf: &Config) -> EdgeV {
        EdgeV
    }

    fn pprint<P>(&self, printer: &mut P, puzzle: &Puzzle, p: Point) -> io::Result<()>
        where P: Printer
    {
        let (s, side) = match puzzle.edge_v(p) {
            Some(Edge::Cross) => (" ", puzzle.side(p)),
            Some(Edge::Line) => ("|", None),
            None => ("?", None),
        };
        try!(printer.write_pretty(side, s));
        Ok(())
    }
}

struct Cell {
    nums: [String; 5],
    space: String,
}

impl Cell {
    fn new(conf: &Config) -> Cell {
        Cell {
            nums: [format!("{:^1$}", 0, conf.cell_width),
                   format!("{:^1$}", 1, conf.cell_width),
                   format!("{:^1$}", 2, conf.cell_width),
                   format!("{:^1$}", 3, conf.cell_width),
                   format!("{:^1$}", 4, conf.cell_width)],
            space: format!("{:^1$}", "", conf.cell_width),
        }
    }

    fn pprint<P>(&self,
                 printer: &mut P,
                 puzzle: &Puzzle,
                 p: Point,
                 num_line: bool)
                 -> io::Result<()>
        where P: Printer
    {
        let side = puzzle.side(p);
        match puzzle.hint(p) {
            Some(x) if num_line => {
                try!(printer.write_pretty(side, &self.nums[x as usize]))
            }
            _ => {
                try!(printer.write_pretty(side, &self.space))
            }
        }
        Ok(())
    }
}

pub fn print(conf: &Config, puzzle: &Puzzle) -> io::Result<()> {
    let is_color = conf.mode == Mode::Color;

    let table = Table::new(conf);
    match StdoutPrinter::new(is_color) {
        StdoutPrinter::Pretty(mut p) => table.pprint(&mut p, puzzle),
        StdoutPrinter::Raw(mut p) => table.pprint(&mut p, puzzle),
    }
}
<|endoftext|>


<commit_before>#![allow(unsafe_code)]
/// We use this because we never use the weak count on the std
/// `Arc`, but we use a LOT of `Arc`'s, so the extra 8 bytes
/// turn into a huge overhead.
use std::{
    alloc::{alloc, dealloc, Layout},
    convert::TryFrom,
    fmt::{self, Debug},
    mem,
    ops::Deref,
    ptr,
    sync::atomic::{AtomicUsize, Ordering},
};

// we make this repr(C) because we do a raw
// write to the beginning where we expect
// the rc to be.
#[repr(C)]
struct ArcInner<T: ?Sized> {
    rc: AtomicUsize,
    inner: T,
}

pub struct Arc<T: ?Sized> {
    ptr: *mut ArcInner<T>,
}

unsafe impl<T: Send + Sync + ?Sized> Send for Arc<T> {}
unsafe impl<T: Send + Sync + ?Sized> Sync for Arc<T> {}

impl<T: Debug + ?Sized> Debug for Arc<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        Debug::fmt(&**self, f)
    }
}

impl<T> Arc<T> {
    pub fn new(inner: T) -> Arc<T> {
        let bx = Box::new(ArcInner { inner, rc: AtomicUsize::new(1) });
        let ptr = Box::into_raw(bx);
        Arc { ptr }
    }

    // See std::sync::arc::Arc::copy_from_slice,
    // "Unsafe because the caller must either take ownership or bind `T: Copy`"
    unsafe fn copy_from_slice(s: &[T]) -> Arc<[T]> {
        let align =
            std::cmp::max(mem::align_of::<T>(), mem::align_of::<AtomicUsize>());

        let rc_width = std::cmp::max(align, mem::size_of::<AtomicUsize>());
        let data_width = mem::size_of::<T>().checked_mul(s.len()).unwrap();

        let size_unpadded = rc_width.checked_add(data_width).unwrap();
        // Pad size out to alignment
        let size_padded = (size_unpadded + align - 1) & !(align - 1);

        let layout = Layout::from_size_align(size_padded, align).unwrap();

        let ptr = alloc(layout);

        assert!(!ptr.is_null(), "failed to allocate Arc");
        #[allow(clippy::cast_ptr_alignment)]
        ptr::write(ptr as _, AtomicUsize::new(1));

        let data_ptr = ptr.add(rc_width);
        ptr::copy_nonoverlapping(s.as_ptr(), data_ptr as _, s.len());

        let fat_ptr: *const ArcInner<[T]> = Arc::fatten(ptr, s.len());

        Arc { ptr: fat_ptr as *mut _ }
    }

    /// <https://users.rust-lang.org/t/construct-fat-pointer-to-struct/29198/9>
    #[allow(trivial_casts)]
    fn fatten(data: *const u8, len: usize) -> *const ArcInner<[T]> {
        // Requirements of slice::from_raw_parts.
        assert!(!data.is_null());
        assert!(isize::try_from(len).is_ok());

        let slice =
            unsafe { core::slice::from_raw_parts(data as *const (), len) };
        slice as *const [()] as *const _
    }

    pub fn into_raw(arc: Arc<T>) -> *const T {
        let ptr = unsafe { &(*arc.ptr).inner };
        #[allow(clippy::mem_forget)]
        mem::forget(arc);
        ptr
    }

    pub unsafe fn from_raw(ptr: *const T) -> Arc<T> {
        let align =
            std::cmp::max(mem::align_of::<T>(), mem::align_of::<AtomicUsize>());

        let rc_width = std::cmp::max(align, mem::size_of::<AtomicUsize>());

        let sub_ptr = (ptr as *const u8).sub(rc_width) as *mut ArcInner<T>;

        Arc { ptr: sub_ptr }
    }
}

impl<T: ?Sized> Arc<T> {
    pub fn strong_count(arc: &Arc<T>) -> usize {
        unsafe { (*arc.ptr).rc.load(Ordering::Acquire) }
    }

    pub fn get_mut(arc: &mut Arc<T>) -> Option<&mut T> {
        if Arc::strong_count(arc) == 1 {
            Some(unsafe { &mut arc.ptr.as_mut().unwrap().inner })
        } else {
            None
        }
    }
}

impl<T: ?Sized + Clone> Arc<T> {
    pub fn make_mut(arc: &mut Arc<T>) -> &mut T {
        if Arc::strong_count(arc) != 1 {
            *arc = Arc::new((**arc).clone());
            assert_eq!(Arc::strong_count(arc), 1);
        }
        Arc::get_mut(arc).unwrap()
    }
}

impl<T: Default> Default for Arc<T> {
    fn default() -> Arc<T> {
        Arc::new(T::default())
    }
}

impl<T: ?Sized> Clone for Arc<T> {
    fn clone(&self) -> Arc<T> {
        // safe to use Relaxed ordering below because
        // of the required synchronization for passing
        // any objects to another thread.
        let last_count =
            unsafe { (*self.ptr).rc.fetch_add(1, Ordering::Relaxed) };

        if last_count == usize::max_value() {
            #[cold]
            std::process::abort();
        }

        Arc { ptr: self.ptr }
    }
}

impl<T: ?Sized> Drop for Arc<T> {
    fn drop(&mut self) {
        unsafe {
            let rc = (*self.ptr).rc.fetch_sub(1, Ordering::Release) - 1;
            if rc == 0 {
                std::sync::atomic::fence(Ordering::Acquire);
                Box::from_raw(self.ptr);
            }
        }
    }
}

impl<T: Copy> From<&[T]> for Arc<[T]> {
    #[inline]
    fn from(s: &[T]) -> Arc<[T]> {
        unsafe { Arc::copy_from_slice(s) }
    }
}

#[allow(clippy::fallible_impl_from)]
impl<T> From<Box<[T]>> for Arc<[T]> {
    #[inline]
    fn from(b: Box<[T]>) -> Arc<[T]> {
        let len = b.len();
        unsafe {
            let src = Box::into_raw(b);
            let value_layout = Layout::for_value(&*src);
            let align = std::cmp::max(value_layout.align(), mem::align_of::<AtomicUsize>());
            let rc_width = std::cmp::max(align, mem::size_of::<AtomicUsize>());
            let unpadded_size = rc_width.checked_add(value_layout.size()).unwrap();
            let size = (unpadded_size + align - 1) & !(align - 1);
            let dst_layout = Layout::from_size_align(size, align).unwrap();
            let dst = alloc(dst_layout);
            assert!(!dst.is_null(), "failed to allocate Arc");

            #[allow(clippy::cast_ptr_alignment)]
            ptr::write(dst as _, AtomicUsize::new(1));
            let data_ptr = dst.add(rc_width);
            ptr::copy_nonoverlapping(src as *const u8, data_ptr, len);

            // free the old box memory without running Drop
            dealloc(src as *mut u8, value_layout);

            let fat_ptr: *const ArcInner<[T]> = Arc::fatten(dst, len);

            Arc { ptr: fat_ptr as *mut _ }
        }
    }
}

impl<T> From<Vec<T>> for Arc<[T]> {
    #[inline]
    fn from(mut v: Vec<T>) -> Arc<[T]> {
        unsafe {
            let arc = Arc::copy_from_slice(&v);

            // Allow the Vec to free its memory, but not destroy its contents
            v.set_len(0);

            arc
        }
    }
}

impl<T: ?Sized> Deref for Arc<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &(*self.ptr).inner }
    }
}

impl<T: ?Sized> std::borrow::Borrow<T> for Arc<T> {
    fn borrow(&self) -> &T {
        &**self
    }
}

impl<T: ?Sized> AsRef<T> for Arc<T> {
    fn as_ref(&self) -> &T {
        &**self
    }
}
<commit_msg>Add test, fix size handling<commit_after>#![allow(unsafe_code)]
/// We use this because we never use the weak count on the std
/// `Arc`, but we use a LOT of `Arc`'s, so the extra 8 bytes
/// turn into a huge overhead.
use std::{
    alloc::{alloc, dealloc, Layout},
    convert::TryFrom,
    fmt::{self, Debug},
    mem,
    ops::Deref,
    ptr,
    sync::atomic::{AtomicUsize, Ordering},
};

// we make this repr(C) because we do a raw
// write to the beginning where we expect
// the rc to be.
#[repr(C)]
struct ArcInner<T: ?Sized> {
    rc: AtomicUsize,
    inner: T,
}

pub struct Arc<T: ?Sized> {
    ptr: *mut ArcInner<T>,
}

unsafe impl<T: Send + Sync + ?Sized> Send for Arc<T> {}
unsafe impl<T: Send + Sync + ?Sized> Sync for Arc<T> {}

impl<T: Debug + ?Sized> Debug for Arc<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        Debug::fmt(&**self, f)
    }
}

impl<T> Arc<T> {
    pub fn new(inner: T) -> Arc<T> {
        let bx = Box::new(ArcInner { inner, rc: AtomicUsize::new(1) });
        let ptr = Box::into_raw(bx);
        Arc { ptr }
    }

    // See std::sync::arc::Arc::copy_from_slice,
    // "Unsafe because the caller must either take ownership or bind `T: Copy`"
    unsafe fn copy_from_slice(s: &[T]) -> Arc<[T]> {
        let align =
            std::cmp::max(mem::align_of::<T>(), mem::align_of::<AtomicUsize>());

        let rc_width = std::cmp::max(align, mem::size_of::<AtomicUsize>());
        let data_width = mem::size_of::<T>().checked_mul(s.len()).unwrap();

        let size_unpadded = rc_width.checked_add(data_width).unwrap();
        // Pad size out to alignment
        let size_padded = (size_unpadded + align - 1) & !(align - 1);

        let layout = Layout::from_size_align(size_padded, align).unwrap();

        let ptr = alloc(layout);

        assert!(!ptr.is_null(), "failed to allocate Arc");
        #[allow(clippy::cast_ptr_alignment)]
        ptr::write(ptr as _, AtomicUsize::new(1));

        let data_ptr = ptr.add(rc_width);
        ptr::copy_nonoverlapping(s.as_ptr(), data_ptr as _, s.len());

        let fat_ptr: *const ArcInner<[T]> = Arc::fatten(ptr, s.len());

        Arc { ptr: fat_ptr as *mut _ }
    }

    /// <https://users.rust-lang.org/t/construct-fat-pointer-to-struct/29198/9>
    #[allow(trivial_casts)]
    fn fatten(data: *const u8, len: usize) -> *const ArcInner<[T]> {
        // Requirements of slice::from_raw_parts.
        assert!(!data.is_null());
        assert!(isize::try_from(len).is_ok());

        let slice =
            unsafe { core::slice::from_raw_parts(data as *const (), len) };
        slice as *const [()] as *const _
    }

    pub fn into_raw(arc: Arc<T>) -> *const T {
        let ptr = unsafe { &(*arc.ptr).inner };
        #[allow(clippy::mem_forget)]
        mem::forget(arc);
        ptr
    }

    pub unsafe fn from_raw(ptr: *const T) -> Arc<T> {
        let align =
            std::cmp::max(mem::align_of::<T>(), mem::align_of::<AtomicUsize>());

        let rc_width = std::cmp::max(align, mem::size_of::<AtomicUsize>());

        let sub_ptr = (ptr as *const u8).sub(rc_width) as *mut ArcInner<T>;

        Arc { ptr: sub_ptr }
    }
}

impl<T: ?Sized> Arc<T> {
    pub fn strong_count(arc: &Arc<T>) -> usize {
        unsafe { (*arc.ptr).rc.load(Ordering::Acquire) }
    }

    pub fn get_mut(arc: &mut Arc<T>) -> Option<&mut T> {
        if Arc::strong_count(arc) == 1 {
            Some(unsafe { &mut arc.ptr.as_mut().unwrap().inner })
        } else {
            None
        }
    }
}

impl<T: ?Sized + Clone> Arc<T> {
    pub fn make_mut(arc: &mut Arc<T>) -> &mut T {
        if Arc::strong_count(arc) != 1 {
            *arc = Arc::new((**arc).clone());
            assert_eq!(Arc::strong_count(arc), 1);
        }
        Arc::get_mut(arc).unwrap()
    }
}

impl<T: Default> Default for Arc<T> {
    fn default() -> Arc<T> {
        Arc::new(T::default())
    }
}

impl<T: ?Sized> Clone for Arc<T> {
    fn clone(&self) -> Arc<T> {
        // safe to use Relaxed ordering below because
        // of the required synchronization for passing
        // any objects to another thread.
        let last_count =
            unsafe { (*self.ptr).rc.fetch_add(1, Ordering::Relaxed) };

        if last_count == usize::max_value() {
            #[cold]
            std::process::abort();
        }

        Arc { ptr: self.ptr }
    }
}

impl<T: ?Sized> Drop for Arc<T> {
    fn drop(&mut self) {
        unsafe {
            let rc = (*self.ptr).rc.fetch_sub(1, Ordering::Release) - 1;
            if rc == 0 {
                std::sync::atomic::fence(Ordering::Acquire);
                Box::from_raw(self.ptr);
            }
        }
    }
}

impl<T: Copy> From<&[T]> for Arc<[T]> {
    #[inline]
    fn from(s: &[T]) -> Arc<[T]> {
        unsafe { Arc::copy_from_slice(s) }
    }
}

#[allow(clippy::fallible_impl_from)]
impl<T> From<Box<[T]>> for Arc<[T]> {
    #[inline]
    fn from(b: Box<[T]>) -> Arc<[T]> {
        let len = b.len();
        unsafe {
            let src = Box::into_raw(b);
            let value_layout = Layout::for_value(&*src);
            let align = std::cmp::max(value_layout.align(), mem::align_of::<AtomicUsize>());
            let rc_width = std::cmp::max(align, mem::size_of::<AtomicUsize>());
            let unpadded_size = rc_width.checked_add(value_layout.size()).unwrap();
            let size = (unpadded_size + align - 1) & !(align - 1);
            let dst_layout = Layout::from_size_align(size, align).unwrap();
            let dst = alloc(dst_layout);
            assert!(!dst.is_null(), "failed to allocate Arc");

            #[allow(clippy::cast_ptr_alignment)]
            ptr::write(dst as _, AtomicUsize::new(1));
            let data_ptr = dst.add(rc_width);
            ptr::copy_nonoverlapping(src as *const u8, data_ptr, value_layout.size());

            // free the old box memory without running Drop
            if value_layout.size() != 0 {
                dealloc(src as *mut u8, value_layout);
            }

            let fat_ptr: *const ArcInner<[T]> = Arc::fatten(dst, len);

            Arc { ptr: fat_ptr as *mut _ }
        }
    }
}

#[test]
fn boxed_slice_to_arc_slice() {
    let box1: Box<[u8]> = Box::new([1, 2, 3]);
    let arc1: Arc<[u8]> = box1.into();
    assert_eq!(&*arc1, &*vec![1, 2, 3]);
    let box2: Box<[u8]> = Box::new([]);
    let arc2: Arc<[u8]> = box2.into();
    assert_eq!(&*arc2, &*vec![]);
    let box3: Box<[u64]> = Box::new([1, 2, 3]);
    let arc3: Arc<[u64]> = box3.into();
    assert_eq!(&*arc3, &*vec![1, 2, 3]);
}

impl<T> From<Vec<T>> for Arc<[T]> {
    #[inline]
    fn from(mut v: Vec<T>) -> Arc<[T]> {
        unsafe {
            let arc = Arc::copy_from_slice(&v);

            // Allow the Vec to free its memory, but not destroy its contents
            v.set_len(0);

            arc
        }
    }
}

impl<T: ?Sized> Deref for Arc<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &(*self.ptr).inner }
    }
}

impl<T: ?Sized> std::borrow::Borrow<T> for Arc<T> {
    fn borrow(&self) -> &T {
        &**self
    }
}

impl<T: ?Sized> AsRef<T> for Arc<T> {
    fn as_ref(&self) -> &T {
        &**self
    }
}
<|endoftext|>