<commit_before>use crate::memory::{
    io::{BgControl, BgOffset},
    VRAM_SIZE,
};
use byteorder::{ByteOrder as _, LittleEndian as LE};
use util::mem::{read_u32_unchecked, read_u64_unchecked};

use super::line::LineBuffer;

type Vram = [u8; VRAM_SIZE as usize];

pub fn render_4bpp(
    buf: &mut LineBuffer,
    line: u16,
    bgidx: usize,
    bgcnt: BgControl,
    bgofs: BgOffset,
    vram: &Vram,
) {
    pub const BYTES_PER_TILE: usize = 32;
    pub const BYTES_PER_LINE: usize = 4;

    buf.layer_attrs_mut(bgidx).set_4bpp();

    // FIXME implement mosaic.
    let mosaic_x = 0;
    let mosaic_y = 0;

    let screen_size = bgcnt.screen_size();
    let screen_w = screen_size.width(false);
    let screen_h = screen_size.height(false);
    let char_base = bgcnt.character_base() as usize;

    let start_scx = bg_wrapped_x_offset(bgofs.x() as _, screen_w, mosaic_x);
    let scy = bg_wrapped_y_offset(bgofs.y() as _, screen_h, line as _, mosaic_y);
    let ty = scy as usize % 8;

    let mut dx = 0;
    let mut tile_loader = TileLoader::new(vram, bgcnt.screen_base(), start_scx, scy, screen_h);

    while dx < 240 {
        let scx = start_scx + dx;

        if scx % 8 == 0 {
            tile_loader.advance();
        }

        // try to do 8 pixels at a time if possible:
        if (scx % 8) == 0 && dx <= 232 {
            let pixel_offset =
                tile_loader.tile_pixel_offset(BYTES_PER_TILE, BYTES_PER_LINE, char_base, ty);
            let palette = tile_loader.tile_palette();

            // we read all 8 nibbles (4 bytes) in one go:
            let entries8 = unsafe { read_u32_unchecked(vram, pixel_offset) };
            if tile_loader.hflip() {
                let dx = dx as usize;
                buf.put_4bpp(bgidx, dx + 7, palette, (entries8 & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 6, palette, ((entries8 >> 4) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 5, palette, ((entries8 >> 8) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 4, palette, ((entries8 >> 12) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 3, palette, ((entries8 >> 16) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 2, palette, ((entries8 >> 20) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 1, palette, ((entries8 >> 24) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx, palette, ((entries8 >> 28) & 0xF) as u8);
            } else {
                let dx = dx as usize;
                buf.put_4bpp(bgidx, dx, palette, (entries8 & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 1, palette, ((entries8 >> 4) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 2, palette, ((entries8 >> 8) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 3, palette, ((entries8 >> 12) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 4, palette, ((entries8 >> 16) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 5, palette, ((entries8 >> 20) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 6, palette, ((entries8 >> 24) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 7, palette, ((entries8 >> 28) & 0xF) as u8);
            }
            dx += 8;
        } else {
            let mut pixel_offset =
                tile_loader.tile_pixel_offset(BYTES_PER_TILE, BYTES_PER_LINE, char_base, ty);

            // get the x offset of the pixel:
            let tx = if tile_loader.hflip() {
                7 - (scx % 8)
            } else {
                scx % 8
            };
            pixel_offset += tx as usize / 2;

            let palette = tile_loader.tile_palette();

            let entry = (vram[pixel_offset as usize] >> ((tx % 2) << 2)) & 0xF;
            buf.put_4bpp(bgidx, dx as usize, palette, entry);
            dx += 1;
        }
    }
}

pub fn render_8bpp(
    buf: &mut LineBuffer,
    line: u16,
    bgidx: usize,
    bgcnt: BgControl,
    bgofs: BgOffset,
    vram: &Vram,
) {
    pub const BYTES_PER_TILE: usize = 64;
    pub const BYTES_PER_LINE: usize = 8;

    buf.layer_attrs_mut(bgidx).set_4bpp();

    // FIXME implement mosaic.
    let mosaic_x = 0;
    let mosaic_y = 0;

    let screen_size = bgcnt.screen_size();
    let screen_w = screen_size.width(false);
    let screen_h = screen_size.height(false);
    let char_base = bgcnt.character_base() as usize;

    let start_scx = bg_wrapped_x_offset(bgofs.x() as _, screen_w, mosaic_x);
    let scy = bg_wrapped_y_offset(bgofs.y() as _, screen_h, line as _, mosaic_y);
    let ty = scy as usize % 8;

    let mut dx = 0;
    let mut tile_loader = TileLoader::new(vram, bgcnt.screen_base(), start_scx, scy, screen_h);

    while dx < 240 {
        let scx = start_scx + dx;

        if scx % 8 == 0 {
            tile_loader.advance();
        }

        // try to do 8 pixels at a time if possible:
        if (scx % 8) == 0 && dx <= 232 {
            let pixel_offset =
                tile_loader.tile_pixel_offset(BYTES_PER_TILE, BYTES_PER_LINE, char_base, ty);

            if pixel_offset < 0x10000 {
                let mut entries = unsafe { read_u64_unchecked(vram, pixel_offset as usize) };
                if tile_loader.hflip() {
                    entries = entries.swap_bytes();
                }
                buf.put_8bpp_8(bgidx, dx as usize, entries);
            }

            dx += 8;
        } else {
            let mut pixel_offset =
                tile_loader.tile_pixel_offset(BYTES_PER_TILE, BYTES_PER_LINE, char_base, ty);

            if pixel_offset < 0x10000 {
                if tile_loader.hflip() {
                    pixel_offset += 7 - (scx as usize % 8);
                } else {
                    pixel_offset += scx as usize % 8;
                }
                let entry = vram[pixel_offset as usize];
                buf.put_8bpp(bgidx, dx as usize, entry);
            }

            dx += 1;
        }
    }
}

/// Returns the real x offset of a text mode background taking into account wrapping and
/// the mosaic register x value.
fn bg_wrapped_x_offset(offset: u32, width: u32, mosaic: u32) -> u32 {
    let wrapped = offset & (width - 1);
    if mosaic > 0 {
        wrapped - (wrapped % mosaic)
    } else {
        wrapped
    }
}

/// Returns the real y offset of a text mode background taking into account wrapping and
/// the mosaic register x value.
fn bg_wrapped_y_offset(offset: u32, height: u32, line: u32, mosaic: u32) -> u32 {
    let wrapped = (offset + line) & (height - 1);
    if mosaic > 0 {
        wrapped - (wrapped & mosaic)
    } else {
        wrapped
    }
}

struct TileLoader<'v> {
    vram: &'v Vram,
    block: u64,
    offset: usize,
    line_end: usize,
    next_area: usize,
}

impl<'v> TileLoader<'v> {
    /// This function expects that X and Y do not exceed the width and height of the screen map.
    fn new(vram: &'v Vram, base: u32, x: u32, y: u32, width: u32) -> TileLoader<'v> {
        let area = Self::get_area(x, y, width) as usize;
        // Get the x and y coordinates within the current area:
        let (area_x, area_y) = (x % 256, y % 256);
        // Get the x and y TILE coordinates within the current area:
        let (area_tx, area_ty) = (area_x / 8, area_y / 8);

        let mut offset =
            base as usize + (area * 0x800) + (area_ty as usize * 64) + (area_tx as usize * 2);
        let line_end = (offset & !0x3F) + 64;

        let misalignment = offset % 8;
        let block = if misalignment != 0 {
            let v = LE::read_u64(&vram[offset & !0x7..]); // aligned load
            if x % 8 != 0 {
                offset += 2;
                v >> (misalignment * 8)
            } else {
                // Because this is aligned, the extra offset increment and shift that is done above
                // will be done by the immediate call to advance.
                v >> ((misalignment - 2) * 8)
            }
        } else if x % 8 != 0 {
            // We're block aligned, but since we're not tile aligned, we have to preload the block
            // because a call to advance won't be done before the next pixel offset is read.
            let v = LE::read_u64(&vram[offset..]);
            offset += 2;
            v
        } else {
            0
        };

        TileLoader {
            vram,
            block,
            offset,
            line_end,
            next_area: if width > 256 {
                if area % 2 == 0 {
                    // this is on the left and we want to increment the area
                    0x800
                } else {
                    // this is on the right and we want to decrement the area
                    (-0x800isize) as usize
                }
            } else {
                0
            },
        }
    }

    /// This should be called any time we're going to draw a pixel at a tile aligned boundary.
    /// It will correctly load in the next tile (or the next block/area if necessary).
    fn advance(&mut self) {
        // We load a new block because the offset is 8 byte aligned.
        // This all works because the TileLoader does not bother loading any data to start with if
        // the first pixel being drawn is aligned to the left edge of a tile. So offset % 8 will be
        // 0 and the first call to next will load a block.

        if self.offset % 8 == 0 {
            if self.offset == self.line_end {
                self.offset = (self.offset.wrapping_sub(2) & !0x3F).wrapping_add(self.next_area);
                self.line_end = self.offset + 64;
                self.block = LE::read_u64(&self.vram[self.offset..]);
            } else {
                self.block = LE::read_u64(&self.vram[self.offset..]);
            }
        } else {
            self.block >>= 16;
        }
        self.offset += 2;
    }

    fn tile_palette(&self) -> u8 {
        ((self.block >> 12) & 0xF) as u8
    }

    fn hflip(&self) -> bool {
        (self.block & 0x400) != 0
    }

    fn tile_pixel_offset(
        &self,
        bytes_per_tile: usize,
        bytes_per_line: usize,
        char_base: usize,
        ty: usize,
    ) -> usize {
        let tile_number = (self.block & 0x3FF) as usize;
        let vflip = (self.block & 0x800) != 0;
        let ty = if vflip { 7 - ty } else { ty };
        let tile_data_start = char_base + (bytes_per_tile * tile_number);

        (tile_data_start + (ty * bytes_per_line)) as usize
    }

    fn get_area(x: u32, y: u32, width: u32) -> u32 {
        let area_y_inc = if width > 256 { 2 } else { 1 };
        (if x < 256 { 0 } else { 1 }) + (if y < 256 { 0 } else { area_y_inc })
    }
}
<commit_msg>Fix typo in 8bpp and 4bpp tile rendering.<commit_after>use crate::memory::{
    io::{BgControl, BgOffset},
    VRAM_SIZE,
};
use byteorder::{ByteOrder as _, LittleEndian as LE};
use util::mem::{read_u32_unchecked, read_u64_unchecked};

use super::line::LineBuffer;

type Vram = [u8; VRAM_SIZE as usize];

pub fn render_4bpp(
    buf: &mut LineBuffer,
    line: u16,
    bgidx: usize,
    bgcnt: BgControl,
    bgofs: BgOffset,
    vram: &Vram,
) {
    pub const BYTES_PER_TILE: usize = 32;
    pub const BYTES_PER_LINE: usize = 4;

    buf.layer_attrs_mut(bgidx).set_4bpp();

    // FIXME implement mosaic.
    let mosaic_x = 0;
    let mosaic_y = 0;

    let screen_size = bgcnt.screen_size();
    let screen_w = screen_size.width(false);
    let screen_h = screen_size.height(false);
    let char_base = bgcnt.character_base() as usize;

    let start_scx = bg_wrapped_x_offset(bgofs.x() as _, screen_w, mosaic_x);
    let scy = bg_wrapped_y_offset(bgofs.y() as _, screen_h, line as _, mosaic_y);
    let ty = scy as usize % 8;

    let mut dx = 0;
    let mut tile_loader = TileLoader::new(vram, bgcnt.screen_base(), start_scx, scy, screen_w);

    while dx < 240 {
        let scx = start_scx + dx;

        if scx % 8 == 0 {
            tile_loader.advance();
        }

        // try to do 8 pixels at a time if possible:
        if (scx % 8) == 0 && dx <= 232 {
            let pixel_offset =
                tile_loader.tile_pixel_offset(BYTES_PER_TILE, BYTES_PER_LINE, char_base, ty);
            let palette = tile_loader.tile_palette();

            // we read all 8 nibbles (4 bytes) in one go:
            let entries8 = unsafe { read_u32_unchecked(vram, pixel_offset) };
            if tile_loader.hflip() {
                let dx = dx as usize;
                buf.put_4bpp(bgidx, dx + 7, palette, (entries8 & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 6, palette, ((entries8 >> 4) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 5, palette, ((entries8 >> 8) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 4, palette, ((entries8 >> 12) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 3, palette, ((entries8 >> 16) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 2, palette, ((entries8 >> 20) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 1, palette, ((entries8 >> 24) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx, palette, ((entries8 >> 28) & 0xF) as u8);
            } else {
                let dx = dx as usize;
                buf.put_4bpp(bgidx, dx, palette, (entries8 & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 1, palette, ((entries8 >> 4) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 2, palette, ((entries8 >> 8) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 3, palette, ((entries8 >> 12) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 4, palette, ((entries8 >> 16) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 5, palette, ((entries8 >> 20) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 6, palette, ((entries8 >> 24) & 0xF) as u8);
                buf.put_4bpp(bgidx, dx + 7, palette, ((entries8 >> 28) & 0xF) as u8);
            }
            dx += 8;
        } else {
            let mut pixel_offset =
                tile_loader.tile_pixel_offset(BYTES_PER_TILE, BYTES_PER_LINE, char_base, ty);

            // get the x offset of the pixel:
            let tx = if tile_loader.hflip() {
                7 - (scx % 8)
            } else {
                scx % 8
            };
            pixel_offset += tx as usize / 2;

            let palette = tile_loader.tile_palette();

            let entry = (vram[pixel_offset as usize] >> ((tx % 2) << 2)) & 0xF;
            buf.put_4bpp(bgidx, dx as usize, palette, entry);
            dx += 1;
        }
    }
}

pub fn render_8bpp(
    buf: &mut LineBuffer,
    line: u16,
    bgidx: usize,
    bgcnt: BgControl,
    bgofs: BgOffset,
    vram: &Vram,
) {
    pub const BYTES_PER_TILE: usize = 64;
    pub const BYTES_PER_LINE: usize = 8;

    buf.layer_attrs_mut(bgidx).set_4bpp();

    // FIXME implement mosaic.
    let mosaic_x = 0;
    let mosaic_y = 0;

    let screen_size = bgcnt.screen_size();
    let screen_w = screen_size.width(false);
    let screen_h = screen_size.height(false);
    let char_base = bgcnt.character_base() as usize;

    let start_scx = bg_wrapped_x_offset(bgofs.x() as _, screen_w, mosaic_x);
    let scy = bg_wrapped_y_offset(bgofs.y() as _, screen_h, line as _, mosaic_y);
    let ty = scy as usize % 8;

    let mut dx = 0;
    let mut tile_loader = TileLoader::new(vram, bgcnt.screen_base(), start_scx, scy, screen_w);

    while dx < 240 {
        let scx = start_scx + dx;

        if scx % 8 == 0 {
            tile_loader.advance();
        }

        // try to do 8 pixels at a time if possible:
        if (scx % 8) == 0 && dx <= 232 {
            let pixel_offset =
                tile_loader.tile_pixel_offset(BYTES_PER_TILE, BYTES_PER_LINE, char_base, ty);

            if pixel_offset < 0x10000 {
                let mut entries = unsafe { read_u64_unchecked(vram, pixel_offset as usize) };
                if tile_loader.hflip() {
                    entries = entries.swap_bytes();
                }
                buf.put_8bpp_8(bgidx, dx as usize, entries);
            }

            dx += 8;
        } else {
            let mut pixel_offset =
                tile_loader.tile_pixel_offset(BYTES_PER_TILE, BYTES_PER_LINE, char_base, ty);

            if pixel_offset < 0x10000 {
                if tile_loader.hflip() {
                    pixel_offset += 7 - (scx as usize % 8);
                } else {
                    pixel_offset += scx as usize % 8;
                }
                let entry = vram[pixel_offset as usize];
                buf.put_8bpp(bgidx, dx as usize, entry);
            }

            dx += 1;
        }
    }
}

/// Returns the real x offset of a text mode background taking into account wrapping and
/// the mosaic register x value.
fn bg_wrapped_x_offset(offset: u32, width: u32, mosaic: u32) -> u32 {
    let wrapped = offset & (width - 1);
    if mosaic > 0 {
        wrapped - (wrapped % mosaic)
    } else {
        wrapped
    }
}

/// Returns the real y offset of a text mode background taking into account wrapping and
/// the mosaic register x value.
fn bg_wrapped_y_offset(offset: u32, height: u32, line: u32, mosaic: u32) -> u32 {
    let wrapped = (offset + line) & (height - 1);
    if mosaic > 0 {
        wrapped - (wrapped & mosaic)
    } else {
        wrapped
    }
}

struct TileLoader<'v> {
    vram: &'v Vram,
    block: u64,
    offset: usize,
    line_end: usize,
    next_area: usize,
}

impl<'v> TileLoader<'v> {
    /// This function expects that X and Y do not exceed the width and height of the screen map.
    fn new(vram: &'v Vram, base: u32, x: u32, y: u32, width: u32) -> TileLoader<'v> {
        let area = Self::get_area(x, y, width) as usize;
        // Get the x and y coordinates within the current area:
        let (area_x, area_y) = (x % 256, y % 256);
        // Get the x and y TILE coordinates within the current area:
        let (area_tx, area_ty) = (area_x / 8, area_y / 8);

        let mut offset =
            base as usize + (area * 0x800) + (area_ty as usize * 64) + (area_tx as usize * 2);
        let line_end = (offset & !0x3F) + 64;

        let misalignment = offset % 8;
        let block = if misalignment != 0 {
            let v = LE::read_u64(&vram[offset & !0x7..]); // aligned load
            if x % 8 != 0 {
                offset += 2;
                v >> (misalignment * 8)
            } else {
                // Because this is aligned, the extra offset increment and shift that is done above
                // will be done by the immediate call to advance.
                v >> ((misalignment - 2) * 8)
            }
        } else if x % 8 != 0 {
            // We're block aligned, but since we're not tile aligned, we have to preload the block
            // because a call to advance won't be done before the next pixel offset is read.
            let v = LE::read_u64(&vram[offset..]);
            offset += 2;
            v
        } else {
            0
        };

        TileLoader {
            vram,
            block,
            offset,
            line_end,
            next_area: if width > 256 {
                if area % 2 == 0 {
                    // this is on the left and we want to increment the area
                    0x800
                } else {
                    // this is on the right and we want to decrement the area
                    (-0x800isize) as usize
                }
            } else {
                0
            },
        }
    }

    /// This should be called any time we're going to draw a pixel at a tile aligned boundary.
    /// It will correctly load in the next tile (or the next block/area if necessary).
    fn advance(&mut self) {
        // We load a new block because the offset is 8 byte aligned.
        // This all works because the TileLoader does not bother loading any data to start with if
        // the first pixel being drawn is aligned to the left edge of a tile. So offset % 8 will be
        // 0 and the first call to next will load a block.

        if self.offset % 8 == 0 {
            if self.offset == self.line_end {
                self.offset = (self.offset.wrapping_sub(2) & !0x3F).wrapping_add(self.next_area);
                self.line_end = self.offset + 64;
                self.block = LE::read_u64(&self.vram[self.offset..]);
            } else {
                self.block = LE::read_u64(&self.vram[self.offset..]);
            }
        } else {
            self.block >>= 16;
        }
        self.offset += 2;
    }

    fn tile_palette(&self) -> u8 {
        ((self.block >> 12) & 0xF) as u8
    }

    fn hflip(&self) -> bool {
        (self.block & 0x400) != 0
    }

    fn tile_pixel_offset(
        &self,
        bytes_per_tile: usize,
        bytes_per_line: usize,
        char_base: usize,
        ty: usize,
    ) -> usize {
        let tile_number = (self.block & 0x3FF) as usize;
        let vflip = (self.block & 0x800) != 0;
        let ty = if vflip { 7 - ty } else { ty };
        let tile_data_start = char_base + (bytes_per_tile * tile_number);

        (tile_data_start + (ty * bytes_per_line)) as usize
    }

    fn get_area(x: u32, y: u32, width: u32) -> u32 {
        let area_y_inc = if width > 256 { 2 } else { 1 };
        (if x < 256 { 0 } else { 1 }) + (if y < 256 { 0 } else { area_y_inc })
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::rc::Rc;
use std::cell::RefCell;
use sfml::graphics::{RenderWindow, RenderTarget, Font};
use sfml::window::{ContextSettings, VideoMode, Close};
use sfml::window::event;
use sfml::window::keyboard::Key;
use sfml::window::mouse::MouseButton;
use sfml::graphics::Color;
use sfml::system::vector2::Vector2i;
use na::{Pnt2, Pnt3, Iso2};
use na;
use nphysics::world::World;
use nphysics::object::RigidBody;
use nphysics::detection::joint::{Fixed, Anchor};
use camera::Camera;
use fps::Fps;
use engine::GraphicsManager;
use draw_helper;

fn usage(exe_name: &str) {
    println!("Usage: {} [OPTION] ", exe_name);
    println!("");
    println!("Options:");
    println!("    --help  - prints this help message and exits.");
    println!("    --pause - do not start the simulation right away.");
    println!("");
    println!("The following keyboard commands are supported:");
    println!("    t     - pause/continue the simulation.");
    println!("    s     - pause then execute only one simulation step.");
    println!("    space - display/hide contacts.");
}

#[derive(PartialEq)]
enum RunMode {
    Running,
    Stop,
    Step
}

pub struct Testbed<'a> {
    world:    World,
    window:   RenderWindow,
    graphics: GraphicsManager<'a>
}

struct TestbedState<'a> {
    running: RunMode,
    draw_colls: bool,
    camera: Camera,
    fps: Fps<'a>,
    grabbed_object: Option<Rc<RefCell<RigidBody>>>,
    grabbed_object_joint: Option<Rc<RefCell<Fixed>>>,
}

impl<'a> TestbedState<'a> {
    fn new(fnt: &'a Font) -> TestbedState<'a> {
        TestbedState{
            running: RunMode::Running,
            draw_colls: false,
            camera: Camera::new(),
            fps: Fps::new(&fnt),
            grabbed_object: None,
            grabbed_object_joint: None,
        }
    }
}

impl<'a> Testbed<'a> {
    pub fn new_empty() -> Testbed<'a> {
        let mode    = VideoMode::new_init(800, 600, 32);
        let setting = ContextSettings {
            depth_bits:         10,
            stencil_bits:       10,
            antialiasing_level: 2,
            major_version:      0,
            minor_version:      1
        };
        let window =
            match RenderWindow::new(mode, "nphysics 2d demo", Close, &setting) {
                Some(rwindow) => rwindow,
                None          => panic!("Error on creating the sfml window.")
            };
        let graphics = GraphicsManager::new();

        Testbed {
            world:    World::new(),
            window:   window,
            graphics: graphics
        }
    }

    pub fn new(world: World) -> Testbed<'a> {
        let mut res = Testbed::new_empty();

        res.set_world(world);

        res
    }

    pub fn set_world(&mut self, world: World) {
        self.world = world;
        self.graphics.clear();

        for rb in self.world.bodies() {
            self.graphics.add(rb.clone());
        }
    }

    pub fn set_color(&mut self, body: &Rc<RefCell<RigidBody>>, color: Pnt3<f32>) {
        let color = Pnt3::new(
            (color.x * 255.0) as u8,
            (color.y * 255.0) as u8,
            (color.z * 255.0) as u8
        );

        self.graphics.set_color(body, color);
    }

    pub fn run(&mut self) {
        let font_mem = include_bytes!("Inconsolata.otf");
        let     fnt  = Font::new_from_memory(font_mem).unwrap();

        let mut state = TestbedState::new(&fnt);

        let mut args    = env::args();

        if args.len() > 1 {
            let exname = args.next().unwrap();
            for arg in args {
                if &arg[..] == "--help" || &arg[..] == "-h" {
                    usage(&exname[..]);
                    return;
                }
                else if &arg[..] == "--pause" {
                    state.running = RunMode::Stop;
                }
            }
        }

        self.window.set_framerate_limit(60);

        self.foo(state);

        self.window.close();
    }

    fn foo(&mut self, mut state: TestbedState) {
        while self.window.is_open() {
            self.foo_loop(&mut state);

            self.window.clear(&Color::black());

            state.fps.reset();

            if state.running != RunMode::Stop {
                self.world.step(0.016);
            }

            if state.running == RunMode::Step {
                state.running = RunMode::Stop;
            }
            state.fps.register_delta();
            self.graphics.draw(&mut self.window, &state.camera);

            state.camera.activate_scene(&mut self.window);
            if state.draw_colls {
                draw_helper::draw_colls(&mut self.window, &mut self.world);
            }

            state.camera.activate_ui(&mut self.window);
            state.fps.draw_registered(&mut self.window);

            self.window.display();
        }
    }

    fn foo_loop(&mut self, mut state: &mut TestbedState) {
        loop {
            match self.window.poll_event() {
                event::KeyPressed{code, ..} => self.process_key_press(&mut state, code),
                event::MouseButtonPressed{button, x, y} => self.process_mouse_press(&mut state, button, x, y),
                event::MouseButtonReleased{button, x, y} => self.process_mouse_release(&mut state, button, x, y),
                event::MouseMoved{x, y} => self.process_mouse_moved(&mut state, x, y),
                event::Closed  => self.window.close(),
                event::NoEvent => break,
                e              => state.camera.handle_event(&e)
            }
        }
    }

    fn process_key_press(&mut self, state: &mut TestbedState, code: Key) {
        match code {
            Key::Escape => self.window.close(),
            Key::S      => state.running = RunMode::Step,
            Key::Space  => state.draw_colls = !state.draw_colls,
            Key::T      => {
                if state.running == RunMode::Stop {
                    state.running = RunMode::Running;
                }
                else {
                    state.running = RunMode::Stop;
                }
            },
            _                => { }
        }
    }

    fn process_mouse_press(&mut self, state: &mut TestbedState, button: MouseButton, x: i32, y: i32) {
        match button {
            MouseButton::MouseLeft => {
                let mapped_coords = state.camera.map_pixel_to_coords(Vector2i::new(x, y));
                let mapped_point = Pnt2::new(mapped_coords.x, mapped_coords.y);
                self.world.interferences_with_point(&mapped_point, |b| {
                    if b.borrow().can_move() {
                        state.grabbed_object = Some(b.clone())
                    }
                });

                match state.grabbed_object {
                    Some(ref b) => {
                        for node in self.graphics.body_to_scene_node(b).unwrap().iter_mut() {
                            match state.grabbed_object_joint {
                                Some(ref j) => self.world.remove_fixed(j),
                                None        => { }
                            }

                            let _1: Iso2<f32> = na::one();
                            let attach2 = na::append_translation(&_1, mapped_point.as_vec());
                            let attach1 = na::inv(&na::transformation(b.borrow().position())).unwrap() * attach2;
                            let anchor1 = Anchor::new(Some(state.grabbed_object.as_ref().unwrap().clone()), attach1);
                            let anchor2 = Anchor::new(None, attach2);
                            let joint = Fixed::new(anchor1, anchor2);
                            state.grabbed_object_joint = Some(self.world.add_fixed(joint));
                            node.select()
                        }
                    },
                    None => { }
                }
            },
            _ => {
                state.camera.handle_event(&event::MouseButtonPressed{ button: button, x: x, y: y })
            }
        }
    }

    fn process_mouse_release(&mut self, state: &mut TestbedState, button: MouseButton, x: i32, y: i32) {
        match button {
            MouseButton::MouseLeft => {
                match state.grabbed_object {
                    Some(ref b) => {
                        for node in self.graphics.body_to_scene_node(b).unwrap().iter_mut() {
                            node.unselect()
                        }
                    },
                    None => { }
                }

                match state.grabbed_object_joint {
                    Some(ref j) => self.world.remove_fixed(j),
                    None => { }
                }

                state.grabbed_object = None;
                state.grabbed_object_joint = None;
            },
            _ => {
                state.camera.handle_event(&event::MouseButtonReleased{ button: button, x: x, y: y })
            }
        }
    }

    fn process_mouse_moved(&mut self, state: &mut TestbedState, x: i32, y: i32) {
        let mapped_coords = state.camera.map_pixel_to_coords(Vector2i::new(x, y));
        let mapped_point = Pnt2::new(mapped_coords.x, mapped_coords.y);
        let _1: Iso2<f32> = na::one();
        let attach2 = na::append_translation(&_1, (mapped_point).as_vec());
        match state.grabbed_object {
            Some(_) => {
                let joint = state.grabbed_object_joint.as_ref().unwrap();
                joint.borrow_mut().set_local2(attach2);
            },
            None => state.camera.handle_event(&event::MouseMoved{x: x, y: y})
        };
    }
}
<commit_msg>Use name that is more appropriate for revealed functionality<commit_after>use std::env;
use std::rc::Rc;
use std::cell::RefCell;
use sfml::graphics::{RenderWindow, RenderTarget, Font};
use sfml::window::{ContextSettings, VideoMode, Close};
use sfml::window::event;
use sfml::window::keyboard::Key;
use sfml::window::mouse::MouseButton;
use sfml::graphics::Color;
use sfml::system::vector2::Vector2i;
use na::{Pnt2, Pnt3, Iso2};
use na;
use nphysics::world::World;
use nphysics::object::RigidBody;
use nphysics::detection::joint::{Fixed, Anchor};
use camera::Camera;
use fps::Fps;
use engine::GraphicsManager;
use draw_helper;

fn usage(exe_name: &str) {
    println!("Usage: {} [OPTION] ", exe_name);
    println!("");
    println!("Options:");
    println!("    --help  - prints this help message and exits.");
    println!("    --pause - do not start the simulation right away.");
    println!("");
    println!("The following keyboard commands are supported:");
    println!("    t     - pause/continue the simulation.");
    println!("    s     - pause then execute only one simulation step.");
    println!("    space - display/hide contacts.");
}

#[derive(PartialEq)]
enum RunMode {
    Running,
    Stop,
    Step
}

pub struct Testbed<'a> {
    world:    World,
    window:   RenderWindow,
    graphics: GraphicsManager<'a>
}

struct TestbedState<'a> {
    running: RunMode,
    draw_colls: bool,
    camera: Camera,
    fps: Fps<'a>,
    grabbed_object: Option<Rc<RefCell<RigidBody>>>,
    grabbed_object_joint: Option<Rc<RefCell<Fixed>>>,
}

impl<'a> TestbedState<'a> {
    fn new(fnt: &'a Font) -> TestbedState<'a> {
        TestbedState{
            running: RunMode::Running,
            draw_colls: false,
            camera: Camera::new(),
            fps: Fps::new(&fnt),
            grabbed_object: None,
            grabbed_object_joint: None,
        }
    }
}

impl<'a> Testbed<'a> {
    pub fn new_empty() -> Testbed<'a> {
        let mode    = VideoMode::new_init(800, 600, 32);
        let setting = ContextSettings {
            depth_bits:         10,
            stencil_bits:       10,
            antialiasing_level: 2,
            major_version:      0,
            minor_version:      1
        };
        let window =
            match RenderWindow::new(mode, "nphysics 2d demo", Close, &setting) {
                Some(rwindow) => rwindow,
                None          => panic!("Error on creating the sfml window.")
            };
        let graphics = GraphicsManager::new();

        Testbed {
            world:    World::new(),
            window:   window,
            graphics: graphics
        }
    }

    pub fn new(world: World) -> Testbed<'a> {
        let mut res = Testbed::new_empty();

        res.set_world(world);

        res
    }

    pub fn set_world(&mut self, world: World) {
        self.world = world;
        self.graphics.clear();

        for rb in self.world.bodies() {
            self.graphics.add(rb.clone());
        }
    }

    pub fn set_color(&mut self, body: &Rc<RefCell<RigidBody>>, color: Pnt3<f32>) {
        let color = Pnt3::new(
            (color.x * 255.0) as u8,
            (color.y * 255.0) as u8,
            (color.z * 255.0) as u8
        );

        self.graphics.set_color(body, color);
    }

    pub fn run(&mut self) {
        let font_mem = include_bytes!("Inconsolata.otf");
        let     fnt  = Font::new_from_memory(font_mem).unwrap();

        let mut state = TestbedState::new(&fnt);

        let mut args    = env::args();

        if args.len() > 1 {
            let exname = args.next().unwrap();
            for arg in args {
                if &arg[..] == "--help" || &arg[..] == "-h" {
                    usage(&exname[..]);
                    return;
                }
                else if &arg[..] == "--pause" {
                    state.running = RunMode::Stop;
                }
            }
        }

        self.window.set_framerate_limit(60);

        self.foo(state);

        self.window.close();
    }

    fn foo(&mut self, mut state: TestbedState) {
        while self.window.is_open() {
            self.process_events(&mut state);

            self.window.clear(&Color::black());

            state.fps.reset();

            if state.running != RunMode::Stop {
                self.world.step(0.016);
            }

            if state.running == RunMode::Step {
                state.running = RunMode::Stop;
            }
            state.fps.register_delta();
            self.graphics.draw(&mut self.window, &state.camera);

            state.camera.activate_scene(&mut self.window);
            if state.draw_colls {
                draw_helper::draw_colls(&mut self.window, &mut self.world);
            }

            state.camera.activate_ui(&mut self.window);
            state.fps.draw_registered(&mut self.window);

            self.window.display();
        }
    }

    fn process_events(&mut self, mut state: &mut TestbedState) {
        loop {
            match self.window.poll_event() {
                event::KeyPressed{code, ..} => self.process_key_press(&mut state, code),
                event::MouseButtonPressed{button, x, y} => self.process_mouse_press(&mut state, button, x, y),
                event::MouseButtonReleased{button, x, y} => self.process_mouse_release(&mut state, button, x, y),
                event::MouseMoved{x, y} => self.process_mouse_moved(&mut state, x, y),
                event::Closed  => self.window.close(),
                event::NoEvent => break,
                e              => state.camera.handle_event(&e)
            }
        }
    }

    fn process_key_press(&mut self, state: &mut TestbedState, code: Key) {
        match code {
            Key::Escape => self.window.close(),
            Key::S      => state.running = RunMode::Step,
            Key::Space  => state.draw_colls = !state.draw_colls,
            Key::T      => {
                if state.running == RunMode::Stop {
                    state.running = RunMode::Running;
                }
                else {
                    state.running = RunMode::Stop;
                }
            },
            _                => { }
        }
    }

    fn process_mouse_press(&mut self, state: &mut TestbedState, button: MouseButton, x: i32, y: i32) {
        match button {
            MouseButton::MouseLeft => {
                let mapped_coords = state.camera.map_pixel_to_coords(Vector2i::new(x, y));
                let mapped_point = Pnt2::new(mapped_coords.x, mapped_coords.y);
                self.world.interferences_with_point(&mapped_point, |b| {
                    if b.borrow().can_move() {
                        state.grabbed_object = Some(b.clone())
                    }
                });

                match state.grabbed_object {
                    Some(ref b) => {
                        for node in self.graphics.body_to_scene_node(b).unwrap().iter_mut() {
                            match state.grabbed_object_joint {
                                Some(ref j) => self.world.remove_fixed(j),
                                None        => { }
                            }

                            let _1: Iso2<f32> = na::one();
                            let attach2 = na::append_translation(&_1, mapped_point.as_vec());
                            let attach1 = na::inv(&na::transformation(b.borrow().position())).unwrap() * attach2;
                            let anchor1 = Anchor::new(Some(state.grabbed_object.as_ref().unwrap().clone()), attach1);
                            let anchor2 = Anchor::new(None, attach2);
                            let joint = Fixed::new(anchor1, anchor2);
                            state.grabbed_object_joint = Some(self.world.add_fixed(joint));
                            node.select()
                        }
                    },
                    None => { }
                }
            },
            _ => {
                state.camera.handle_event(&event::MouseButtonPressed{ button: button, x: x, y: y })
            }
        }
    }

    fn process_mouse_release(&mut self, state: &mut TestbedState, button: MouseButton, x: i32, y: i32) {
        match button {
            MouseButton::MouseLeft => {
                match state.grabbed_object {
                    Some(ref b) => {
                        for node in self.graphics.body_to_scene_node(b).unwrap().iter_mut() {
                            node.unselect()
                        }
                    },
                    None => { }
                }

                match state.grabbed_object_joint {
                    Some(ref j) => self.world.remove_fixed(j),
                    None => { }
                }

                state.grabbed_object = None;
                state.grabbed_object_joint = None;
            },
            _ => {
                state.camera.handle_event(&event::MouseButtonReleased{ button: button, x: x, y: y })
            }
        }
    }

    fn process_mouse_moved(&mut self, state: &mut TestbedState, x: i32, y: i32) {
        let mapped_coords = state.camera.map_pixel_to_coords(Vector2i::new(x, y));
        let mapped_point = Pnt2::new(mapped_coords.x, mapped_coords.y);
        let _1: Iso2<f32> = na::one();
        let attach2 = na::append_translation(&_1, (mapped_point).as_vec());
        match state.grabbed_object {
            Some(_) => {
                let joint = state.grabbed_object_joint.as_ref().unwrap();
                joint.borrow_mut().set_local2(attach2);
            },
            None => state.camera.handle_event(&event::MouseMoved{x: x, y: y})
        };
    }
}
<|endoftext|>


<commit_before>use crate::transform::{MirPass, MirSource};
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;

pub struct MatchBranchSimplification;

// What's the intent of this pass?
// If one block is found that switches between blocks which both go to the same place
// AND both of these blocks set a similar const in their ->
// condense into 1 block based on discriminant AND goto the destination afterwards

impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
        let param_env = tcx.param_env(src.def_id());
        let bbs = body.basic_blocks_mut();
        'outer: for bb_idx in bbs.indices() {
            let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
                TerminatorKind::SwitchInt {
                    discr: Operand::Move(ref place),
                    switch_ty,
                    ref targets,
                    ref values,
                    ..
                } if targets.len() == 2 && values.len() == 1 => {
                    (place, values[0], switch_ty, targets[0], targets[1])
                }
                // Only optimize switch int statements
                _ => continue,
            };

            // Check that destinations are identical, and if not, then don't optimize this block
            if &bbs[first].terminator().kind != &bbs[second].terminator().kind {
                continue;
            }

            // Check that blocks are assignments of consts to the same place or same statement,
            // and match up 1-1, if not don't optimize this block.
            let first_stmts = &bbs[first].statements;
            let scnd_stmts = &bbs[second].statements;
            if first_stmts.len() != scnd_stmts.len() {
                continue;
            }
            for (f, s) in first_stmts.iter().zip(scnd_stmts.iter()) {
                match (&f.kind, &s.kind) {
                    // If two statements are exactly the same just ignore them.
                    (f_s, s_s) if f_s == s_s => (),

                    (
                        StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))),
                        StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
                    ) if lhs_f == lhs_s => {
                        if let Some(f_c) = f_c.literal.try_eval_bool(tcx, param_env) {
                            // This should also be a bool because it's writing to the same place
                            let s_c = s_c.literal.try_eval_bool(tcx, param_env).unwrap();
                            // Check that only const assignments of opposite bool values are
                            // permitted.
                            if f_c != s_c {
                              continue
                            }
                        }
                        continue 'outer;
                    }
                    // If there are not exclusively assignments, then ignore this
                    _ => continue 'outer,
                }
            }
            // Take owenership of items now that we know we can optimize.
            let discr = discr.clone();

            bbs[bb_idx].terminator_mut().kind = TerminatorKind::Goto { target: first };
            for s in bbs[first].statements.iter_mut() {
                if let StatementKind::Assign(box (_, ref mut rhs)) = s.kind {
                    let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
                    let const_cmp = Operand::const_from_scalar(
                        tcx,
                        switch_ty,
                        crate::interpret::Scalar::from_uint(val, size),
                        rustc_span::DUMMY_SP,
                    );
                    *rhs = Rvalue::BinaryOp(BinOp::Eq, Operand::Move(discr), const_cmp);
                }
            }
        }
    }
}
<commit_msg>Update to pick Eq or Ne<commit_after>use crate::transform::{MirPass, MirSource};
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;

pub struct MatchBranchSimplification;

// What's the intent of this pass?
// If one block is found that switches between blocks which both go to the same place
// AND both of these blocks set a similar const in their ->
// condense into 1 block based on discriminant AND goto the destination afterwards

impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
        let param_env = tcx.param_env(src.def_id());
        let bbs = body.basic_blocks_mut();
        'outer: for bb_idx in bbs.indices() {
            let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
                TerminatorKind::SwitchInt {
                    discr: Operand::Move(ref place),
                    switch_ty,
                    ref targets,
                    ref values,
                    ..
                } if targets.len() == 2 && values.len() == 1 => {
                    (place, values[0], switch_ty, targets[0], targets[1])
                }
                // Only optimize switch int statements
                _ => continue,
            };

            // Check that destinations are identical, and if not, then don't optimize this block
            if &bbs[first].terminator().kind != &bbs[second].terminator().kind {
                continue;
            }

            // Check that blocks are assignments of consts to the same place or same statement,
            // and match up 1-1, if not don't optimize this block.
            let first_stmts = &bbs[first].statements;
            let scnd_stmts = &bbs[second].statements;
            if first_stmts.len() != scnd_stmts.len() {
                continue;
            }
            for (f, s) in first_stmts.iter().zip(scnd_stmts.iter()) {
                match (&f.kind, &s.kind) {
                    // If two statements are exactly the same just ignore them.
                    (f_s, s_s) if f_s == s_s => (),

                    (
                        StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))),
                        StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
                    ) if lhs_f == lhs_s => {
                        if let Some(f_c) = f_c.literal.try_eval_bool(tcx, param_env) {
                            // This should also be a bool because it's writing to the same place
                            let s_c = s_c.literal.try_eval_bool(tcx, param_env).unwrap();
                            assert_ne!(f_c, s_c, "Unexpected match would've compared eq earlier");
                            continue;
                        }
                        continue 'outer;
                    }
                    // If there are not exclusively assignments, then ignore this
                    _ => continue 'outer,
                }
            }
            // Take owenership of items now that we know we can optimize.
            let discr = discr.clone();

            bbs[bb_idx].terminator_mut().kind = TerminatorKind::Goto { target: first };
            for s in bbs[first].statements.iter_mut() {
                if let StatementKind::Assign(box (_, ref mut rhs)) = s.kind {
                    if let Rvalue::Use(Operand::Constant(c)) = rhs {
                        let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
                        let const_cmp = Operand::const_from_scalar(
                            tcx,
                            switch_ty,
                            crate::interpret::Scalar::from_uint(val, size),
                            rustc_span::DUMMY_SP,
                        );
                        if let Some(c) = c.literal.try_eval_bool(tcx, param_env) {
                            let op = if c { BinOp::Eq } else { BinOp::Ne };
                            *rhs = Rvalue::BinaryOp(op, Operand::Move(discr), const_cmp);
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use card_strategy::CardStrategy;

use card::Card;
use game_status::GameStatus;
use player::PlayerName;

use std::collections::BTreeMap;

#[derive(Debug)]
pub struct MyCardStrategy;

impl MyCardStrategy {
    // Lowest penalty for me using highest penalty card.
    // Lowest penalty for me using highest ranked card.
    // Lowest potential penalty for me using highest ranked card.
    // filter valid cards
    // order by: penalty to me ascending, penalty descending, rank descending
    fn score_card<'a>(card: &'a Card, game_status: &'a GameStatus, player_name: &PlayerName) -> (i32, i32, i32, i32) {
        let card_penalty_to_me = MyCardStrategy::card_penalty_to_me(card, game_status, player_name);
        let card_penalty = 0 - MyCardStrategy::card_penalty(card, game_status);
        let trouble = MyCardStrategy::trouble_score(card, game_status);
        let card_rank = 0 - (u32::from(card.rank) as i32);
        (card_penalty_to_me, card_penalty, trouble, card_rank)
    }

    fn card_penalty(card: &Card, game_status: &GameStatus) -> i32 {
        game_status.round_parameters.card_points.get(card).map(|penalty| penalty.clone()).unwrap_or_default()
    }

    fn card_penalty_to_me(card: &Card, game_status: &GameStatus, player_name: &PlayerName) -> i32 {
        if MyCardStrategy::will_win_deal(card, game_status) {
            MyCardStrategy::card_penalty(card, game_status)
        } else {
            0
        }
    }

    fn trouble_score(card: &Card, game_status: &GameStatus) -> i32 {
        if MyCardStrategy::will_win_deal(card, game_status) {
            let rank_number: u32 = card.rank.into();
            rank_number as i32
        } else {
            0
        }
    }

    fn will_win_deal(card: &Card, game_status: &GameStatus) -> bool {
        match game_status.my_in_progress_deal {
            Some(ref deal) => {
                match deal.suit {
                    Some(current_suit) => {
                        let mut option_winning_card: Option<Card> = None;

                        for deal_card in deal.deal_cards.iter() {
                            if deal_card.card.suit == current_suit {
                                match option_winning_card {
                                    None => option_winning_card = Some(deal_card.card.clone()),
                                    Some(winning_card) => {
                                        if deal_card.card.rank > winning_card.rank {
                                            option_winning_card = Some(deal_card.card.clone())
                                        }
                                    }
                                }
                            }
                        }

                        let will_win_rank = match option_winning_card {
                            Some(winning_card) => card.rank > winning_card.rank,
                            None => true
                        };

                        card.suit == current_suit && will_win_rank
                    }
                    None => true
                }
            }
            None => true
        }
    }
}

impl CardStrategy for MyCardStrategy {

    fn pass_cards<'a>(&mut self, game_status: &'a GameStatus) -> Vec<&'a Card> {
        game_status.my_initial_hand.iter().take(3).collect()
    }

    fn play_card<'a>(&mut self, game_status: &'a GameStatus, player_name: &PlayerName) -> &'a Card {
        let current_suit = game_status.my_in_progress_deal.as_ref().and_then(|deal| deal.suit);
        let mut valid_cards: Vec<&'a Card> = game_status.my_current_hand.iter().filter(|card| Some(card.suit) == current_suit).collect();

        if valid_cards.is_empty() {
            valid_cards.extend(&game_status.my_current_hand);
        }

        let scored_cards: BTreeMap<((i32, i32, i32, i32), &Card), &Card> = valid_cards.into_iter().map(|card| {
            ((MyCardStrategy::score_card(card, game_status, player_name), card), card)
        }).collect();

        scored_cards.values().next().expect("No valid cards to play!")
    }

}<commit_msg>better trouble score<commit_after>use card_strategy::CardStrategy;

use card::Card;
use game_status::GameStatus;
use player::PlayerName;

use std::collections::BTreeMap;

#[derive(Debug)]
pub struct MyCardStrategy;

impl MyCardStrategy {
    fn score_card<'a>(card: &'a Card, game_status: &'a GameStatus, player_name: &PlayerName) -> (i32, i32, i32, i32) {
        let card_penalty_to_me = MyCardStrategy::card_penalty_to_me(card, game_status, player_name);
        let card_penalty = 0 - MyCardStrategy::card_penalty(card, game_status);
        let trouble = card_penalty_to_me * (u32::from(card.rank) as i32);
        let card_rank = 0 - (u32::from(card.rank) as i32);
        (card_penalty_to_me, card_penalty, trouble, card_rank)
    }

    fn card_penalty(card: &Card, game_status: &GameStatus) -> i32 {
        game_status.round_parameters.card_points.get(card).map(|penalty| penalty.clone()).unwrap_or_default()
    }

    fn card_penalty_to_me(card: &Card, game_status: &GameStatus, player_name: &PlayerName) -> i32 {
        if MyCardStrategy::will_win_deal(card, game_status) {
            MyCardStrategy::card_penalty(card, game_status)
        } else {
            0
        }
    }

    fn will_win_deal(card: &Card, game_status: &GameStatus) -> bool {
        match game_status.my_in_progress_deal {
            Some(ref deal) => {
                match deal.suit {
                    Some(current_suit) => {
                        let mut option_winning_card: Option<Card> = None;

                        for deal_card in deal.deal_cards.iter() {
                            if deal_card.card.suit == current_suit {
                                match option_winning_card {
                                    None => option_winning_card = Some(deal_card.card.clone()),
                                    Some(winning_card) => {
                                        if deal_card.card.rank > winning_card.rank {
                                            option_winning_card = Some(deal_card.card.clone())
                                        }
                                    }
                                }
                            }
                        }

                        let will_win_rank = match option_winning_card {
                            Some(winning_card) => card.rank > winning_card.rank,
                            None => true
                        };

                        card.suit == current_suit && will_win_rank
                    }
                    None => true
                }
            }
            None => true
        }
    }
}

impl CardStrategy for MyCardStrategy {

    fn pass_cards<'a>(&mut self, game_status: &'a GameStatus) -> Vec<&'a Card> {
        game_status.my_initial_hand.iter().take(3).collect()
    }

    fn play_card<'a>(&mut self, game_status: &'a GameStatus, player_name: &PlayerName) -> &'a Card {
        let current_suit = game_status.my_in_progress_deal.as_ref().and_then(|deal| deal.suit);
        let mut valid_cards: Vec<&'a Card> = game_status.my_current_hand.iter().filter(|card| Some(card.suit) == current_suit).collect();

        if valid_cards.is_empty() {
            valid_cards.extend(&game_status.my_current_hand);
        }

        let scored_cards: BTreeMap<((i32, i32, i32, i32), &Card), &Card> = valid_cards.into_iter().map(|card| {
            ((MyCardStrategy::score_card(card, game_status, player_name), card), card)
        }).collect();

        scored_cards.values().next().expect("No valid cards to play!")
    }

}<|endoftext|>


<commit_before>#![allow(dead_code)]
#![deny(unsafe_code)]

extern crate libc;
#[macro_use] extern crate linjs;
#[macro_use] extern crate linjs_derive;

use linjs::CanAlloc;
use linjs::CanInitialize;
use linjs::Initialized;
use linjs::JSThreadLocalClass;
use linjs::JSOwnedClass;
use linjs::JSContext;
use linjs::JSGlobalizeable;
use linjs::JSManaged;
use linjs::JSRunnable;

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

type Window<'a, C> = JSManaged<'a, C, NativeWindow<'a, C>>;

#[derive(JSTraceable, JSManageable)]
struct NativeWindow<'a, C> {
    console: Console<'a, C>,
    body: Element<'a, C>,
}

type DOMContext<'a, C> = JSContext<Initialized<Window<'a, C>>>;

fn init_window<'a, C, S>(cx: JSContext<S>) -> DOMContext<'a, C> where
    C: 'a,
    S: CanInitialize<C>,
{
    let mut cx = cx.pre_init();
    rooted!(in(cx) let console = new_console(&mut cx));
    rooted!(in(cx) let body = new_element(&mut cx));
    cx.post_init(NativeWindow {
        console: console,
        body: body,
    })
}

// This is boilerplate which should be deriveable.

thread_local! { static WINDOW_CLASS: JSOwnedClass = JSOwnedClass::new("Window"); }

impl<'a, C> JSGlobalizeable for NativeWindow<'a, C> {
    fn js_class() -> JSThreadLocalClass { &WINDOW_CLASS }
}

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

type Console<'a, C> = JSManaged<'a, C, NativeConsole>;

#[derive(JSTraceable, JSManageable)]
struct NativeConsole();

fn new_console<'a, C, S>(cx: &'a mut JSContext<S>) -> Console<'a, C> where
    C: 'a,
    S: CanAlloc<C>,
{
    cx.manage(NativeConsole())
}

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

type Element<'a, C> = JSManaged<'a, C, NativeElement<'a, C>>;

#[derive(JSTraceable, JSManageable)]
struct NativeElement<'a, C> {
    parent: Option<Element<'a, C>>,
    children: Vec<Element<'a, C>>,
}

fn new_element<'a, C, S>(cx: &'a mut JSContext<S>) -> Element<'a, C> where
    S: CanAlloc<C>,
    C: 'a,
{
    cx.manage(NativeElement {
        parent: None,
        children: Vec::new(),
    })
}

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

struct Main;

impl JSRunnable for Main {
    fn run<C, S>(self, cx: JSContext<S>) where S: CanInitialize<C> {
        let ref mut _cx = init_window(cx);
    }
}

fn main() {
    Main.start();
}
<commit_msg>Added Document class to minidom example.<commit_after>#![allow(dead_code)]
#![deny(unsafe_code)]

extern crate libc;
#[macro_use] extern crate linjs;
#[macro_use] extern crate linjs_derive;

use linjs::CanAlloc;
use linjs::CanInitialize;
use linjs::CanRoot;
use linjs::Initialized;
use linjs::JSThreadLocalClass;
use linjs::JSOwnedClass;
use linjs::JSContext;
use linjs::JSGlobalizeable;
use linjs::JSManaged;
use linjs::JSRunnable;

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

type Window<'a, C> = JSManaged<'a, C, NativeWindow<'a, C>>;

#[derive(JSTraceable, JSManageable)]
struct NativeWindow<'a, C> {
    console: Console<'a, C>,
    document: Document<'a, C>,
}

type DOMContext<'a, C> = JSContext<Initialized<Window<'a, C>>>;

fn init_window<'a, C, S>(cx: JSContext<S>) -> DOMContext<'a, C> where
    C: 'a,
    S: CanInitialize<C>,
{
    let mut cx = cx.pre_init();
    rooted!(in(cx) let console = new_console(&mut cx));
    rooted!(in(cx) let document = new_document(&mut cx));
    cx.post_init(NativeWindow {
        console: console,
        document: document,
    })
}

// This is boilerplate which should be deriveable.

thread_local! { static WINDOW_CLASS: JSOwnedClass = JSOwnedClass::new("Window"); }

impl<'a, C> JSGlobalizeable for NativeWindow<'a, C> {
    fn js_class() -> JSThreadLocalClass { &WINDOW_CLASS }
}

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

type Console<'a, C> = JSManaged<'a, C, NativeConsole>;

#[derive(JSTraceable, JSManageable)]
struct NativeConsole();

fn new_console<'a, C, S>(cx: &'a mut JSContext<S>) -> Console<'a, C> where
    C: 'a,
    S: CanAlloc<C>,
{
    cx.manage(NativeConsole())
}

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

