<commit_before>extern crate puck;
#[macro_use]
extern crate puck_core;
extern crate cgmath;
extern crate rand;

#[macro_use]
extern crate serde_derive;
extern crate serde;

use cgmath::{Zero, InnerSpace, vec3, vec2, Rad};
use std::f64::consts::PI;

use puck_core::{Vec2f, Vec3f, Vec3, Tick, HashMap, TreeMap, Color, clamp};
use puck_core::app::{App, Event, SimSettings, Sink, CombinedSink};

use puck::app::{RenderedApp, RenderSettings};
use puck::{FileResources, RenderTick, Input, Dimensions, Camera};
use puck::audio::{SoundRender, Listener, SoundEvent};
use puck::render::gfx::OpenGLRenderer;
use puck::render::*;

use std::collections::Bound;
use std::collections::Bound::*;

use std::hash::Hash;

#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub enum Id {
    Game,
    Player,
    Rock(u64),
    Shot(u64),
}

impl Id {
    pub fn next(&self) -> Option<Id> {
        match self {
            &Id::Game => None,
            &Id::Player => None,
            &Id::Rock(id) => Some(Id::Rock(id + 1)),
            &Id::Shot(id) => Some(Id::Shot(id + 1)),
        }
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub enum ActorKind {
    Player,
    Rock,
    Shot
}

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum Entity {
    Game { level: u64, score: u64 },
    Actor(Actor),
}

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub struct Actor {
    pub kind: ActorKind,
    pub pos: Vec2f,
    pub facing: f32,
    pub velocity: Vec2f,
    pub rvel: f32,
    pub bbox_size: f32,
    pub life: f32, // for shots, times alive, for players/rocks hp
    pub thrust: bool,
    pub shooting: bool,
}

const PLAYER_LIFE: f32 = 1.0;
const SHOT_LIFE: f32 = 2.0;
const ROCK_LIFE: f32 = 1.0;

const PLAYER_BBOX: f32 = 12.0;
const ROCK_BBOX: f32 = 12.0;
const SHOT_BBOX: f32 = 6.0;

const MAX_ROCK_VEL: f32 = 50.0;

const SHOT_SPEED: f32 = 200.0;
const SHOT_RVEL: f32 = 0.1;
const SPRITE_SIZE: u32 = 32;

// Acceleration in pixels per second, more or less.
const PLAYER_THRUST: f32 = 100.0;
// Rotation in radians per second.
const PLAYER_TURN_RATE: f32 = 3.05;
// Seconds between shots
const PLAYER_SHOT_TIME: f32 = 0.5;

const MAX_PHYSICS_VEL: f32 = 250.0;

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum EntityEvent {
    UpdateShipControls { rvel: f32, thrust: bool, shooting: bool },
    UpdatePhysics { velocity : Vec2f, facing: f32, position: Vec2f },
    SetLife(f32),
    IncreaseLevel,
    IncreaseScore,
}

fn create_player() -> Actor {
    Actor {
        kind: ActorKind::Player,
        pos: Vec2f::zero(),
        facing: 0.,
        velocity: Vec2f::zero(),
        rvel: 0.,
        bbox_size: PLAYER_BBOX,
        life: 0.0,
        thrust: false,
        shooting: false,
    }
}

fn create_rock() -> Actor {
    Actor {
        kind: ActorKind::Rock,
        pos: Vec2f::zero(),
        facing: 0.,
        velocity: Vec2f::zero(),
        rvel: 0.,
        bbox_size: ROCK_BBOX,
        life: ROCK_LIFE,
        thrust: false,
        shooting: false,
    }
}

fn create_shot(pos: Vec2f, facing: f32, velocity: Vec2f) -> Actor {
    Actor {
        kind: ActorKind::Shot,
        pos,
        facing,
        velocity,
        rvel: SHOT_RVEL,
        bbox_size: SHOT_BBOX,
        life: SHOT_LIFE,
        thrust: false,
        shooting: false,
    }
}

fn random_vec(max_magnitude: f32) -> Vec2f {
    let angle = rand::random::<f32>() * 2.0 * std::f32::consts::PI;
    let mag = rand::random::<f32>() * max_magnitude;
    vec_from_angle(angle) * (mag)
}

fn vec_from_angle(angle: f32) -> Vec2f { // should probably fix this on the rendering end :-/
    let ang = -angle + PI as f32;

    let vx = ang.sin();
    let vy = ang.cos();

    Vec2f::new(vx, vy)
}

fn create_rocks(num: u64, exclusion: Vec2f, min_radius: f32, max_radius: f32) -> Vec<(Id, Entity)> {
    assert!(max_radius > min_radius);
    let new_rock = |n| {
        let mut rock = create_rock();
        let r_angle = rand::random::<f32>() * 2.0 * std::f32::consts::PI;
        let r_distance = rand::random::<f32>() * (max_radius - min_radius) + min_radius;
        rock.pos = exclusion + vec_from_angle(r_angle) * r_distance;
        rock.velocity = random_vec(MAX_ROCK_VEL);
        (Id::Rock(n), Entity::Actor(rock))
    };
    (0..num).map(new_rock).collect()
}

fn wrapped_position(pos:Vec2f, wrap_x:f32, wrap_y:f32) -> Vec2f {
    let mut wrapped_pos = pos;

    if pos.x > wrap_x {
        wrapped_pos.x -= wrap_x;
    } else if pos.x < 0. {
        wrapped_pos.x += wrap_x;
    };
    if pos.y > wrap_y {
        wrapped_pos.y -= wrap_y;
    } else if pos.y < 0. {
        wrapped_pos.y += wrap_y;
    }
    wrapped_pos
}

fn update_life(actor:&Actor, time:f32) -> EntityEvent {
    let new_life = if actor.life > 0.0 {
        clamp(actor.life - time, 0.0, 1000.0)
    } else {
        actor.life
    };
    EntityEvent::SetLife(new_life)
}

fn update_physics(actor:&Actor, time:f32, wrap_x:f32, wrap_y: f32) -> EntityEvent {
    // Clamp the velocity to the max efficiently

    let norm = actor.velocity.magnitude();
    let vel = if norm > MAX_PHYSICS_VEL {
        actor.velocity / norm * MAX_PHYSICS_VEL
    } else {
        actor.velocity
    };

    let accel = if actor.thrust {
        let v = vec_from_angle(actor.facing);
        v * PLAYER_THRUST
    } else {
        vec2(0., 0.)
    };

    EntityEvent::UpdatePhysics {
        velocity : vel + accel * time,
        facing: actor.facing + actor.rvel * time,
        position: wrapped_position(actor.pos + actor.velocity * time, wrap_x, wrap_y),
    }
}

pub fn main() {
    println!("astroblasto");
    let file_resources = FileResources::default_relative();
    let sim_settings = SimSettings { tick_rate: 60 };
    let render_settings = RenderSettings { dimensions: (640, 480), vsync: false, title: "Astroblasto!".into() };

    let init_state = treemap![Id::Game => Entity::Game { level: 0, score: 0 }];

    let run_result = puck::app::runner::run::<AstroApp>(file_resources, sim_settings, render_settings, Vec::new(), init_state);
}

struct AstroApp();

pub type IdRange = (Bound<Id>, Bound<Id>);

pub const ALL_ROCKS : IdRange = (Included(Id::Rock(0)), Included(Id::Rock(1000)));
pub const ALL_SHOTS : IdRange = (Included(Id::Shot(0)), Included(Id::Shot(1000)));

//struct RenderState {
//    pub sound_events: Vec<SoundEvent>,
//
//}

impl App for AstroApp {
    type Id = Id;
    type Entity = Entity; // do we need Eq?
    type EntityEvent = EntityEvent;
    type RenderEvent = SoundEvent;

    fn handle_entity_event(event:&Self::EntityEvent, id: &Self::Id, entity: &mut Self::Entity, sink: &mut Sink<Event<Self::Id, Self::Entity, Self::EntityEvent, Self::RenderEvent>>) {
        use Entity::*;
        use EntityEvent::*;

        match (event, entity) {
            (&IncreaseLevel, &mut Game { mut level, .. }) => { level += 1 },
            (&IncreaseScore, &mut Game { mut score, ..}) => { score += 1 },
            (&UpdateShipControls { rvel, thrust, shooting }, &mut Actor(ref mut actor)) => {
                actor.rvel = rvel;
                actor.thrust = thrust;
                actor.shooting = shooting;
            }
            (&UpdatePhysics { velocity, facing, position }, &mut Actor(ref mut actor)) => {
                actor.velocity = velocity;
                actor.facing = facing;
                actor.pos = position;

            }
            (&SetLife(life), &mut Actor(ref mut actor)) => {
                actor.life = life;
            },
            (ev, ent) => {
                println!("uhhh, dont recognize {:?} with {:?}", ev, ent);
            },
        }
    }

    fn simulate(time:Tick, entities:&TreeMap<Self::Id, Self::Entity>, id: &Self::Id, entity: &Self::Entity, sink: &mut CombinedSink<Self::EntityEvent, Event<Self::Id, Self::Entity, Self::EntityEvent, Self::RenderEvent>>)  {
        use puck_core::app::Event::*;
        use Entity::*;
        use EntityEvent::*;
        use ActorKind::*;
        match entity {
            &Game { level, .. } => {
                if let Some(&Entity::Actor(player)) = entities.get(&Id::Player) {
                    let rock_count = entities.range(ALL_ROCKS).count();
                    if rock_count == 0 {
                        let spawn_rocks : Vec<_> = create_rocks(level + 6, player.pos, 100.0, 250.0).into_iter().map(|(id, entity)| {
                            Event::SpawnEvent(id, entity)
                        }).collect();
                        sink.push_self(IncreaseLevel);
                        for ev in spawn_rocks {
                            sink.push_event(ev);
                        }
                    }
                } else {
                    // no player
                    sink.push_event(SpawnEvent(Id::Player, Entity::Actor(create_player())));
                }
            },
            &Actor(ref actor) => {
                sink.push_self(update_physics(actor, time.tick_duration as f32, 640.0, 480.0));
                match actor.kind {
                    Player => {
                        if actor.shooting && actor.life <= 0.0 {
                            let shot_velocity = vec_from_angle(actor.facing) * SHOT_SPEED;
                            let shot = create_shot(actor.pos, actor.facing, shot_velocity);
                            sink.push_self(SetLife(PLAYER_LIFE));
                            let shot_id = entities.range(ALL_SHOTS).last().and_then(|(id,_)| id.next() ).unwrap_or(Id::Shot(0));
                            sink.push_event(SpawnEvent(shot_id, Entity::Actor(shot)));
                        } else {
                            sink.push_self(update_life(actor, time.tick_duration as f32));
                        }
                    },
                    Rock => (),
                    Shot => sink.push_self(update_life(actor, time.tick_duration as f32)),
                }
            },
        }
    }
}

impl RenderedApp for AstroApp {
    type RenderState = Vec<SoundEvent>;

    fn handle_input(input:&Input, dimensions: &Dimensions, entities: &TreeMap<Self::Id, Self::Entity>, sink: &mut Sink<Event<Self::Id, Self::Entity, Self::EntityEvent, Self::RenderEvent>>) {
        if let Some(&Entity::Actor(actor)) = entities.get(&Id::Player) {
           let rvel = if input.keys.down.contains(&puck::input::VirtualKeyCode::A) {
               -PLAYER_TURN_RATE
           } else if input.keys.down.contains(&puck::input::VirtualKeyCode::D) {
                PLAYER_TURN_RATE
           } else {
               0.0
           };
           let thrust = input.keys.down.contains(&puck::input::VirtualKeyCode::W);
           let shooting = input.keys.down.contains(&puck::input::VirtualKeyCode::Space);
           sink.push(Event::EntityEvent(Id::Player, EntityEvent::UpdateShipControls { rvel, thrust, shooting }));
        }
    }

    fn handle_render_event(event: &Self::RenderEvent, render_state: &mut Self::RenderState) {
        render_state.push(event.clone());
    }

    fn render(time: RenderTick, dimensions: &Dimensions, entities:&TreeMap<Self::Id, Self::Entity>, render_state: &mut Self::RenderState, renderer: &mut OpenGLRenderer) -> SoundRender {
        use Entity::*;
        use ActorKind::*;

        renderer.clear_depth_and_color(Color::BLACK);

        let tesselator = GeometryTesselator::new(Vec3::new(1.0, 1.0, 1.0));
        let mut verticies = Vec::new();

        let atlas = TextureAtlas {
            texture_size: 512,
            tile_size: 32,
        };
        let rock = atlas.at(0, 0);
        let shot = atlas.at(1, 0);
        let player = atlas.at(2, 0);

        for (id, e) in entities {
            match e {
                &Game { level, score } => {
                    // render some ui stuff?
                },
                &Actor(actor) => {
                    let tex = match actor.kind {
                        Shot => shot,
                        Player => player,
                        Rock => rock,
                    };

                    tesselator.draw_floor_centre_anchored_rotated_at(&mut verticies, &tex, vec3(actor.pos.x as f64, 0.0, actor.pos.y as f64), actor.facing as f64, 0.0);
                },
            }
        }

        let (w, h) = dimensions.points;
        let camera = Camera {
            at: vec3(w as f64 / 2.0, 0., h as f64 / 2.0),
            pitch: Rad(PI / 4.0_f64),
            viewport: *dimensions,
            points_per_unit: 1.0,
            near_far: (-1000., 1000.),
        };

        renderer.draw_vertices(&verticies, Uniforms {
            transform : camera.view_projection(),
            color: Color::WHITE,
        }, Blend::None).expect("the ability to draw");
        renderer.finish_frame().expect("finished frame");

        let out = render_state.split_off(0);
        SoundRender::non_positional_effects(Vec::new())
    }
}

<commit_msg>Cleaning up astro<commit_after>extern crate puck;
#[macro_use]
extern crate puck_core;
extern crate cgmath;
extern crate rand;

#[macro_use]
extern crate serde_derive;
extern crate serde;

use cgmath::{Zero, InnerSpace, vec3, vec2, Rad};
use std::f64::consts::PI;

use puck_core::{Vec2f, Vec3f, Vec3, Tick, HashMap, TreeMap, Color, clamp};
use puck_core::app::{App, Event, SimSettings, Sink, CombinedSink};

use puck::app::{RenderedApp, RenderSettings};
use puck::{FileResources, RenderTick, Input, Dimensions, Camera};
use puck::audio::{SoundRender, Listener, SoundEvent};
use puck::render::gfx::OpenGLRenderer;
use puck::render::*;

use std::collections::Bound;
use std::collections::Bound::*;

use std::hash::Hash;

#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub enum Id {
    Game,
    Player,
    Rock(u64),
    Shot(u64),
}

impl Id {
    pub fn next(&self) -> Option<Id> {
        match self {
            &Id::Game => None,
            &Id::Player => None,
            &Id::Rock(id) => Some(Id::Rock(id + 1)),
            &Id::Shot(id) => Some(Id::Shot(id + 1)),
        }
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub enum ActorKind {
    Player,
    Rock,
    Shot
}

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum Entity {
    Game { level: u64, score: u64 },
    Actor(Actor),
}

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub struct Actor {
    pub kind: ActorKind,
    pub pos: Vec2f,
    pub facing: f32,
    pub velocity: Vec2f,
    pub rvel: f32,
    pub bbox_size: f32,
    pub life: f32, // for shots, times alive, for players/rocks hp
    pub thrust: bool,
    pub shooting: bool,
}

const PLAYER_LIFE: f32 = 1.0;
const SHOT_LIFE: f32 = 2.0;
const ROCK_LIFE: f32 = 1.0;

const PLAYER_BBOX: f32 = 12.0;
const ROCK_BBOX: f32 = 12.0;
const SHOT_BBOX: f32 = 6.0;

const MAX_ROCK_VEL: f32 = 50.0;

const SHOT_SPEED: f32 = 200.0;
const SHOT_RVEL: f32 = 0.1;
const SPRITE_SIZE: u32 = 32;

// Acceleration in pixels per second, more or less.
const PLAYER_THRUST: f32 = 100.0;
// Rotation in radians per second.
const PLAYER_TURN_RATE: f32 = 3.05;
// Seconds between shots
const PLAYER_SHOT_TIME: f32 = 0.5;

const MAX_PHYSICS_VEL: f32 = 250.0;

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum EntityEvent {
    UpdateShipControls { rvel: f32, thrust: bool, shooting: bool },
    UpdatePhysics { velocity : Vec2f, facing: f32, position: Vec2f },
    SetLife(f32),
    IncreaseLevel,
    IncreaseScore,
}

fn create_player() -> Actor {
    Actor {
        kind: ActorKind::Player,
        pos: Vec2f::zero(),
        facing: 0.,
        velocity: Vec2f::zero(),
        rvel: 0.,
        bbox_size: PLAYER_BBOX,
        life: 0.0,
        thrust: false,
        shooting: false,
    }
}

fn create_rock() -> Actor {
    Actor {
        kind: ActorKind::Rock,
        pos: Vec2f::zero(),
        facing: 0.,
        velocity: Vec2f::zero(),
        rvel: 0.,
        bbox_size: ROCK_BBOX,
        life: ROCK_LIFE,
        thrust: false,
        shooting: false,
    }
}

fn create_shot(pos: Vec2f, facing: f32, velocity: Vec2f) -> Actor {
    Actor {
        kind: ActorKind::Shot,
        pos,
        facing,
        velocity,
        rvel: SHOT_RVEL,
        bbox_size: SHOT_BBOX,
        life: SHOT_LIFE,
        thrust: false,
        shooting: false,
    }
}

fn random_vec(max_magnitude: f32) -> Vec2f {
    let angle = rand::random::<f32>() * 2.0 * std::f32::consts::PI;
    let mag = rand::random::<f32>() * max_magnitude;
    vec_from_angle(angle) * (mag)
}

fn vec_from_angle(angle: f32) -> Vec2f { // should probably fix this on the rendering end :-/
    let ang = -angle + PI as f32;

    let vx = ang.sin();
    let vy = ang.cos();

    Vec2f::new(vx, vy)
}

fn create_rocks(num: u64, exclusion: Vec2f, min_radius: f32, max_radius: f32) -> Vec<(Id, Entity)> {
    assert!(max_radius > min_radius);
    let new_rock = |n| {
        let mut rock = create_rock();
        let r_angle = rand::random::<f32>() * 2.0 * std::f32::consts::PI;
        let r_distance = rand::random::<f32>() * (max_radius - min_radius) + min_radius;
        rock.pos = exclusion + vec_from_angle(r_angle) * r_distance;
        rock.velocity = random_vec(MAX_ROCK_VEL);
        (Id::Rock(n), Entity::Actor(rock))
    };
    (0..num).map(new_rock).collect()
}

fn wrapped_position(pos:Vec2f, wrap_x:f32, wrap_y:f32) -> Vec2f {
    let mut wrapped_pos = pos;

    if pos.x > wrap_x {
        wrapped_pos.x -= wrap_x;
    } else if pos.x < 0. {
        wrapped_pos.x += wrap_x;
    };
    if pos.y > wrap_y {
        wrapped_pos.y -= wrap_y;
    } else if pos.y < 0. {
        wrapped_pos.y += wrap_y;
    }
    wrapped_pos
}

fn update_life(actor:&Actor, time:f32) -> EntityEvent {
    let new_life = if actor.life > 0.0 {
        clamp(actor.life - time, 0.0, 1000.0)
    } else {
        actor.life
    };
    EntityEvent::SetLife(new_life)
}

fn update_physics(actor:&Actor, time:f32, wrap_x:f32, wrap_y: f32) -> EntityEvent {
    // Clamp the velocity to the max efficiently

    let norm = actor.velocity.magnitude();
    let vel = if norm > MAX_PHYSICS_VEL {
        actor.velocity / norm * MAX_PHYSICS_VEL
    } else {
        actor.velocity
    };

    let accel = if actor.thrust {
        let v = vec_from_angle(actor.facing);
        v * PLAYER_THRUST
    } else {
        vec2(0., 0.)
    };

    EntityEvent::UpdatePhysics {
        velocity : vel + accel * time,
        facing: actor.facing + actor.rvel * time,
        position: wrapped_position(actor.pos + actor.velocity * time, wrap_x, wrap_y),
    }
}

pub fn main() {
    println!("astroblasto");
    let file_resources = FileResources::default_relative();
    let sim_settings = SimSettings { tick_rate: 60 };
    let render_settings = RenderSettings { dimensions: (640, 480), vsync: false, title: "Astroblasto!".into() };

    let init_state = treemap![Id::Game => Entity::Game { level: 0, score: 0 }];

    let run_result = puck::app::runner::run::<AstroApp>(file_resources, sim_settings, render_settings, Vec::new(), init_state);
}

struct AstroApp();

pub type IdRange = (Bound<Id>, Bound<Id>);

pub const ALL_ROCKS : IdRange = (Included(Id::Rock(0)), Included(Id::Rock(1000)));
pub const ALL_SHOTS : IdRange = (Included(Id::Shot(0)), Included(Id::Shot(1000)));

//struct RenderState {
//    pub sound_events: Vec<SoundEvent>,
//
//}

impl App for AstroApp {
    type Id = Id;
    type Entity = Entity; // do we need Eq?
    type EntityEvent = EntityEvent;
    type RenderEvent = SoundEvent;

    fn handle_entity_event(event:&Self::EntityEvent, id: &Self::Id, entity: &mut Self::Entity, sink: &mut Sink<Event<Self::Id, Self::Entity, Self::EntityEvent, Self::RenderEvent>>) {
        use Entity::*;
        use EntityEvent::*;

        match (event, entity) {
            (&IncreaseLevel, &mut Game { mut level, .. }) => { level += 1 },
            (&IncreaseScore, &mut Game { mut score, ..}) => { score += 1 },
            (&UpdateShipControls { rvel, thrust, shooting }, &mut Actor(ref mut actor)) => {
                actor.rvel = rvel;
                actor.thrust = thrust;
                actor.shooting = shooting;
            }
            (&UpdatePhysics { velocity, facing, position }, &mut Actor(ref mut actor)) => {
                actor.velocity = velocity;
                actor.facing = facing;
                actor.pos = position;
            }
            (&SetLife(life), &mut Actor(ref mut actor)) => {
                actor.life = life;
            },
            (ev, ent) => {
                println!("uhhh, dont recognize {:?} with {:?}", ev, ent);
            },
        }
    }

    fn simulate(time:Tick, entities:&TreeMap<Self::Id, Self::Entity>, id: &Self::Id, entity: &Self::Entity, sink: &mut CombinedSink<Self::EntityEvent, Event<Self::Id, Self::Entity, Self::EntityEvent, Self::RenderEvent>>)  {
        use puck_core::app::Event::*;
        use Entity::*;
        use EntityEvent::*;
        use ActorKind::*;
        match entity {
            &Game { level, .. } => {
                if let Some(&Entity::Actor(player)) = entities.get(&Id::Player) {
                    let rock_count = entities.range(ALL_ROCKS).count();
                    if rock_count == 0 {
                        sink.push_self(IncreaseLevel);
                        let spawn_rocks : Vec<_> = create_rocks(level + 6, player.pos, 100.0, 250.0).into_iter().map(|(id, entity)| {
                            Event::SpawnEvent(id, entity)
                        }).collect();
                        for ev in spawn_rocks {
                            sink.push_event(ev);
                        }
                    }
                } else {
                    // no player
                    sink.push_event(SpawnEvent(Id::Player, Entity::Actor(create_player())));
                }
            },
            &Actor(ref actor) => {
                sink.push_self(update_physics(actor, time.tick_duration as f32, 640.0, 480.0));
                match actor.kind {
                    Player => {
                        if actor.shooting && actor.life <= 0.0 {
                            let shot_velocity = vec_from_angle(actor.facing) * SHOT_SPEED;
                            let shot = create_shot(actor.pos, actor.facing, shot_velocity);
                            sink.push_self(SetLife(PLAYER_LIFE));
                            let shot_id = entities.range(ALL_SHOTS).last().and_then(|(id,_)| id.next() ).unwrap_or(Id::Shot(0));
                            sink.push_event(SpawnEvent(shot_id, Entity::Actor(shot)));
                        } else {
                            sink.push_self(update_life(actor, time.tick_duration as f32));
                        }
                    },
                    Rock => (),
                    Shot => sink.push_self(update_life(actor, time.tick_duration as f32)),
                }
            },
        }
    }
}

impl RenderedApp for AstroApp {
    type RenderState = Vec<SoundEvent>;

    fn handle_input(input:&Input, dimensions: &Dimensions, entities: &TreeMap<Self::Id, Self::Entity>, sink: &mut Sink<Event<Self::Id, Self::Entity, Self::EntityEvent, Self::RenderEvent>>) {
        if let Some(&Entity::Actor(actor)) = entities.get(&Id::Player) {
           let rvel = if input.keys.down.contains(&puck::input::VirtualKeyCode::A) {
               -PLAYER_TURN_RATE
           } else if input.keys.down.contains(&puck::input::VirtualKeyCode::D) {
                PLAYER_TURN_RATE
           } else {
               0.0
           };
           let thrust = input.keys.down.contains(&puck::input::VirtualKeyCode::W);
           let shooting = input.keys.down.contains(&puck::input::VirtualKeyCode::Space);
           sink.push(Event::EntityEvent(Id::Player, EntityEvent::UpdateShipControls { rvel, thrust, shooting }));
        }
    }

    fn handle_render_event(event: &Self::RenderEvent, render_state: &mut Self::RenderState) {
        render_state.push(event.clone());
    }

    fn render(time: RenderTick, dimensions: &Dimensions, entities:&TreeMap<Self::Id, Self::Entity>, render_state: &mut Self::RenderState, renderer: &mut OpenGLRenderer) -> SoundRender {
        use Entity::*;
        use ActorKind::*;

        renderer.clear_depth_and_color(Color::BLACK);

        let tesselator = GeometryTesselator::new(Vec3::new(1.0, 1.0, 1.0));
        let mut verticies = Vec::new();

        let atlas = TextureAtlas {
            texture_size: 512,
            tile_size: 32,
        };
        let rock = atlas.at(0, 0);
        let shot = atlas.at(1, 0);
        let player = atlas.at(2, 0);

        for (id, e) in entities {
            match e {
                &Game { level, score } => {
                    // render some ui stuff?
                },
                &Actor(actor) => {
                    let tex = match actor.kind {
                        Shot => shot,
                        Player => player,
                        Rock => rock,
                    };

                    tesselator.draw_floor_centre_anchored_rotated_at(&mut verticies, &tex, vec3(actor.pos.x as f64, 0.0, actor.pos.y as f64), actor.facing as f64, 0.0);
                },
            }
        }

        let (w, h) = dimensions.points;
        let camera = Camera {
            at: vec3(w as f64 / 2.0, 0., h as f64 / 2.0),
            pitch: Rad(PI / 4.0_f64),
            viewport: *dimensions,
            points_per_unit: 1.0,
            near_far: (-1000., 1000.),
        };

        renderer.draw_vertices(&verticies, Uniforms {
            transform : camera.view_projection(),
            color: Color::WHITE,
        }, Blend::None).expect("the ability to draw");
        renderer.finish_frame().expect("finished frame");

        let out = render_state.split_off(0);
        SoundRender::non_positional_effects(Vec::new())
    }
}

<|endoftext|>


<commit_before>// Routines useful for garbage collection.

import lib::llvm::False;
import lib::llvm::True;
import lib::llvm::llvm::ValueRef;
import middle::trans;
import middle::trans::{ get_tydesc, tps_normal };
import middle::trans_common::*;
import middle::ty;
import std::option::none;
import std::option::some;
import std::ptr;
import std::str;
import std::istr;
import std::unsafe;
import std::vec;

import lll = lib::llvm::llvm;
import bld = trans_build;

type ctxt = @{mutable next_tydesc_num: uint};

fn mk_ctxt() -> ctxt { ret @{mutable next_tydesc_num: 0u}; }

fn add_global(ccx: &@crate_ctxt, llval: ValueRef, name: &istr) -> ValueRef {
    let llglobal = istr::as_buf(name, { |buf|
        lll::LLVMAddGlobal(ccx.llmod, val_ty(llval), buf)
    });
    lll::LLVMSetInitializer(llglobal, llval);
    lll::LLVMSetGlobalConstant(llglobal, True);
    ret llglobal;
}

fn add_gc_root(cx: &@block_ctxt, llval: ValueRef, ty: ty::t) -> @block_ctxt {
    let bcx = cx;
    if !type_is_gc_relevant(bcx_tcx(cx), ty) ||
           ty::type_has_dynamic_size(bcx_tcx(cx), ty) {
        ret bcx;
    }

    let gc_cx = bcx_ccx(cx).gc_cx;

    // FIXME (issue #839): For now, we are unconditionally zeroing out all
    // GC-relevant types. Eventually we should use typestate for this.
    bcx = trans::zero_alloca(bcx, llval, ty).bcx;

    let ti = none;
    let td_r = get_tydesc(bcx, ty, false, tps_normal, ti);
    bcx = td_r.result.bcx;
    let lltydesc = td_r.result.val;

    let gcroot = bcx_ccx(bcx).intrinsics.get(~"llvm.gcroot");
    let llvalptr = bld::PointerCast(bcx, llval, T_ptr(T_ptr(T_i8())));

    alt td_r.kind {
      tk_derived. {
        // It's a derived type descriptor. First, spill it.
        let lltydescptr = trans::alloca(bcx, val_ty(lltydesc));
        bld::Store(bcx, lltydesc, lltydescptr);

        let number = gc_cx.next_tydesc_num;
        gc_cx.next_tydesc_num += 1u;

        let lldestindex =
            add_global(bcx_ccx(bcx), C_struct([C_int(0), C_uint(number)]),
                       ~"rust_gc_tydesc_dest_index");
        let llsrcindex =
            add_global(bcx_ccx(bcx), C_struct([C_int(1), C_uint(number)]),
                       ~"rust_gc_tydesc_src_index");

        lldestindex = lll::LLVMConstPointerCast(lldestindex, T_ptr(T_i8()));
        llsrcindex = lll::LLVMConstPointerCast(llsrcindex, T_ptr(T_i8()));

        lltydescptr =
            bld::PointerCast(bcx, lltydescptr, T_ptr(T_ptr(T_i8())));

        bld::Call(bcx, gcroot, [lltydescptr, lldestindex]);
        bld::Call(bcx, gcroot, [llvalptr, llsrcindex]);
      }
      tk_param. {
        bcx_tcx(cx).sess.bug(~"we should never be trying to root values " +
                                 ~"of a type parameter");
      }
      tk_static. {
        // Static type descriptor.

        let llstaticgcmeta =
            add_global(bcx_ccx(bcx), C_struct([C_int(2), lltydesc]),
                       ~"rust_gc_tydesc_static_gc_meta");
        let llstaticgcmetaptr =
            lll::LLVMConstPointerCast(llstaticgcmeta, T_ptr(T_i8()));

        bld::Call(bcx, gcroot, [llvalptr, llstaticgcmetaptr]);
      }
    }

    ret bcx;
}

fn type_is_gc_relevant(cx: &ty::ctxt, ty: ty::t) -> bool {
    alt ty::struct(cx, ty) {
      ty::ty_nil. | ty::ty_bot. | ty::ty_bool. | ty::ty_int. | ty::ty_float. |
      ty::ty_uint. | ty::ty_machine(_) | ty::ty_char. | ty::ty_istr. |
      ty::ty_type. | ty::ty_native(_) | ty::ty_ptr(_) | ty::ty_type. |
      ty::ty_native(_) {
        ret false;
      }

      ty::ty_rec(fields) {
        for f in fields { if type_is_gc_relevant(cx, f.mt.ty) { ret true; } }
        ret false;
      }
      ty::ty_tup(elts) {
        for elt in elts { if type_is_gc_relevant(cx, elt) { ret true; } }
        ret false;
      }

      ty::ty_tag(did, tps) {
        let variants = ty::tag_variants(cx, did);
        for variant in variants {
            for aty in variant.args {
                let arg_ty = ty::substitute_type_params(cx, tps, aty);
                if type_is_gc_relevant(cx, arg_ty) { ret true; }
            }
        }
        ret false;
      }

      ty::ty_vec(tm) {
        ret type_is_gc_relevant(cx, tm.ty);
      }
      ty::ty_constr(sub, _) { ret type_is_gc_relevant(cx, sub); }

      ty::ty_str. | ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_fn(_, _, _, _, _)
      | ty::ty_native_fn(_, _, _) | ty::ty_obj(_) | ty::ty_param(_, _) |
      ty::ty_res(_, _, _) {
        ret true;
      }

      ty::ty_var(_) {
        fail "ty_var in type_is_gc_relevant";
      }
    }
}

<commit_msg>rustc: Hoist derived tydesc GC roots up to the top of the function so the GC doesn't try to access uninitialized tydescs<commit_after>// Routines useful for garbage collection.

import lib::llvm::False;
import lib::llvm::True;
import lib::llvm::llvm::ValueRef;
import middle::trans;
import middle::trans::{ get_tydesc, tps_normal };
import middle::trans_common::*;
import middle::ty;
import std::option::none;
import std::option::some;
import std::ptr;
import std::str;
import std::istr;
import std::unsafe;
import std::vec;

import lll = lib::llvm::llvm;
import bld = trans_build;

type ctxt = @{mutable next_tydesc_num: uint};

fn mk_ctxt() -> ctxt { ret @{mutable next_tydesc_num: 0u}; }

fn add_global(ccx: &@crate_ctxt, llval: ValueRef, name: &istr) -> ValueRef {
    let llglobal = istr::as_buf(name, { |buf|
        lll::LLVMAddGlobal(ccx.llmod, val_ty(llval), buf)
    });
    lll::LLVMSetInitializer(llglobal, llval);
    lll::LLVMSetGlobalConstant(llglobal, True);
    ret llglobal;
}

fn add_gc_root(cx: &@block_ctxt, llval: ValueRef, ty: ty::t) -> @block_ctxt {
    let bcx = cx;
    if !type_is_gc_relevant(bcx_tcx(cx), ty) ||
           ty::type_has_dynamic_size(bcx_tcx(cx), ty) {
        ret bcx;
    }

    let gc_cx = bcx_ccx(cx).gc_cx;

    // FIXME (issue #839): For now, we are unconditionally zeroing out all
    // GC-relevant types. Eventually we should use typestate for this.
    bcx = trans::zero_alloca(bcx, llval, ty).bcx;

    let ti = none;
    let td_r = get_tydesc(bcx, ty, false, tps_normal, ti);
    bcx = td_r.result.bcx;
    let lltydesc = td_r.result.val;

    let gcroot = bcx_ccx(bcx).intrinsics.get(~"llvm.gcroot");
    let llvalptr = bld::PointerCast(bcx, llval, T_ptr(T_ptr(T_i8())));

    alt td_r.kind {
      tk_derived. {
        // It's a derived type descriptor. First, spill it.
        let lltydescptr = trans::alloca(bcx, val_ty(lltydesc));

        let llderivedtydescs =
            trans::llderivedtydescs_block_ctxt(bcx_fcx(bcx));
        bld::Store(llderivedtydescs, lltydesc, lltydescptr);

        let number = gc_cx.next_tydesc_num;
        gc_cx.next_tydesc_num += 1u;

        let lldestindex =
            add_global(bcx_ccx(bcx), C_struct([C_int(0), C_uint(number)]),
                       ~"rust_gc_tydesc_dest_index");
        let llsrcindex =
            add_global(bcx_ccx(bcx), C_struct([C_int(1), C_uint(number)]),
                       ~"rust_gc_tydesc_src_index");

        lldestindex = lll::LLVMConstPointerCast(lldestindex, T_ptr(T_i8()));
        llsrcindex = lll::LLVMConstPointerCast(llsrcindex, T_ptr(T_i8()));

        lltydescptr = bld::PointerCast(llderivedtydescs, lltydescptr,
                                       T_ptr(T_ptr(T_i8())));

        bld::Call(llderivedtydescs, gcroot, [lltydescptr, lldestindex]);
        bld::Call(bcx, gcroot, [llvalptr, llsrcindex]);
      }
      tk_param. {
        bcx_tcx(cx).sess.bug(~"we should never be trying to root values " +
                                 ~"of a type parameter");
      }
      tk_static. {
        // Static type descriptor.

        let llstaticgcmeta =
            add_global(bcx_ccx(bcx), C_struct([C_int(2), lltydesc]),
                       ~"rust_gc_tydesc_static_gc_meta");
        let llstaticgcmetaptr =
            lll::LLVMConstPointerCast(llstaticgcmeta, T_ptr(T_i8()));

        bld::Call(bcx, gcroot, [llvalptr, llstaticgcmetaptr]);
      }
    }

    ret bcx;
}

fn type_is_gc_relevant(cx: &ty::ctxt, ty: ty::t) -> bool {
    alt ty::struct(cx, ty) {
      ty::ty_nil. | ty::ty_bot. | ty::ty_bool. | ty::ty_int. | ty::ty_float. |
      ty::ty_uint. | ty::ty_machine(_) | ty::ty_char. | ty::ty_istr. |
      ty::ty_type. | ty::ty_native(_) | ty::ty_ptr(_) | ty::ty_type. |
      ty::ty_native(_) {
        ret false;
      }

      ty::ty_rec(fields) {
        for f in fields { if type_is_gc_relevant(cx, f.mt.ty) { ret true; } }
        ret false;
      }
      ty::ty_tup(elts) {
        for elt in elts { if type_is_gc_relevant(cx, elt) { ret true; } }
        ret false;
      }

      ty::ty_tag(did, tps) {
        let variants = ty::tag_variants(cx, did);
        for variant in variants {
            for aty in variant.args {
                let arg_ty = ty::substitute_type_params(cx, tps, aty);
                if type_is_gc_relevant(cx, arg_ty) { ret true; }
            }
        }
        ret false;
      }

      ty::ty_vec(tm) {
        ret type_is_gc_relevant(cx, tm.ty);
      }
      ty::ty_constr(sub, _) { ret type_is_gc_relevant(cx, sub); }

      ty::ty_str. | ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_fn(_, _, _, _, _)
      | ty::ty_native_fn(_, _, _) | ty::ty_obj(_) | ty::ty_param(_, _) |
      ty::ty_res(_, _, _) {
        ret true;
      }

      ty::ty_var(_) {
        fail "ty_var in type_is_gc_relevant";
      }
    }
}

<|endoftext|>


<commit_before>use crate::{
    executor::Executor,
    message::{Delivery, DeliveryResult},
    types::ShortString,
    BasicProperties, Error, Result,
};
use crossbeam_channel::{Receiver, Sender};
use futures_core::stream::Stream;
use log::trace;
use parking_lot::{Mutex, MutexGuard};
use std::{
    fmt,
    future::Future,
    pin::Pin,
    sync::Arc,
    task::{Context, Poll, Waker},
};

pub trait ConsumerDelegate: Send + Sync {
    fn on_new_delivery(&self, delivery: DeliveryResult)
        -> Pin<Box<dyn Future<Output = ()> + Send>>;
    fn drop_prefetched_messages(&self) -> Pin<Box<dyn Future<Output = ()> + Send>> {
        Box::pin(async move {})
    }
}

impl<
        F: Future<Output = ()> + Send + 'static,
        DeliveryHandler: Fn(DeliveryResult) -> F + Send + Sync + 'static,
    > ConsumerDelegate for DeliveryHandler
{
    fn on_new_delivery(
        &self,
        delivery: DeliveryResult,
    ) -> Pin<Box<dyn Future<Output = ()> + Send>> {
        Box::pin(self(delivery))
    }
}

#[derive(Clone)]
pub struct Consumer {
    inner: Arc<Mutex<ConsumerInner>>,
}

impl Consumer {
    pub(crate) fn new(consumer_tag: ShortString, executor: Arc<dyn Executor>) -> Consumer {
        Consumer {
            inner: Arc::new(Mutex::new(ConsumerInner::new(consumer_tag, executor))),
        }
    }

    pub fn inner(&self) -> MutexGuard<'_, ConsumerInner> {
        self.inner.lock()
    }

    pub fn set_delegate<D: ConsumerDelegate + 'static>(&self, delegate: D) {
        let mut inner = self.inner();
        while let Some(delivery) = inner.next_delivery() {
            delegate.on_new_delivery(delivery);
        }
        inner.delegate = Some(Arc::new(Box::new(delegate)));
    }

