<commit_before>use byteorder::{ByteOrder, LittleEndian};

use opcodes::{AddressingMode, OpCode};

pub struct Disassembler;

impl Disassembler {
    pub fn disassemble(raw: &[u8]) -> String {
        let mut result = String::new();

        let mut i: usize = 0;
        while i < raw.len() {
            let opcode = OpCode::from_raw_byte(raw[i]);
            let val = match opcode.mode {
                AddressingMode::Implied |
                AddressingMode::Accumulator => String::from(""),
                AddressingMode::Immediate => format!(" #${:02X}", raw[i + 0x01]),
                AddressingMode::Indirect => {
                    format!(" (${:04X})", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::Relative => format!(" #${:02X}", raw[i + 0x01]),
                AddressingMode::ZeroPage => format!(" ${:02X}", raw[i + 0x01]),
                AddressingMode::ZeroPageX => format!(" ${:02X},X", raw[i + 0x01]),
                AddressingMode::ZeroPageY => format!(" ${:02X},Y", raw[i + 0x01]),
                AddressingMode::Absolute => {
                    format!(" ${:04X}", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::AbsoluteX => {
                    format!(" ${:04X},X", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::AbsoluteY => {
                    format!(" ${:04X},Y", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::IndirectX => format!(" (${:02X},X)", raw[i + 0x01]),
                AddressingMode::IndirectY => format!(" (${:02X}),Y", raw[i + 0x01]),
            };
            let opcode_text = format!("{}{}\n", opcode.mnemonic, val);
            result.push_str(&opcode_text);
            i += opcode.length as usize;
        }

        result
    }

    /// Returns a Vector of Strings where each entry
    /// is a non-empty line from some text input, with
    /// all leading and trailing whitespace removed.
    fn clean_asm<I>(input: I) -> Vec<String>
        where I: Into<String>
    {
        input.into()
            .lines()
            .map(|line| line.trim())
            .map(String::from)
            .filter(|line| line.len() > 0)
            .collect()
    }
}

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

    #[test]
    fn can_disassemble_basic_instructions() {
        let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            LDA #$20
            STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_jmp() {
        let code: Vec<u8> = vec![0x6C, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            JMP ($4400)

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_relative_addressing() {
        let code: Vec<u8> = vec![0xD0, 0xFF];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            BNE #$FF

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_addressing() {
        let code: Vec<u8> = vec![0xA5, 0x35];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            LDA $35

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_indexed_addressing() {
        let code: Vec<u8> = vec![0x95, 0x44, 0x96, 0xFE];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            STA $44,X
            STX $FE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_addressing() {
        let code: Vec<u8> = vec![0x8D, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_indexed_addressing() {
        let code: Vec<u8> = vec![0x9D, 0x00, 0x44, 0x99, 0xFE, 0xFF];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            STA $4400,X
            STA $FFFE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_indexed_addressing() {
        let code: Vec<u8> = vec![0x81, 0x44, 0x91, 0xFE];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            STA ($44,X)
            STA ($FE),Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn move_memory_down_test() {
        let code: Vec<u8> = vec![0xA0, 0x00, 0xAE, 0x00, 0x00, 0xF0, 0x10, 0xB1, 0x02, 0x91, 0x03,
                                 0xC8, 0xD0, 0xF9, 0xEE, 0x02, 0x00, 0xEE, 0x03, 0x00, 0xCA, 0xD0,
                                 0xF0, 0xAE, 0x01, 0x00, 0xF0, 0x08, 0xB1, 0x02, 0x91, 0x03, 0xC8,
                                 0xCA, 0xD0, 0xF8, 0x60];

        let asm = Disassembler::disassemble(&code);

        print!("{}", asm);
    }
}
<commit_msg>Disassmble simple memcpy implementation<commit_after>use byteorder::{ByteOrder, LittleEndian};

use opcodes::{AddressingMode, OpCode};

pub struct Disassembler;

impl Disassembler {
    pub fn disassemble(raw: &[u8]) -> String {
        let mut result = String::new();

        let mut i: usize = 0;
        while i < raw.len() {
            let opcode = OpCode::from_raw_byte(raw[i]);
            let val = match opcode.mode {
                AddressingMode::Implied |
                AddressingMode::Accumulator => String::from(""),
                AddressingMode::Immediate => format!(" #${:02X}", raw[i + 0x01]),
                AddressingMode::Indirect => {
                    format!(" (${:04X})", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::Relative => {
                    let mut offset = raw[i + 0x01] as i8;
                    println!("i: {}, Offset: {}, op: {}", i, offset, opcode.mnemonic);
                    let addr = if offset < 0 {
                        i - (-offset - 0x02) as usize
                    } else {
                        i + (offset as usize) + 0x02
                    };
                    format!(" ${:04X}", addr)
                }
                AddressingMode::ZeroPage => format!(" ${:02X}", raw[i + 0x01]),
                AddressingMode::ZeroPageX => format!(" ${:02X},X", raw[i + 0x01]),
                AddressingMode::ZeroPageY => format!(" ${:02X},Y", raw[i + 0x01]),
                AddressingMode::Absolute => {
                    format!(" ${:04X}", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::AbsoluteX => {
                    format!(" ${:04X},X", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::AbsoluteY => {
                    format!(" ${:04X},Y", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::IndirectX => format!(" (${:02X},X)", raw[i + 0x01]),
                AddressingMode::IndirectY => format!(" (${:02X}),Y", raw[i + 0x01]),
            };
            let opcode_text = format!("{:04X} {}{}\n", i, opcode.mnemonic, val);
            result.push_str(&opcode_text);
            i += opcode.length as usize;
        }

        result
    }

    /// Returns a Vector of Strings where each entry
    /// is a non-empty line from some text input, with
    /// all leading and trailing whitespace removed.
    fn clean_asm<I>(input: I) -> Vec<String>
        where I: Into<String>
    {
        input.into()
            .lines()
            .map(|line| line.trim())
            .map(String::from)
            .filter(|line| line.len() > 0)
            .collect()
    }
}

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

    #[test]
    fn can_disassemble_basic_instructions() {
        let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$20
            0002 STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_jmp() {
        let code: Vec<u8> = vec![0x6C, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 JMP ($4400)

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_relative_addressing() {
        let code: Vec<u8> = vec![0xA9, 0x20, 0x69, 0x10, 0xD0, 0xFA];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$20
            0002 ADC #$10
            0004 BNE $0000

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_addressing() {
        let code: Vec<u8> = vec![0xA5, 0x35];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA $35

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_indexed_addressing() {
        let code: Vec<u8> = vec![0x95, 0x44, 0x96, 0xFE];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $44,X
            0002 STX $FE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_addressing() {
        let code: Vec<u8> = vec![0x8D, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_indexed_addressing() {
        let code: Vec<u8> = vec![0x9D, 0x00, 0x44, 0x99, 0xFE, 0xFF];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $4400,X
            0003 STA $FFFE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_indexed_addressing() {
        let code: Vec<u8> = vec![0x81, 0x44, 0x91, 0xFE];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA ($44,X)
            0002 STA ($FE),Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn move_memory_down_test() {
        let code: Vec<u8> = vec![0xA0, 0x00, 0xAE, 0x00, 0x00, 0xF0, 0x10, 0xB1, 0x02, 0x91, 0x03,
                                 0xC8, 0xD0, 0xF9, 0xEE, 0x02, 0x00, 0xEE, 0x03, 0x00, 0xCA, 0xD0,
                                 0xF0, 0xAE, 0x01, 0x00, 0xF0, 0x08, 0xB1, 0x02, 0x91, 0x03, 0xC8,
                                 0xCA, 0xD0, 0xF8, 0x60];

        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

0000 LDY #$00
0002 LDX $0000
0005 BEQ $0017
0007 LDA ($02),Y
0009 STA ($03),Y
000B INY
000C BNE $0007
000E INC $0002
0011 INC $0003
0014 DEX
0015 BNE $0007
0017 LDX $0001
001A BEQ $0024
001C LDA ($02),Y
001E STA ($03),Y
0020 INY
0021 DEX
0022 BNE $001C
0024 RTS

        "),
                   Disassembler::clean_asm(asm));
    }
}
<|endoftext|>


<commit_before>use std::f32;

use cgmath;
use cgmath::{Angle, Deg, Point2};
use num::{Num, NumCast};

use crate::bullet::BulletDrawable;
use crate::character::CharacterDrawable;
use crate::game::{constants::{RESOLUTION_Y, TERRAIN_OBJECTS, TILE_SIZE, TILES_PCS_H, TILES_PCS_W, Y_OFFSET}, get_rand_from_range};
use crate::gfx_app::{mouse_controls::MouseInputState};
use crate::graphics::{dimensions::Dimensions, orientation::Orientation};
use crate::shaders::Position;
use crate::terrain_object::TerrainObjectDrawable;
use crate::zombie::ZombieDrawable;

pub mod camera;
pub mod dimensions;
mod graphics_test;
pub mod mesh;
pub mod orientation;
pub mod texture;

#[derive(Default)]
pub struct DeltaTime(pub f64);

#[derive(Default)]
pub struct GameTime(pub u64);

pub fn flip_y_axel(point: Point2<f32>) -> Point2<f32> {
  Point2::new(point.x, RESOLUTION_Y as f32 - point.y)
}

pub fn direction(start_point: Point2<f32>, end_point: Point2<f32>) -> f32 {
  let theta = Angle::atan2(end_point.y - start_point.y, end_point.x - start_point.x);
  let Deg(angle) = theta;
  if angle < 0.0 { (360.0 + angle) } else { angle }
}

pub fn direction_movement(direction: f32) -> Point2<f32> {
  let angle = Deg(direction);
  Point2::new(Angle::cos(angle), Angle::sin(angle))
}

pub fn direction_movement_180(movement_direction: Point2<f32>) -> Point2<f32> {
  let angle = Deg(direction(Point2::new(0.0, 0.0), movement_direction) + 180.0);
  Point2::new(Angle::cos(angle), Angle::sin(angle))
}

pub fn orientation_to_direction(angle_in_degrees: f32) -> Orientation {
  match angle_in_degrees as u32 {
    345..=360 | 0..=22 => Orientation::Right,
    23..=68 => Orientation::UpRight,
    69..=114 => Orientation::Up,
    115..=160 => Orientation::UpLeft,
    161..=206 => Orientation::Left,
    207..=252 => Orientation::DownLeft,
    253..=298 => Orientation::Down,
    299..=344 => Orientation::DownRight,
    _ => unreachable!("Invalid orientation")
  }
}

pub fn get_orientation_from_center(mouse_input: &MouseInputState, dim: &Dimensions) -> Orientation {
  if let Some(end_point_gl) = mouse_input.left_click_point {
    let start_point = Point2::new(dim.window_width / 2.0 * dim.hidpi_factor, dim.window_height / 2.0 * dim.hidpi_factor);
    let dir = direction(start_point, flip_y_axel(end_point_gl));
    orientation_to_direction(dir)
  } else {
    Orientation::Right
  }
}

pub fn overlaps(area: Position, el: Position, width: f32, height: f32) -> bool {
  area.x() - width < el.x() &&
    area.x() + width > el.x() &&
    area.y() - height < el.y() &&
    area.y() + height > el.y()
}

pub fn is_within_map_borders(point: Point2<f32>) -> bool {
  point.x >= 0.0 && point.x < (TILES_PCS_W as f32 - 1f32) && point.y >= 0.0 && point.y < (TILES_PCS_H as f32 - 1f32)
}

pub fn can_move(screen_pos: Position) -> bool {
  let point = coords_to_tile(screen_pos);
  is_within_map_borders(Point2::new(point.x as f32, point.y as f32))
}

fn is_not_terrain_object<T>(pos: Point2<T>) -> bool
  where T: NumCast + Num, i32: std::cmp::PartialEq<T> {
  !TERRAIN_OBJECTS.iter().any(|e| (e[0] == pos.x) && (e[1] == pos.y))
}

fn is_map_tile(pos: Point2<i32>) -> bool {
  pos.x > 0 && pos.y > 0 && pos.x < (TILES_PCS_W - 1) as i32 && pos.y < (TILES_PCS_H - 1) as i32
}

pub fn can_move_to_tile(screen_pos: Position) -> bool {
  let tile_pos = coords_to_tile(screen_pos);
  is_not_terrain_object(tile_pos) && is_map_tile(tile_pos)
}

pub fn check_terrain_elevation(critter_pos: Position, objects: &[[i32; 2]]) -> f32 {
  let offset = TILE_SIZE / 2.0;
  let nearest_hill = objects.iter()
    .map(|x| {
      position_distance(
        critter_pos,
        Position::new(TILE_SIZE * -x[0] as f32, TILE_SIZE * -x[1] as f32).tile_center(0.0, offset)
      )
    })
    .fold(100_000_000f32, |mut min, val| {
      if val < min {
        min = val;
      }
      min
    });

  if nearest_hill < TILE_SIZE * 2.0 {
    (nearest_hill - TILE_SIZE * 2.0).abs()
  } else {
    0.0
  }
}

pub fn set_position(x: i32, y: i32) -> Position {
  let x_val = x as f32;
  let y_val = y as f32;
  Position::new(
    TILE_SIZE * x_val,
    TILE_SIZE * 0.9 * y_val,
  )
}

pub fn coords_to_tile(position: Position) -> Point2<i32> {
  let pos = Point2::new(-position.x(), position.y() + Y_OFFSET);
  Point2::new(((pos.x + pos.y) / TILE_SIZE) as i32, ((pos.y - pos.x) / TILE_SIZE) as i32)
}

pub fn tile_to_coords(tile: Point2<i32>) -> Position {
  let new_tile = Point2::new(tile.x as f32, tile.y as f32);
  let x = round(new_tile.x * TILE_SIZE - new_tile.y / TILE_SIZE, 3);
  let y = round(new_tile.y * TILE_SIZE - new_tile.x / TILE_SIZE, 3);
  Position::new(-x, y - Y_OFFSET)
}

fn round(number: f32, precision: usize) -> f32 {
  let ten: f32 = 10.0;
  let divider = ten.powf(precision as f32);
  (number * divider).round() / divider
}

pub fn get_nearest_random_tile_position(pos: Position) -> Position {
  fn iter(pos: Position) -> Position {
    let offset = Position::new(get_rand_from_range(-2, 2) as f32, get_rand_from_range(-2, 2) as f32);
    let offset_point = Position::new(
      round(offset.x() * TILE_SIZE - offset.y() / TILE_SIZE, 3),
      round(offset.y() * TILE_SIZE - offset.y() / TILE_SIZE, 3),
    );
    pos + offset_point
  }
  loop {
    let res = iter(pos);
    if can_move_to_tile(res) {
      return res;
    }
  }
}

pub fn distance(a: f32, b: f32) -> f32 {
  (a.powf(2.0) + b.powf(2.0)).sqrt()
}

fn position_distance(a: Position, b: Position) -> f32 {
  let d = a - b;
  distance(d.x(), d.y())
}

pub enum Drawables<'b> {
  Bullet(&'b BulletDrawable),
  Character(&'b mut CharacterDrawable),
  TerrainAmmo(&'b TerrainObjectDrawable),
  TerrainHouse(&'b TerrainObjectDrawable),
  TerrainTree(&'b TerrainObjectDrawable),
  Zombie(&'b mut ZombieDrawable),
}

impl<'b> Drawables<'b> {
  pub fn get_vertical_pos(drawable: &Drawables) -> f32 {
    match drawable {
      Drawables::Bullet(e) => e.position.y(),
      Drawables::Zombie(e) => e.position.y(),
      Drawables::TerrainAmmo(e) => e.position.y(),
      Drawables::TerrainHouse(e) => e.position.y(),
      Drawables::TerrainTree(e) => e.position.y(),
      Drawables::Character(e) => e.position.y(),
    }
  }
}
<commit_msg>Refactor is_within_map_borders fn signature<commit_after>use std::f32;

use cgmath;
use cgmath::{Angle, Deg, Point2};
use num::{Num, NumCast};

use crate::bullet::BulletDrawable;
use crate::character::CharacterDrawable;
use crate::game::{constants::{RESOLUTION_Y, TERRAIN_OBJECTS, TILE_SIZE, TILES_PCS_H, TILES_PCS_W, Y_OFFSET}, get_rand_from_range};
use crate::gfx_app::{mouse_controls::MouseInputState};
use crate::graphics::{dimensions::Dimensions, orientation::Orientation};
use crate::shaders::Position;
use crate::terrain_object::TerrainObjectDrawable;
use crate::zombie::ZombieDrawable;

pub mod camera;
pub mod dimensions;
mod graphics_test;
pub mod mesh;
pub mod orientation;
pub mod texture;

#[derive(Default)]
pub struct DeltaTime(pub f64);

#[derive(Default)]
pub struct GameTime(pub u64);

pub fn flip_y_axel(point: Point2<f32>) -> Point2<f32> {
  Point2::new(point.x, RESOLUTION_Y as f32 - point.y)
}

pub fn direction(start_point: Point2<f32>, end_point: Point2<f32>) -> f32 {
  let theta = Angle::atan2(end_point.y - start_point.y, end_point.x - start_point.x);
  let Deg(angle) = theta;
  if angle < 0.0 { (360.0 + angle) } else { angle }
}

pub fn direction_movement(direction: f32) -> Point2<f32> {
  let angle = Deg(direction);
  Point2::new(Angle::cos(angle), Angle::sin(angle))
}

pub fn direction_movement_180(movement_direction: Point2<f32>) -> Point2<f32> {
  let angle = Deg(direction(Point2::new(0.0, 0.0), movement_direction) + 180.0);
  Point2::new(Angle::cos(angle), Angle::sin(angle))
}

pub fn orientation_to_direction(angle_in_degrees: f32) -> Orientation {
  match angle_in_degrees as u32 {
    345..=360 | 0..=22 => Orientation::Right,
    23..=68 => Orientation::UpRight,
    69..=114 => Orientation::Up,
    115..=160 => Orientation::UpLeft,
    161..=206 => Orientation::Left,
    207..=252 => Orientation::DownLeft,
    253..=298 => Orientation::Down,
    299..=344 => Orientation::DownRight,
    _ => unreachable!("Invalid orientation")
  }
}

pub fn get_orientation_from_center(mouse_input: &MouseInputState, dim: &Dimensions) -> Orientation {
  if let Some(end_point_gl) = mouse_input.left_click_point {
    let start_point = Point2::new(dim.window_width / 2.0 * dim.hidpi_factor, dim.window_height / 2.0 * dim.hidpi_factor);
    let dir = direction(start_point, flip_y_axel(end_point_gl));
    orientation_to_direction(dir)
  } else {
    Orientation::Right
  }
}

pub fn overlaps(area: Position, el: Position, width: f32, height: f32) -> bool {
  area.x() - width < el.x() &&
    area.x() + width > el.x() &&
    area.y() - height < el.y() &&
    area.y() + height > el.y()
}

pub fn is_within_map_borders(point: Point2<usize>) -> bool {
  point.x < (TILES_PCS_W - 1) && point.y < (TILES_PCS_H - 1)
}

pub fn can_move(screen_pos: Position) -> bool {
  let point = coords_to_tile(screen_pos);
  is_within_map_borders(Point2::new(point.x as usize, point.y as usize))
}

fn is_not_terrain_object<T>(pos: Point2<T>) -> bool
  where T: NumCast + Num, i32: std::cmp::PartialEq<T> {
  !TERRAIN_OBJECTS.iter().any(|e| (e[0] == pos.x) && (e[1] == pos.y))
}

fn is_map_tile(pos: Point2<i32>) -> bool {
  pos.x > 0 && pos.y > 0 && pos.x < (TILES_PCS_W - 1) as i32 && pos.y < (TILES_PCS_H - 1) as i32
}

pub fn can_move_to_tile(screen_pos: Position) -> bool {
  let tile_pos = coords_to_tile(screen_pos);
  is_not_terrain_object(tile_pos) && is_map_tile(tile_pos)
}

pub fn check_terrain_elevation(critter_pos: Position, objects: &[[i32; 2]]) -> f32 {
  let offset = TILE_SIZE / 2.0;
  let nearest_hill = objects.iter()
    .map(|x| {
      position_distance(
        critter_pos,
        Position::new(TILE_SIZE * -x[0] as f32, TILE_SIZE * -x[1] as f32).tile_center(0.0, offset)
      )
    })
    .fold(100_000_000f32, |mut min, val| {
      if val < min {
        min = val;
      }
      min
    });

  if nearest_hill < TILE_SIZE * 2.0 {
    (nearest_hill - TILE_SIZE * 2.0).abs()
  } else {
    0.0
  }
}

pub fn set_position(x: i32, y: i32) -> Position {
  let x_val = x as f32;
  let y_val = y as f32;
  Position::new(
    TILE_SIZE * x_val,
    TILE_SIZE * 0.9 * y_val,
  )
}

pub fn coords_to_tile(position: Position) -> Point2<i32> {
  let pos = Point2::new(-position.x(), position.y() + Y_OFFSET);
  Point2::new(((pos.x + pos.y) / TILE_SIZE) as i32, ((pos.y - pos.x) / TILE_SIZE) as i32)
}

pub fn tile_to_coords(tile: Point2<i32>) -> Position {
  let new_tile = Point2::new(tile.x as f32, tile.y as f32);
  let x = round(new_tile.x * TILE_SIZE - new_tile.y / TILE_SIZE, 3);
  let y = round(new_tile.y * TILE_SIZE - new_tile.x / TILE_SIZE, 3);
  Position::new(-x, y - Y_OFFSET)
}

fn round(number: f32, precision: usize) -> f32 {
  let ten: f32 = 10.0;
  let divider = ten.powf(precision as f32);
  (number * divider).round() / divider
}

pub fn get_nearest_random_tile_position(pos: Position) -> Position {
  fn iter(pos: Position) -> Position {
    let offset = Position::new(get_rand_from_range(-2, 2) as f32, get_rand_from_range(-2, 2) as f32);
    let offset_point = Position::new(
      round(offset.x() * TILE_SIZE - offset.y() / TILE_SIZE, 3),
      round(offset.y() * TILE_SIZE - offset.y() / TILE_SIZE, 3),
    );
    pos + offset_point
  }
  loop {
    let res = iter(pos);
    if can_move_to_tile(res) {
      return res;
    }
  }
}

pub fn distance(a: f32, b: f32) -> f32 {
  (a.powf(2.0) + b.powf(2.0)).sqrt()
}

fn position_distance(a: Position, b: Position) -> f32 {
  let d = a - b;
  distance(d.x(), d.y())
}

pub enum Drawables<'b> {
  Bullet(&'b BulletDrawable),
  Character(&'b mut CharacterDrawable),
  TerrainAmmo(&'b TerrainObjectDrawable),
  TerrainHouse(&'b TerrainObjectDrawable),
  TerrainTree(&'b TerrainObjectDrawable),
  Zombie(&'b mut ZombieDrawable),
}

impl<'b> Drawables<'b> {
  pub fn get_vertical_pos(drawable: &Drawables) -> f32 {
    match drawable {
      Drawables::Bullet(e) => e.position.y(),
      Drawables::Zombie(e) => e.position.y(),
      Drawables::TerrainAmmo(e) => e.position.y(),
      Drawables::TerrainHouse(e) => e.position.y(),
      Drawables::TerrainTree(e) => e.position.y(),
      Drawables::Character(e) => e.position.y(),
    }
  }
}
<|endoftext|>


<commit_before>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// Creates a new `GroupingMap` from `iter`
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    GroupingMap { iter }
}

/// `GroupingMap` is an intermediate struct for efficient "group-and-fold" operations.
/// It groups elements by their key and at the same time fold each group
/// using some aggregating operation.
///
/// No method on this struct performs temporary allocations.
///
// See [`.into_grouping_map()`](../trait.Itertools.html#method.into_grouping_map)
// for more information.
pub struct GroupingMap<I> {
    iter: I,
}

impl<I, K, V> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in an `HashMap`.
    ///
    /// The `operation` function is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group if there is currently one;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being aggregated;
    /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
    /// otherwise the previous accumulation is discarded.
    ///
    /// Return a `HashMap` associating the key of each group with the result of aggregation of the group elements.
    /// If there's no result then there won't be an entry associated to that key.
    ///
    /// This is the generic way to perform any operations on a `Grouping`.
    /// It's suggested to use it only to implement custom operations when the already provided ones are not enough.
    pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
    where
        FO: FnMut(Option<R>, &K, V) -> Option<R>,
    {
        let mut destination_map = HashMap::new();

        for (key, val) in self.iter {
            let acc = destination_map.remove(&key);
            if let Some(op_res) = operation(acc, &key, val) {
                destination_map.insert(key, op_res);
            }
        }

        destination_map
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// `init` is the value from which will be cloned the initial value of each accumulator.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
    where
        R: Clone,
        FO: FnMut(R, &K, V) -> R,
    {
        self.aggregate(|acc, key, val| {
            let acc = acc.unwrap_or_else(|| init.clone());
            Some(operation(acc, key, val))
        })
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// This is similar to [`fold`] but the initial value of the accumulator is the first element of the group.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// [`fold`]: #tymethod.fold
    pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
    where
        FO: FnMut(V, &K, V) -> V,
    {
        self.aggregate(|acc, key, val| {
            Some(match acc {
                Some(acc) => operation(acc, key, val),
                None => val,
            })
        })
    }

    /// Groups elements from the `GroupingMap` source by key and collects the elements of each group in
    /// an instance of `C`. The iteration order is preserved when inserting elements.
    pub fn collect<C>(self) -> HashMap<K, C>
    where
        C: Default + Extend<V>,
    {
        self.aggregate(|acc, _, v| {
            let mut acc = acc.unwrap_or_else(C::default);
            acc.extend(Some(v));
            Some(acc)
        })
    }

    pub fn count(self) -> HashMap<K, usize> {
        self.fold(0, |acc, _, _| acc + 1)
    }
}
<commit_msg>Added doc for GroupingMap::count<commit_after>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// Creates a new `GroupingMap` from `iter`
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    GroupingMap { iter }
}

/// `GroupingMap` is an intermediate struct for efficient "group-and-fold" operations.
/// It groups elements by their key and at the same time fold each group
/// using some aggregating operation.
///
/// No method on this struct performs temporary allocations.
///
// See [`.into_grouping_map()`](../trait.Itertools.html#method.into_grouping_map)
// for more information.
pub struct GroupingMap<I> {
    iter: I,
}

impl<I, K, V> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in an `HashMap`.
    ///
    /// The `operation` function is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group if there is currently one;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being aggregated;
    /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
    /// otherwise the previous accumulation is discarded.
    ///
    /// Return a `HashMap` associating the key of each group with the result of aggregation of the group elements.
    /// If there's no result then there won't be an entry associated to that key.
    ///
    /// This is the generic way to perform any operations on a `Grouping`.
    /// It's suggested to use it only to implement custom operations when the already provided ones are not enough.
    pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
    where
        FO: FnMut(Option<R>, &K, V) -> Option<R>,
    {
        let mut destination_map = HashMap::new();

        for (key, val) in self.iter {
            let acc = destination_map.remove(&key);
            if let Some(op_res) = operation(acc, &key, val) {
                destination_map.insert(key, op_res);
            }
        }

        destination_map
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// `init` is the value from which will be cloned the initial value of each accumulator.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
    where
        R: Clone,
        FO: FnMut(R, &K, V) -> R,
    {
        self.aggregate(|acc, key, val| {
            let acc = acc.unwrap_or_else(|| init.clone());
            Some(operation(acc, key, val))
        })
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// This is similar to [`fold`] but the initial value of the accumulator is the first element of the group.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// [`fold`]: #tymethod.fold
    pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
    where
        FO: FnMut(V, &K, V) -> V,
    {
        self.aggregate(|acc, key, val| {
            Some(match acc {
                Some(acc) => operation(acc, key, val),
                None => val,
            })
        })
    }

    /// Groups elements from the `GroupingMap` source by key and collects the elements of each group in
    /// an instance of `C`. The iteration order is preserved when inserting elements.
    pub fn collect<C>(self) -> HashMap<K, C>
    where
        C: Default + Extend<V>,
    {
        self.aggregate(|acc, _, v| {
            let mut acc = acc.unwrap_or_else(C::default);
            acc.extend(Some(v));
            Some(acc)
        })
    }

    /// Groups elements from the `GroupingMap` source by key and counts them.
    ///
    /// Return a `HashMap` associating the key of each group with the number of elements in that group.
    pub fn count(self) -> HashMap<K, usize> {
        self.fold(0, |acc, _, _| acc + 1)
    }
}
<|endoftext|>


<commit_before>extern crate num as libnum;
extern crate rand;

pub mod linalg {

    pub trait Metric<T> {
        fn norm(&self) -> T;
	}

    pub mod matrix;
    pub mod vector;
    pub mod utils;
    pub mod macros;
}

pub mod learning {
    pub mod lin_reg;
    pub mod k_means;
    pub mod nnet;

    /// Trait for supervised model.
    pub trait SupModel<T,U> {

        /// Predict output from data.
        fn predict(&self, data: T) -> U;

        /// Train the model using data and outputs.
        fn train(&mut self, data: T, value: U);
	}

    /// Trait for unsupervised model.
	pub trait UnSupModel<T, U> {

        /// Predict output from data.
        fn predict(&self, data: T) -> U;

        /// Train the model using data.
        fn train(&mut self, data: T);
	}

    pub mod optim {
        pub trait OptimAlgorithm<T> {
            fn optimize(&self, start: T, f: &Fn(T) -> (f64, T)) -> T;
        }

        pub mod grad_desc;
    }
}
<commit_msg>Adding documentation for module roots.<commit_after>extern crate num as libnum;
extern crate rand;

/// Module for linear algebra.
pub mod linalg {

    pub trait Metric<T> {
        fn norm(&self) -> T;
	}

    pub mod matrix;
    pub mod vector;
    pub mod utils;
    pub mod macros;
}

/// Module for machine learning.
pub mod learning {
    pub mod lin_reg;
    pub mod k_means;
    pub mod nnet;

    /// Trait for supervised model.
    pub trait SupModel<T,U> {

        /// Predict output from data.
        fn predict(&self, data: T) -> U;

        /// Train the model using data and outputs.
        fn train(&mut self, data: T, value: U);
	}

    /// Trait for unsupervised model.
	pub trait UnSupModel<T, U> {

        /// Predict output from data.
        fn predict(&self, data: T) -> U;

        /// Train the model using data.
        fn train(&mut self, data: T);
	}

    /// Module for optimization in machine learning setting.
    pub mod optim {
        pub trait OptimAlgorithm<T> {
            fn optimize(&self, start: T, f: &Fn(T) -> (f64, T)) -> T;
        }

        pub mod grad_desc;
    }
}
<|endoftext|>


<commit_before>extern mod extra;
extern mod frog;
use std::rand;
use std::vec;
use extra::time;
use frog::ga::GeneticAlgorithm;

fn bench(name: &str, thresh: f64, ga: &mut GeneticAlgorithm<f64>, fit_fn: &fn(code: &[f64]) -> f64)
{
    let old = time::precise_time_s();
    println("Testing " + name +" function\n");
    let mut count = 0u;
    while ga.best.score <= thresh {
      do ga.step |c| {
        fit_fn(c)
      }
      count = count + 1;
      println("Epoch : " + count.to_str() + " - best score: " + (ga.best.score).to_str());
    }

    let rand_code: ~[f64] = vec::from_fn(ga.best.code.len(), |_| rand::random());
    let time = time::precise_time_s() - old;

    println("\nElpased time: " + time.to_str() + " seconds\n");
    println("Best generation : " + ga.best.code.to_str());
    println("with performance : " + ga.best.score.to_str());
    println("\nRand generation : " + rand_code.to_str());
    println("with performance : " + fit_fn(rand_code).to_str());
}

#[main]
fn main() {
    let mut ga: GeneticAlgorithm<f64> = GeneticAlgorithm::new(2000, 2, 0.2, 40.0, 100);
    do bench("Michalewicz", 1.8, &mut ga) |c| {
        // Restrict to hypercube -5.12 <= x <= 5.12

        let mut res  = 0.0;
        for (i, e) in c.iter().enumerate() {
            let e2 = *e * 3.141592;
            let e3: f64 = (((i + 1) as f64) * e2 * *e).sin();
            res += e2.sin() * e3.pow(~20.0);
        }
        res
    }
}
<commit_msg>Change Michalewicz to dimension 10<commit_after>extern mod extra;
extern mod frog;
use std::rand;
use std::vec;
use extra::time;
use frog::ga::GeneticAlgorithm;

fn bench(name: &str, thresh: f64, ga: &mut GeneticAlgorithm<f64>, fit_fn: &fn(code: &[f64]) -> f64)
{
    let old = time::precise_time_s();
    println("Testing " + name +" function\n");
    let mut count = 0u;
    while ga.best.score <= thresh {
      do ga.step |c| {
        fit_fn(c)
      }
      count = count + 1;
      println("Epoch : " + count.to_str() + " - best score: " + (ga.best.score).to_str());
    }

    let rand_code: ~[f64] = vec::from_fn(ga.best.code.len(), |_| rand::random());
    let time = time::precise_time_s() - old;

    println("\nElpased time: " + time.to_str() + " seconds\n");
    println("Best generation : " + ga.best.code.to_str());
    println("with performance : " + ga.best.score.to_str());
    println("\nRand generation : " + rand_code.to_str());
    println("with performance : " + fit_fn(rand_code).to_str());
}

#[main]
fn main() {
    let mut ga: GeneticAlgorithm<f64> = GeneticAlgorithm::new(3000, 10, 0.2, 60.0, 130);
    do bench("Michalewicz", 9.66, &mut ga) |c| {
        // Restrict to hypercube -5.12 <= x <= 5.12

        let mut res  = 0.0;
        for (i, e) in c.iter().enumerate() {
            let e2 = *e * 3.141592;
            let e3: f64 = (((i + 1) as f64) * e2 * *e).sin();
            res += e2.sin() * e3.pow(~20.0);
        }
        res
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;
extern crate blockchain_explorer;
extern crate sandbox;
extern crate exonum;
extern crate configuration_service;
extern crate serde_json;
extern crate serde;
#[macro_use]
extern crate log;

#[cfg(test)]
mod tests {

    use std::collections::BTreeMap;
    use exonum::storage::{Map, StorageValue};
    use exonum::messages::Message;
    use exonum::blockchain::config::StoredConfiguration;
    use exonum::blockchain::Service;
    use sandbox::sandbox_with_services;
    use sandbox::sandbox::Sandbox;
    use sandbox::timestamping::TimestampingService;
    use sandbox::sandbox_tests_helper::{SandboxState, add_one_height_with_transactions};
    use configuration_service::{TxConfigPropose, TxConfigVote, ConfigurationService,
                                ConfigurationSchema};
    use serde_json::{Value};
    use serde_json::value::ToJson;
    use blockchain_explorer;

    pub fn configuration_sandbox() -> Sandbox {
        let sandbox = sandbox_with_services(vec![Box::new(TimestampingService::new()),
                                                 Box::new(ConfigurationService::new())]);
        sandbox
    }

    #[derive(Serialize)]
    struct CfgStub {
        cfg_string: String,
    }

    #[test]
    fn test_change_service_config() {
        let _ = blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();
        let initial_cfg = sandbox.cfg();

        let target_height = 10;
        for _ in 0..target_height {
            add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        }
        sandbox.assert_state(target_height + 1, 1);

        let services = gen_timestamping_cfg("First cfg");

        let new_cfg = StoredConfiguration {
            actual_from: target_height + 4,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let new_cfg_bytes = new_cfg.clone().serialize();
        let new_cfg_hash = new_cfg.hash();
        let initial_cfg_hash = initial_cfg.hash();

        let propose_tx = TxConfigPropose::new(&sandbox.p(1),
                                              &initial_cfg_hash,
                                              &new_cfg_bytes,
                                              sandbox.s(1));
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[propose_tx.raw().clone()]);
        sandbox.assert_state(target_height + 2, 1);

        let view = sandbox.blockchain_ref().view();
        let schema = ConfigurationSchema::new(&view);
        let proposes = schema.config_proposes();
        assert_eq!(propose_tx, proposes.get(&new_cfg_hash).unwrap().unwrap());

        let vote1 = TxConfigVote::new(&sandbox.p(0), &new_cfg_hash, sandbox.s(0));
        let vote2 = TxConfigVote::new(&sandbox.p(1), &new_cfg_hash, sandbox.s(1));
        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[vote1.raw().clone(), vote2.raw().clone()]);
        sandbox.assert_state(target_height + 3, 1);

        let view = sandbox.blockchain_ref().view();
        let schema = ConfigurationSchema::new(&view);
        let votes = schema.config_votes(new_cfg_hash);
        assert_eq!(vote1, votes.get(&sandbox.p(0)).unwrap().unwrap());
        assert_eq!(vote2, votes.get(&sandbox.p(1)).unwrap().unwrap());
        assert_eq!(None, votes.get(&sandbox.p(2)).unwrap());
        assert_eq!(initial_cfg, sandbox.cfg());

        let vote3 = TxConfigVote::new(&sandbox.p(2), &new_cfg_hash, sandbox.s(2));
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[vote3.raw().clone()]);
        sandbox.assert_state(target_height + 4, 1);

        let view = sandbox.blockchain_ref().view();
        let schema = ConfigurationSchema::new(&view);
        let votes = schema.config_votes(new_cfg_hash);
        assert_eq!(vote3, votes.get(&sandbox.p(2)).unwrap().unwrap());
        assert_eq!(new_cfg, sandbox.cfg());
    }

    fn gen_timestamping_cfg(cfg_message: &str) -> BTreeMap<u16, Value> {
        let mut services: BTreeMap<u16, Value> = BTreeMap::new();
        let tmstmp_id = TimestampingService::new().service_id();
        let service_cfg = CfgStub { cfg_string: cfg_message.to_string() };
        services.insert(tmstmp_id, service_cfg.to_json());
        services
    }

    /// regression: votes' were summed for all proposes simultaneously, and not for the same propose
    #[test]
    fn test_regression_majority_votes_for_different_proposes() {

        let _ = blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();

        let initial_cfg = sandbox.cfg();
        let initial_cfg_hash = initial_cfg.hash();
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        sandbox.assert_state(2, 1);

        let actual_from = 6;

        let services = gen_timestamping_cfg("First cfg");
        let new_cfg1 = StoredConfiguration {
            actual_from: actual_from,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let services = gen_timestamping_cfg("Second cfg");
        let new_cfg2 = StoredConfiguration {
            actual_from: actual_from,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let new_cfg1_bytes = new_cfg1.clone().serialize();
        let new_cfg2_bytes = new_cfg2.clone().serialize();
        let new_cfg1_hash =  new_cfg1.hash();
        let new_cfg2_hash =  new_cfg2.hash();

        let propose_tx1 = TxConfigPropose::new(&sandbox.p(1),
                                               &initial_cfg_hash,
                                               &new_cfg1_bytes,
                                               sandbox.s(1));
        let propose_tx2 = TxConfigPropose::new(&sandbox.p(1),
                                               &initial_cfg_hash,
                                               &new_cfg2_bytes,
                                               sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[propose_tx1.raw().clone(), propose_tx2.raw().clone()]);
        sandbox.assert_state(3, 1);

        let prop1_validator0 =
            TxConfigVote::new(&sandbox.p(0), &new_cfg1_hash, sandbox.s(0));
        let prop1_validator1 =
            TxConfigVote::new(&sandbox.p(1), &new_cfg1_hash, sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator0.raw().clone(),
                                           prop1_validator1.raw().clone()]);
        sandbox.assert_state(4, 1);
        assert_eq!(initial_cfg, sandbox.cfg());

        let prop2_validator2 =
            TxConfigVote::new(&sandbox.p(2), &new_cfg2_hash, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop2_validator2.raw().clone()]);
        sandbox.assert_state(5, 1);
        assert_eq!(initial_cfg, sandbox.cfg());

        let prop1_validator2 =
            TxConfigVote::new(&sandbox.p(2), &new_cfg1_hash, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator2.raw().clone()]);
        sandbox.assert_state(6, 1);
        assert_eq!(new_cfg1, sandbox.cfg());
    }

    #[test]
    fn test_regression_new_vote_for_older_config_applies_old_config() {

        let _ = blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();

        let initial_cfg = sandbox.cfg();
        let initial_cfg_hash = initial_cfg.hash();

        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        sandbox.assert_state(2, 1);

        let services = gen_timestamping_cfg("First cfg");
        let new_cfg1 = StoredConfiguration {
            actual_from: 4,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let services = gen_timestamping_cfg("Second cfg");
        let new_cfg2 = StoredConfiguration {
            actual_from: 6,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let new_cfg1_bytes = new_cfg1.clone().serialize();
        let new_cfg2_bytes = new_cfg2.clone().serialize();
        let new_cfg1_hash =  new_cfg1.hash();
        let new_cfg2_hash =  new_cfg2.hash();

        let propose_tx1 = TxConfigPropose::new(&sandbox.p(1),
                                               &initial_cfg_hash,
                                               &new_cfg1_bytes,
                                               sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[propose_tx1.raw().clone()]);
        sandbox.assert_state(3, 1);

        let prop1_validator0 =
            TxConfigVote::new(&sandbox.p(0), &new_cfg1_hash, sandbox.s(0));
        let prop1_validator1 =
            TxConfigVote::new(&sandbox.p(1), &new_cfg1_hash, sandbox.s(1));
        let prop1_validator2 =
            TxConfigVote::new(&sandbox.p(2), &new_cfg1_hash, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator0.raw().clone(),
                                           prop1_validator1.raw().clone(),
                                           prop1_validator2.raw().clone()]);
        sandbox.assert_state(4, 1);
        assert_eq!(new_cfg1, sandbox.cfg());

        let propose_tx2 = TxConfigPropose::new(&sandbox.p(1),
                                               &new_cfg1_hash,
                                               &new_cfg2_bytes,
                                               sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[propose_tx2.raw().clone()]);
        sandbox.assert_state(5, 1);

        let prop2_validator0 =
            TxConfigVote::new(&sandbox.p(0), &new_cfg2_hash, sandbox.s(0));
        let prop2_validator1 =
            TxConfigVote::new(&sandbox.p(1), &new_cfg2_hash, sandbox.s(1));
        let prop2_validator2 =
            TxConfigVote::new(&sandbox.p(2), &new_cfg2_hash, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop2_validator0.raw().clone(),
                                           prop2_validator1.raw().clone(),
                                           prop2_validator2.raw().clone()]);
        sandbox.assert_state(6, 1);
        assert_eq!(new_cfg2, sandbox.cfg());

        let prop1_validator3 =
            TxConfigVote::new(&sandbox.p(3), &new_cfg1_hash, sandbox.s(3));
        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator3.raw().clone()]);
        sandbox.assert_state(7, 1);
        assert_eq!(new_cfg2, sandbox.cfg());
    }
}
<commit_msg>Added testcase<commit_after>#[macro_use]
extern crate serde_derive;
extern crate blockchain_explorer;
extern crate sandbox;
extern crate exonum;
extern crate configuration_service;
extern crate serde_json;
extern crate serde;
#[macro_use]
extern crate log;

#[cfg(test)]
mod tests {

    use std::collections::BTreeMap;
    use exonum::storage::{Map, StorageValue};
    use exonum::messages::Message;
    use exonum::blockchain::config::StoredConfiguration;
    use exonum::blockchain::Service;
    use sandbox::sandbox_with_services;
    use sandbox::sandbox::Sandbox;
    use sandbox::timestamping::TimestampingService;
    use sandbox::sandbox_tests_helper::{SandboxState, add_one_height_with_transactions};
    use configuration_service::{TxConfigPropose, TxConfigVote, ConfigurationService,
                                ConfigurationSchema};
    use serde_json::{Value};
    use serde_json::value::ToJson;
    use blockchain_explorer;

    pub fn configuration_sandbox() -> Sandbox {
        let sandbox = sandbox_with_services(vec![Box::new(TimestampingService::new()),
                                                 Box::new(ConfigurationService::new())]);
        sandbox
    }

    #[derive(Serialize)]
    struct CfgStub {
        cfg_string: String,
    }

    #[test]
    fn test_config_txs_discarded_when_following_config_present() {
        let _ = blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();
        let initial_cfg = sandbox.cfg();
        sandbox.assert_state(1, 1);

        let services = gen_timestamping_cfg("Following cfg at height 6");
        let following_config = StoredConfiguration {
            actual_from: 6,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };

        let foll_cfg_bytes = following_config.clone().serialize();
        let foll_cfg_hash = following_config.hash();
        let initial_cfg_hash = initial_cfg.hash();

        let propose_tx = TxConfigPropose::new(&sandbox.p(1),
                                              &initial_cfg_hash,
                                              &foll_cfg_bytes,
                                              sandbox.s(1));
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[propose_tx.raw().clone()]);
        sandbox.assert_state(2, 1);
        let view = sandbox.blockchain_ref().view();
        let schema = ConfigurationSchema::new(&view);
        let proposes = schema.config_proposes();
        assert_eq!(Some(propose_tx), proposes.get(&foll_cfg_hash).unwrap());

        let votes = (0..3).map(|validator|{
            TxConfigVote::new(&sandbox.p(validator), &foll_cfg_hash, sandbox.s(validator)).raw().clone()
        }).collect::<Vec<_>>();
        add_one_height_with_transactions(&sandbox, &sandbox_state, &votes);
        sandbox.assert_state(3, 1);
        assert_eq!(sandbox.cfg(), initial_cfg);
        assert_eq!(sandbox.following_cfg(), Some(following_config.clone()));

        let services = gen_timestamping_cfg("New cfg");
        let new_cfg = StoredConfiguration {
            actual_from: 7,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let new_cfg_bytes = new_cfg.clone().serialize();
        let new_cfg_hash = new_cfg.hash();

        let propose_tx_new = TxConfigPropose::new(&sandbox.p(1),
                                              &initial_cfg_hash,
                                              &new_cfg_bytes,
                                              sandbox.s(1));
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[propose_tx_new.raw().clone()]);
        sandbox.assert_state(4, 1);

        let view = sandbox.blockchain_ref().view();
        let schema = ConfigurationSchema::new(&view);
        let proposes = schema.config_proposes();
        assert_eq!(None, proposes.get(&new_cfg_hash).unwrap());

        let vote_validator_3 = TxConfigVote::new(&sandbox.p(3), &foll_cfg_hash, sandbox.s(3));
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[vote_validator_3.raw().clone()]);
        sandbox.assert_state(5, 1);

        let view = sandbox.blockchain_ref().view();
        let schema = ConfigurationSchema::new(&view);
        let votes_for_following_cfg = schema.config_votes(foll_cfg_hash);
        assert!(votes_for_following_cfg.get(&sandbox.p(0)).unwrap().is_some());
        assert!(votes_for_following_cfg.get(&sandbox.p(3)).unwrap().is_none());
        assert_eq!(initial_cfg, sandbox.cfg());

        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        sandbox.assert_state(6, 1);
        assert_eq!(following_config, sandbox.cfg());
    }

    #[test]
    fn test_change_service_config() {
        let _ = blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();
        let initial_cfg = sandbox.cfg();

        let target_height = 10;
        for _ in 0..target_height {
            add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        }
        sandbox.assert_state(target_height + 1, 1);

        let services = gen_timestamping_cfg("First cfg");

        let new_cfg = StoredConfiguration {
            actual_from: target_height + 4,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let new_cfg_bytes = new_cfg.clone().serialize();
        let new_cfg_hash = new_cfg.hash();
        let initial_cfg_hash = initial_cfg.hash();

        let propose_tx = TxConfigPropose::new(&sandbox.p(1),
                                              &initial_cfg_hash,
                                              &new_cfg_bytes,
                                              sandbox.s(1));
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[propose_tx.raw().clone()]);
        sandbox.assert_state(target_height + 2, 1);

        let view = sandbox.blockchain_ref().view();
        let schema = ConfigurationSchema::new(&view);
        let proposes = schema.config_proposes();
        assert_eq!(propose_tx, proposes.get(&new_cfg_hash).unwrap().unwrap());

        let vote1 = TxConfigVote::new(&sandbox.p(0), &new_cfg_hash, sandbox.s(0));
        let vote2 = TxConfigVote::new(&sandbox.p(1), &new_cfg_hash, sandbox.s(1));
        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[vote1.raw().clone(), vote2.raw().clone()]);
        sandbox.assert_state(target_height + 3, 1);

        let view = sandbox.blockchain_ref().view();
        let schema = ConfigurationSchema::new(&view);
        let votes = schema.config_votes(new_cfg_hash);
        assert_eq!(vote1, votes.get(&sandbox.p(0)).unwrap().unwrap());
        assert_eq!(vote2, votes.get(&sandbox.p(1)).unwrap().unwrap());
        assert_eq!(None, votes.get(&sandbox.p(2)).unwrap());
        assert_eq!(initial_cfg, sandbox.cfg());

        let vote3 = TxConfigVote::new(&sandbox.p(2), &new_cfg_hash, sandbox.s(2));
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[vote3.raw().clone()]);
        sandbox.assert_state(target_height + 4, 1);

        let view = sandbox.blockchain_ref().view();
        let schema = ConfigurationSchema::new(&view);
        let votes = schema.config_votes(new_cfg_hash);
        assert_eq!(vote3, votes.get(&sandbox.p(2)).unwrap().unwrap());
        assert_eq!(new_cfg, sandbox.cfg());
    }

    fn gen_timestamping_cfg(cfg_message: &str) -> BTreeMap<u16, Value> {
        let mut services: BTreeMap<u16, Value> = BTreeMap::new();
        let tmstmp_id = TimestampingService::new().service_id();
        let service_cfg = CfgStub { cfg_string: cfg_message.to_string() };
        services.insert(tmstmp_id, service_cfg.to_json());
        services
    }

    /// regression: votes' were summed for all proposes simultaneously, and not for the same propose
    #[test]
    fn test_regression_majority_votes_for_different_proposes() {

        let _ = blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();

        let initial_cfg = sandbox.cfg();
        let initial_cfg_hash = initial_cfg.hash();
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        sandbox.assert_state(2, 1);

        let actual_from = 6;

        let services = gen_timestamping_cfg("First cfg");
        let new_cfg1 = StoredConfiguration {
            actual_from: actual_from,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let services = gen_timestamping_cfg("Second cfg");
        let new_cfg2 = StoredConfiguration {
            actual_from: actual_from,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let new_cfg1_bytes = new_cfg1.clone().serialize();
        let new_cfg2_bytes = new_cfg2.clone().serialize();
        let new_cfg1_hash =  new_cfg1.hash();
        let new_cfg2_hash =  new_cfg2.hash();

        let propose_tx1 = TxConfigPropose::new(&sandbox.p(1),
                                               &initial_cfg_hash,
                                               &new_cfg1_bytes,
                                               sandbox.s(1));
        let propose_tx2 = TxConfigPropose::new(&sandbox.p(1),
                                               &initial_cfg_hash,
                                               &new_cfg2_bytes,
                                               sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[propose_tx1.raw().clone(), propose_tx2.raw().clone()]);
        sandbox.assert_state(3, 1);

        let prop1_validator0 =
            TxConfigVote::new(&sandbox.p(0), &new_cfg1_hash, sandbox.s(0));
        let prop1_validator1 =
            TxConfigVote::new(&sandbox.p(1), &new_cfg1_hash, sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator0.raw().clone(),
                                           prop1_validator1.raw().clone()]);
        sandbox.assert_state(4, 1);
        assert_eq!(initial_cfg, sandbox.cfg());

        let prop2_validator2 =
            TxConfigVote::new(&sandbox.p(2), &new_cfg2_hash, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop2_validator2.raw().clone()]);
        sandbox.assert_state(5, 1);
        assert_eq!(initial_cfg, sandbox.cfg());

        let prop1_validator2 =
            TxConfigVote::new(&sandbox.p(2), &new_cfg1_hash, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator2.raw().clone()]);
        sandbox.assert_state(6, 1);
        assert_eq!(new_cfg1, sandbox.cfg());
    }

    #[test]
    fn test_regression_new_vote_for_older_config_applies_old_config() {

        let _ = blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();

        let initial_cfg = sandbox.cfg();
        let initial_cfg_hash = initial_cfg.hash();

        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        sandbox.assert_state(2, 1);

        let services = gen_timestamping_cfg("First cfg");
        let new_cfg1 = StoredConfiguration {
            actual_from: 4,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let services = gen_timestamping_cfg("Second cfg");
        let new_cfg2 = StoredConfiguration {
            actual_from: 6,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let new_cfg1_bytes = new_cfg1.clone().serialize();
        let new_cfg2_bytes = new_cfg2.clone().serialize();
        let new_cfg1_hash =  new_cfg1.hash();
        let new_cfg2_hash =  new_cfg2.hash();

        let propose_tx1 = TxConfigPropose::new(&sandbox.p(1),
                                               &initial_cfg_hash,
                                               &new_cfg1_bytes,
                                               sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[propose_tx1.raw().clone()]);
        sandbox.assert_state(3, 1);

        let prop1_validator0 =
            TxConfigVote::new(&sandbox.p(0), &new_cfg1_hash, sandbox.s(0));
        let prop1_validator1 =
            TxConfigVote::new(&sandbox.p(1), &new_cfg1_hash, sandbox.s(1));
        let prop1_validator2 =
            TxConfigVote::new(&sandbox.p(2), &new_cfg1_hash, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator0.raw().clone(),
                                           prop1_validator1.raw().clone(),
                                           prop1_validator2.raw().clone()]);
        sandbox.assert_state(4, 1);
        assert_eq!(new_cfg1, sandbox.cfg());

        let propose_tx2 = TxConfigPropose::new(&sandbox.p(1),
                                               &new_cfg1_hash,
                                               &new_cfg2_bytes,
                                               sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[propose_tx2.raw().clone()]);
        sandbox.assert_state(5, 1);

        let prop2_validator0 =
            TxConfigVote::new(&sandbox.p(0), &new_cfg2_hash, sandbox.s(0));
        let prop2_validator1 =
            TxConfigVote::new(&sandbox.p(1), &new_cfg2_hash, sandbox.s(1));
        let prop2_validator2 =
            TxConfigVote::new(&sandbox.p(2), &new_cfg2_hash, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop2_validator0.raw().clone(),
                                           prop2_validator1.raw().clone(),
                                           prop2_validator2.raw().clone()]);
        sandbox.assert_state(6, 1);
        assert_eq!(new_cfg2, sandbox.cfg());

        let prop1_validator3 =
            TxConfigVote::new(&sandbox.p(3), &new_cfg1_hash, sandbox.s(3));
        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator3.raw().clone()]);
        sandbox.assert_state(7, 1);
        assert_eq!(new_cfg2, sandbox.cfg());
    }
}
<|endoftext|>


<commit_before>use core::any::*;

#[derive(PartialEq, Debug)]
struct Test;

static TEST: &'static str = "Test";

#[test]
fn any_referenced() {
    let (a, b, c) = (&5 as &dyn Any, &TEST as &dyn Any, &Test as &dyn Any);

    assert!(a.is::<i32>());
    assert!(!b.is::<i32>());
    assert!(!c.is::<i32>());

    assert!(!a.is::<&'static str>());
    assert!(b.is::<&'static str>());
    assert!(!c.is::<&'static str>());

    assert!(!a.is::<Test>());
    assert!(!b.is::<Test>());
    assert!(c.is::<Test>());
}

#[test]
fn any_owning() {
    let (a, b, c) =
        (box 5_usize as Box<dyn Any>, box TEST as Box<dyn Any>, box Test as Box<dyn Any>);

    assert!(a.is::<usize>());
    assert!(!b.is::<usize>());
    assert!(!c.is::<usize>());

    assert!(!a.is::<&'static str>());
    assert!(b.is::<&'static str>());
    assert!(!c.is::<&'static str>());

    assert!(!a.is::<Test>());
    assert!(!b.is::<Test>());
    assert!(c.is::<Test>());
}

#[test]
fn any_downcast_ref() {
    let a = &5_usize as &dyn Any;

    match a.downcast_ref::<usize>() {
        Some(&5) => {}
        x => panic!("Unexpected value {:?}", x),
    }

    match a.downcast_ref::<Test>() {
        None => {}
        x => panic!("Unexpected value {:?}", x),
    }
}

#[test]
fn any_downcast_mut() {
    let mut a = 5_usize;
    let mut b: Box<_> = box 7_usize;

    let a_r = &mut a as &mut dyn Any;
    let tmp: &mut usize = &mut *b;
    let b_r = tmp as &mut dyn Any;

    match a_r.downcast_mut::<usize>() {
        Some(x) => {
            assert_eq!(*x, 5);
            *x = 612;
        }
        x => panic!("Unexpected value {:?}", x),
    }

    match b_r.downcast_mut::<usize>() {
        Some(x) => {
            assert_eq!(*x, 7);
            *x = 413;
        }
        x => panic!("Unexpected value {:?}", x),
    }

    match a_r.downcast_mut::<Test>() {
        None => (),
        x => panic!("Unexpected value {:?}", x),
    }

    match b_r.downcast_mut::<Test>() {
        None => (),
        x => panic!("Unexpected value {:?}", x),
    }

    match a_r.downcast_mut::<usize>() {
        Some(&mut 612) => {}
        x => panic!("Unexpected value {:?}", x),
    }

    match b_r.downcast_mut::<usize>() {
        Some(&mut 413) => {}
        x => panic!("Unexpected value {:?}", x),
    }
}

#[test]
fn any_fixed_vec() {
    let test = [0_usize; 8];
    let test = &test as &dyn Any;
    assert!(test.is::<[usize; 8]>());
    assert!(!test.is::<[usize; 10]>());
}

#[test]
fn any_unsized() {
    fn is_any<T: Any + ?Sized>() {}
    is_any::<[i32]>();
}
<commit_msg>Add test for issue 84666.<commit_after>use core::any::*;

#[derive(PartialEq, Debug)]
struct Test;

static TEST: &'static str = "Test";

#[test]
fn any_referenced() {
    let (a, b, c) = (&5 as &dyn Any, &TEST as &dyn Any, &Test as &dyn Any);

    assert!(a.is::<i32>());
    assert!(!b.is::<i32>());
    assert!(!c.is::<i32>());

    assert!(!a.is::<&'static str>());
    assert!(b.is::<&'static str>());
    assert!(!c.is::<&'static str>());

    assert!(!a.is::<Test>());
    assert!(!b.is::<Test>());
    assert!(c.is::<Test>());
}

#[test]
fn any_owning() {
    let (a, b, c) =
        (box 5_usize as Box<dyn Any>, box TEST as Box<dyn Any>, box Test as Box<dyn Any>);

    assert!(a.is::<usize>());
    assert!(!b.is::<usize>());
    assert!(!c.is::<usize>());

    assert!(!a.is::<&'static str>());
    assert!(b.is::<&'static str>());
    assert!(!c.is::<&'static str>());

    assert!(!a.is::<Test>());
    assert!(!b.is::<Test>());
    assert!(c.is::<Test>());
}

#[test]
fn any_downcast_ref() {
    let a = &5_usize as &dyn Any;

    match a.downcast_ref::<usize>() {
        Some(&5) => {}
        x => panic!("Unexpected value {:?}", x),
    }

    match a.downcast_ref::<Test>() {
        None => {}
        x => panic!("Unexpected value {:?}", x),
    }
}

#[test]
fn any_downcast_mut() {
    let mut a = 5_usize;
    let mut b: Box<_> = box 7_usize;

    let a_r = &mut a as &mut dyn Any;
    let tmp: &mut usize = &mut *b;
    let b_r = tmp as &mut dyn Any;

    match a_r.downcast_mut::<usize>() {
        Some(x) => {
            assert_eq!(*x, 5);
            *x = 612;
        }
        x => panic!("Unexpected value {:?}", x),
    }

    match b_r.downcast_mut::<usize>() {
        Some(x) => {
            assert_eq!(*x, 7);
            *x = 413;
        }
        x => panic!("Unexpected value {:?}", x),
    }

    match a_r.downcast_mut::<Test>() {
        None => (),
        x => panic!("Unexpected value {:?}", x),
    }

    match b_r.downcast_mut::<Test>() {
        None => (),
        x => panic!("Unexpected value {:?}", x),
    }

    match a_r.downcast_mut::<usize>() {
        Some(&mut 612) => {}
        x => panic!("Unexpected value {:?}", x),
    }

    match b_r.downcast_mut::<usize>() {
        Some(&mut 413) => {}
        x => panic!("Unexpected value {:?}", x),
    }
}

#[test]
fn any_fixed_vec() {
    let test = [0_usize; 8];
    let test = &test as &dyn Any;
    assert!(test.is::<[usize; 8]>());
    assert!(!test.is::<[usize; 10]>());
}

#[test]
fn any_unsized() {
    fn is_any<T: Any + ?Sized>() {}
    is_any::<[i32]>();
}

#[test]
fn distinct_type_names() {
    // https://github.com/rust-lang/rust/issues/84666

    struct Velocity(f32, f32);

    fn type_name_of_val<T>(_: T) -> &'static str {
        type_name::<T>()
    }

    assert_ne!(type_name_of_val(Velocity), type_name_of_val(Velocity(0.0, -9.8)),);
}
<|endoftext|>


<commit_before>//! Standard library macros
//!
//! This modules contains a set of macros which are exported from the standard
//! library. Each macro is available for use when linking against the standard
//! library.

#[doc(include = "../../core/src/macros/panic.md")]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(libstd_sys_internals)]
macro_rules! panic {
    () => ({ $crate::panic!("explicit panic") });
    ($msg:expr) => ({ $crate::rt::begin_panic($msg) });
    ($msg:expr,) => ({ $crate::panic!($msg) });
    ($fmt:expr, $($arg:tt)+) => ({
        $crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))
    });
}

/// Prints to the standard output.
///
/// Equivalent to the [`println!`] macro except that a newline is not printed at
/// the end of the message.
///
/// Note that stdout is frequently line-buffered by default so it may be
/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted
/// immediately.
///
/// Use `print!` only for the primary output of your program. Use
/// [`eprint!`] instead to print error and progress messages.
///
/// [`println!`]: ../std/macro.println.html
/// [flush]: ../std/io/trait.Write.html#tymethod.flush
/// [`eprint!`]: ../std/macro.eprint.html
///
/// # Panics
///
/// Panics if writing to `io::stdout()` fails.
///
/// # Examples
///
/// ```
/// use std::io::{self, Write};
///
/// print!("this ");
/// print!("will ");
/// print!("be ");
/// print!("on ");
/// print!("the ");
/// print!("same ");
/// print!("line ");
///
/// io::stdout().flush().unwrap();
///
/// print!("this string has a newline, why not choose println! instead?\n");
///
/// io::stdout().flush().unwrap();
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(print_internals)]
macro_rules! print {
    ($($arg:tt)*) => ($crate::io::_print($crate::format_args!($($arg)*)));
}

/// Prints to the standard output, with a newline.
///
/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
/// (no additional CARRIAGE RETURN (`\r`/`U+000D`)).
///
/// Use the [`format!`] syntax to write data to the standard output.
/// See [`std::fmt`] for more information.
///
/// Use `println!` only for the primary output of your program. Use
/// [`eprintln!`] instead to print error and progress messages.
///
/// [`format!`]: ../std/macro.format.html
/// [`std::fmt`]: ../std/fmt/index.html
/// [`eprintln!`]: ../std/macro.eprintln.html
/// # Panics
///
/// Panics if writing to `io::stdout` fails.
///
/// # Examples
///
/// ```
/// println!(); // prints just a newline
/// println!("hello there!");
/// println!("format {} arguments", "some");
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! println {
    () => ($crate::print!("\n"));
    ($($arg:tt)*) => ({
        $crate::io::_print($crate::format_args_nl!($($arg)*));
    })
}

/// Prints to the standard error.
///
/// Equivalent to the [`print!`] macro, except that output goes to
/// [`io::stderr`] instead of `io::stdout`. See [`print!`] for
/// example usage.
///
/// Use `eprint!` only for error and progress messages. Use `print!`
/// instead for the primary output of your program.
///
/// [`io::stderr`]: ../std/io/struct.Stderr.html
/// [`print!`]: ../std/macro.print.html
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Examples
///
/// ```
/// eprint!("Error: Could not complete task");
/// ```
#[macro_export]
#[stable(feature = "eprint", since = "1.19.0")]
#[allow_internal_unstable(print_internals)]
macro_rules! eprint {
    ($($arg:tt)*) => ($crate::io::_eprint($crate::format_args!($($arg)*)));
}

/// Prints to the standard error, with a newline.
///
/// Equivalent to the [`println!`] macro, except that output goes to
/// [`io::stderr`] instead of `io::stdout`. See [`println!`] for
/// example usage.
///
/// Use `eprintln!` only for error and progress messages. Use `println!`
/// instead for the primary output of your program.
///
/// [`io::stderr`]: ../std/io/struct.Stderr.html
/// [`println!`]: ../std/macro.println.html
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Examples
///
/// ```
/// eprintln!("Error: Could not complete task");
/// ```
#[macro_export]
#[stable(feature = "eprint", since = "1.19.0")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! eprintln {
    () => ($crate::eprint!("\n"));
    ($($arg:tt)*) => ({
        $crate::io::_eprint($crate::format_args_nl!($($arg)*));
    })
}

/// Prints and returns the value of a given expression for quick and dirty
/// debugging.
///
/// An example:
///
/// ```rust
/// let a = 2;
/// let b = dbg!(a * 2) + 1;
/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
/// assert_eq!(b, 5);
/// ```
///
/// The macro works by using the `Debug` implementation of the type of
/// the given expression to print the value to [stderr] along with the
/// source location of the macro invocation as well as the source code
/// of the expression.
///
/// Invoking the macro on an expression moves and takes ownership of it
/// before returning the evaluated expression unchanged. If the type
/// of the expression does not implement `Copy` and you don't want
/// to give up ownership, you can instead borrow with `dbg!(&expr)`
/// for some expression `expr`.
///
/// The `dbg!` macro works exactly the same in release builds.
/// This is useful when debugging issues that only occur in release
/// builds or when debugging in release mode is significantly faster.
///
/// Note that the macro is intended as a debugging tool and therefore you
/// should avoid having uses of it in version control for long periods.
/// Use cases involving debug output that should be added to version control
/// are better served by macros such as [`debug!`] from the [`log`] crate.
///
/// # Stability
///
/// The exact output printed by this macro should not be relied upon
/// and is subject to future changes.
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Further examples
///
/// With a method call:
///
/// ```rust
/// fn foo(n: usize) {
///     if let Some(_) = dbg!(n.checked_sub(4)) {
///         // ...
///     }
/// }
///
/// foo(3)
/// ```
///
/// This prints to [stderr]:
///
/// ```text,ignore
/// [src/main.rs:4] n.checked_sub(4) = None
/// ```
///
/// Naive factorial implementation:
///
/// ```rust
/// fn factorial(n: u32) -> u32 {
///     if dbg!(n <= 1) {
///         dbg!(1)
///     } else {
///         dbg!(n * factorial(n - 1))
///     }
/// }
///
/// dbg!(factorial(4));
/// ```
///
/// This prints to [stderr]:
///
/// ```text,ignore
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = true
/// [src/main.rs:4] 1 = 1
/// [src/main.rs:5] n * factorial(n - 1) = 2
/// [src/main.rs:5] n * factorial(n - 1) = 6
/// [src/main.rs:5] n * factorial(n - 1) = 24
/// [src/main.rs:11] factorial(4) = 24
/// ```
///
/// The `dbg!(..)` macro moves the input:
///
/// ```compile_fail
/// /// A wrapper around `usize` which importantly is not Copyable.
/// #[derive(Debug)]
/// struct NoCopy(usize);
///
/// let a = NoCopy(42);
/// let _ = dbg!(a); // <-- `a` is moved here.
/// let _ = dbg!(a); // <-- `a` is moved again; error!
/// ```
///
/// You can also use `dbg!()` without a value to just print the
/// file and line whenever it's reached.
///
/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
/// a tuple (and return it, too):
///
/// ```
/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
/// ```
///
/// However, a single argument with a trailing comma will still not be treated
/// as a tuple, following the convention of ignoring trailing commas in macro
/// invocations. You can use a 1-tuple directly if you need one:
///
/// ```
/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
/// ```
///
/// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)
/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
/// [`log`]: https://crates.io/crates/log
#[macro_export]
#[stable(feature = "dbg_macro", since = "1.32.0")]
macro_rules! dbg {
    () => {
        $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!());
    };
    ($val:expr) => {
        // Use of `match` here is intentional because it affects the lifetimes
        // of temporaries - https://stackoverflow.com/a/48732525/1063961
        match $val {
            tmp => {
                $crate::eprintln!("[{}:{}] {} = {:#?}",
                    $crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp);
                tmp
            }
        }
    };
    // Trailing comma with single argument is ignored
    ($val:expr,) => { $crate::dbg!($val) };
    ($($val:expr),+ $(,)?) => {
        ($($crate::dbg!($val)),+,)
    };
}

#[cfg(test)]
macro_rules! assert_approx_eq {
    ($a:expr, $b:expr) => {{
        let (a, b) = (&$a, &$b);
        assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
    }};
}
<commit_msg>Switch to intra-doc links in `std::macros`<commit_after>//! Standard library macros
//!
//! This module contains a set of macros which are exported from the standard
//! library. Each macro is available for use when linking against the standard
//! library.

#[doc(include = "../../core/src/macros/panic.md")]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(libstd_sys_internals)]
macro_rules! panic {
    () => ({ $crate::panic!("explicit panic") });
    ($msg:expr) => ({ $crate::rt::begin_panic($msg) });
    ($msg:expr,) => ({ $crate::panic!($msg) });
    ($fmt:expr, $($arg:tt)+) => ({
        $crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))
    });
}

/// Prints to the standard output.
///
/// Equivalent to the [`println!`] macro except that a newline is not printed at
/// the end of the message.
///
/// Note that stdout is frequently line-buffered by default so it may be
/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted
/// immediately.
///
/// Use `print!` only for the primary output of your program. Use
/// [`eprint!`] instead to print error and progress messages.
///
/// [flush]: crate::io::Write::flush
///
/// # Panics
///
/// Panics if writing to `io::stdout()` fails.
///
/// # Examples
///
/// ```
/// use std::io::{self, Write};
///
/// print!("this ");
/// print!("will ");
/// print!("be ");
/// print!("on ");
/// print!("the ");
/// print!("same ");
/// print!("line ");
///
/// io::stdout().flush().unwrap();
///
/// print!("this string has a newline, why not choose println! instead?\n");
///
/// io::stdout().flush().unwrap();
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(print_internals)]
macro_rules! print {
    ($($arg:tt)*) => ($crate::io::_print($crate::format_args!($($arg)*)));
}

/// Prints to the standard output, with a newline.
///
/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
/// (no additional CARRIAGE RETURN (`\r`/`U+000D`)).
///
/// Use the [`format!`] syntax to write data to the standard output.
/// See [`std::fmt`] for more information.
///
/// Use `println!` only for the primary output of your program. Use
/// [`eprintln!`] instead to print error and progress messages.
///
/// # Panics
///
/// Panics if writing to `io::stdout` fails.
///
/// [`io::stdout`]: crate::io::stdout
///
/// # Examples
///
/// ```
/// println!(); // prints just a newline
/// println!("hello there!");
/// println!("format {} arguments", "some");
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! println {
    () => ($crate::print!("\n"));
    ($($arg:tt)*) => ({
        $crate::io::_print($crate::format_args_nl!($($arg)*));
    })
}

/// Prints to the standard error.
///
/// Equivalent to the [`print!`] macro, except that output goes to
/// [`io::stderr`] instead of `io::stdout`. See [`print!`] for
/// example usage.
///
/// Use `eprint!` only for error and progress messages. Use `print!`
/// instead for the primary output of your program.
///
/// [`io::stderr`]: crate::io::stderr
/// [`io::stdout`]: crate::io::stdout
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Examples
///
/// ```
/// eprint!("Error: Could not complete task");
/// ```
#[macro_export]
#[stable(feature = "eprint", since = "1.19.0")]
#[allow_internal_unstable(print_internals)]
macro_rules! eprint {
    ($($arg:tt)*) => ($crate::io::_eprint($crate::format_args!($($arg)*)));
}

/// Prints to the standard error, with a newline.
///
/// Equivalent to the [`println!`] macro, except that output goes to
/// [`io::stderr`] instead of `io::stdout`. See [`println!`] for
/// example usage.
///
/// Use `eprintln!` only for error and progress messages. Use `println!`
/// instead for the primary output of your program.
///
/// [`io::stderr`]: crate::io::stderr
/// [`io::stdout`]: crate::io::stdout
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Examples
///
/// ```
/// eprintln!("Error: Could not complete task");
/// ```
#[macro_export]
#[stable(feature = "eprint", since = "1.19.0")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! eprintln {
    () => ($crate::eprint!("\n"));
    ($($arg:tt)*) => ({
        $crate::io::_eprint($crate::format_args_nl!($($arg)*));
    })
}

/// Prints and returns the value of a given expression for quick and dirty
/// debugging.
///
/// An example:
///
/// ```rust
/// let a = 2;
/// let b = dbg!(a * 2) + 1;
/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
/// assert_eq!(b, 5);
/// ```
///
/// The macro works by using the `Debug` implementation of the type of
/// the given expression to print the value to [stderr] along with the
/// source location of the macro invocation as well as the source code
/// of the expression.
///
/// Invoking the macro on an expression moves and takes ownership of it
/// before returning the evaluated expression unchanged. If the type
/// of the expression does not implement `Copy` and you don't want
/// to give up ownership, you can instead borrow with `dbg!(&expr)`
/// for some expression `expr`.
///
/// The `dbg!` macro works exactly the same in release builds.
/// This is useful when debugging issues that only occur in release
/// builds or when debugging in release mode is significantly faster.
///
/// Note that the macro is intended as a debugging tool and therefore you
/// should avoid having uses of it in version control for long periods.
/// Use cases involving debug output that should be added to version control
/// are better served by macros such as [`debug!`] from the [`log`] crate.
///
/// # Stability
///
/// The exact output printed by this macro should not be relied upon
/// and is subject to future changes.
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Further examples
///
/// With a method call:
///
/// ```rust
/// fn foo(n: usize) {
///     if let Some(_) = dbg!(n.checked_sub(4)) {
///         // ...
///     }
/// }
///
/// foo(3)
/// ```
///
/// This prints to [stderr]:
///
/// ```text,ignore
/// [src/main.rs:4] n.checked_sub(4) = None
/// ```
///
/// Naive factorial implementation:
///
/// ```rust
/// fn factorial(n: u32) -> u32 {
///     if dbg!(n <= 1) {
///         dbg!(1)
///     } else {
///         dbg!(n * factorial(n - 1))
///     }
/// }
///
/// dbg!(factorial(4));
/// ```
///
/// This prints to [stderr]:
///
/// ```text,ignore
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = true
/// [src/main.rs:4] 1 = 1
/// [src/main.rs:5] n * factorial(n - 1) = 2
/// [src/main.rs:5] n * factorial(n - 1) = 6
/// [src/main.rs:5] n * factorial(n - 1) = 24
/// [src/main.rs:11] factorial(4) = 24
/// ```
///
/// The `dbg!(..)` macro moves the input:
///
/// ```compile_fail
/// /// A wrapper around `usize` which importantly is not Copyable.
/// #[derive(Debug)]
/// struct NoCopy(usize);
///
/// let a = NoCopy(42);
/// let _ = dbg!(a); // <-- `a` is moved here.
/// let _ = dbg!(a); // <-- `a` is moved again; error!
/// ```
///
/// You can also use `dbg!()` without a value to just print the
/// file and line whenever it's reached.
///
/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
/// a tuple (and return it, too):
///
/// ```
/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
/// ```
///
/// However, a single argument with a trailing comma will still not be treated
/// as a tuple, following the convention of ignoring trailing commas in macro
/// invocations. You can use a 1-tuple directly if you need one:
///
/// ```
/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
/// ```
///
/// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)
/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
/// [`log`]: https://crates.io/crates/log
#[macro_export]
#[stable(feature = "dbg_macro", since = "1.32.0")]
macro_rules! dbg {
    () => {
        $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!());
    };
    ($val:expr) => {
        // Use of `match` here is intentional because it affects the lifetimes
        // of temporaries - https://stackoverflow.com/a/48732525/1063961
        match $val {
            tmp => {
                $crate::eprintln!("[{}:{}] {} = {:#?}",
                    $crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp);
                tmp
            }
        }
    };
    // Trailing comma with single argument is ignored
    ($val:expr,) => { $crate::dbg!($val) };
    ($($val:expr),+ $(,)?) => {
        ($($crate::dbg!($val)),+,)
    };
}

#[cfg(test)]
macro_rules! assert_approx_eq {
    ($a:expr, $b:expr) => {{
        let (a, b) = (&$a, &$b);
        assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
    }};
}
<|endoftext|>


<commit_before>use std::borrow::IntoCow;
use syntax::ast::{Expr, Ident, Stmt};
use syntax::ext::base::ExtCtxt;
use syntax::parse::token;
use syntax::ptr::P;

use maud;

#[derive(Copy, PartialEq, Show)]
pub enum Escape {
    PassThru,
    Escape,
}

pub struct Renderer<'cx, 's: 'cx, 'o> {
    pub cx: &'cx mut ExtCtxt<'s>,
    stmts: &'o mut Vec<P<Stmt>>,
    w: Ident,
}

impl<'cx, 's, 'o> Renderer<'cx, 's, 'o> {
    pub fn with<F>(cx: &'cx mut ExtCtxt<'s>, f: F) -> P<Expr> where
        F: for<'o_> FnOnce(&mut Renderer<'cx, 's, 'o_>)
    {
        let mut stmts = vec![];
        let w = Ident::new(token::intern("w"));
        let cx = {
            let mut render = Renderer {
                cx: cx,
                stmts: &mut stmts,
                w: w,
            };
            f(&mut render);
            render.cx
        };
        quote_expr!(cx,
            ::maud::rt::make_markup(&|&: $w: &mut ::std::fmt::Writer| -> Result<(), ::std::fmt::Error> {
                $stmts
                Ok(())
            }))
    }

    /// Append a literal pre-escaped string.
    pub fn write(&mut self, s: &str) {
        let w = self.w;
        self.stmts.push(quote_stmt!(self.cx, try!($w.write_str($s))));
    }

    /// Append a literal string, with the specified escaping method.
    pub fn string(&mut self, s: &str, escape: Escape) {
        let s = match escape {
            Escape::PassThru => s.into_cow(),
            Escape::Escape => maud::escape(s).into_cow(),
        };
        self.write(s.as_slice());
    }

    /// Append the result of an expression, with the specified escaping method.
    pub fn splice(&mut self, expr: P<Expr>, escape: Escape) {
        let w = self.w;
        self.stmts.push(match escape {
            Escape::PassThru => quote_stmt!(self.cx, try!(write!($w, "{}", $expr))),
            Escape::Escape =>
                quote_stmt!(self.cx,
                    try!(::maud::rt::escape($w, |w| write!(w, "{}", $expr)))),
        });
    }

    pub fn element_open_start(&mut self, name: &str) {
        self.write("<");
        self.write(name);
    }

    pub fn attribute_start(&mut self, name: &str) {
        self.write(" ");
        self.write(name);
        self.write("=\"");
    }

    pub fn attribute_empty(&mut self, name: &str) {
        self.write(" ");
        self.write(name);
    }

    pub fn attribute_end(&mut self) {
        self.write("\"");
    }

    pub fn element_open_end(&mut self) {
        self.write(">");
    }

    pub fn element_close(&mut self, name: &str) {
        self.write("</");
        self.write(name);
        self.write(">");
    }
}
<commit_msg>Make `Renderer::write()` private<commit_after>use std::borrow::IntoCow;
use syntax::ast::{Expr, Ident, Stmt};
use syntax::ext::base::ExtCtxt;
use syntax::parse::token;
use syntax::ptr::P;

use maud;

#[derive(Copy, PartialEq, Show)]
pub enum Escape {
    PassThru,
    Escape,
}

pub struct Renderer<'cx, 's: 'cx, 'o> {
    pub cx: &'cx mut ExtCtxt<'s>,
    stmts: &'o mut Vec<P<Stmt>>,
    w: Ident,
}

impl<'cx, 's, 'o> Renderer<'cx, 's, 'o> {
    pub fn with<F>(cx: &'cx mut ExtCtxt<'s>, f: F) -> P<Expr> where
        F: for<'o_> FnOnce(&mut Renderer<'cx, 's, 'o_>)
    {
        let mut stmts = vec![];
        let w = Ident::new(token::intern("w"));
        let cx = {
            let mut render = Renderer {
                cx: cx,
                stmts: &mut stmts,
                w: w,
            };
            f(&mut render);
            render.cx
        };
        quote_expr!(cx,
            ::maud::rt::make_markup(&|&: $w: &mut ::std::fmt::Writer| -> Result<(), ::std::fmt::Error> {
                $stmts
                Ok(())
            }))
    }

    /// Append a literal pre-escaped string.
    fn write(&mut self, s: &str) {
        let w = self.w;
        self.stmts.push(quote_stmt!(self.cx, try!($w.write_str($s))));
    }

    /// Append a literal string, with the specified escaping method.
    pub fn string(&mut self, s: &str, escape: Escape) {
        let s = match escape {
            Escape::PassThru => s.into_cow(),
            Escape::Escape => maud::escape(s).into_cow(),
        };
        self.write(s.as_slice());
    }

    /// Append the result of an expression, with the specified escaping method.
    pub fn splice(&mut self, expr: P<Expr>, escape: Escape) {
        let w = self.w;
        self.stmts.push(match escape {
            Escape::PassThru => quote_stmt!(self.cx, try!(write!($w, "{}", $expr))),
            Escape::Escape =>
                quote_stmt!(self.cx,
                    try!(::maud::rt::escape($w, |w| write!(w, "{}", $expr)))),
        });
    }

    pub fn element_open_start(&mut self, name: &str) {
        self.write("<");
        self.write(name);
    }

    pub fn attribute_start(&mut self, name: &str) {
        self.write(" ");
        self.write(name);
        self.write("=\"");
    }

    pub fn attribute_empty(&mut self, name: &str) {
        self.write(" ");
        self.write(name);
    }

    pub fn attribute_end(&mut self) {
        self.write("\"");
    }

    pub fn element_open_end(&mut self) {
        self.write(">");
    }

    pub fn element_close(&mut self, name: &str) {
        self.write("</");
        self.write(name);
        self.write(">");
    }
}
<|endoftext|>