type Document<'a, C> = JSManaged<'a, C, NativeDocument<'a, C>>;

#[derive(JSTraceable, JSManageable)]
struct NativeDocument<'a, C> {
    body: Element<'a, C>,
}

fn new_document<'a, C, S>(cx: &'a mut JSContext<S>) -> Document<'a, C> where
    C: 'a,
    S: CanAlloc<C> + CanRoot,
{
    rooted!(in(cx) let body = new_element(cx));
    cx.manage(NativeDocument {
        body: body,
    })
}

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

type Element<'a, C> = JSManaged<'a, C, NativeElement<'a, C>>;

#[derive(JSTraceable, JSManageable)]
struct NativeElement<'a, C> {
    parent: Option<Element<'a, C>>,
    children: Vec<Element<'a, C>>,
}

fn new_element<'a, C, S>(cx: &'a mut JSContext<S>) -> Element<'a, C> where
    S: CanAlloc<C>,
    C: 'a,
{
    cx.manage(NativeElement {
        parent: None,
        children: Vec::new(),
    })
}

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

struct Main;

impl JSRunnable for Main {
    fn run<C, S>(self, cx: JSContext<S>) where S: CanInitialize<C> {
        let ref mut _cx = init_window(cx);
    }
}

fn main() {
    Main.start();
}
<|endoftext|>


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