    pub(crate) fn start_new_delivery(&mut self, delivery: Delivery) {
        self.inner().current_message = Some(delivery)
    }

    pub(crate) fn set_delivery_properties(&mut self, properties: BasicProperties) {
        if let Some(delivery) = self.inner().current_message.as_mut() {
            delivery.properties = properties;
        }
    }

    pub(crate) fn receive_delivery_content(&mut self, payload: Vec<u8>) {
        if let Some(delivery) = self.inner().current_message.as_mut() {
            delivery.receive_content(payload);
        }
    }

    pub(crate) fn new_delivery_complete(&mut self) -> Result<()> {
        let mut inner = self.inner();
        if let Some(delivery) = inner.current_message.take() {
            inner.new_delivery(delivery)?;
        }
        Ok(())
    }

    pub(crate) fn drop_prefetched_messages(&self) -> Result<()> {
        self.inner().drop_prefetched_messages()
    }

    pub(crate) fn cancel(&self) -> Result<()> {
        self.inner().cancel()
    }

    pub(crate) fn set_error(&self, error: Error) -> Result<()> {
        self.inner().set_error(error)
    }
}

pub struct ConsumerInner {
    current_message: Option<Delivery>,
    deliveries_in: Sender<DeliveryResult>,
    deliveries_out: Receiver<DeliveryResult>,
    task: Option<Waker>,
    tag: ShortString,
    delegate: Option<Arc<Box<dyn ConsumerDelegate>>>,
    executor: Arc<dyn Executor>,
}

pub struct ConsumerIterator {
    receiver: Receiver<DeliveryResult>,
}

impl Iterator for ConsumerIterator {
    type Item = Result<Delivery>;

