<commit_before>use std::time::Duration;
use std::ops::AddAssign;
use ggez::{Context, GameResult, graphics, event};

mod well;
mod tetromino;
mod shapes;
mod bag;
mod util;

use ggez::event::*;
use self::well::Well;
use self::tetromino::Piece;
use self::bag::PieceBag;
use self::util::DurationExt;

const BLOCK_SIZE: f32 = 30.0;
const FALL_SPEED: f64 = 0.5;
const INPUT_DELAY_TIME: f64 = 0.10;

#[derive(Copy, Clone, Debug)]
pub struct Position {
    x: i32,
    y: i32,
}

impl Position {
    fn new(x: i32, y: i32) -> Self {
        Self {
            x: x,
            y: y,
        }
    }
}

impl AddAssign for Position {
    fn add_assign(&mut self, other: Position) {
        *self = Position {
            x: self.x + other.x,
            y: self.y + other.y,
        };
    }
}

#[derive(Debug, Copy, Clone)]
pub struct InputStateField {
    is_active: bool,
    delay_timer: f64,
}

impl Default for InputStateField {
    fn default() -> Self {
        InputStateField {
            is_active: false,
            delay_timer: INPUT_DELAY_TIME,
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct InputState {
    left: InputStateField,
    right: InputStateField,
    soft_drop: InputStateField,
    hard_drop: InputStateField,
    rotate_clockwise: InputStateField,
    rotate_counterclockwise: InputStateField,
    drop: InputStateField,
}

impl Default for InputState {
    fn default() -> Self {

        InputState {
            left: InputStateField::default(),
            right: InputStateField::default(),
            soft_drop: InputStateField::default(),
            hard_drop: InputStateField::default(),
            rotate_clockwise: InputStateField::default(),
            rotate_counterclockwise: InputStateField::default(),
            drop: InputStateField::default(),
        }
    }
}

pub struct PlayState {
    input: InputState,
    prev_input: InputState,

    well: Well,
    bag: PieceBag,
    current_piece: Piece,

    fall_timer: f64,
    score: u32,
    cleared_lines: u16,
    level: u32,
    game_over: bool,

    // temp
    image: graphics::Image,
}

impl PlayState {
    pub fn new(ctx: &mut Context) -> GameResult<PlayState> {
        let image = graphics::Image::new(ctx, "/block.png")?;
        let mut bag = PieceBag::new();
        let first_piece = bag.take_piece();

        let state = PlayState {
            input: InputState::default(),
            prev_input: InputState::default(),

            well: Well::new(),
            bag: bag,
            current_piece: first_piece,

            fall_timer: 0.0,
            score: 0,
            cleared_lines: 0,
            level: 0,
            game_over: false,

            image: image,
        };

        Ok(state)
    }

    fn handle_user_input(&mut self, dt: Duration) -> GameResult<()> {
        if self.input.left.is_active {
            self.input.left.delay_timer += dt.as_subsec_millis();
            if self.input.left.delay_timer >= INPUT_DELAY_TIME {
                self.move_piece(Position::new(-1, 0));
                self.input.left.delay_timer = 0.0;
            }
        } else if self.input.right.is_active {
            self.input.right.delay_timer += dt.as_subsec_millis();
            if self.input.right.delay_timer >= INPUT_DELAY_TIME {
                self.move_piece(Position::new(1, 0));
                self.input.right.delay_timer = 0.0;
            }
        } else if self.input.soft_drop.is_active {
            self.input.soft_drop.delay_timer += dt.as_subsec_millis();
            if self.input.soft_drop.delay_timer >= INPUT_DELAY_TIME {
                self.move_piece(Position::new(0, 1));
                self.input.soft_drop.delay_timer = 0.0;
            }
        } else if self.input.rotate_clockwise.is_active {
            if self.input.rotate_clockwise.is_active != self.prev_input.rotate_clockwise.is_active {
                self.rotate_piece(1);
            }
        } else if self.input.rotate_counterclockwise.is_active {
            if self.input.rotate_counterclockwise.is_active != self.prev_input.rotate_counterclockwise.is_active {
                self.rotate_piece(-1);
            }
        } else if self.input.hard_drop.is_active {
            if self.input.hard_drop.is_active != self.prev_input.hard_drop.is_active {
                self.current_piece.top_left = self.current_piece.get_shadow_position();
                self.well.land(&self.current_piece);
                self.current_piece = self.bag.take_piece();
            }
        }

        Ok(())
    }

    fn move_piece(&mut self, potential_new_position: Position) {
        self.current_piece.potential_top_left += potential_new_position;
        let current_shape = self.current_piece.get_shape();
        let collision_found = self.well
            .check_for_collisions(&current_shape, &self.current_piece.potential_top_left);

        if collision_found {
            self.current_piece.potential_top_left = self.current_piece.top_left;
        }

        self.current_piece.top_left = self.current_piece.potential_top_left; // advance tetromino
    }

    fn rotate_piece(&mut self, direction: i32) {
        let next_shape = self.current_piece.get_next_shape(direction);
        let collision_found = self.well
            .check_for_collisions(&next_shape, &self.current_piece.top_left);

        if !collision_found {
            self.current_piece.change_shape(direction);
        } else {
            // wall kick attempt!
            // need to do 2 checks:
            // move one piece to the right & perform all above checks
            let mut potential_position = self.current_piece.top_left; // creates a copy of 'Position' struct
            potential_position.x += 1;
            let collision_found = self.well
                .check_for_collisions(&next_shape, &potential_position);

            if !collision_found {
                self.current_piece.top_left = potential_position;
                self.current_piece.potential_top_left = potential_position;
                self.current_piece.change_shape(direction);
            } else {
                let mut potential_position = self.current_piece.top_left;
                potential_position.x -= 1;
                let collision_found = self.well
                    .check_for_collisions(&next_shape, &potential_position);

                if !collision_found {
                    self.current_piece.top_left = potential_position;
                    self.current_piece.potential_top_left = potential_position;
                    self.current_piece.change_shape(direction);
                }
            }
        }

    }

    /// Advance the fall time. If enough time has passed, allow gravity to
    /// affect the current piece.
    /// Returns a `GameResult<false>` if a landing occured.
    /// Returns a `GameResult<true>` if no landing occured and the piece can advance.
    fn handle_gravity(&mut self, dt: Duration) -> GameResult<bool> {
        self.fall_timer += dt.as_subsec_millis();

        if self.fall_timer >= FALL_SPEED {
            let current_shape = self.current_piece.get_shape();
            self.fall_timer = 0.0;
            self.current_piece.potential_top_left.y += 1;

            let did_land = self.well
                .check_for_landing(&current_shape, &self.current_piece.potential_top_left);

            if did_land {
                if self.current_piece.top_left.y < 2 {
                    println!("game over!");
                    self.game_over = true;
                    return Ok(false);
                }

                // game isn't over - take another piece and move to next frame
                self.well.land(&self.current_piece);
                self.current_piece = self.bag.take_piece();
                return Ok(false);
            }

            // piece did not land - advance!
            self.current_piece.top_left = self.current_piece.potential_top_left;
        }

        Ok(true)
    }

    fn handle_shadow_piece(&mut self) -> GameResult<()> {
        let mut shadow_position = self.current_piece.top_left;
        let mut potential_shadow_position = shadow_position;
        loop {
            potential_shadow_position.y += 1;
            let collision_found = self.well
                .check_for_landing(&self.current_piece.get_shape(), &potential_shadow_position);

            if collision_found {
                break;
            }

            shadow_position = potential_shadow_position;
            self.current_piece.set_shadow_position(shadow_position);
        }

        Ok(())
    }

    fn handle_line_clears(&mut self) -> GameResult<()> {
        // check for line clears
        let mut lines_cleared = 0;
        for r in (0..self.well.data.len()).rev() {
            let mut is_row_filled = true;
            for (c, _) in self.well.data[r].iter().enumerate() {
                if self.well.data[r][c] == 0 {
                    is_row_filled = false;
                    break; // no need to continue iterating, line is not clear...
                }
            }

            if is_row_filled {
                // TODO: implement more line clearing algorithms
                // TODO: make the current line clearing algorithm user selectable
                self.well.naive_line_clear(r);
                lines_cleared += 1;
            }
        }

        // add to score
        let level = self.level;
        match lines_cleared {
            1 => self.increase_score(40, level),
            2 => self.increase_score(100, level),
            3 => self.increase_score(300, level),
            4 => self.increase_score(1200, level),
            _ => (),
        }

        self.cleared_lines += lines_cleared;

        Ok(())
    }

    fn increase_score(&mut self, base_score: u32, level: u32) {
        self.score += base_score * (level + 1);
    }
}

impl event::EventHandler for PlayState {
    fn update(&mut self, _: &mut Context, dt: Duration) -> GameResult<()> {
        println!("[state.update] Start of update method");
        println!("[state.update] current score: {}", self.score);

        if self.game_over {
            // do game over stuff
            return Ok(());
        }

        // TODO: handle/respond user input
        self.handle_user_input(dt)?;

        // handle shadow piece
        // TODO: put behind option
        self.handle_shadow_piece()?;

        // handle gravity - return from update if our current piece landed
        if let Ok(false) = self.handle_gravity(dt) {
            return Ok(());
        }

        self.handle_line_clears()?;

        self.prev_input = self.input;

        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::set_background_color(ctx, graphics::Color::new(0.0, 0.0, 0.0, 255.0));
        graphics::clear(ctx);

        self.well.draw(ctx, &self.image)?;
        self.current_piece
            .draw_shadow(ctx, &self.image, &self.current_piece.get_shadow_position())?;
        self.current_piece.draw(ctx, &self.image)?;

        graphics::present(ctx);

        Ok(())
    }

    fn key_down_event(&mut self, keycode: Keycode, _keymod: Mod, _repeat: bool) {
        match keycode {
            Keycode::Left => self.input.left.is_active = true,
            Keycode::Right => self.input.right.is_active = true,
            Keycode::Up => self.input.hard_drop.is_active = true,
            Keycode::Down => self.input.soft_drop.is_active = true,
            Keycode::Z => self.input.rotate_counterclockwise.is_active = true,
            Keycode::X => self.input.rotate_clockwise.is_active = true,
            _ => (),
        }

    }

    fn key_up_event(&mut self, keycode: Keycode, _keymod: Mod, _repeat: bool) {
        match keycode {
            Keycode::Left => {
                self.input.left.is_active = false;
                self.input.left.delay_timer = INPUT_DELAY_TIME;
            }
            Keycode::Right => {
                self.input.right.is_active = false;
                self.input.right.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::Up => {
                self.input.hard_drop.is_active = false;
                self.input.hard_drop.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::Down => {
                self.input.soft_drop.is_active = false;
                self.input.soft_drop.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::Z => {
                self.input.rotate_counterclockwise.is_active = false;
                self.input.rotate_counterclockwise.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::X => {
                self.input.rotate_clockwise.is_active = false;
                self.input.rotate_clockwise.delay_timer = INPUT_DELAY_TIME;
            },
            _ => (),
        }
    }
}
<commit_msg>mess around with input delay timer<commit_after>use std::time::Duration;
use std::ops::AddAssign;
use ggez::{Context, GameResult, graphics, event};

mod well;
mod tetromino;
mod shapes;
mod bag;
mod util;

use ggez::event::*;
use self::well::Well;
use self::tetromino::Piece;
use self::bag::PieceBag;
use self::util::DurationExt;

const BLOCK_SIZE: f32 = 30.0;
const FALL_SPEED: f64 = 0.5;
const INPUT_DELAY_TIME: f64 = 0.05;

#[derive(Copy, Clone, Debug)]
pub struct Position {
    x: i32,
    y: i32,
}

impl Position {
    fn new(x: i32, y: i32) -> Self {
        Self {
            x: x,
            y: y,
        }
    }
}

impl AddAssign for Position {
    fn add_assign(&mut self, other: Position) {
        *self = Position {
            x: self.x + other.x,
            y: self.y + other.y,
        };
    }
}

#[derive(Debug, Copy, Clone)]
pub struct InputStateField {
    is_active: bool,
    delay_timer: f64,
}

impl Default for InputStateField {
    fn default() -> Self {
        InputStateField {
            is_active: false,
            delay_timer: INPUT_DELAY_TIME,
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct InputState {
    left: InputStateField,
    right: InputStateField,
    soft_drop: InputStateField,
    hard_drop: InputStateField,
    rotate_clockwise: InputStateField,
    rotate_counterclockwise: InputStateField,
    drop: InputStateField,
}

impl Default for InputState {
    fn default() -> Self {

        InputState {
            left: InputStateField::default(),
            right: InputStateField::default(),
            soft_drop: InputStateField::default(),
            hard_drop: InputStateField::default(),
            rotate_clockwise: InputStateField::default(),
            rotate_counterclockwise: InputStateField::default(),
            drop: InputStateField::default(),
        }
    }
}

pub struct PlayState {
    input: InputState,
    prev_input: InputState,

    well: Well,
    bag: PieceBag,
    current_piece: Piece,

    fall_timer: f64,
    score: u32,
    cleared_lines: u16,
    level: u32,
    game_over: bool,

    // temp
    image: graphics::Image,
}

impl PlayState {
    pub fn new(ctx: &mut Context) -> GameResult<PlayState> {
        let image = graphics::Image::new(ctx, "/block.png")?;
        let mut bag = PieceBag::new();
        let first_piece = bag.take_piece();

        let state = PlayState {
            input: InputState::default(),
            prev_input: InputState::default(),

            well: Well::new(),
            bag: bag,
            current_piece: first_piece,

            fall_timer: 0.0,
            score: 0,
            cleared_lines: 0,
            level: 0,
            game_over: false,

            image: image,
        };

        Ok(state)
    }

    fn handle_user_input(&mut self, dt: Duration) -> GameResult<()> {
        if self.input.left.is_active {
            self.input.left.delay_timer += dt.as_subsec_millis();
            if self.input.left.delay_timer >= INPUT_DELAY_TIME {
                self.move_piece(Position::new(-1, 0));
                self.input.left.delay_timer = 0.0;
            }
        } else if self.input.right.is_active {
            self.input.right.delay_timer += dt.as_subsec_millis();
            if self.input.right.delay_timer >= INPUT_DELAY_TIME {
                self.move_piece(Position::new(1, 0));
                self.input.right.delay_timer = 0.0;
            }
        } else if self.input.soft_drop.is_active {
            self.input.soft_drop.delay_timer += dt.as_subsec_millis();
            if self.input.soft_drop.delay_timer >= INPUT_DELAY_TIME {
                self.move_piece(Position::new(0, 1));
                self.input.soft_drop.delay_timer = 0.0;
            }
        } else if self.input.rotate_clockwise.is_active {
            if self.input.rotate_clockwise.is_active != self.prev_input.rotate_clockwise.is_active {
                self.rotate_piece(1);
            }
        } else if self.input.rotate_counterclockwise.is_active {
            if self.input.rotate_counterclockwise.is_active != self.prev_input.rotate_counterclockwise.is_active {
                self.rotate_piece(-1);
            }
        } else if self.input.hard_drop.is_active {
            if self.input.hard_drop.is_active != self.prev_input.hard_drop.is_active {
                self.current_piece.top_left = self.current_piece.get_shadow_position();
                self.well.land(&self.current_piece);
                self.current_piece = self.bag.take_piece();
            }
        }

        Ok(())
    }

    fn move_piece(&mut self, potential_new_position: Position) {
        self.current_piece.potential_top_left += potential_new_position;
        let current_shape = self.current_piece.get_shape();
        let collision_found = self.well
            .check_for_collisions(&current_shape, &self.current_piece.potential_top_left);

        if collision_found {
            self.current_piece.potential_top_left = self.current_piece.top_left;
        }

        self.current_piece.top_left = self.current_piece.potential_top_left; // advance tetromino
    }

    fn rotate_piece(&mut self, direction: i32) {
        let next_shape = self.current_piece.get_next_shape(direction);
        let collision_found = self.well
            .check_for_collisions(&next_shape, &self.current_piece.top_left);

        if !collision_found {
            self.current_piece.change_shape(direction);
        } else {
            // wall kick attempt!
            // need to do 2 checks:
            // move one piece to the right & perform all above checks
            let mut potential_position = self.current_piece.top_left; // creates a copy of 'Position' struct
            potential_position.x += 1;
            let collision_found = self.well
                .check_for_collisions(&next_shape, &potential_position);

            if !collision_found {
                self.current_piece.top_left = potential_position;
                self.current_piece.potential_top_left = potential_position;
                self.current_piece.change_shape(direction);
            } else {
                let mut potential_position = self.current_piece.top_left;
                potential_position.x -= 1;
                let collision_found = self.well
                    .check_for_collisions(&next_shape, &potential_position);

                if !collision_found {
                    self.current_piece.top_left = potential_position;
                    self.current_piece.potential_top_left = potential_position;
                    self.current_piece.change_shape(direction);
                }
            }
        }

    }

    /// Advance the fall time. If enough time has passed, allow gravity to
    /// affect the current piece.
    /// Returns a `GameResult<false>` if a landing occured.
    /// Returns a `GameResult<true>` if no landing occured and the piece can advance.
    fn handle_gravity(&mut self, dt: Duration) -> GameResult<bool> {
        self.fall_timer += dt.as_subsec_millis();

        if self.fall_timer >= FALL_SPEED {
            let current_shape = self.current_piece.get_shape();
            self.fall_timer = 0.0;
            self.current_piece.potential_top_left.y += 1;

            let did_land = self.well
                .check_for_landing(&current_shape, &self.current_piece.potential_top_left);

            if did_land {
                if self.current_piece.top_left.y < 2 {
                    println!("game over!");
                    self.game_over = true;
                    return Ok(false);
                }

                // game isn't over - take another piece and move to next frame
                self.well.land(&self.current_piece);
                self.current_piece = self.bag.take_piece();
                return Ok(false);
            }

            // piece did not land - advance!
            self.current_piece.top_left = self.current_piece.potential_top_left;
        }

        Ok(true)
    }

    fn handle_shadow_piece(&mut self) -> GameResult<()> {
        let mut shadow_position = self.current_piece.top_left;
        let mut potential_shadow_position = shadow_position;
        loop {
            potential_shadow_position.y += 1;
            let collision_found = self.well
                .check_for_landing(&self.current_piece.get_shape(), &potential_shadow_position);

            if collision_found {
                break;
            }

            shadow_position = potential_shadow_position;
            self.current_piece.set_shadow_position(shadow_position);
        }

        Ok(())
    }

    fn handle_line_clears(&mut self) -> GameResult<()> {
        // check for line clears
        let mut lines_cleared = 0;
        for r in (0..self.well.data.len()).rev() {
            let mut is_row_filled = true;
            for (c, _) in self.well.data[r].iter().enumerate() {
                if self.well.data[r][c] == 0 {
                    is_row_filled = false;
                    break; // no need to continue iterating, line is not clear...
                }
            }

            if is_row_filled {
                // TODO: implement more line clearing algorithms
                // TODO: make the current line clearing algorithm user selectable
                self.well.naive_line_clear(r);
                lines_cleared += 1;
            }
        }

        // add to score
        let level = self.level;
        match lines_cleared {
            1 => self.increase_score(40, level),
            2 => self.increase_score(100, level),
            3 => self.increase_score(300, level),
            4 => self.increase_score(1200, level),
            _ => (),
        }

        self.cleared_lines += lines_cleared;

        Ok(())
    }

    fn increase_score(&mut self, base_score: u32, level: u32) {
        self.score += base_score * (level + 1);
    }
}

impl event::EventHandler for PlayState {
    fn update(&mut self, _: &mut Context, dt: Duration) -> GameResult<()> {
        println!("[state.update] Start of update method");
        println!("[state.update] current score: {}", self.score);

        if self.game_over {
            // do game over stuff
            return Ok(());
        }

        // TODO: handle/respond user input
        self.handle_user_input(dt)?;

        // handle shadow piece
        // TODO: put behind option
        self.handle_shadow_piece()?;

        // handle gravity - return from update if our current piece landed
        if let Ok(false) = self.handle_gravity(dt) {
            return Ok(());
        }

        self.handle_line_clears()?;

        self.prev_input = self.input;

        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::set_background_color(ctx, graphics::Color::new(0.0, 0.0, 0.0, 255.0));
        graphics::clear(ctx);

        self.well.draw(ctx, &self.image)?;
        self.current_piece
            .draw_shadow(ctx, &self.image, &self.current_piece.get_shadow_position())?;
        self.current_piece.draw(ctx, &self.image)?;

        graphics::present(ctx);

        Ok(())
    }

    fn key_down_event(&mut self, keycode: Keycode, _keymod: Mod, _repeat: bool) {
        match keycode {
            Keycode::Left => self.input.left.is_active = true,
            Keycode::Right => self.input.right.is_active = true,
            Keycode::Up => self.input.hard_drop.is_active = true,
            Keycode::Down => self.input.soft_drop.is_active = true,
            Keycode::Z => self.input.rotate_counterclockwise.is_active = true,
            Keycode::X => self.input.rotate_clockwise.is_active = true,
            _ => (),
        }

    }

    fn key_up_event(&mut self, keycode: Keycode, _keymod: Mod, _repeat: bool) {
        match keycode {
            Keycode::Left => {
                self.input.left.is_active = false;
                self.input.left.delay_timer = INPUT_DELAY_TIME;
            }
            Keycode::Right => {
                self.input.right.is_active = false;
                self.input.right.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::Up => {
                self.input.hard_drop.is_active = false;
                self.input.hard_drop.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::Down => {
                self.input.soft_drop.is_active = false;
                self.input.soft_drop.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::Z => {
                self.input.rotate_counterclockwise.is_active = false;
                self.input.rotate_counterclockwise.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::X => {
                self.input.rotate_clockwise.is_active = false;
                self.input.rotate_clockwise.delay_timer = INPUT_DELAY_TIME;
            },
            _ => (),
        }
    }
}
<|endoftext|>


<commit_before>// This is a test for optimal Ord trait implementation for bool.
// See <https://github.com/rust-lang/rust/issues/66780> for more info.

// compile-flags: -C opt-level=3

#![crate_type = "lib"]

use std::cmp::Ordering;

// CHECK-LABEL: @cmp_bool
#[no_mangle]
pub fn cmp_bool(a: bool, b: bool) -> Ordering {
// CHECK: zext i1
// CHECK: zext i1
// CHECK: sub nsw
    a.cmp(&b)
}
<commit_msg>Update bool-cmp.rs codegen<commit_after>// This is a test for optimal Ord trait implementation for bool.
// See <https://github.com/rust-lang/rust/issues/66780> for more info.

// compile-flags: -C opt-level=3

#![crate_type = "lib"]

use std::cmp::Ordering;

// CHECK-LABEL: @cmp_bool
#[no_mangle]
pub fn cmp_bool(a: bool, b: bool) -> Ordering {
// LLVM 10 produces (zext a) + (sext b), but the final lowering is (zext a) - (zext b).
// CHECK: zext i1
// CHECK: {{z|s}}ext i1
// CHECK: {{sub|add}} nsw
    a.cmp(&b)
}
<|endoftext|>


<commit_before>use crate::text::{Attributes, Color, Text};
use crate::widgets::{Widget, WidgetStream};
use anyhow::{anyhow, Context, Error, Result};
use std::f64;
use std::fs::File;
use std::io::Read;
use std::str::FromStr;
use std::time::Duration;
use tokio::time;
use tokio_stream::wrappers::IntervalStream;
use tokio_stream::StreamExt;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Full,
    Charging,
    Discharging,
    Unknown,
}

impl FromStr for Status {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "Full" => Ok(Status::Full),
            "Charging" => Ok(Status::Charging),
            "Discharging" => Ok(Status::Discharging),
            "Unknown" => Ok(Status::Unknown),
            _ => Err(anyhow!("Unknown Status: {}", s)),
        }
    }
}

/// Shows battery charge percentage and (dis)charge time.
///
/// This widget shows the battery's current charge percentage and the amount of
/// remaining (dis)charge time, depending on whether the battery is charging or
/// discharging. The format of the output is `(PP% HH:MM)`.
///
/// When the battery has less than 10% charge remaining, the widget's text will
/// change to the specified `warning_color`.
///
/// Battery charge information is read from [`/sys/class/power_supply/BAT0/`].
///
/// [`/sys/class/power_supply/BAT0/`]: https://www.kernel.org/doc/Documentation/power/power_supply_class.txt
pub struct Battery {
    update_interval: Duration,
    battery: String,
    attr: Attributes,
    warning_color: Color,
    render: Option<Box<dyn Fn(BatteryInfo) -> String>>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct BatteryInfo {
    pub charge_full: f64,
    pub charge_now: f64,
    pub current_now: f64,
    pub status: Status,
}

impl Battery {
    ///  Creates a new Battery widget.
    ///
    ///  Creates a new `Battery` widget, whose text will be displayed with the
    ///  given [`Attributes`]. The caller can provide use the `warning_color`
    ///  argument, to control the [`Color`] of the text once the battery has
    ///  less than 10% charge remaining.
    ///
    ///  The [`Cnx`] instance is borrowed during construction in order to get
    ///  access to handles of its event loop. However, it is not borrowed for
    ///  the lifetime of the widget. See the [`cnx_add_widget!()`] for more
    ///  discussion about the lifetime of the borrow.
    ///
    /// [`Attributes`]: ../text/struct.Attributes.html
    /// [`Color`]: ../text/struct.Color.html
    /// [`Cnx`]: ../struct.Cnx.html
    /// [`cnx_add_widget!()`]: ../macro.cnx_add_widget.html
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use]
    /// # extern crate cnx;
    /// #
    /// # use cnx::*;
    /// # use cnx::text::*;
    /// # use cnx::widgets::*;
    /// # use anyhow::Result;
    /// #
    /// # fn run() -> Result<()> {
    /// let attr = Attributes {
    ///     font: Font::new("SourceCodePro 21"),
    ///     fg_color: Color::white(),
    ///     bg_color: None,
    ///     padding: Padding::new(8.0, 8.0, 0.0, 0.0),
    /// };
    ///
    /// let mut cnx = Cnx::new(Position::Top);
    /// cnx.add_widget(Battery::new(attr.clone(), Color::red(), None, None));
    /// # Ok(())
    /// # }
    /// # fn main() { run().unwrap(); }
    /// ```
    pub fn new(
        attr: Attributes,
        warning_color: Color,
        battery: Option<String>,
        render: Option<Box<dyn Fn(BatteryInfo) -> String>>,
    ) -> Battery {
        Battery {
            update_interval: Duration::from_secs(60),
            battery: battery.unwrap_or_else(|| "BAT0".into()),
            attr,
            warning_color,
            render,
        }
    }

    fn load_value_inner<T>(&self, file: &str) -> Result<T>
    where
        T: FromStr,
        <T as FromStr>::Err: Into<Error>,
    {
        let path = format!("/sys/class/power_supply/{}/{}", self.battery, file);
        let mut file = File::open(path)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        let s = FromStr::from_str(contents.trim())
            .map_err(|e: <T as FromStr>::Err| e.into())
            .context("Failed to parse value")?;
        Ok(s)
    }

    fn load_value<T>(&self, file: &str) -> Result<T>
    where
        T: FromStr,
        <T as FromStr>::Err: Into<Error>,
    {
        let value = self
            .load_value_inner(file)
            .with_context(|| format!("Could not load value from battery status file: {}", file))?;
        Ok(value)
    }

    fn get_value(&self) -> Result<BatteryInfo> {
        let full: f64 = self.load_value("charge_full")?;
        let now: f64 = self.load_value("charge_now")?;

        // If we're discharging, show time to empty.
        // If we're charging, show time to full.
        let power: f64 = self.load_value("current_now")?;
        let status: Status = self.load_value("status")?;
        Ok(BatteryInfo {
            charge_full: full,
            charge_now: now,
            current_now: power,
            status,
        })
    }

    fn tick(&self) -> Result<Vec<Text>> {
        let battery_info = self.get_value()?;

        let time = match battery_info.status {
            Status::Discharging => battery_info.charge_now / battery_info.current_now,
            Status::Charging => {
                (battery_info.charge_full - battery_info.charge_now) / battery_info.current_now
            }
            _ => 0.0,
        };
        let hours = time as u64;
        let minutes = (time * 60.0) as u64 % 60;

        let percentage = (battery_info.charge_now / battery_info.charge_full) * 100.0;

        let default_text = format!(
            "({percentage:.0}% - {hours}:{minutes:02})",
            percentage = percentage,
            hours = hours,
            minutes = minutes
        );
        let text = self
            .render
            .as_ref()
            .map_or(default_text, |x| (x)(battery_info.clone()));

        // If we're discharging and have <=10% left, then render with a
        // special warning color.
        let mut attr = self.attr.clone();
        if battery_info.status == Status::Discharging && percentage <= 10.0 {
            attr.fg_color = self.warning_color.clone()
        }

        Ok(vec![Text {
            attr,
            text,
            stretch: false,
            markup: self.render.is_some(),
        }])
    }
}

impl Widget for Battery {
    fn into_stream(self: Box<Self>) -> Result<WidgetStream> {
        let interval = time::interval(self.update_interval);
        let stream = IntervalStream::new(interval).map(move |_| self.tick());

        Ok(Box::pin(stream))
    }
}
<commit_msg>Simplify BatteryInfo to directly read the capacity<commit_after>use crate::text::{Attributes, Color, Text};
use crate::widgets::{Widget, WidgetStream};
use anyhow::{anyhow, Context, Error, Result};
use std::fs::File;
use std::io::Read;
use std::str::FromStr;
use std::time::Duration;
use tokio::time;
use tokio_stream::wrappers::IntervalStream;
use tokio_stream::StreamExt;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Full,
    Charging,
    Discharging,
    Unknown,
}

impl FromStr for Status {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "Full" => Ok(Status::Full),
            "Charging" => Ok(Status::Charging),
            "Discharging" => Ok(Status::Discharging),
            "Unknown" => Ok(Status::Unknown),
            _ => Err(anyhow!("Unknown Status: {}", s)),
        }
    }
}

/// Shows battery charge percentage and (dis)charge time.
///
/// This widget shows the battery's current charge percentage and the amount of
/// remaining (dis)charge time, depending on whether the battery is charging or
/// discharging. The format of the output is `(PP% HH:MM)`.
///
/// When the battery has less than 10% charge remaining, the widget's text will
/// change to the specified `warning_color`.
///
/// Battery charge information is read from [`/sys/class/power_supply/BAT0/`].
///
/// [`/sys/class/power_supply/BAT0/`]: https://www.kernel.org/doc/Documentation/power/power_supply_class.txt
pub struct Battery {
    update_interval: Duration,
    battery: String,
    attr: Attributes,
    warning_color: Color,
    render: Option<Box<dyn Fn(BatteryInfo) -> String>>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct BatteryInfo {
    pub status: Status,
    pub capacity: u8,
}

impl Battery {
    ///  Creates a new Battery widget.
    ///
    ///  Creates a new `Battery` widget, whose text will be displayed with the
    ///  given [`Attributes`]. The caller can provide use the `warning_color`
    ///  argument, to control the [`Color`] of the text once the battery has
    ///  less than 10% charge remaining.
    ///
    ///  The [`Cnx`] instance is borrowed during construction in order to get
    ///  access to handles of its event loop. However, it is not borrowed for
    ///  the lifetime of the widget. See the [`cnx_add_widget!()`] for more
    ///  discussion about the lifetime of the borrow.
    ///
    /// [`Attributes`]: ../text/struct.Attributes.html
    /// [`Color`]: ../text/struct.Color.html
    /// [`Cnx`]: ../struct.Cnx.html
    /// [`cnx_add_widget!()`]: ../macro.cnx_add_widget.html
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use]
    /// # extern crate cnx;
    /// #
    /// # use cnx::*;
    /// # use cnx::text::*;
    /// # use cnx::widgets::*;
    /// # use anyhow::Result;
    /// #
    /// # fn run() -> Result<()> {
    /// let attr = Attributes {
    ///     font: Font::new("SourceCodePro 21"),
    ///     fg_color: Color::white(),
    ///     bg_color: None,
    ///     padding: Padding::new(8.0, 8.0, 0.0, 0.0),
    /// };
    ///
    /// let mut cnx = Cnx::new(Position::Top);
    /// cnx.add_widget(Battery::new(attr.clone(), Color::red(), None, None));
    /// # Ok(())
    /// # }
    /// # fn main() { run().unwrap(); }
    /// ```
    pub fn new(
        attr: Attributes,
        warning_color: Color,
        battery: Option<String>,
        render: Option<Box<dyn Fn(BatteryInfo) -> String>>,
    ) -> Battery {
        Battery {
            update_interval: Duration::from_secs(60),
            battery: battery.unwrap_or_else(|| "BAT0".into()),
            attr,
            warning_color,
            render,
        }
    }

    fn load_value_inner<T>(&self, file: &str) -> Result<T>
    where
        T: FromStr,
        <T as FromStr>::Err: Into<Error>,
    {
        let path = format!("/sys/class/power_supply/{}/{}", self.battery, file);
        let mut file = File::open(path)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        let s = FromStr::from_str(contents.trim())
            .map_err(|e: <T as FromStr>::Err| e.into())
            .context("Failed to parse value")?;
        Ok(s)
    }

    fn load_value<T>(&self, file: &str) -> Result<T>
    where
        T: FromStr,
        <T as FromStr>::Err: Into<Error>,
    {
        let value = self
            .load_value_inner(file)
            .with_context(|| format!("Could not load value from battery status file: {}", file))?;
        Ok(value)
    }

    fn get_value(&self) -> Result<BatteryInfo> {
        let capacity: u8 = self.load_value("capacity")?;
        let status: Status = self.load_value("status")?;
        Ok(BatteryInfo { capacity, status })
    }

    fn tick(&self) -> Result<Vec<Text>> {
        let battery_info = self.get_value()?;

        let default_text = format!("({percentage:.0}%)", percentage = battery_info.capacity,);
        let text = self
            .render
            .as_ref()
            .map_or(default_text, |x| (x)(battery_info.clone()));

        // If we're discharging and have <=10% left, then render with a
        // special warning color.
        let mut attr = self.attr.clone();
        if battery_info.status == Status::Discharging && battery_info.capacity <= 10 {
            attr.fg_color = self.warning_color.clone()
        }

        Ok(vec![Text {
            attr,
            text,
            stretch: false,
            markup: self.render.is_some(),
        }])
    }
}

impl Widget for Battery {
    fn into_stream(self: Box<Self>) -> Result<WidgetStream> {
        let interval = time::interval(self.update_interval);
        let stream = IntervalStream::new(interval).map(move |_| self.tick());

        Ok(Box::pin(stream))
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

use build_helper::{output, tracked_env_var_os};

fn detect_llvm_link() -> (&'static str, &'static str) {
    // Force the link mode we want, preferring static by default, but
    // possibly overridden by `configure --enable-llvm-link-shared`.
    if tracked_env_var_os("LLVM_LINK_SHARED").is_some() {
        ("dylib", "--link-shared")
    } else {
        ("static", "--link-static")
    }
}

fn main() {
    if tracked_env_var_os("RUST_CHECK").is_some() {
        // If we're just running `check`, there's no need for LLVM to be built.
        return;
    }

    build_helper::restore_library_path();

    let target = env::var("TARGET").expect("TARGET was not set");
    let llvm_config =
        tracked_env_var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| {
            if let Some(dir) = tracked_env_var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
                let to_test = dir
                    .parent()
                    .unwrap()
                    .parent()
                    .unwrap()
                    .join(&target)
                    .join("llvm/bin/llvm-config");
                if Command::new(&to_test).output().is_ok() {
                    return Some(to_test);
                }
            }
            None
        });

    if let Some(llvm_config) = &llvm_config {
        println!("cargo:rerun-if-changed={}", llvm_config.display());
    }
    let llvm_config = llvm_config.unwrap_or_else(|| PathBuf::from("llvm-config"));

    // Test whether we're cross-compiling LLVM. This is a pretty rare case
    // currently where we're producing an LLVM for a different platform than
    // what this build script is currently running on.
    //
    // In that case, there's no guarantee that we can actually run the target,
    // so the build system works around this by giving us the LLVM_CONFIG for
    // the host platform. This only really works if the host LLVM and target
    // LLVM are compiled the same way, but for us that's typically the case.
    //
    // We *want* detect this cross compiling situation by asking llvm-config
    // what its host-target is. If that's not the TARGET, then we're cross
    // compiling. Unfortunately `llvm-config` seems either be buggy, or we're
    // misconfiguring it, because the `i686-pc-windows-gnu` build of LLVM will
    // report itself with a `--host-target` of `x86_64-pc-windows-gnu`. This
    // tricks us into thinking we're doing a cross build when we aren't, so
    // havoc ensues.
    //
    // In any case, if we're cross compiling, this generally just means that we
    // can't trust all the output of llvm-config because it might be targeted
    // for the host rather than the target. As a result a bunch of blocks below
    // are gated on `if !is_crossed`
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    let is_crossed = target != host;

    let mut optional_components = vec![
        "x86",
        "arm",
        "aarch64",
        "amdgpu",
        "avr",
        "mips",
        "powerpc",
        "systemz",
        "jsbackend",
        "webassembly",
        "msp430",
        "sparc",
        "nvptx",
        "hexagon",
    ];

    let mut version_cmd = Command::new(&llvm_config);
    version_cmd.arg("--version");
    let version_output = output(&mut version_cmd);
    let mut parts = version_output.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
    let (major, _minor) = if let (Some(major), Some(minor)) = (parts.next(), parts.next()) {
        (major, minor)
    } else {
        (6, 0)
    };

    if major > 6 {
        optional_components.push("riscv");
    }

    let required_components = &[
        "ipo",
        "bitreader",
        "bitwriter",
        "linker",
        "asmparser",
        "lto",
        "coverage",
        "instrumentation",
    ];

    let components = output(Command::new(&llvm_config).arg("--components"));
    let mut components = components.split_whitespace().collect::<Vec<_>>();
    components.retain(|c| optional_components.contains(c) || required_components.contains(c));

    for component in required_components {
        if !components.contains(component) {
            panic!("require llvm component {} but wasn't found", component);
        }
    }

    for component in components.iter() {
        println!("cargo:rustc-cfg=llvm_component=\"{}\"", component);
    }

    if major >= 9 {
        println!("cargo:rustc-cfg=llvm_has_msp430_asm_parser");
    }

    // Link in our own LLVM shims, compiled with the same flags as LLVM
    let mut cmd = Command::new(&llvm_config);
    cmd.arg("--cxxflags");
    let cxxflags = output(&mut cmd);
    let mut cfg = cc::Build::new();
    cfg.warnings(false);
    for flag in cxxflags.split_whitespace() {
        // Ignore flags like `-m64` when we're doing a cross build
        if is_crossed && flag.starts_with("-m") {
            continue;
        }

        if flag.starts_with("-flto") {
            continue;
        }

        // -Wdate-time is not supported by the netbsd cross compiler
        if is_crossed && target.contains("netbsd") && flag.contains("date-time") {
            continue;
        }

        // Include path contains host directory, replace it with target
        if is_crossed && flag.starts_with("-I") {
            cfg.flag(&flag.replace(&host, &target));
            continue;
        }

        cfg.flag(flag);
    }

    for component in &components {
        let mut flag = String::from("LLVM_COMPONENT_");
        flag.push_str(&component.to_uppercase());
        cfg.define(&flag, None);
    }

    if tracked_env_var_os("LLVM_RUSTLLVM").is_some() {
        cfg.define("LLVM_RUSTLLVM", None);
    }

    if tracked_env_var_os("LLVM_NDEBUG").is_some() {
        cfg.define("NDEBUG", None);
        cfg.debug(false);
    }

    build_helper::rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper"));
    cfg.file("llvm-wrapper/PassWrapper.cpp")
        .file("llvm-wrapper/RustWrapper.cpp")
        .file("llvm-wrapper/ArchiveWrapper.cpp")
        .file("llvm-wrapper/CoverageMappingWrapper.cpp")
        .file("llvm-wrapper/Linker.cpp")
        .cpp(true)
        .cpp_link_stdlib(None) // we handle this below
        .compile("llvm-wrapper");

    let (llvm_kind, llvm_link_arg) = detect_llvm_link();

    // Link in all LLVM libraries, if we're using the "wrong" llvm-config then
    // we don't pick up system libs because unfortunately they're for the host
    // of llvm-config, not the target that we're attempting to link.
    let mut cmd = Command::new(&llvm_config);
    cmd.arg(llvm_link_arg).arg("--libs");

    if !is_crossed {
        cmd.arg("--system-libs");
    } else if target.contains("windows-gnu") {
        println!("cargo:rustc-link-lib=shell32");
        println!("cargo:rustc-link-lib=uuid");
    } else if target.contains("netbsd") || target.contains("haiku") {
        println!("cargo:rustc-link-lib=z");
    }
    cmd.args(&components);

    for lib in output(&mut cmd).split_whitespace() {
        let name = if lib.starts_with("-l") {
            &lib[2..]
        } else if lib.starts_with('-') {
            &lib[1..]
        } else if Path::new(lib).exists() {
            // On MSVC llvm-config will print the full name to libraries, but
            // we're only interested in the name part
            let name = Path::new(lib).file_name().unwrap().to_str().unwrap();
            name.trim_end_matches(".lib")
        } else if lib.ends_with(".lib") {
            // Some MSVC libraries just come up with `.lib` tacked on, so chop
            // that off
            lib.trim_end_matches(".lib")
        } else {
            continue;
        };

        // Don't need or want this library, but LLVM's CMake build system
        // doesn't provide a way to disable it, so filter it here even though we
        // may or may not have built it. We don't reference anything from this
        // library and it otherwise may just pull in extra dependencies on
        // libedit which we don't want
        if name == "LLVMLineEditor" {
            continue;
        }

        let kind = if name.starts_with("LLVM") { llvm_kind } else { "dylib" };
        println!("cargo:rustc-link-lib={}={}", kind, name);
    }

    // LLVM ldflags
    //
    // If we're a cross-compile of LLVM then unfortunately we can't trust these
    // ldflags (largely where all the LLVM libs are located). Currently just
    // hack around this by replacing the host triple with the target and pray
    // that those -L directories are the same!
    let mut cmd = Command::new(&llvm_config);
    cmd.arg(llvm_link_arg).arg("--ldflags");
    for lib in output(&mut cmd).split_whitespace() {
        if is_crossed {
            if lib.starts_with("-LIBPATH:") {
                println!("cargo:rustc-link-search=native={}", lib[9..].replace(&host, &target));
            } else if lib.starts_with("-L") {
                println!("cargo:rustc-link-search=native={}", lib[2..].replace(&host, &target));
            }
        } else if lib.starts_with("-LIBPATH:") {
            println!("cargo:rustc-link-search=native={}", &lib[9..]);
        } else if lib.starts_with("-l") {
            println!("cargo:rustc-link-lib={}", &lib[2..]);
        } else if lib.starts_with("-L") {
            println!("cargo:rustc-link-search=native={}", &lib[2..]);
        }
    }

    // Some LLVM linker flags (-L and -l) may be needed even when linking
    // rustc_llvm, for example when using static libc++, we may need to
    // manually specify the library search path and -ldl -lpthread as link
    // dependencies.
    let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS");
    if let Some(s) = llvm_linker_flags {
        for lib in s.into_string().unwrap().split_whitespace() {
            if lib.starts_with("-l") {
                println!("cargo:rustc-link-lib={}", &lib[2..]);
            } else if lib.starts_with("-L") {
                println!("cargo:rustc-link-search=native={}", &lib[2..]);
            }
        }
    }

    let llvm_static_stdcpp = tracked_env_var_os("LLVM_STATIC_STDCPP");
    let llvm_use_libcxx = tracked_env_var_os("LLVM_USE_LIBCXX");

    let stdcppname = if target.contains("openbsd") {
        if target.contains("sparc64") { "estdc++" } else { "c++" }
    } else if target.contains("freebsd") {
        "c++"
    } else if target.contains("darwin") {
        "c++"
    } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() {
        // NetBSD uses a separate library when relocation is required
        "stdc++_pic"
    } else if llvm_use_libcxx.is_some() {
        "c++"
    } else {
        "stdc++"
    };

    // RISC-V requires libatomic for sub-word atomic operations
    if target.starts_with("riscv") {
        println!("cargo:rustc-link-lib=atomic");
    }

    // C++ runtime library
    if !target.contains("msvc") {
        if let Some(s) = llvm_static_stdcpp {
            assert!(!cxxflags.contains("stdlib=libc++"));
            let path = PathBuf::from(s);
            println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
            if target.contains("windows") {
                println!("cargo:rustc-link-lib=static-nobundle={}", stdcppname);
            } else {
                println!("cargo:rustc-link-lib=static={}", stdcppname);
            }
        } else if cxxflags.contains("stdlib=libc++") {
            println!("cargo:rustc-link-lib=c++");
        } else {
            println!("cargo:rustc-link-lib={}", stdcppname);
        }
    }

    // Libstdc++ depends on pthread which Rust doesn't link on MinGW
    // since nothing else requires it.
    if target.contains("windows-gnu") {
        println!("cargo:rustc-link-lib=static-nobundle=pthread");
    }
}
<commit_msg>Simplify some code in rustc_llvm/build.rs now that LLVM 8 is required<commit_after>use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

use build_helper::{output, tracked_env_var_os};

fn detect_llvm_link() -> (&'static str, &'static str) {
    // Force the link mode we want, preferring static by default, but
    // possibly overridden by `configure --enable-llvm-link-shared`.
    if tracked_env_var_os("LLVM_LINK_SHARED").is_some() {
        ("dylib", "--link-shared")
    } else {
        ("static", "--link-static")
    }
}

fn main() {
    if tracked_env_var_os("RUST_CHECK").is_some() {
        // If we're just running `check`, there's no need for LLVM to be built.
        return;
    }

    build_helper::restore_library_path();

    let target = env::var("TARGET").expect("TARGET was not set");
    let llvm_config =
        tracked_env_var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| {
            if let Some(dir) = tracked_env_var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
                let to_test = dir
                    .parent()
                    .unwrap()
                    .parent()
                    .unwrap()
                    .join(&target)
                    .join("llvm/bin/llvm-config");
                if Command::new(&to_test).output().is_ok() {
                    return Some(to_test);
                }
            }
            None
        });

    if let Some(llvm_config) = &llvm_config {
        println!("cargo:rerun-if-changed={}", llvm_config.display());
    }
    let llvm_config = llvm_config.unwrap_or_else(|| PathBuf::from("llvm-config"));

    // Test whether we're cross-compiling LLVM. This is a pretty rare case
    // currently where we're producing an LLVM for a different platform than
    // what this build script is currently running on.
    //
    // In that case, there's no guarantee that we can actually run the target,
    // so the build system works around this by giving us the LLVM_CONFIG for
    // the host platform. This only really works if the host LLVM and target
    // LLVM are compiled the same way, but for us that's typically the case.
    //
    // We *want* detect this cross compiling situation by asking llvm-config
    // what its host-target is. If that's not the TARGET, then we're cross
    // compiling. Unfortunately `llvm-config` seems either be buggy, or we're
    // misconfiguring it, because the `i686-pc-windows-gnu` build of LLVM will
    // report itself with a `--host-target` of `x86_64-pc-windows-gnu`. This
    // tricks us into thinking we're doing a cross build when we aren't, so
    // havoc ensues.
    //
    // In any case, if we're cross compiling, this generally just means that we
    // can't trust all the output of llvm-config because it might be targeted
    // for the host rather than the target. As a result a bunch of blocks below
    // are gated on `if !is_crossed`
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    let is_crossed = target != host;

    let optional_components = &[
        "x86",
        "arm",
        "aarch64",
        "amdgpu",
        "avr",
        "mips",
        "powerpc",
        "systemz",
        "jsbackend",
        "webassembly",
        "msp430",
        "sparc",
        "nvptx",
        "hexagon",
        "riscv",
    ];

    let mut version_cmd = Command::new(&llvm_config);
    version_cmd.arg("--version");
    let version_output = output(&mut version_cmd);
    let mut parts = version_output.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
    let (major, _minor) = if let (Some(major), Some(minor)) = (parts.next(), parts.next()) {
        (major, minor)
    } else {
        (8, 0)
    };

    let required_components = &[
        "ipo",
        "bitreader",
        "bitwriter",
        "linker",
        "asmparser",
        "lto",
        "coverage",
        "instrumentation",
    ];

    let components = output(Command::new(&llvm_config).arg("--components"));
    let mut components = components.split_whitespace().collect::<Vec<_>>();
    components.retain(|c| optional_components.contains(c) || required_components.contains(c));

    for component in required_components {
        if !components.contains(component) {
            panic!("require llvm component {} but wasn't found", component);
        }
    }

    for component in components.iter() {
        println!("cargo:rustc-cfg=llvm_component=\"{}\"", component);
    }

    if major >= 9 {
        println!("cargo:rustc-cfg=llvm_has_msp430_asm_parser");
    }

    // Link in our own LLVM shims, compiled with the same flags as LLVM
    let mut cmd = Command::new(&llvm_config);
    cmd.arg("--cxxflags");
    let cxxflags = output(&mut cmd);
    let mut cfg = cc::Build::new();
    cfg.warnings(false);
    for flag in cxxflags.split_whitespace() {
        // Ignore flags like `-m64` when we're doing a cross build
        if is_crossed && flag.starts_with("-m") {
            continue;
        }

        if flag.starts_with("-flto") {
            continue;
        }

        // -Wdate-time is not supported by the netbsd cross compiler
        if is_crossed && target.contains("netbsd") && flag.contains("date-time") {
            continue;
        }

        // Include path contains host directory, replace it with target
        if is_crossed && flag.starts_with("-I") {
            cfg.flag(&flag.replace(&host, &target));
            continue;
        }

        cfg.flag(flag);
    }

    for component in &components {
        let mut flag = String::from("LLVM_COMPONENT_");
        flag.push_str(&component.to_uppercase());
        cfg.define(&flag, None);
    }

    if tracked_env_var_os("LLVM_RUSTLLVM").is_some() {
        cfg.define("LLVM_RUSTLLVM", None);
    }

    if tracked_env_var_os("LLVM_NDEBUG").is_some() {
        cfg.define("NDEBUG", None);
        cfg.debug(false);
    }

    build_helper::rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper"));
    cfg.file("llvm-wrapper/PassWrapper.cpp")
        .file("llvm-wrapper/RustWrapper.cpp")
        .file("llvm-wrapper/ArchiveWrapper.cpp")
        .file("llvm-wrapper/CoverageMappingWrapper.cpp")
        .file("llvm-wrapper/Linker.cpp")
        .cpp(true)
        .cpp_link_stdlib(None) // we handle this below
        .compile("llvm-wrapper");

    let (llvm_kind, llvm_link_arg) = detect_llvm_link();

    // Link in all LLVM libraries, if we're using the "wrong" llvm-config then
    // we don't pick up system libs because unfortunately they're for the host
    // of llvm-config, not the target that we're attempting to link.
    let mut cmd = Command::new(&llvm_config);
    cmd.arg(llvm_link_arg).arg("--libs");

    if !is_crossed {
        cmd.arg("--system-libs");
    } else if target.contains("windows-gnu") {
        println!("cargo:rustc-link-lib=shell32");
        println!("cargo:rustc-link-lib=uuid");
    } else if target.contains("netbsd") || target.contains("haiku") {
        println!("cargo:rustc-link-lib=z");
    }
    cmd.args(&components);

    for lib in output(&mut cmd).split_whitespace() {
        let name = if lib.starts_with("-l") {
            &lib[2..]
        } else if lib.starts_with('-') {
            &lib[1..]
        } else if Path::new(lib).exists() {
            // On MSVC llvm-config will print the full name to libraries, but
            // we're only interested in the name part
            let name = Path::new(lib).file_name().unwrap().to_str().unwrap();
            name.trim_end_matches(".lib")
        } else if lib.ends_with(".lib") {
            // Some MSVC libraries just come up with `.lib` tacked on, so chop
            // that off
            lib.trim_end_matches(".lib")
        } else {
            continue;
        };

        // Don't need or want this library, but LLVM's CMake build system
        // doesn't provide a way to disable it, so filter it here even though we
        // may or may not have built it. We don't reference anything from this
        // library and it otherwise may just pull in extra dependencies on
        // libedit which we don't want
        if name == "LLVMLineEditor" {
            continue;
        }

        let kind = if name.starts_with("LLVM") { llvm_kind } else { "dylib" };
        println!("cargo:rustc-link-lib={}={}", kind, name);
    }

    // LLVM ldflags
    //
    // If we're a cross-compile of LLVM then unfortunately we can't trust these
    // ldflags (largely where all the LLVM libs are located). Currently just
    // hack around this by replacing the host triple with the target and pray
    // that those -L directories are the same!
    let mut cmd = Command::new(&llvm_config);
    cmd.arg(llvm_link_arg).arg("--ldflags");
    for lib in output(&mut cmd).split_whitespace() {
        if is_crossed {
            if lib.starts_with("-LIBPATH:") {
                println!("cargo:rustc-link-search=native={}", lib[9..].replace(&host, &target));
            } else if lib.starts_with("-L") {
                println!("cargo:rustc-link-search=native={}", lib[2..].replace(&host, &target));
            }
        } else if lib.starts_with("-LIBPATH:") {
            println!("cargo:rustc-link-search=native={}", &lib[9..]);
        } else if lib.starts_with("-l") {
            println!("cargo:rustc-link-lib={}", &lib[2..]);
        } else if lib.starts_with("-L") {
            println!("cargo:rustc-link-search=native={}", &lib[2..]);
        }
    }

    // Some LLVM linker flags (-L and -l) may be needed even when linking
    // rustc_llvm, for example when using static libc++, we may need to
    // manually specify the library search path and -ldl -lpthread as link
    // dependencies.
    let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS");
    if let Some(s) = llvm_linker_flags {
        for lib in s.into_string().unwrap().split_whitespace() {
            if lib.starts_with("-l") {
                println!("cargo:rustc-link-lib={}", &lib[2..]);
            } else if lib.starts_with("-L") {
                println!("cargo:rustc-link-search=native={}", &lib[2..]);
            }
        }
    }

    let llvm_static_stdcpp = tracked_env_var_os("LLVM_STATIC_STDCPP");
    let llvm_use_libcxx = tracked_env_var_os("LLVM_USE_LIBCXX");

    let stdcppname = if target.contains("openbsd") {
        if target.contains("sparc64") { "estdc++" } else { "c++" }
    } else if target.contains("freebsd") {
        "c++"
    } else if target.contains("darwin") {
        "c++"
    } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() {
        // NetBSD uses a separate library when relocation is required
        "stdc++_pic"
    } else if llvm_use_libcxx.is_some() {
        "c++"
    } else {
        "stdc++"
    };

    // RISC-V requires libatomic for sub-word atomic operations
    if target.starts_with("riscv") {
        println!("cargo:rustc-link-lib=atomic");
    }

    // C++ runtime library
    if !target.contains("msvc") {
        if let Some(s) = llvm_static_stdcpp {
            assert!(!cxxflags.contains("stdlib=libc++"));
            let path = PathBuf::from(s);
            println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
            if target.contains("windows") {
                println!("cargo:rustc-link-lib=static-nobundle={}", stdcppname);
            } else {
                println!("cargo:rustc-link-lib=static={}", stdcppname);
            }
        } else if cxxflags.contains("stdlib=libc++") {
            println!("cargo:rustc-link-lib=c++");
        } else {
            println!("cargo:rustc-link-lib={}", stdcppname);
        }
    }

    // Libstdc++ depends on pthread which Rust doesn't link on MinGW
    // since nothing else requires it.
    if target.contains("windows-gnu") {
        println!("cargo:rustc-link-lib=static-nobundle=pthread");
    }
}
<|endoftext|>


<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Test casts for alignment issues

#![feature(libc)]

extern crate libc;

#[warn(clippy::cast_ptr_alignment)]
#[allow(clippy::no_effect, clippy::unnecessary_operation, clippy::cast_lossless)]
fn main() {
    /* These should be warned against */

    // cast to more-strictly-aligned type
    (&1u8 as *const u8) as *const u16;
    (&mut 1u8 as *mut u8) as *mut u16;

    /* These should be okay */

    // not a pointer type
    1u8 as u16;
    // cast to less-strictly-aligned type
    (&1u16 as *const u16) as *const u8;
    (&mut 1u16 as *mut u16) as *mut u8;
    // For c_void, we should trust the user. See #2677
    (&1u32 as *const u32 as *const std::os::raw::c_void) as *const u32;
    (&1u32 as *const u32 as *const libc::c_void) as *const u32;
}
<commit_msg>rustup https://github.com/rust-lang/rust/pull/56092<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Test casts for alignment issues

#![feature(rustc_private)]
extern crate libc;

#[warn(clippy::cast_ptr_alignment)]
#[allow(clippy::no_effect, clippy::unnecessary_operation, clippy::cast_lossless)]
fn main() {
    /* These should be warned against */

    // cast to more-strictly-aligned type
    (&1u8 as *const u8) as *const u16;
    (&mut 1u8 as *mut u8) as *mut u16;

    /* These should be okay */

    // not a pointer type
    1u8 as u16;
    // cast to less-strictly-aligned type
    (&1u16 as *const u16) as *const u8;
    (&mut 1u16 as *mut u16) as *mut u8;
    // For c_void, we should trust the user. See #2677
    (&1u32 as *const u32 as *const std::os::raw::c_void) as *const u32;
    (&1u32 as *const u32 as *const libc::c_void) as *const u32;
}
<|endoftext|>


<commit_before>use crate::task::JoinHandle;

cfg_rt_multi_thread! {
    /// Runs the provided blocking function on the current thread without
    /// blocking the executor.
    ///
    /// In general, issuing a blocking call or performing a lot of compute in a
    /// future without yielding is problematic, as it may prevent the executor
    /// from driving other tasks forward. Calling this function informs the
    /// executor that the currently executing task is about to block the thread,
    /// so the executor is able to hand off any other tasks it has to a new
    /// worker thread before that happens. See the [CPU-bound tasks and blocking
    /// code][blocking] section for more information.
    ///
    /// Be aware that although this function avoids starving other independently
    /// spawned tasks, any other code running concurrently in the same task will
    /// be suspended during the call to `block_in_place`. This can happen e.g.
    /// when using the [`join!`] macro. To avoid this issue, use
    /// [`spawn_blocking`] instead of `block_in_place`.
    ///
    /// Note that this function cannot be used within a [`current_thread`] runtime
    /// because in this case there are no other worker threads to hand off tasks
    /// to. On the other hand, calling the function outside a runtime is
    /// allowed. In this case, `block_in_place` just calls the provided closure
    /// normally.
    ///
    /// Code running behind `block_in_place` cannot be cancelled. When you shut
    /// down the executor, it will wait indefinitely for all blocking operations
    /// to finish. You can use [`shutdown_timeout`] to stop waiting for them
    /// after a certain timeout. Be aware that this will still not cancel the
    /// tasks — they are simply allowed to keep running after the method
    /// returns.
    ///
    /// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code
    /// [`spawn_blocking`]: fn@crate::task::spawn_blocking
    /// [`join!`]: macro@join
    /// [`thread::spawn`]: fn@std::thread::spawn
    /// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::task;
    ///
    /// # async fn docs() {
    /// task::block_in_place(move || {
    ///     // do some compute-heavy work or call synchronous code
    /// });
    /// # }
    /// ```
    ///
    /// Code running inside `block_in_place` may use `block_on` to reenter the
    /// async context.
    ///
    /// ```
    /// use tokio::task;
    /// use tokio::runtime::Handle;
    ///
    /// # async fn docs() {
    /// task::block_in_place(move || {
    ///     Handle::current().block_on(async move {
    ///         // do something async
    ///     });
    /// });
    /// # }
    /// ```
    ///
    /// # Panics
    ///
    /// This function panics if called from a [`current_thread`] runtime.
    ///
    /// [`current_thread`]: fn@crate::runtime::Builder::new_current_thread
    pub fn block_in_place<F, R>(f: F) -> R
    where
        F: FnOnce() -> R,
    {
        crate::runtime::thread_pool::block_in_place(f)
    }
}

cfg_rt! {
    /// Runs the provided closure on a thread where blocking is acceptable.
    ///
    /// In general, issuing a blocking call or performing a lot of compute in a
    /// future without yielding is problematic, as it may prevent the executor from
    /// driving other futures forward. This function runs the provided closure on a
    /// thread dedicated to blocking operations. See the [CPU-bound tasks and
    /// blocking code][blocking] section for more information.
    ///
    /// Tokio will spawn more blocking threads when they are requested through this
    /// function until the upper limit configured on the [`Builder`] is reached.
    /// This limit is very large by default, because `spawn_blocking` is often used
    /// for various kinds of IO operations that cannot be performed asynchronously.
    /// When you run CPU-bound code using `spawn_blocking`, you should keep this
    /// large upper limit in mind. When running many CPU-bound computations, a
    /// semaphore or some other synchronization primitive should be used to limit
    /// the number of computation executed in parallel. Specialized CPU-bound
    /// executors, such as [rayon], may also be a good fit.
    ///
    /// This function is intended for non-async operations that eventually finish on
    /// their own. If you want to spawn an ordinary thread, you should use
    /// [`thread::spawn`] instead.
    ///
    /// Closures spawned using `spawn_blocking` cannot be cancelled. When you shut
    /// down the executor, it will wait indefinitely for all blocking operations to
    /// finish. You can use [`shutdown_timeout`] to stop waiting for them after a
    /// certain timeout. Be aware that this will still not cancel the tasks — they
    /// are simply allowed to keep running after the method returns.
    ///
    /// Note that if you are using the single threaded runtime, this function will
    /// still spawn additional threads for blocking operations. The basic
    /// scheduler's single thread is only used for asynchronous code.
    ///
    /// [`Builder`]: struct@crate::runtime::Builder
    /// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code
    /// [rayon]: https://docs.rs/rayon
    /// [`thread::spawn`]: fn@std::thread::spawn
    /// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::task;
    ///
    /// # async fn docs() -> Result<(), Box<dyn std::error::Error>>{
    /// let res = task::spawn_blocking(move || {
    ///     // do some compute-heavy work or call synchronous code
    ///     "done computing"
    /// }).await?;
    ///
    /// assert_eq!(res, "done computing");
    /// # Ok(())
    /// # }
    /// ```
    #[cfg_attr(tokio_track_caller, track_caller)]
    pub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
    where
        F: FnOnce() -> R + Send + 'static,
        R: Send + 'static,
    {
        crate::runtime::spawn_blocking(f)
    }
}
<commit_msg>task: elaborate on queue behavior of spawn_blocking (#3981)<commit_after>use crate::task::JoinHandle;

cfg_rt_multi_thread! {
    /// Runs the provided blocking function on the current thread without
    /// blocking the executor.
    ///
    /// In general, issuing a blocking call or performing a lot of compute in a
    /// future without yielding is problematic, as it may prevent the executor
    /// from driving other tasks forward. Calling this function informs the
    /// executor that the currently executing task is about to block the thread,
    /// so the executor is able to hand off any other tasks it has to a new
    /// worker thread before that happens. See the [CPU-bound tasks and blocking
    /// code][blocking] section for more information.
    ///
    /// Be aware that although this function avoids starving other independently
    /// spawned tasks, any other code running concurrently in the same task will
    /// be suspended during the call to `block_in_place`. This can happen e.g.
    /// when using the [`join!`] macro. To avoid this issue, use
    /// [`spawn_blocking`] instead of `block_in_place`.
    ///
    /// Note that this function cannot be used within a [`current_thread`] runtime
    /// because in this case there are no other worker threads to hand off tasks
    /// to. On the other hand, calling the function outside a runtime is
    /// allowed. In this case, `block_in_place` just calls the provided closure
    /// normally.
    ///
    /// Code running behind `block_in_place` cannot be cancelled. When you shut
    /// down the executor, it will wait indefinitely for all blocking operations
    /// to finish. You can use [`shutdown_timeout`] to stop waiting for them
    /// after a certain timeout. Be aware that this will still not cancel the
    /// tasks — they are simply allowed to keep running after the method
    /// returns.
    ///
    /// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code
    /// [`spawn_blocking`]: fn@crate::task::spawn_blocking
    /// [`join!`]: macro@join
    /// [`thread::spawn`]: fn@std::thread::spawn
    /// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::task;
    ///
    /// # async fn docs() {
    /// task::block_in_place(move || {
    ///     // do some compute-heavy work or call synchronous code
    /// });
    /// # }
    /// ```
    ///
    /// Code running inside `block_in_place` may use `block_on` to reenter the
    /// async context.
    ///
    /// ```
    /// use tokio::task;
    /// use tokio::runtime::Handle;
    ///
    /// # async fn docs() {
    /// task::block_in_place(move || {
    ///     Handle::current().block_on(async move {
    ///         // do something async
    ///     });
    /// });
    /// # }
    /// ```
    ///
    /// # Panics
    ///
    /// This function panics if called from a [`current_thread`] runtime.
    ///
    /// [`current_thread`]: fn@crate::runtime::Builder::new_current_thread
    pub fn block_in_place<F, R>(f: F) -> R
    where
        F: FnOnce() -> R,
    {
        crate::runtime::thread_pool::block_in_place(f)
    }
}

cfg_rt! {
    /// Runs the provided closure on a thread where blocking is acceptable.
    ///
    /// In general, issuing a blocking call or performing a lot of compute in a
    /// future without yielding is problematic, as it may prevent the executor from
    /// driving other futures forward. This function runs the provided closure on a
    /// thread dedicated to blocking operations. See the [CPU-bound tasks and
    /// blocking code][blocking] section for more information.
    ///
    /// Tokio will spawn more blocking threads when they are requested through this
    /// function until the upper limit configured on the [`Builder`] is reached.
    /// After reaching the upper limit, the tasks are put in a queue.
    /// The thread limit is very large by default, because `spawn_blocking` is often
    /// used for various kinds of IO operations that cannot be performed
    /// asynchronously.  When you run CPU-bound code using `spawn_blocking`, you
    /// should keep this large upper limit in mind. When running many CPU-bound
    /// computations, a semaphore or some other synchronization primitive should be
    /// used to limit the number of computation executed in parallel. Specialized
    /// CPU-bound executors, such as [rayon], may also be a good fit.
    ///
    /// This function is intended for non-async operations that eventually finish on
    /// their own. If you want to spawn an ordinary thread, you should use
    /// [`thread::spawn`] instead.
    ///
    /// Closures spawned using `spawn_blocking` cannot be cancelled. When you shut
    /// down the executor, it will wait indefinitely for all blocking operations to
    /// finish. You can use [`shutdown_timeout`] to stop waiting for them after a
    /// certain timeout. Be aware that this will still not cancel the tasks — they
    /// are simply allowed to keep running after the method returns.
    ///
    /// Note that if you are using the single threaded runtime, this function will
    /// still spawn additional threads for blocking operations. The basic
    /// scheduler's single thread is only used for asynchronous code.
    ///
    /// [`Builder`]: struct@crate::runtime::Builder
    /// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code
    /// [rayon]: https://docs.rs/rayon
    /// [`thread::spawn`]: fn@std::thread::spawn
    /// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::task;
    ///
    /// # async fn docs() -> Result<(), Box<dyn std::error::Error>>{
    /// let res = task::spawn_blocking(move || {
    ///     // do some compute-heavy work or call synchronous code
    ///     "done computing"
    /// }).await?;
    ///
    /// assert_eq!(res, "done computing");
    /// # Ok(())
    /// # }
    /// ```
    #[cfg_attr(tokio_track_caller, track_caller)]
    pub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
    where
        F: FnOnce() -> R + Send + 'static,
        R: Send + 'static,
    {
        crate::runtime::spawn_blocking(f)
    }
}
<|endoftext|>