use std::sync::Arc;
use {DeviceUintRect, DevicePoint};
use {TileOffset, TileSize};

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ImageKey(pub u32, pub u32);

impl ImageKey {
    pub fn new(key0: u32, key1: u32) -> ImageKey {
        ImageKey(key0, key1)
    }
}

/// An arbitrary identifier for an external image provided by the
/// application. It must be a unique identifier for each external
/// image.
#[repr(C)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ExternalImageId(pub u64);

#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum ExternalImageType {
    Texture2DHandle,        // gl TEXTURE_2D handle
    TextureRectHandle,      // gl TEXTURE_RECT handle
    TextureExternalHandle,  // gl TEXTURE_EXTERNAL handle
    ExternalBuffer,
}

#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ExternalImageData {
    pub id: ExternalImageId,
    pub channel_index: u8,
    pub image_type: ExternalImageType,
}

#[repr(u32)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ImageFormat {
    Invalid  = 0,
    A8       = 1,
    RGB8     = 2,
    RGBA8    = 3,
    RGBAF32  = 4,
    RG8      = 5,
}

impl ImageFormat {
    pub fn bytes_per_pixel(self) -> Option<u32> {
        match self {
            ImageFormat::A8 => Some(1),
            ImageFormat::RGB8 => Some(3),
            ImageFormat::RGBA8 => Some(4),
            ImageFormat::RGBAF32 => Some(16),
            ImageFormat::RG8 => Some(2),
            ImageFormat::Invalid => None,
        }
    }
}