    fn next(&mut self) -> Option<Self::Item> {
        self.receiver.recv().ok().and_then(Result::transpose)
    }
}

impl IntoIterator for Consumer {
    type Item = Result<Delivery>;
    type IntoIter = ConsumerIterator;

    fn into_iter(self) -> Self::IntoIter {
        ConsumerIterator {
            receiver: self.inner().deliveries_out.clone(),
        }
    }
}

impl fmt::Debug for Consumer {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut debug = f.debug_struct("Consumer");
        if let Some(inner) = self.inner.try_lock() {
            debug
                .field("tag", &inner.tag)
                .field("executor", &inner.executor)
                .field("task", &inner.task);
        }
        debug.finish()
    }
}

impl ConsumerInner {
    fn new(consumer_tag: ShortString, executor: Arc<dyn Executor>) -> Self {
        let (sender, receiver) = crossbeam_channel::unbounded();
        Self {
            current_message: None,
            deliveries_in: sender,
            deliveries_out: receiver,
            task: None,
            tag: consumer_tag,
            delegate: None,
            executor,
        }
    }

    pub fn next_delivery(&mut self) -> Option<DeliveryResult> {
        self.deliveries_out.try_recv().ok()
    }

    pub fn tag(&self) -> &ShortString {
        &self.tag
    }

    fn new_delivery(&mut self, delivery: Delivery) -> Result<()> {
        trace!("new_delivery; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .spawn(delegate.on_new_delivery(Ok(Some(delivery))))?;
        } else {
            self.deliveries_in
                .send(Ok(Some(delivery)))
                .expect("failed to send delivery to consumer");
        }
        if let Some(task) = self.task.as_ref() {
            task.wake_by_ref();
        }
        Ok(())
    }

    fn drop_prefetched_messages(&mut self) -> Result<()> {
        trace!("drop_prefetched_messages; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor.spawn(delegate.drop_prefetched_messages())?;
        }
        while let Some(_) = self.next_delivery() {}
        Ok(())
    }

    fn cancel(&mut self) -> Result<()> {
        trace!("cancel; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor.spawn(delegate.on_new_delivery(Ok(None)))?;
        } else {
            self.deliveries_in
                .send(Ok(None))
                .expect("failed to send cancel to consumer");
        }
        if let Some(task) = self.task.take() {
            task.wake();
        }
        Ok(())
    }

    pub fn set_error(&mut self, error: Error) -> Result<()> {
        trace!("set_error; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor.spawn(delegate.on_new_delivery(Err(error)))?;
        } else {
            self.deliveries_in
                .send(Err(error))
                .expect("failed to send error to consumer");
        }
        self.cancel()
    }
}