#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct ImageDescriptor {
    pub format: ImageFormat,
    pub width: u32,
    pub height: u32,
    pub stride: Option<u32>,
    pub offset: u32,
    pub is_opaque: bool,
}

impl ImageDescriptor {
    pub fn new(width: u32, height: u32, format: ImageFormat, is_opaque: bool) -> Self {
        ImageDescriptor {
            width: width,
            height: height,
            format: format,
            stride: None,
            offset: 0,
            is_opaque: is_opaque,
        }
    }

    pub fn compute_stride(&self) -> u32 {
        self.stride.unwrap_or(self.width * self.format.bytes_per_pixel().unwrap())
    }
}

#[derive(Clone, Serialize, Deserialize)]
pub enum ImageData {
    Raw(Arc<Vec<u8>>),
    Blob(BlobImageData),
    External(ExternalImageData),
}

impl ImageData {
    pub fn new(bytes: Vec<u8>) -> ImageData {
        ImageData::Raw(Arc::new(bytes))
    }

    pub fn new_shared(bytes: Arc<Vec<u8>>) -> ImageData {
        ImageData::Raw(bytes)
    }

    pub fn new_blob_image(commands: Vec<u8>) -> ImageData {
        ImageData::Blob(commands)
    }

    #[inline]
    pub fn is_blob(&self) -> bool {
        match self {
            &ImageData::Blob(_) => true,
            _ => false,
        }
    }
}