impl Stream for Consumer {
    type Item = Result<Delivery>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        trace!("consumer poll_next");
        let mut inner = self.inner();
        trace!(
            "consumer poll; acquired inner lock, consumer_tag={}",
            inner.tag()
        );
        inner.task = Some(cx.waker().clone());
        if let Some(delivery) = inner.next_delivery() {
            match delivery {
                Ok(Some(delivery)) => {
                    trace!(
                        "delivery; consumer_tag={}, delivery_tag={:?}",
                        inner.tag(),
                        delivery.delivery_tag
                    );
                    Poll::Ready(Some(Ok(delivery)))
                }
                Ok(None) => {
                    trace!("consumer canceled; consumer_tag={}", inner.tag());
                    Poll::Ready(None)
                }
                Err(error) => Poll::Ready(Some(Err(error))),
            }
        } else {
            trace!("delivery; status=NotReady, consumer_tag={}", inner.tag());
            Poll::Pending
        }
    }
}

#[cfg(test)]
mod futures_tests {
    use super::*;
    use crate::executor::DefaultExecutor;

    use std::task::{Context, Poll};

    use futures_test::task::new_count_waker;
    use futures_util::stream::StreamExt;

    #[test]
    fn stream_on_cancel() {
        let (waker, awoken_count) = new_count_waker();
        let mut cx = Context::from_waker(&waker);

        let mut consumer = Consumer::new(
            ShortString::from("test-consumer"),
            Arc::new(DefaultExecutor::default()),
        );

        assert_eq!(awoken_count.get(), 0);
        assert_eq!(consumer.poll_next_unpin(&mut cx), Poll::Pending);

        consumer.cancel().unwrap();

        assert_eq!(awoken_count.get(), 1);
        assert_eq!(consumer.poll_next_unpin(&mut cx), Poll::Ready(None));
    }

    #[test]
    fn stream_on_error() {
        let (waker, awoken_count) = new_count_waker();
        let mut cx = Context::from_waker(&waker);

        let mut consumer = Consumer::new(
            ShortString::from("test-consumer"),
            Arc::new(DefaultExecutor::default()),
        );

        assert_eq!(awoken_count.get(), 0);
        assert_eq!(consumer.poll_next_unpin(&mut cx), Poll::Pending);

        consumer.set_error(Error::ChannelsLimitReached).unwrap();

        assert_eq!(awoken_count.get(), 1);
        assert_eq!(
            consumer.poll_next_unpin(&mut cx),
            Poll::Ready(Some(Err(Error::ChannelsLimitReached)))
        );
    }
}
<commit_msg>Spawn in executor for pending messages<commit_after>use crate::{
    executor::Executor,
    message::{Delivery, DeliveryResult},
    types::ShortString,
    BasicProperties, Error, Result,
};
use crossbeam_channel::{Receiver, Sender};
use futures_core::stream::Stream;
use log::trace;
use parking_lot::{Mutex, MutexGuard};
use std::{
    fmt,
    future::Future,
    pin::Pin,
    sync::Arc,
    task::{Context, Poll, Waker},
};

pub trait ConsumerDelegate: Send + Sync {
    fn on_new_delivery(&self, delivery: DeliveryResult)
        -> Pin<Box<dyn Future<Output = ()> + Send>>;
    fn drop_prefetched_messages(&self) -> Pin<Box<dyn Future<Output = ()> + Send>> {
        Box::pin(async move {})
    }
}

impl<
        F: Future<Output = ()> + Send + 'static,
        DeliveryHandler: Fn(DeliveryResult) -> F + Send + Sync + 'static,
    > ConsumerDelegate for DeliveryHandler
{
    fn on_new_delivery(
        &self,
        delivery: DeliveryResult,
    ) -> Pin<Box<dyn Future<Output = ()> + Send>> {
        Box::pin(self(delivery))
    }
}

#[derive(Clone)]
pub struct Consumer {
    inner: Arc<Mutex<ConsumerInner>>,
}

impl Consumer {
    pub(crate) fn new(consumer_tag: ShortString, executor: Arc<dyn Executor>) -> Consumer {
        Consumer {
            inner: Arc::new(Mutex::new(ConsumerInner::new(consumer_tag, executor))),
        }
    }

    pub fn inner(&self) -> MutexGuard<'_, ConsumerInner> {
        self.inner.lock()
    }

    pub fn set_delegate<D: ConsumerDelegate + 'static>(&self, delegate: D) {
        let mut inner = self.inner();
        while let Some(delivery) = inner.next_delivery() {
            if let Err(err) = inner.executor.spawn(delegate.on_new_delivery(delivery)) {
                trace!("Error trying to spawn in executor: {:?}", err)
            }
        }
        inner.delegate = Some(Arc::new(Box::new(delegate)));
    }

    pub(crate) fn start_new_delivery(&mut self, delivery: Delivery) {
        self.inner().current_message = Some(delivery)
    }

    pub(crate) fn set_delivery_properties(&mut self, properties: BasicProperties) {
        if let Some(delivery) = self.inner().current_message.as_mut() {
            delivery.properties = properties;
        }
    }

    pub(crate) fn receive_delivery_content(&mut self, payload: Vec<u8>) {
        if let Some(delivery) = self.inner().current_message.as_mut() {
            delivery.receive_content(payload);
        }
    }

    pub(crate) fn new_delivery_complete(&mut self) -> Result<()> {
        let mut inner = self.inner();
        if let Some(delivery) = inner.current_message.take() {
            inner.new_delivery(delivery)?;
        }
        Ok(())
    }

    pub(crate) fn drop_prefetched_messages(&self) -> Result<()> {
        self.inner().drop_prefetched_messages()
    }

    pub(crate) fn cancel(&self) -> Result<()> {
        self.inner().cancel()
    }

    pub(crate) fn set_error(&self, error: Error) -> Result<()> {
        self.inner().set_error(error)
    }
}

pub struct ConsumerInner {
    current_message: Option<Delivery>,
    deliveries_in: Sender<DeliveryResult>,
    deliveries_out: Receiver<DeliveryResult>,
    task: Option<Waker>,
    tag: ShortString,
    delegate: Option<Arc<Box<dyn ConsumerDelegate>>>,
    executor: Arc<dyn Executor>,
}

pub struct ConsumerIterator {
    receiver: Receiver<DeliveryResult>,
}

impl Iterator for ConsumerIterator {
    type Item = Result<Delivery>;

    fn next(&mut self) -> Option<Self::Item> {
        self.receiver.recv().ok().and_then(Result::transpose)
    }
}

impl IntoIterator for Consumer {
    type Item = Result<Delivery>;
    type IntoIter = ConsumerIterator;

    fn into_iter(self) -> Self::IntoIter {
        ConsumerIterator {
            receiver: self.inner().deliveries_out.clone(),
        }
    }
}

impl fmt::Debug for Consumer {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut debug = f.debug_struct("Consumer");
        if let Some(inner) = self.inner.try_lock() {
            debug
                .field("tag", &inner.tag)
                .field("executor", &inner.executor)
                .field("task", &inner.task);
        }
        debug.finish()
    }
}

impl ConsumerInner {
    fn new(consumer_tag: ShortString, executor: Arc<dyn Executor>) -> Self {
        let (sender, receiver) = crossbeam_channel::unbounded();
        Self {
            current_message: None,
            deliveries_in: sender,
            deliveries_out: receiver,
            task: None,
            tag: consumer_tag,
            delegate: None,
            executor,
        }
    }

    pub fn next_delivery(&mut self) -> Option<DeliveryResult> {
        self.deliveries_out.try_recv().ok()
    }

    pub fn tag(&self) -> &ShortString {
        &self.tag
    }

    fn new_delivery(&mut self, delivery: Delivery) -> Result<()> {
        trace!("new_delivery; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .spawn(delegate.on_new_delivery(Ok(Some(delivery))))?;
        } else {
            self.deliveries_in
                .send(Ok(Some(delivery)))
                .expect("failed to send delivery to consumer");
        }
        if let Some(task) = self.task.as_ref() {
            task.wake_by_ref();
        }
        Ok(())
    }

    fn drop_prefetched_messages(&mut self) -> Result<()> {
        trace!("drop_prefetched_messages; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor.spawn(delegate.drop_prefetched_messages())?;
        }
        while let Some(_) = self.next_delivery() {}
        Ok(())
    }

    fn cancel(&mut self) -> Result<()> {
        trace!("cancel; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor.spawn(delegate.on_new_delivery(Ok(None)))?;
        } else {
            self.deliveries_in
                .send(Ok(None))
                .expect("failed to send cancel to consumer");
        }
        if let Some(task) = self.task.take() {
            task.wake();
        }
        Ok(())
    }

    pub fn set_error(&mut self, error: Error) -> Result<()> {
        trace!("set_error; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor.spawn(delegate.on_new_delivery(Err(error)))?;
        } else {
            self.deliveries_in
                .send(Err(error))
                .expect("failed to send error to consumer");
        }
        self.cancel()
    }
}

impl Stream for Consumer {
    type Item = Result<Delivery>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        trace!("consumer poll_next");
        let mut inner = self.inner();
        trace!(
            "consumer poll; acquired inner lock, consumer_tag={}",
            inner.tag()
        );
        inner.task = Some(cx.waker().clone());
        if let Some(delivery) = inner.next_delivery() {
            match delivery {
                Ok(Some(delivery)) => {
                    trace!(
                        "delivery; consumer_tag={}, delivery_tag={:?}",
                        inner.tag(),
                        delivery.delivery_tag
                    );
                    Poll::Ready(Some(Ok(delivery)))
                }
                Ok(None) => {
                    trace!("consumer canceled; consumer_tag={}", inner.tag());
                    Poll::Ready(None)
                }
                Err(error) => Poll::Ready(Some(Err(error))),
            }
        } else {
            trace!("delivery; status=NotReady, consumer_tag={}", inner.tag());
            Poll::Pending
        }
    }
}

#[cfg(test)]
mod futures_tests {
    use super::*;
    use crate::executor::DefaultExecutor;

    use std::task::{Context, Poll};

    use futures_test::task::new_count_waker;
    use futures_util::stream::StreamExt;

    #[test]
    fn stream_on_cancel() {
        let (waker, awoken_count) = new_count_waker();
        let mut cx = Context::from_waker(&waker);

        let mut consumer = Consumer::new(
            ShortString::from("test-consumer"),
            Arc::new(DefaultExecutor::default()),
        );

        assert_eq!(awoken_count.get(), 0);
        assert_eq!(consumer.poll_next_unpin(&mut cx), Poll::Pending);

        consumer.cancel().unwrap();

        assert_eq!(awoken_count.get(), 1);
        assert_eq!(consumer.poll_next_unpin(&mut cx), Poll::Ready(None));
    }