pub trait BlobImageRenderer: Send {
    fn add(&mut self, key: ImageKey, data: BlobImageData, tiling: Option<TileSize>);

    fn update(&mut self, key: ImageKey, data: BlobImageData);

    fn delete(&mut self, key: ImageKey);

    fn request(&mut self,
               key: BlobImageRequest,
               descriptor: &BlobImageDescriptor,
               dirty_rect: Option<DeviceUintRect>,
               images: &ImageStore);

    fn resolve(&mut self, key: BlobImageRequest) -> BlobImageResult;
}

pub type BlobImageData = Vec<u8>;

pub type BlobImageResult = Result<RasterizedBlobImage, BlobImageError>;

#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct BlobImageDescriptor {
    pub width: u32,
    pub height: u32,
    pub offset: DevicePoint,
    pub format: ImageFormat,
}

pub struct RasterizedBlobImage {
    pub width: u32,
    pub height: u32,
    pub data: Vec<u8>,
}

#[derive(Clone, Debug)]
pub enum BlobImageError {
    Oom,
    InvalidKey,
    InvalidData,
    Other(String),
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct BlobImageRequest {
    pub key: ImageKey,
    pub tile: Option<TileOffset>,
}

pub trait ImageStore {
    fn get_image(&self, key: ImageKey) -> Option<(&ImageData, &ImageDescriptor)>;
}
<commit_msg>Add #[repr(u32)] for ExternalImageType enum.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::sync::Arc;
use {DeviceUintRect, DevicePoint};
use {TileOffset, TileSize};

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ImageKey(pub u32, pub u32);

impl ImageKey {
    pub fn new(key0: u32, key1: u32) -> ImageKey {
        ImageKey(key0, key1)
    }
}

/// An arbitrary identifier for an external image provided by the
/// application. It must be a unique identifier for each external
/// image.
#[repr(C)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ExternalImageId(pub u64);

#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum ExternalImageType {
    Texture2DHandle,        // gl TEXTURE_2D handle
    TextureRectHandle,      // gl TEXTURE_RECT handle
    TextureExternalHandle,  // gl TEXTURE_EXTERNAL handle
    ExternalBuffer,
}