    #[test]
    fn stream_on_error() {
        let (waker, awoken_count) = new_count_waker();
        let mut cx = Context::from_waker(&waker);

        let mut consumer = Consumer::new(
            ShortString::from("test-consumer"),
            Arc::new(DefaultExecutor::default()),
        );

        assert_eq!(awoken_count.get(), 0);
        assert_eq!(consumer.poll_next_unpin(&mut cx), Poll::Pending);

        consumer.set_error(Error::ChannelsLimitReached).unwrap();

        assert_eq!(awoken_count.get(), 1);
        assert_eq!(
            consumer.poll_next_unpin(&mut cx),
            Poll::Ready(Some(Err(Error::ChannelsLimitReached)))
        );
    }
}
<|endoftext|>


<commit_before>use std::iter::once;

use hir::Semantics;
use ide_db::{base_db::FileRange, RootDatabase};
use itertools::Itertools;
use syntax::{
    algo, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange,
};
use text_edit::{TextEdit, TextEditBuilder};

pub enum Direction {
    Up,
    Down,
}

// Feature: Move Item
//
// Move item under cursor or selection up and down.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Move item up**
// | VS Code | **Rust Analyzer: Move item down**
// |===
pub(crate) fn move_item(
    db: &RootDatabase,
    range: FileRange,
    direction: Direction,
) -> Option<TextEdit> {
    let sema = Semantics::new(db);
    let file = sema.parse(range.file_id);

    let item = file.syntax().covering_element(range.range);
    find_ancestors(item, direction, range.range)
}

fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> {
    let root = match item {
        NodeOrToken::Node(node) => node,
        NodeOrToken::Token(token) => token.parent()?,
    };

    let movable = [
        SyntaxKind::ARG_LIST,
        SyntaxKind::GENERIC_PARAM_LIST,
        SyntaxKind::GENERIC_ARG_LIST,
        SyntaxKind::VARIANT_LIST,
        SyntaxKind::TYPE_BOUND_LIST,
        SyntaxKind::MATCH_ARM,
        SyntaxKind::PARAM,
        SyntaxKind::LET_STMT,
        SyntaxKind::EXPR_STMT,
        SyntaxKind::MATCH_EXPR,
        SyntaxKind::MACRO_CALL,
        SyntaxKind::TYPE_ALIAS,
        SyntaxKind::TRAIT,
        SyntaxKind::IMPL,
        SyntaxKind::MACRO_DEF,
        SyntaxKind::STRUCT,
        SyntaxKind::UNION,
        SyntaxKind::ENUM,
        SyntaxKind::FN,
        SyntaxKind::MODULE,
        SyntaxKind::USE,
        SyntaxKind::STATIC,
        SyntaxKind::CONST,
        SyntaxKind::MACRO_RULES,
    ];

    let ancestor = once(root.clone())
        .chain(root.ancestors())
        .find(|ancestor| movable.contains(&ancestor.kind()))?;

    move_in_direction(&ancestor, direction, range)
}

fn move_in_direction(
    node: &SyntaxNode,
    direction: Direction,
    range: TextRange,
) -> Option<TextEdit> {
    match_ast! {
        match node {
            ast::ArgList(it) => swap_sibling_in_list(it.args(), range, direction),
            ast::GenericParamList(it) => swap_sibling_in_list(it.generic_params(), range, direction),
            ast::GenericArgList(it) => swap_sibling_in_list(it.generic_args(), range, direction),
            ast::VariantList(it) => swap_sibling_in_list(it.variants(), range, direction),
            ast::TypeBoundList(it) => swap_sibling_in_list(it.bounds(), range, direction),
            _ => Some(replace_nodes(node, &match direction {
                Direction::Up => node.prev_sibling(),
                Direction::Down => node.next_sibling(),
            }?))
        }
    }
}

fn swap_sibling_in_list<'i, A: AstNode + Clone, I: Iterator<Item = A>>(
    list: I,
    range: TextRange,
    direction: Direction,
) -> Option<TextEdit> {
    let (l, r) = list
        .tuple_windows()
        .filter(|(l, r)| match direction {
            Direction::Up => r.syntax().text_range().contains_range(range),
            Direction::Down => l.syntax().text_range().contains_range(range),
        })
        .next()?;

    Some(replace_nodes(l.syntax(), r.syntax()))
}

fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit {
    let mut edit = TextEditBuilder::default();

    algo::diff(first, second).into_text_edit(&mut edit);
    algo::diff(second, first).into_text_edit(&mut edit);

    edit.finish()
}

#[cfg(test)]
mod tests {
    use crate::fixture;
    use expect_test::{expect, Expect};

    use crate::Direction;

    fn check(ra_fixture: &str, expect: Expect, direction: Direction) {
        let (analysis, range) = fixture::range(ra_fixture);
        let edit = analysis.move_item(range, direction).unwrap().unwrap_or_default();
        let mut file = analysis.file_text(range.file_id).unwrap().to_string();
        edit.apply(&mut file);
        expect.assert_eq(&file);
    }