#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ExternalImageData {
    pub id: ExternalImageId,
    pub channel_index: u8,
    pub image_type: ExternalImageType,
}

#[repr(u32)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ImageFormat {
    Invalid  = 0,
    A8       = 1,
    RGB8     = 2,
    RGBA8    = 3,
    RGBAF32  = 4,
    RG8      = 5,
}

impl ImageFormat {
    pub fn bytes_per_pixel(self) -> Option<u32> {
        match self {
            ImageFormat::A8 => Some(1),
            ImageFormat::RGB8 => Some(3),
            ImageFormat::RGBA8 => Some(4),
            ImageFormat::RGBAF32 => Some(16),
            ImageFormat::RG8 => Some(2),
            ImageFormat::Invalid => None,
        }
    }
}

#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct ImageDescriptor {
    pub format: ImageFormat,
    pub width: u32,
    pub height: u32,
    pub stride: Option<u32>,
    pub offset: u32,
    pub is_opaque: bool,
}

impl ImageDescriptor {
    pub fn new(width: u32, height: u32, format: ImageFormat, is_opaque: bool) -> Self {
        ImageDescriptor {
            width: width,
            height: height,
            format: format,
            stride: None,
            offset: 0,
            is_opaque: is_opaque,
        }
    }

    pub fn compute_stride(&self) -> u32 {
        self.stride.unwrap_or(self.width * self.format.bytes_per_pixel().unwrap())
    }
}

#[derive(Clone, Serialize, Deserialize)]
pub enum ImageData {
    Raw(Arc<Vec<u8>>),
    Blob(BlobImageData),
    External(ExternalImageData),
}

impl ImageData {
    pub fn new(bytes: Vec<u8>) -> ImageData {
        ImageData::Raw(Arc::new(bytes))
    }

    pub fn new_shared(bytes: Arc<Vec<u8>>) -> ImageData {
        ImageData::Raw(bytes)
    }

    pub fn new_blob_image(commands: Vec<u8>) -> ImageData {
        ImageData::Blob(commands)
    }

    #[inline]
    pub fn is_blob(&self) -> bool {
        match self {
            &ImageData::Blob(_) => true,
            _ => false,
        }
    }
}

pub trait BlobImageRenderer: Send {
    fn add(&mut self, key: ImageKey, data: BlobImageData, tiling: Option<TileSize>);

    fn update(&mut self, key: ImageKey, data: BlobImageData);

    fn delete(&mut self, key: ImageKey);

    fn request(&mut self,
               key: BlobImageRequest,
               descriptor: &BlobImageDescriptor,
               dirty_rect: Option<DeviceUintRect>,
               images: &ImageStore);

    fn resolve(&mut self, key: BlobImageRequest) -> BlobImageResult;
}

pub type BlobImageData = Vec<u8>;

pub type BlobImageResult = Result<RasterizedBlobImage, BlobImageError>;

#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct BlobImageDescriptor {
    pub width: u32,
    pub height: u32,
    pub offset: DevicePoint,
    pub format: ImageFormat,
}

pub struct RasterizedBlobImage {
    pub width: u32,
    pub height: u32,
    pub data: Vec<u8>,
}

#[derive(Clone, Debug)]
pub enum BlobImageError {
    Oom,
    InvalidKey,
    InvalidData,
    Other(String),
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct BlobImageRequest {
    pub key: ImageKey,
    pub tile: Option<TileOffset>,
}

pub trait ImageStore {
    fn get_image(&self, key: ImageKey) -> Option<(&ImageData, &ImageDescriptor)>;
}
<|endoftext|>


<commit_before>//! # The implementation of librsvg
//!
//! The implementation of librsvg is in the `rsvg_internals` crate.  It is not a public
//! crate; instead, it exports the primitives necessary to implement librsvg's public APIs,
//! both the C and Rust APIs.  It has the XML and CSS parsing code, the SVG element
//! definitions and tree of elements, and all the drawing logic.
//!
//! Some interesting parts of rsvg_internals:
//!
//! * [The `Handle` struct](handle/struct.Handle.html) provides the primitives to implement
//! the public APIs, such as loading an SVG file and rendering it.
//!
//! * [The `DrawingCtx` struct](drawing_ctx/struct.DrawingCtx.html) is active while an SVG
//! handle is being drawn or queried for its geometry.  It has all the mutable state related
//! to the drawing process.
//!
//! * [The `Document` struct](document/struct.Document.html) represents a loaded SVG
//! document.  It holds the tree of [`Node`] elements, and a mapping of `id` attributes
//! to the corresponding element nodes.
//!
//! * [The `node` module](node/index.html) provides the [`Node`] struct and
//! [`ElementTrait`], which form the basis for the tree of SVG elements.
//!
//! * [The `xml` module](xml/index.html) receives events from the XML parser, and builds a
//! [`Document`] as a tree of [`Node`].
//!
//! * [The `properties` module](properties/index.html) contains structs that represent
//! collections of CSS properties.
//!
//! * [The `property_defs` module](property_defs/index.html) contains one type for each of
//! the CSS style properties that librsvg supports.
//!
//! [`Document`]: document/struct.Document.html
//! [`Node`]: node/type.Node.html
//! [`ElementTrait`]: node/trait.ElementTrait.html

#![allow(clippy::clone_on_ref_ptr)]
#![allow(clippy::not_unsafe_ptr_arg_deref)]
#![allow(clippy::too_many_arguments)]
#![warn(unused)]
use ::xml as xml_rs;

pub use crate::color::Color;

pub use crate::dpi::{rsvg_rust_set_default_dpi_x_y, Dpi};

pub use crate::error::{DefsLookupErrorKind, HrefError, LoadingError, RenderingError};

pub use crate::handle::{
    Handle, LoadOptions, RsvgDimensionData, RsvgPositionData, RsvgSizeFunc, SizeCallback,
};

pub use crate::length::{Length, LengthUnit, RsvgLength};

pub use crate::parsers::Parse;

pub use crate::rect::IRect;

pub use crate::structure::IntrinsicDimensions;

pub use crate::surface_utils::{
    iterators::Pixels,
    shared_surface::{SharedImageSurface, SurfaceType},
};

pub use crate::viewbox::ViewBox;

#[macro_use]
pub mod log;

#[macro_use]
mod parsers;

#[macro_use]
mod coord_units;

#[macro_use]
mod float_eq_cairo;

#[macro_use]
mod property_macros;

mod allowed_url;
mod angle;
mod aspect_ratio;
mod bbox;
mod color;
mod cond;
mod css;
mod dasharray;
mod document;
mod dpi;
mod drawing_ctx;
mod element;
mod error;
mod filter;
pub mod filters;
mod font_props;
mod gradient;
mod handle;
mod image;
mod io;
mod iri;
mod length;
mod limits;
mod marker;
mod node;
mod number_list;
mod paint_server;
mod path_builder;
mod path_parser;
mod pattern;
mod properties;
mod property_bag;
mod property_defs;
pub mod rect;
mod shapes;
mod space;
mod structure;
mod style;
pub mod surface_utils;
mod text;
mod transform;
mod unit_interval;
mod util;
mod viewbox;
mod xml;
mod xml2;
mod xml2_load;
<commit_msg>Fix links in the documentation intro<commit_after>//! # The implementation of librsvg
//!
//! The implementation of librsvg is in the `rsvg_internals` crate.  It is not a public
//! crate; instead, it exports the primitives necessary to implement librsvg's public APIs,
//! both the C and Rust APIs.  It has the XML and CSS parsing code, the SVG element
//! definitions and tree of elements, and all the drawing logic.
//!
//! Some interesting parts of rsvg_internals:
//!
//! * [The `Handle` struct](handle/struct.Handle.html) provides the primitives to implement
//! the public APIs, such as loading an SVG file and rendering it.
//!
//! * [The `DrawingCtx` struct](drawing_ctx/struct.DrawingCtx.html) is active while an SVG
//! handle is being drawn or queried for its geometry.  It has all the mutable state related
//! to the drawing process.
//!
//! * [The `Document` struct](document/struct.Document.html) represents a loaded SVG
//! document.  It holds the tree of [`Node`] elements, and a mapping of `id` attributes
//! to the corresponding element nodes.
//!
//! * [The `node` module](node/index.html) provides the [`Node`] struct and
//! helper traits used to operate on nodes.
//!
//! * [The `element` module](node/index.html) provides the [`Element`] struct and
//! [`ElementTrait`] which is implemented by all SVG elements.
//!
//! * [The `xml` module](xml/index.html) receives events from the XML parser, and builds a
//! [`Document`] as a tree of [`Node`].
//!
//! * [The `properties` module](properties/index.html) contains structs that represent
//! collections of CSS properties.
//!
//! * [The `property_defs` module](property_defs/index.html) contains one type for each of
//! the CSS style properties that librsvg supports.
//!
//! * [The `css` module](css/index.html) contains the implementation of CSS parsing
//! and matching.
//!
//! [`Document`]: document/struct.Document.html
//! [`Node`]: node/type.Node.html
//! [`Element`]: element/struct.Element.html
//! [`ElementTrait`]: element/trait.ElementTrait.html

#![allow(clippy::clone_on_ref_ptr)]
#![allow(clippy::not_unsafe_ptr_arg_deref)]
#![allow(clippy::too_many_arguments)]
#![warn(unused)]
use ::xml as xml_rs;

pub use crate::color::Color;

pub use crate::dpi::{rsvg_rust_set_default_dpi_x_y, Dpi};

pub use crate::error::{DefsLookupErrorKind, HrefError, LoadingError, RenderingError};

pub use crate::handle::{
    Handle, LoadOptions, RsvgDimensionData, RsvgPositionData, RsvgSizeFunc, SizeCallback,
};

pub use crate::length::{Length, LengthUnit, RsvgLength};

pub use crate::parsers::Parse;

pub use crate::rect::IRect;

pub use crate::structure::IntrinsicDimensions;

pub use crate::surface_utils::{
    iterators::Pixels,
    shared_surface::{SharedImageSurface, SurfaceType},
};

pub use crate::viewbox::ViewBox;

#[macro_use]
pub mod log;

#[macro_use]
mod parsers;

#[macro_use]
mod coord_units;

#[macro_use]
mod float_eq_cairo;

#[macro_use]
mod property_macros;

mod allowed_url;
mod angle;
mod aspect_ratio;
mod bbox;
mod color;
mod cond;
mod css;
mod dasharray;
mod document;
mod dpi;
mod drawing_ctx;
mod element;
mod error;
mod filter;
pub mod filters;
mod font_props;
mod gradient;
mod handle;
mod image;
mod io;
mod iri;
mod length;
mod limits;
mod marker;
mod node;
mod number_list;
mod paint_server;
mod path_builder;
mod path_parser;
mod pattern;
mod properties;
mod property_bag;
mod property_defs;
pub mod rect;
mod shapes;
mod space;
mod structure;
mod style;
pub mod surface_utils;
mod text;
mod transform;
mod unit_interval;
mod util;
mod viewbox;
mod xml;
mod xml2;
mod xml2_load;
<|endoftext|>


<commit_before>
pub( crate ) mod internal
{
  use former::Former;
  use crate::string::split::*;
  use std::collections::HashMap;

  ///
  /// Wrapper types to make transformation.
  ///

  #[ derive( Debug, Clone, PartialEq ) ]
  pub enum OpType<T>
  {
    /// Wrapper over single element of type <T>.
    Primitive( T ),
    /// Wrapper over vector of elements of type <T>.
    Vector( Vec<T> ),
    /// Wrapper over hash map of elements of type <T>.
    Map( HashMap<String, T> ),
  }

  impl<T : Default> Default for OpType<T>
  {
    fn default() -> Self
    {
      OpType::Primitive( T::default() )
    }
  }

  ///
  /// Parsed request data.
  ///

  #[ allow( dead_code ) ]
  #[ derive( Debug, Default, PartialEq ) ]
  pub struct Request< 'a >
  {
    /// Original request string.
    pub original : &'a str,
    /// Delimeter for pairs `key:value`.
    pub key_val_delimeter : &'a str,
    /// Delimeter for commands.
    pub commands_delimeter : &'a str,
    /// Parsed subject of first command.
    pub subject : String,
    /// All subjects of the commands in request.
    pub subjects : Vec<String>,
    /// Options map of first command.
    pub map : HashMap<String, OpType<String>>,
    /// All options maps of the commands in request.
    pub maps : Vec<HashMap<String, OpType<String>>>,
  }

  ///
  /// Options for parser.
  ///

  #[ derive( Debug ) ]
  #[ derive( Former ) ]
  #[ perform( fn parse( mut self ) -> Request< 'a > ) ]
  pub struct ParseOptions< 'a >
  {
    #[ default( "" ) ]
    src : &'a str,
    #[ default( ":" ) ]
    key_val_delimeter : &'a str,
    #[ default( ";" ) ]
    commands_delimeter : &'a str,
    #[ default( true ) ]
    quoting : bool,
    #[ default( true ) ]
    unquoting : bool,
    #[ default( true ) ]
    parsing_arrays : bool,
    #[ default( false ) ]
    several_values : bool,
    #[ default( false ) ]
    subject_win_paths_maybe : bool,
  }

  ///
  /// Adapter for ParseOptions.
  ///

  pub trait ParseOptionsAdapter< 'a >
  {
    /// A string to parse.
    fn src( &self ) -> &'a str;
    /// A delimeter for pairs `key:value`.
    fn key_val_delimeter( &self ) -> &'a str;
    /// Delimeter for commands.
    fn commands_delimeter( &self ) -> &'a str;
    /// Quoting of strings.
    fn quoting( &self ) -> bool;
    /// Unquoting of string.
    fn unquoting( &self ) -> bool;
    /// Parse arrays of values.
    fn parsing_arrays( &self ) -> bool;
    /// Append to a vector a values.
    fn several_values( &self ) -> bool;
    /// Parse subject on Windows taking into account colon in path.
    fn subject_win_paths_maybe( &self ) -> bool;

    /// Do parsing.
    fn parse( self ) -> Request< 'a >
    where
      Self : Sized,
    {
      Request::default()
    }
  }

  impl< 'a > ParseOptionsAdapter< 'a > for ParseOptions< 'a >
  {
    fn src( &self ) -> &'a str
    {
      self.src
    }
    fn key_val_delimeter( &self ) -> &'a str
    {
      self.key_val_delimeter
    }
    fn commands_delimeter( &self ) -> &'a str
    {
      self.commands_delimeter
    }
    fn quoting( &self ) -> bool
    {
      self.quoting
    }
    fn unquoting( &self ) -> bool
    {
      self.unquoting
    }
    fn parsing_arrays( &self ) -> bool
    {
      self.parsing_arrays
    }
    fn several_values( &self ) -> bool
    {
      self.several_values
    }
    fn subject_win_paths_maybe( &self ) -> bool
    {
      self.subject_win_paths_maybe
    }

    fn parse( mut self ) -> Request< 'a >
    where
      Self : Sized,
    {
      let mut result = Request::default();

      result.original = self.src();
      result.key_val_delimeter = self.key_val_delimeter();
      result.commands_delimeter = self.commands_delimeter();

      self.src = self.src.trim();

      if self.src.is_empty()
      {
        return result;
      }

      let commands;
      if self.commands_delimeter.trim().is_empty()
      {
        commands = vec![ self.src().to_string() ];
      }
      else
      {
        /* qqq : should use quoting */
        let iter = split()
        .src( self.src() )
        .delimeter( self.commands_delimeter() )
        // .quoting( self.quoting() )
        .stripping( true )
        .preserving_empty( false )
        .preserving_delimeters( false )
        .perform();
        commands = iter.map( | e | String::from( e ) ).collect::< Vec< _ > >();
      }

      for command in commands
      {
        let mut map_entries;
        if self.key_val_delimeter.trim().is_empty()
        {
          map_entries =  ( command.as_str(), None, "" );
        }
        else
        {
          map_entries = match command.split_once( self.key_val_delimeter )
          {
            Some( entries ) => ( entries.0, Some( self.key_val_delimeter ), entries.1 ),
            None => ( command.as_str(), None, "" ),
          };
        }

        let subject;
        let mut map : HashMap<String, OpType<String>> = HashMap::new();

        if map_entries.1.is_some()
        {
          /* qqq : should be isolate_right* with option quoting */
          let subject_and_key = isolate_right_or_none( map_entries.0.trim(), " " );
          subject = subject_and_key.0;
          map_entries.0 = subject_and_key.2;

          let mut join = String::from( map_entries.0 );
          join.push_str( map_entries.1.unwrap() );
          join.push_str( map_entries.2 );

          /* qqq : implement preserving_quoting */
          let mut splits = split()
          .src( join.as_str() )
          .delimeter( self.key_val_delimeter )
          .stripping( false )
          // .quoting( self.quoting )
          .preserving_empty( true )
          .preserving_delimeters( true )
          // .preserving_quoting( true )
          .perform()
          .map( | e | String::from( e ) ).collect::< Vec< _ > >();

          let mut pairs = vec![];
          for a in ( 0..splits.len() - 2 ).step_by( 2 )
          {
            let mut right = splits[ a + 2 ].clone();

            while a < ( splits.len() - 3 )
            {
              let cuts = isolate_right_or_none( &right.trim(), " " );

              if cuts.1.is_none()
              {
                let mut joined = splits[ a + 2 ].clone();
                joined.push_str( splits[ a + 3 ].as_str() );
                joined.push_str( splits[ a + 4 ].as_str() );

                splits[ a + 2 ] = joined;
                right = splits[ a + 2 ].clone();
                splits.remove( a + 3 );
                splits.remove( a + 4 );
                continue;
              }

              splits[ a + 2 ] = cuts.2.to_string();
              right = cuts.0.to_string();
              break;
            }

            let left = splits[ a ].clone();
            let right = right.trim().to_string();
            if self.unquoting
            {
              if left.contains( "\"" ) || left.contains( "'" ) || right.contains( "\"" ) || right.contains( "'" )
              {
                unimplemented!( "not implemented" );
              }
              // left = str_unquote( left );
              // right = str_unquote( right );
            }

            pairs.push( left );
            pairs.push( right );
          }

          for a in ( 0..pairs.len() - 1 ).step_by( 2 )
          {
            let left = &pairs[ a ];
            let right = &pairs[ a + 1 ];
            // right = _.numberFromStrMaybe( right );
            // right = strToArrayMaybe( right );

            if self.several_values
            {
              unimplemented!( "not implemented" );
              // map[ left ] = _.scalarAppendOnce( map[ left ], right );
            }
            else
            {
              map.insert( left.to_string(), OpType::Primitive( right.to_string() ) );
            }
          }
        }
        else
        {
          subject = map_entries.0;
        }

        if self.unquoting
        {
          if subject.contains( "\"" ) || subject.contains( "'" )
          {
            unimplemented!( "not implemented" );
          }
          // subject = _.strUnquote( subject );
        }

        if self.subject_win_paths_maybe
        {
          unimplemented!( "not implemented" );
          // subject = win_path_subject_check( subject, map );
        }

        result.subjects.push( subject.to_string() );
        result.maps.push( map );
      }

      if result.subjects.len() > 0
      {
        result.subject = result.subjects[ 0 ].clone();
      }
      if result.maps.len() > 0
      {
        result.map = result.maps[ 0 ].clone();
      }

      result
    }
  }