    #[test]
    fn test_moves_match_arm_up() {
        check(
            r#"
fn main() {
    match true {
        true => {
            println!("Hello, world");
        },
        false =>$0$0 {
            println!("Test");
        }
    };
}
            "#,
            expect![[r#"
fn main() {
    match true {
        false => {
            println!("Test");
        },
        true => {
            println!("Hello, world");
        }
    };
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_match_arm_down() {
        check(
            r#"
fn main() {
    match true {
        true =>$0$0 {
            println!("Hello, world");
        },
        false => {
            println!("Test");
        }
    };
}
            "#,
            expect![[r#"
fn main() {
    match true {
        false => {
            println!("Test");
        },
        true => {
            println!("Hello, world");
        }
    };
}
            "#]],
            Direction::Down,
        );
    }

    #[test]
    fn test_nowhere_to_move() {
        check(
            r#"
fn main() {
    match true {
        true =>$0$0 {
            println!("Hello, world");
        },
        false => {
            println!("Test");
        }
    };
}
            "#,
            expect![[r#"
fn main() {
    match true {
        true => {
            println!("Hello, world");
        },
        false => {
            println!("Test");
        }
    };
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_let_stmt_up() {
        check(
            r#"
fn main() {
    let test = 123;
    let test2$0$0 = 456;
}
            "#,
            expect![[r#"
fn main() {
    let test2 = 456;
    let test = 123;
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_expr_up() {
        check(
            r#"
fn main() {
    println!("Hello, world");
    println!("All I want to say is...");$0$0
}
            "#,
            expect![[r#"
fn main() {
    println!("All I want to say is...");
    println!("Hello, world");
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_nowhere_to_move_stmt() {
        check(
            r#"
fn main() {
    println!("All I want to say is...");$0$0
    println!("Hello, world");
}
            "#,
            expect![[r#"
fn main() {
    println!("All I want to say is...");
    println!("Hello, world");
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_move_item() {
        check(
            r#"
fn main() {}

fn foo() {}$0$0
            "#,
            expect![[r#"
fn foo() {}

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_move_impl_up() {
        check(
            r#"
struct Yay;

trait Wow {}

impl Wow for Yay $0$0{}
            "#,
            expect![[r#"
struct Yay;

impl Wow for Yay {}

trait Wow {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_move_use_up() {
        check(
            r#"
use std::vec::Vec;
use std::collections::HashMap$0$0;
            "#,
            expect![[r#"
use std::collections::HashMap;
use std::vec::Vec;
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_match_expr_up() {
        check(
            r#"
fn main() {
    let test = 123;

    $0match test {
        456 => {},
        _ => {}
    };$0
}
            "#,
            expect![[r#"
fn main() {
    match test {
        456 => {},
        _ => {}
    };

    let test = 123;
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_param_up() {
        check(
            r#"
fn test(one: i32, two$0$0: u32) {}

fn main() {
    test(123, 456);
}
            "#,
            expect![[r#"
fn test(two: u32, one: i32) {}

fn main() {
    test(123, 456);
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_arg_up() {
        check(
            r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123, 456$0$0);
}
            "#,
            expect![[r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(456, 123);
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_arg_down() {
        check(
            r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123$0$0, 456);
}
            "#,
            expect![[r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(456, 123);
}
            "#]],
            Direction::Down,
        );
    }

    #[test]
    fn test_nowhere_to_move_arg() {
        check(
            r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123$0$0, 456);
}
            "#,
            expect![[r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123, 456);
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_generic_param_up() {
        check(
            r#"
struct Test<A, B$0$0>(A, B);

fn main() {}
            "#,
            expect![[r#"
struct Test<B, A>(A, B);

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_generic_arg_up() {
        check(
            r#"
struct Test<A, B>(A, B);

fn main() {
    let t = Test::<i32, &str$0$0>(123, "yay");
}
            "#,
            expect![[r#"
struct Test<A, B>(A, B);

fn main() {
    let t = Test::<&str, i32>(123, "yay");
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_variant_up() {
        check(
            r#"
enum Hello {
    One,
    Two$0$0
}

fn main() {}
            "#,
            expect![[r#"
enum Hello {
    Two,
    One
}

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_type_bound_up() {
        check(
            r#"
trait One {}

trait Two {}

fn test<T: One + Two$0$0>(t: T) {}

fn main() {}
            "#,
            expect![[r#"
trait One {}

trait Two {}

fn test<T: Two + One>(t: T) {}

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_prioritizes_trait_items() {
        check(
            r#"
struct Test;

trait Yay {
    type One;

    type Two;

    fn inner();
}

impl Yay for Test {
    type One = i32;

    type Two = u32;

    fn inner() {$0$0
        println!("Mmmm");
    }
}
            "#,
            expect![[r#"
struct Test;

trait Yay {
    type One;

    type Two;

    fn inner();
}

impl Yay for Test {
    type One = i32;

    fn inner() {
        println!("Mmmm");
    }

    type Two = u32;
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_weird_nesting() {
        check(
            r#"
fn test() {
    mod hello {
        fn inner() {}
    }

    mod hi {$0$0
        fn inner() {}
    }
}
            "#,
            expect![[r#"
fn test() {
    mod hi {
        fn inner() {}
    }

    mod hello {
        fn inner() {}
    }
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn handles_empty_file() {
        check(r#"$0$0"#, expect![[r#""#]], Direction::Up);
    }
}
<commit_msg>Remove needless lifetime<commit_after>use std::iter::once;

use hir::Semantics;
use ide_db::{base_db::FileRange, RootDatabase};
use itertools::Itertools;
use syntax::{
    algo, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange,
};
use text_edit::{TextEdit, TextEditBuilder};

pub enum Direction {
    Up,
    Down,
}

// Feature: Move Item
//
// Move item under cursor or selection up and down.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Move item up**
// | VS Code | **Rust Analyzer: Move item down**
// |===
pub(crate) fn move_item(
    db: &RootDatabase,
    range: FileRange,
    direction: Direction,
) -> Option<TextEdit> {
    let sema = Semantics::new(db);
    let file = sema.parse(range.file_id);

    let item = file.syntax().covering_element(range.range);
    find_ancestors(item, direction, range.range)
}

fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> {
    let root = match item {
        NodeOrToken::Node(node) => node,
        NodeOrToken::Token(token) => token.parent()?,
    };

    let movable = [
        SyntaxKind::ARG_LIST,
        SyntaxKind::GENERIC_PARAM_LIST,
        SyntaxKind::GENERIC_ARG_LIST,
        SyntaxKind::VARIANT_LIST,
        SyntaxKind::TYPE_BOUND_LIST,
        SyntaxKind::MATCH_ARM,
        SyntaxKind::PARAM,
        SyntaxKind::LET_STMT,
        SyntaxKind::EXPR_STMT,
        SyntaxKind::MATCH_EXPR,
        SyntaxKind::MACRO_CALL,
        SyntaxKind::TYPE_ALIAS,
        SyntaxKind::TRAIT,
        SyntaxKind::IMPL,
        SyntaxKind::MACRO_DEF,
        SyntaxKind::STRUCT,
        SyntaxKind::UNION,
        SyntaxKind::ENUM,
        SyntaxKind::FN,
        SyntaxKind::MODULE,
        SyntaxKind::USE,
        SyntaxKind::STATIC,
        SyntaxKind::CONST,
        SyntaxKind::MACRO_RULES,
    ];

    let ancestor = once(root.clone())
        .chain(root.ancestors())
        .find(|ancestor| movable.contains(&ancestor.kind()))?;

    move_in_direction(&ancestor, direction, range)
}

fn move_in_direction(
    node: &SyntaxNode,
    direction: Direction,
    range: TextRange,
) -> Option<TextEdit> {
    match_ast! {
        match node {
            ast::ArgList(it) => swap_sibling_in_list(it.args(), range, direction),
            ast::GenericParamList(it) => swap_sibling_in_list(it.generic_params(), range, direction),
            ast::GenericArgList(it) => swap_sibling_in_list(it.generic_args(), range, direction),
            ast::VariantList(it) => swap_sibling_in_list(it.variants(), range, direction),
            ast::TypeBoundList(it) => swap_sibling_in_list(it.bounds(), range, direction),
            _ => Some(replace_nodes(node, &match direction {
                Direction::Up => node.prev_sibling(),
                Direction::Down => node.next_sibling(),
            }?))
        }
    }
}

fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>(
    list: I,
    range: TextRange,
    direction: Direction,
) -> Option<TextEdit> {
    let (l, r) = list
        .tuple_windows()
        .filter(|(l, r)| match direction {
            Direction::Up => r.syntax().text_range().contains_range(range),
            Direction::Down => l.syntax().text_range().contains_range(range),
        })
        .next()?;

    Some(replace_nodes(l.syntax(), r.syntax()))
}

fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit {
    let mut edit = TextEditBuilder::default();

    algo::diff(first, second).into_text_edit(&mut edit);
    algo::diff(second, first).into_text_edit(&mut edit);

    edit.finish()
}

#[cfg(test)]
mod tests {
    use crate::fixture;
    use expect_test::{expect, Expect};

    use crate::Direction;

    fn check(ra_fixture: &str, expect: Expect, direction: Direction) {
        let (analysis, range) = fixture::range(ra_fixture);
        let edit = analysis.move_item(range, direction).unwrap().unwrap_or_default();
        let mut file = analysis.file_text(range.file_id).unwrap().to_string();
        edit.apply(&mut file);
        expect.assert_eq(&file);
    }

    #[test]
    fn test_moves_match_arm_up() {
        check(
            r#"
fn main() {
    match true {
        true => {
            println!("Hello, world");
        },
        false =>$0$0 {
            println!("Test");
        }
    };
}
            "#,
            expect![[r#"
fn main() {
    match true {
        false => {
            println!("Test");
        },
        true => {
            println!("Hello, world");
        }
    };
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_match_arm_down() {
        check(
            r#"
fn main() {
    match true {
        true =>$0$0 {
            println!("Hello, world");
        },
        false => {
            println!("Test");
        }
    };
}
            "#,
            expect![[r#"
fn main() {
    match true {
        false => {
            println!("Test");
        },
        true => {
            println!("Hello, world");
        }
    };
}
            "#]],
            Direction::Down,
        );
    }

    #[test]
    fn test_nowhere_to_move() {
        check(
            r#"
fn main() {
    match true {
        true =>$0$0 {
            println!("Hello, world");
        },
        false => {
            println!("Test");
        }
    };
}
            "#,
            expect![[r#"
fn main() {
    match true {
        true => {
            println!("Hello, world");
        },
        false => {
            println!("Test");
        }
    };
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_let_stmt_up() {
        check(
            r#"
fn main() {
    let test = 123;
    let test2$0$0 = 456;
}
            "#,
            expect![[r#"
fn main() {
    let test2 = 456;
    let test = 123;
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_expr_up() {
        check(
            r#"
fn main() {
    println!("Hello, world");
    println!("All I want to say is...");$0$0
}
            "#,
            expect![[r#"
fn main() {
    println!("All I want to say is...");
    println!("Hello, world");
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_nowhere_to_move_stmt() {
        check(
            r#"
fn main() {
    println!("All I want to say is...");$0$0
    println!("Hello, world");
}
            "#,
            expect![[r#"
fn main() {
    println!("All I want to say is...");
    println!("Hello, world");
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_move_item() {
        check(
            r#"
fn main() {}

fn foo() {}$0$0
            "#,
            expect![[r#"
fn foo() {}

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_move_impl_up() {
        check(
            r#"
struct Yay;

trait Wow {}

impl Wow for Yay $0$0{}
            "#,
            expect![[r#"
struct Yay;

impl Wow for Yay {}

trait Wow {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_move_use_up() {
        check(
            r#"
use std::vec::Vec;
use std::collections::HashMap$0$0;
            "#,
            expect![[r#"
use std::collections::HashMap;
use std::vec::Vec;
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_match_expr_up() {
        check(
            r#"
fn main() {
    let test = 123;

    $0match test {
        456 => {},
        _ => {}
    };$0
}
            "#,
            expect![[r#"
fn main() {
    match test {
        456 => {},
        _ => {}
    };

    let test = 123;
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_param_up() {
        check(
            r#"
fn test(one: i32, two$0$0: u32) {}

fn main() {
    test(123, 456);
}
            "#,
            expect![[r#"
fn test(two: u32, one: i32) {}

fn main() {
    test(123, 456);
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_arg_up() {
        check(
            r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123, 456$0$0);
}
            "#,
            expect![[r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(456, 123);
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_arg_down() {
        check(
            r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123$0$0, 456);
}
            "#,
            expect![[r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(456, 123);
}
            "#]],
            Direction::Down,
        );
    }

    #[test]
    fn test_nowhere_to_move_arg() {
        check(
            r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123$0$0, 456);
}
            "#,
            expect![[r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123, 456);
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_generic_param_up() {
        check(
            r#"
struct Test<A, B$0$0>(A, B);

fn main() {}
            "#,
            expect![[r#"
struct Test<B, A>(A, B);

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_generic_arg_up() {
        check(
            r#"
struct Test<A, B>(A, B);

fn main() {
    let t = Test::<i32, &str$0$0>(123, "yay");
}
            "#,
            expect![[r#"
struct Test<A, B>(A, B);

fn main() {
    let t = Test::<&str, i32>(123, "yay");
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_variant_up() {
        check(
            r#"
enum Hello {
    One,
    Two$0$0
}

fn main() {}
            "#,
            expect![[r#"
enum Hello {
    Two,
    One
}

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_type_bound_up() {
        check(
            r#"
trait One {}

trait Two {}

fn test<T: One + Two$0$0>(t: T) {}

fn main() {}
            "#,
            expect![[r#"
trait One {}

trait Two {}

fn test<T: Two + One>(t: T) {}

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_prioritizes_trait_items() {
        check(
            r#"
struct Test;

trait Yay {
    type One;

    type Two;

    fn inner();
}

impl Yay for Test {
    type One = i32;

    type Two = u32;

    fn inner() {$0$0
        println!("Mmmm");
    }
}
            "#,
            expect![[r#"
struct Test;

trait Yay {
    type One;

    type Two;

    fn inner();
}

impl Yay for Test {
    type One = i32;

    fn inner() {
        println!("Mmmm");
    }

    type Two = u32;
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_weird_nesting() {
        check(
            r#"
fn test() {
    mod hello {
        fn inner() {}
    }

    mod hi {$0$0
        fn inner() {}
    }
}
            "#,
            expect![[r#"
fn test() {
    mod hi {
        fn inner() {}
    }

    mod hello {
        fn inner() {}
    }
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn handles_empty_file() {
        check(r#"$0$0"#, expect![[r#""#]], Direction::Up);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// gpio_status.rs
//
// Retrieves the mode and logic level for each of the pins on the standard
// 40-pin GPIO header, and displays the results in an ASCII table.

use std::fmt;
use std::process::exit;

use rppal::gpio::Gpio;
use rppal::system::{DeviceInfo, Model};

enum PinType {
    Gpio(u8),
    Ground,
    Power3v3,
    Power5v,
}

impl fmt::Display for PinType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            PinType::Gpio(pin) => write!(f, "GPIO{}", pin),
            PinType::Ground => write!(f, "{:<5}", "GND"),
            PinType::Power3v3 => write!(f, "{:<5}", "3.3 V"),
            PinType::Power5v => write!(f, "{:<5}", "5 V"),
        }
    }
}

const HEADER: [PinType; 40] = [
    PinType::Power3v3, // Physical pin 1
    PinType::Power5v,  // Physical pin 2
    PinType::Gpio(2),  // Physical pin 3
    PinType::Power5v,  // Physical pin 4
    PinType::Gpio(3),  // Physical pin 5
    PinType::Ground,   // Physical pin 6
    PinType::Gpio(4),  // Physical pin 7
    PinType::Gpio(14), // Physical pin 8
    PinType::Ground,   // Physical pin 9
    PinType::Gpio(15), // Physical pin 10
    PinType::Gpio(17), // Physical pin 11
    PinType::Gpio(18), // Physical pin 12
    PinType::Gpio(27), // Physical pin 13
    PinType::Ground,   // Physical pin 14
    PinType::Gpio(22), // Physical pin 15
    PinType::Gpio(23), // Physical pin 16
    PinType::Power3v3, // Physical pin 17
    PinType::Gpio(24), // Physical pin 18
    PinType::Gpio(10), // Physical pin 19
    PinType::Ground,   // Physical pin 20
    PinType::Gpio(9),  // Physical pin 21
    PinType::Gpio(25), // Physical pin 22
    PinType::Gpio(11), // Physical pin 23
    PinType::Gpio(8),  // Physical pin 24
    PinType::Ground,   // Physical pin 25
    PinType::Gpio(7),  // Physical pin 26
    PinType::Gpio(0),  // Physical pin 27
    PinType::Gpio(1),  // Physical pin 28
    PinType::Gpio(5),  // Physical pin 29
    PinType::Ground,   // Physical pin 30
    PinType::Gpio(6),  // Physical pin 31
    PinType::Gpio(12), // Physical pin 32
    PinType::Gpio(13), // Physical pin 33
    PinType::Ground,   // Physical pin 34
    PinType::Gpio(19), // Physical pin 35
    PinType::Gpio(16), // Physical pin 36
    PinType::Gpio(26), // Physical pin 37
    PinType::Gpio(20), // Physical pin 38
    PinType::Ground,   // Physical pin 39
    PinType::Gpio(21), // Physical pin 40
];

const MAX_PINS_SHORT: usize = 26;
const MAX_PINS_LONG: usize = 40;

fn format_pin(
    buf: &mut String,
    pin: usize,
    gpio: impl fmt::Display,
    mode: impl fmt::Display,
    level: impl fmt::Display,
) {
    if pin % 2 != 0 {
        buf.push_str(&format!(
            "| {:>4} | {:<5} | {:>1} | {:>2} |",
            gpio, mode, level, pin
        ));
    } else {
        buf.push_str(&format!(
            " {:>2} | {:>1} | {:<5} | {:>4} |\n",
            pin, level, mode, gpio
        ));
    }
}

fn print_header(max: usize) {
    let gpio = Gpio::new().unwrap_or_else(|e| {
        eprintln!("Error: Can't access GPIO peripheral ({})", e);
        exit(1);
    });

    let mut buf = String::with_capacity(1600);

    buf.push_str("+------+-------+---+---------+---+-------+------+\n");
    buf.push_str("| GPIO | Mode  | L |   Pin   | L | Mode  | GPIO |\n");
    buf.push_str("+------+-------+---+----+----+---+-------+------+\n");

    for (idx, pin_type) in HEADER.iter().take(max).enumerate() {
        match pin_type {
            PinType::Gpio(bcm_gpio) => {
                let pin = gpio.get(*bcm_gpio).unwrap_or_else(|| {
                    eprintln!("Error: Can't access GPIO pin {}", *bcm_gpio);
                    exit(1);
                });

                format_pin(
                    &mut buf,
                    idx + 1,
                    bcm_gpio,
                    format!("{}", pin.mode()).to_uppercase(),
                    pin.read() as u8,
                );
            }
            _ => format_pin(&mut buf, idx + 1, "", pin_type, ""),
        };
    }

    buf.push_str("+------+-------+---+----+----+---+-------+------+\n");

    print!("{}", buf);
}

fn main() {
    match DeviceInfo::new()
        .unwrap_or_else(|e| {
            eprintln!("Error: Can't identify Raspberry Pi model ({})", e);
            exit(1);
        })
        .model()
    {
        Model::RaspberryPiA | Model::RaspberryPiBRev1 | Model::RaspberryPiBRev2 => {
            print_header(MAX_PINS_SHORT)
        }
        Model::RaspberryPiAPlus
        | Model::RaspberryPiBPlus
        | Model::RaspberryPi2B
        | Model::RaspberryPi3APlus
        | Model::RaspberryPi3B
        | Model::RaspberryPi3BPlus
        | Model::RaspberryPiZero
        | Model::RaspberryPiZeroW => print_header(MAX_PINS_LONG),
        model => {
            eprintln!("Error: No GPIO header information available for {}", model);
            exit(1);
        }
    }
}
<commit_msg>Update documentation<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// gpio_status.rs
//
// Retrieves the mode and logic level for each of the pins on the 26-pin or
// 40-pin GPIO header, and displays the results in an ASCII table.

use std::fmt;
use std::process::exit;

use rppal::gpio::Gpio;
use rppal::system::{DeviceInfo, Model};

enum PinType {
    Gpio(u8),
    Ground,
    Power3v3,
    Power5v,
}

impl fmt::Display for PinType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            PinType::Gpio(pin) => write!(f, "GPIO{}", pin),
            PinType::Ground => write!(f, "{:<5}", "GND"),
            PinType::Power3v3 => write!(f, "{:<5}", "3.3 V"),
            PinType::Power5v => write!(f, "{:<5}", "5 V"),
        }
    }
}

const HEADER: [PinType; 40] = [
    PinType::Power3v3, // Physical pin 1
    PinType::Power5v,  // Physical pin 2
    PinType::Gpio(2),  // Physical pin 3
    PinType::Power5v,  // Physical pin 4
    PinType::Gpio(3),  // Physical pin 5
    PinType::Ground,   // Physical pin 6
    PinType::Gpio(4),  // Physical pin 7
    PinType::Gpio(14), // Physical pin 8
    PinType::Ground,   // Physical pin 9
    PinType::Gpio(15), // Physical pin 10
    PinType::Gpio(17), // Physical pin 11
    PinType::Gpio(18), // Physical pin 12
    PinType::Gpio(27), // Physical pin 13
    PinType::Ground,   // Physical pin 14
    PinType::Gpio(22), // Physical pin 15
    PinType::Gpio(23), // Physical pin 16
    PinType::Power3v3, // Physical pin 17
    PinType::Gpio(24), // Physical pin 18
    PinType::Gpio(10), // Physical pin 19
    PinType::Ground,   // Physical pin 20
    PinType::Gpio(9),  // Physical pin 21
    PinType::Gpio(25), // Physical pin 22
    PinType::Gpio(11), // Physical pin 23
    PinType::Gpio(8),  // Physical pin 24
    PinType::Ground,   // Physical pin 25
    PinType::Gpio(7),  // Physical pin 26
    PinType::Gpio(0),  // Physical pin 27
    PinType::Gpio(1),  // Physical pin 28
    PinType::Gpio(5),  // Physical pin 29
    PinType::Ground,   // Physical pin 30
    PinType::Gpio(6),  // Physical pin 31
    PinType::Gpio(12), // Physical pin 32
    PinType::Gpio(13), // Physical pin 33
    PinType::Ground,   // Physical pin 34
    PinType::Gpio(19), // Physical pin 35
    PinType::Gpio(16), // Physical pin 36
    PinType::Gpio(26), // Physical pin 37
    PinType::Gpio(20), // Physical pin 38
    PinType::Ground,   // Physical pin 39
    PinType::Gpio(21), // Physical pin 40
];

const MAX_PINS_SHORT: usize = 26;
const MAX_PINS_LONG: usize = 40;

fn format_pin(
    buf: &mut String,
    pin: usize,
    gpio: impl fmt::Display,
    mode: impl fmt::Display,
    level: impl fmt::Display,
) {
    if pin % 2 != 0 {
        buf.push_str(&format!(
            "| {:>4} | {:<5} | {:>1} | {:>2} |",
            gpio, mode, level, pin
        ));
    } else {
        buf.push_str(&format!(
            " {:>2} | {:>1} | {:<5} | {:>4} |\n",
            pin, level, mode, gpio
        ));
    }
}

fn print_header(max: usize) {
    let gpio = Gpio::new().unwrap_or_else(|e| {
        eprintln!("Error: Can't access GPIO peripheral ({})", e);
        exit(1);
    });

    let mut buf = String::with_capacity(1600);

    buf.push_str("+------+-------+---+---------+---+-------+------+\n");
    buf.push_str("| GPIO | Mode  | L |   Pin   | L | Mode  | GPIO |\n");
    buf.push_str("+------+-------+---+----+----+---+-------+------+\n");

    for (idx, pin_type) in HEADER.iter().take(max).enumerate() {
        match pin_type {
            PinType::Gpio(bcm_gpio) => {
                let pin = gpio.get(*bcm_gpio).unwrap_or_else(|| {
                    eprintln!("Error: Can't access GPIO pin {}", *bcm_gpio);
                    exit(1);
                });

                format_pin(
                    &mut buf,
                    idx + 1,
                    bcm_gpio,
                    format!("{}", pin.mode()).to_uppercase(),
                    pin.read() as u8,
                );
            }
            _ => format_pin(&mut buf, idx + 1, "", pin_type, ""),
        };
    }

    buf.push_str("+------+-------+---+----+----+---+-------+------+\n");

    print!("{}", buf);
}

fn main() {
    match DeviceInfo::new()
        .unwrap_or_else(|e| {
            eprintln!("Error: Can't identify Raspberry Pi model ({})", e);
            exit(1);
        })
        .model()
    {
        Model::RaspberryPiA | Model::RaspberryPiBRev1 | Model::RaspberryPiBRev2 => {
            print_header(MAX_PINS_SHORT)
        }
        Model::RaspberryPiAPlus
        | Model::RaspberryPiBPlus
        | Model::RaspberryPi2B
        | Model::RaspberryPi3APlus
        | Model::RaspberryPi3B
        | Model::RaspberryPi3BPlus
        | Model::RaspberryPiZero
        | Model::RaspberryPiZeroW => print_header(MAX_PINS_LONG),
        model => {
            eprintln!("Error: No GPIO header information available for {}", model);
            exit(1);
        }
    }
}
<|endoftext|>


<commit_before>/// Deorginalizes a `String`
///
/// #Examples
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "0.1".to_string();
///     let expected_string: String = "0.1".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "-1st".to_string();
///     let expected_string: String = "-1".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "0th".to_string();
///     let expected_string: String = "0".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "1st".to_string();
///     let expected_string: String = "1".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "2nd".to_string();
///     let expected_string: String = "2".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "3rd".to_string();
///     let expected_string: String = "3".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "9th".to_string();
///     let expected_string: String = "9".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "12th".to_string();
///     let expected_string: String = "12".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "12000th".to_string();
///     let expected_string: String = "12000".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "12001th".to_string();
///     let expected_string: String = "12001".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "12002nd".to_string();
///     let expected_string: String = "12002".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "12003rd".to_string();
///     let expected_string: String = "12003".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "12004th".to_string();
///     let expected_string: String = "12004".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
pub fn deordinalize(non_ordinalized_string: String) -> String {
    if non_ordinalized_string.contains('.') {
        non_ordinalized_string
    } else {
        non_ordinalized_string.trim_right_matches("st")
            .trim_right_matches("nd")
            .trim_right_matches("rd")
            .trim_right_matches("th")
            .to_string()
    }
}
<commit_msg>formatting<commit_after>/// Deorginalizes a `String`
///
/// #Examples
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "0.1".to_string();
///     let expected_string: String = "0.1".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "-1st".to_string();
///     let expected_string: String = "-1".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "0th".to_string();
///     let expected_string: String = "0".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "1st".to_string();
///     let expected_string: String = "1".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "2nd".to_string();
///     let expected_string: String = "2".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "3rd".to_string();
///     let expected_string: String = "3".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "9th".to_string();
///     let expected_string: String = "9".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "12th".to_string();
///     let expected_string: String = "12".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "12000th".to_string();
///     let expected_string: String = "12000".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "12001th".to_string();
///     let expected_string: String = "12001".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "12002nd".to_string();
///     let expected_string: String = "12002".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "12003rd".to_string();
///     let expected_string: String = "12003".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::numbers::deordinalize::deordinalize;
///     let mock_string: String = "12004th".to_string();
///     let expected_string: String = "12004".to_string();
///     let asserted_string: String = deordinalize(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
pub fn deordinalize(non_ordinalized_string: String) -> String {
    if non_ordinalized_string.contains('.') {
        non_ordinalized_string
    } else {
        non_ordinalized_string
            .trim_right_matches("st")
            .trim_right_matches("nd")
            .trim_right_matches("rd")
            .trim_right_matches("th")
            .to_string()
    }
}
<|endoftext|>