  fn isolate_right_or_none<'a>( src : &'a str, delimeter : &'a str ) -> ( &'a str, Option<&'a str>, &'a str )
  {
    let result = match src.trim().rsplit_once( delimeter )
    {
      Some( entries ) => ( entries.0, Some( delimeter ), entries.1 ),
      None => ( "", None, src ),
    };
    result
  }

  ///
  /// Function to parse a string with command request.
  ///
  /// It produces former. To convert former into options and run algorithm of splitting call `perform()`.
  ///

  pub fn request_parse<'a>() -> ParseOptionsFormer<'a>
  {
    ParseOptions::former()
  }
}

/// Owned namespace of the module.
pub mod own
{
  use super::internal as i;

  pub use i::OpType;
  pub use i::Request;
  pub use i::ParseOptions;
  pub use i::ParseOptionsAdapter;
  pub use i::request_parse;
}

pub use own::*;

/// Exposed namespace of the module.
pub mod exposed
{
  use super::internal as i;

  pub use i::ParseOptionsAdapter;
  pub use i::request_parse;
}

/// Namespace of the module to include with `use module::*`.
pub mod prelude
{
  use super::internal as i;

  pub use i::ParseOptionsAdapter;
}
<commit_msg>Extend routine `parse`, implement option `several_values` using method of `OpType`<commit_after>
pub( crate ) mod internal
{
  use former::Former;
  use crate::string::split::*;
  use std::collections::HashMap;

  ///
  /// Wrapper types to make transformation.
  ///

  #[ derive( Debug, Clone, PartialEq ) ]
  pub enum OpType<T>
  {
    /// Wrapper over single element of type <T>.
    Primitive( T ),
    /// Wrapper over vector of elements of type <T>.
    Vector( Vec<T> ),
    /// Wrapper over hash map of elements of type <T>.
    Map( HashMap<String, T> ),
  }

  impl<T : Default> Default for OpType<T>
  {
    fn default() -> Self
    {
      OpType::Primitive( T::default() )
    }
  }

  impl<T : Clone> OpType<T>
  where
    String : From<T>
  {
    /// Append item to current value. If current type is `Primitive`, then it will be converted to
    /// `Vector`.
    pub fn append( mut self, item : T ) -> OpType<T>
    {
      match self
      {
        OpType::Primitive( value ) =>
        {
          let vector = vec![ value, item ];
          OpType::Vector( vector )
        },
        OpType::Vector( ref mut vector ) =>
        {
          vector.push( item );
          self
        },
        OpType::Map( _ ) => panic!( "Unexpected operation. Please, use method `insert` to insert item in hash map." ),
      }
    }
  }

  ///
  /// Parsed request data.
  ///

  #[ allow( dead_code ) ]
  #[ derive( Debug, Default, PartialEq ) ]
  pub struct Request< 'a >
  {
    /// Original request string.
    pub original : &'a str,
    /// Delimeter for pairs `key:value`.
    pub key_val_delimeter : &'a str,
    /// Delimeter for commands.
    pub commands_delimeter : &'a str,
    /// Parsed subject of first command.
    pub subject : String,
    /// All subjects of the commands in request.
    pub subjects : Vec<String>,
    /// Options map of first command.
    pub map : HashMap<String, OpType<String>>,
    /// All options maps of the commands in request.
    pub maps : Vec<HashMap<String, OpType<String>>>,
  }

  ///
  /// Options for parser.
  ///

  #[ derive( Debug ) ]
  #[ derive( Former ) ]
  #[ perform( fn parse( mut self ) -> Request< 'a > ) ]
  pub struct ParseOptions< 'a >
  {
    #[ default( "" ) ]
    src : &'a str,
    #[ default( ":" ) ]
    key_val_delimeter : &'a str,
    #[ default( ";" ) ]
    commands_delimeter : &'a str,
    #[ default( true ) ]
    quoting : bool,
    #[ default( true ) ]
    unquoting : bool,
    #[ default( true ) ]
    parsing_arrays : bool,
    #[ default( false ) ]
    several_values : bool,
    #[ default( false ) ]
    subject_win_paths_maybe : bool,
  }

  ///
  /// Adapter for ParseOptions.
  ///

  pub trait ParseOptionsAdapter< 'a >
  {
    /// A string to parse.
    fn src( &self ) -> &'a str;
    /// A delimeter for pairs `key:value`.
    fn key_val_delimeter( &self ) -> &'a str;
    /// Delimeter for commands.
    fn commands_delimeter( &self ) -> &'a str;
    /// Quoting of strings.
    fn quoting( &self ) -> bool;
    /// Unquoting of string.
    fn unquoting( &self ) -> bool;
    /// Parse arrays of values.
    fn parsing_arrays( &self ) -> bool;
    /// Append to a vector a values.
    fn several_values( &self ) -> bool;
    /// Parse subject on Windows taking into account colon in path.
    fn subject_win_paths_maybe( &self ) -> bool;

    /// Do parsing.
    fn parse( self ) -> Request< 'a >
    where
      Self : Sized,
    {
      Request::default()
    }
  }

  impl< 'a > ParseOptionsAdapter< 'a > for ParseOptions< 'a >
  {
    fn src( &self ) -> &'a str
    {
      self.src
    }
    fn key_val_delimeter( &self ) -> &'a str
    {
      self.key_val_delimeter
    }
    fn commands_delimeter( &self ) -> &'a str
    {
      self.commands_delimeter
    }
    fn quoting( &self ) -> bool
    {
      self.quoting
    }
    fn unquoting( &self ) -> bool
    {
      self.unquoting
    }
    fn parsing_arrays( &self ) -> bool
    {
      self.parsing_arrays
    }
    fn several_values( &self ) -> bool
    {
      self.several_values
    }
    fn subject_win_paths_maybe( &self ) -> bool
    {
      self.subject_win_paths_maybe
    }

    fn parse( mut self ) -> Request< 'a >
    where
      Self : Sized,
    {
      let mut result = Request::default();

      result.original = self.src();
      result.key_val_delimeter = self.key_val_delimeter();
      result.commands_delimeter = self.commands_delimeter();

      self.src = self.src.trim();

      if self.src.is_empty()
      {
        return result;
      }

      let commands;
      if self.commands_delimeter.trim().is_empty()
      {
        commands = vec![ self.src().to_string() ];
      }
      else
      {
        /* qqq : should use quoting */
        let iter = split()
        .src( self.src() )
        .delimeter( self.commands_delimeter() )
        // .quoting( self.quoting() )
        .stripping( true )
        .preserving_empty( false )
        .preserving_delimeters( false )
        .perform();
        commands = iter.map( | e | String::from( e ) ).collect::< Vec< _ > >();
      }

      for command in commands
      {
        let mut map_entries;
        if self.key_val_delimeter.trim().is_empty()
        {
          map_entries =  ( command.as_str(), None, "" );
        }
        else
        {
          map_entries = match command.split_once( self.key_val_delimeter )
          {
            Some( entries ) => ( entries.0, Some( self.key_val_delimeter ), entries.1 ),
            None => ( command.as_str(), None, "" ),
          };
        }

        let subject;
        let mut map : HashMap<String, OpType<String>> = HashMap::new();

        if map_entries.1.is_some()
        {
          /* qqq : should be isolate_right* with option quoting */
          let subject_and_key = isolate_right_or_none( map_entries.0.trim(), " " );
          subject = subject_and_key.0;
          map_entries.0 = subject_and_key.2;

          let mut join = String::from( map_entries.0 );
          join.push_str( map_entries.1.unwrap() );
          join.push_str( map_entries.2 );

          /* qqq : implement preserving_quoting */
          let mut splits = split()
          .src( join.as_str() )
          .delimeter( self.key_val_delimeter )
          .stripping( false )
          // .quoting( self.quoting )
          .preserving_empty( true )
          .preserving_delimeters( true )
          // .preserving_quoting( true )
          .perform()
          .map( | e | String::from( e ) ).collect::< Vec< _ > >();

          let mut pairs = vec![];
          for a in ( 0..splits.len() - 2 ).step_by( 2 )
          {
            let mut right = splits[ a + 2 ].clone();

            while a < ( splits.len() - 3 )
            {
              let cuts = isolate_right_or_none( &right.trim(), " " );

              if cuts.1.is_none()
              {
                let mut joined = splits[ a + 2 ].clone();
                joined.push_str( splits[ a + 3 ].as_str() );
                joined.push_str( splits[ a + 4 ].as_str() );

                splits[ a + 2 ] = joined;
                right = splits[ a + 2 ].clone();
                splits.remove( a + 3 );
                splits.remove( a + 4 );
                continue;
              }

              splits[ a + 2 ] = cuts.2.to_string();
              right = cuts.0.to_string();
              break;
            }

            let left = splits[ a ].clone();
            let right = right.trim().to_string();
            if self.unquoting
            {
              if left.contains( "\"" ) || left.contains( "'" ) || right.contains( "\"" ) || right.contains( "'" )
              {
                unimplemented!( "not implemented" );
              }
              // left = str_unquote( left );
              // right = str_unquote( right );
            }

            pairs.push( left );
            pairs.push( right );
          }

          for a in ( 0..pairs.len() - 1 ).step_by( 2 )
          {
            let left = &pairs[ a ];
            let right = &pairs[ a + 1 ];
            // right = _.numberFromStrMaybe( right );
            // right = strToArrayMaybe( right );

            if self.several_values
            {
              if let Some( op ) = map.get( left )
              {
                let value = op.clone().append( right.to_string() );
                map.insert( left.to_string(), value );
              }
              else
              {
                map.insert( left.to_string(), OpType::Primitive( right.to_string() ) );
              }
            }
            else
            {
              map.insert( left.to_string(), OpType::Primitive( right.to_string() ) );
            }
          }
        }
        else
        {
          subject = map_entries.0;
        }

        if self.unquoting
        {
          if subject.contains( "\"" ) || subject.contains( "'" )
          {
            unimplemented!( "not implemented" );
          }
          // subject = _.strUnquote( subject );
        }

        if self.subject_win_paths_maybe
        {
          unimplemented!( "not implemented" );
          // subject = win_path_subject_check( subject, map );
        }

        result.subjects.push( subject.to_string() );
        result.maps.push( map );
      }

      if result.subjects.len() > 0
      {
        result.subject = result.subjects[ 0 ].clone();
      }
      if result.maps.len() > 0
      {
        result.map = result.maps[ 0 ].clone();
      }

      result
    }
  }

  fn isolate_right_or_none<'a>( src : &'a str, delimeter : &'a str ) -> ( &'a str, Option<&'a str>, &'a str )
  {
    let result = match src.trim().rsplit_once( delimeter )
    {
      Some( entries ) => ( entries.0, Some( delimeter ), entries.1 ),
      None => ( "", None, src ),
    };
    result
  }

  ///
  /// Function to parse a string with command request.
  ///
  /// It produces former. To convert former into options and run algorithm of splitting call `perform()`.
  ///

  pub fn request_parse<'a>() -> ParseOptionsFormer<'a>
  {
    ParseOptions::former()
  }
}

/// Owned namespace of the module.
pub mod own
{
  use super::internal as i;

  pub use i::OpType;
  pub use i::Request;
  pub use i::ParseOptions;
  pub use i::ParseOptionsAdapter;
  pub use i::request_parse;
}

pub use own::*;

/// Exposed namespace of the module.
pub mod exposed
{
  use super::internal as i;

  pub use i::ParseOptionsAdapter;
  pub use i::request_parse;
}

/// Namespace of the module to include with `use module::*`.
pub mod prelude
{
  use super::internal as i;

  pub use i::ParseOptionsAdapter;
}
<|endoftext|>