<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2016-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Initial 32-bit bootloader for x86_64
#![crate_name = "boot"]
#![feature(asm)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(static_recursion)]
#![feature(linkage)]
#![feature(struct_field_attributes)]
#![feature(stmt_expr_attributes)]
#![no_std]

const TABLE_LENGTH: usize = 512;

type Table = [u64; TABLE_LENGTH];

use core::convert;

macro_rules! set_flags {
    (%$register:ident $( |= $body:expr);+ ) => {
        let mut $register: usize;
        asm!( concat!("mov $0, ", stringify!($register))
            : "=r"($register)
            ::: "intel");
        $($register |= $body;)+
        asm!( concat!("mov ", stringify!($register), ", $0")
            :: "r"($register)
            :: "intel");
    }
}

#[repr(C, packed)]
pub struct Gdt { _null: u64
               , code: u64
               }

#[repr(C, packed)]
pub struct GdtPointer { /// the length of the GDT
                        pub limit: u16
                      , /// pointer to the GDT
                        pub base: &'static Gdt
                      }

impl GdtPointer {
    #[cold] #[inline(always)]
    unsafe fn load (&self) {
        asm!("lgdt ($0)" :: "r"(self) : "memory");
    }
}

impl convert::From<&'static Gdt> for GdtPointer {
    #[cold] #[inline(always)]
    fn from(gdt: &'static Gdt) -> Self {
        use core::mem::size_of_val;
        GdtPointer { limit: size_of_val(gdt) as u16 - 1
                   , base: gdt }
    }
}

#[link_name = ".gdt64"]
#[link_section = ".gdt"]
#[no_mangle]
pub static GDT: Gdt
    = Gdt { _null: 0
          , code: (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53)
        //   , data: (1 << 44) | (1 << 47) | (1 << 41)
          };

#[inline(always)]
fn boot_write(s: &[u8]) {
    unsafe {
        use core::ptr::write_volatile;
        let vga_buf = 0xb8000 as *mut u16;
    	for (n, c) in s.iter().enumerate() {
    		write_volatile(vga_buf.offset(n as isize), 0x0200 + *c as u16);
    	}

    }

}

extern "C" {
    static mut pml4_table: Table;
    static mut pdp_table: Table;
    static mut pd_table: Table;
}

#[cold]
#[inline(always)]
#[naked]
unsafe fn create_page_tables() {
    // 3. if everything is okay, create the page tables and start long mode
    const HUGE_PAGE_SIZE: u64 = 2 * 1024 * 1024; // 2 MiB

    //-- map the PML4 and PDP tables -----------------------------------------
    // recursive map last PML4 entry
    pml4_table[511] = (&pml4_table as *const _ as u64) | 0b11;
    // map first PML4 entry to PDP table
    pml4_table[0] = (&pdp_table as *const _ as u64) | 0b11;
    // map first PDPT entry to PD table
    pdp_table[0] = (&pd_table as *const _ as u64) | 0b11;

    boot_write(b"3.1");

    //-- map the PD table ----------------------------------------------------
    for (number, entry) in pd_table.iter_mut().enumerate() {
        // set each PD entry equal to the start address of the page (the page
        // number times the page's size)
        let addr = number as u64 * HUGE_PAGE_SIZE;
        // with the appropriate flags (present + writable + huge)
        // TODO: do we want to do this using bitflags, or is that too
        //       heavyweight for the boot module?
        //          - eliza, 1/23/2017
        *entry = addr | 0b10000011;
    }

    boot_write(b"3.2");
}
#[cold]
#[inline(always)]
#[naked]
unsafe fn set_long_mode() {
    // load PML4 addr to cr3
    asm!("mov cr3, $0" :: "r"(&pml4_table) :: "intel");
    boot_write(b"3.3");

    // // enable PAE flag in cr4
    set_flags!(%cr4 |= 1 << 5 );
    boot_write(b"3.4");

    // set the long mode bit in EFER MSR (model specific register)
    asm!( "mov   ecx, 0xC0000080
           rdmsr
           or    eax, 1 << 8
           wrmsr"
        :::: "intel");
    boot_write(b"3.5");

    // enable paging in cr0
    set_flags!(%cr0 |= 1 << 31;
                    |= 1 << 16 );
}

#[cold]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn _start() {
    boot_write(b"0");
    asm!("cli");

    // 1. Move Multiboot info pointer to edi
    asm!("mov edi, ebx" :::: "intel");
    boot_write(b"1");

    // 2. make sure the system supports SOS
    // TODO: port this from boot.asm
    boot_write(b"2");

    create_page_tables();
    set_long_mode();

    // 4. load the 64-bit GDT
    GdtPointer::from(&GDT).load();
    boot_write(b"4");

    // 6. jump to the 64-bit boot subroutine.
    asm!("ljmpl $$8, $$long_mode_init");

}
<commit_msg>[boot] add test for multiboot support back in<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2016-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Initial 32-bit bootloader for x86_64
#![crate_name = "boot"]
#![feature(asm)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(static_recursion)]
#![feature(linkage)]
#![feature(struct_field_attributes)]
#![feature(stmt_expr_attributes)]
#![no_std]

const TABLE_LENGTH: usize = 512;

type Table = [u64; TABLE_LENGTH];

use core::convert;

macro_rules! set_flags {
    (%$register:ident $( |= $body:expr);+ ) => {
        let mut $register: usize;
        asm!( concat!("mov $0, ", stringify!($register))
            : "=r"($register)
            ::: "intel");
        $($register |= $body;)+
        asm!( concat!("mov ", stringify!($register), ", $0")
            :: "r"($register)
            :: "intel");
    }
}

#[repr(C, packed)]
pub struct Gdt { _null: u64
               , code: u64
               }

#[repr(C, packed)]
pub struct GdtPointer { /// the length of the GDT
                        pub limit: u16
                      , /// pointer to the GDT
                        pub base: &'static Gdt
                      }

impl GdtPointer {
    #[cold] #[inline(always)]
    unsafe fn load (&self) {
        asm!("lgdt ($0)" :: "r"(self) : "memory");
    }
}

impl convert::From<&'static Gdt> for GdtPointer {
    #[cold] #[inline(always)]
    fn from(gdt: &'static Gdt) -> Self {
        use core::mem::size_of_val;
        GdtPointer { limit: size_of_val(gdt) as u16 - 1
                   , base: gdt }
    }
}

#[link_name = ".gdt64"]
#[link_section = ".gdt"]
#[no_mangle]
pub static GDT: Gdt
    = Gdt { _null: 0
          , code: (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53)
        //   , data: (1 << 44) | (1 << 47) | (1 << 41)
          };

#[inline(always)]
fn boot_write(s: &[u8]) {
    unsafe {
        use core::ptr::write_volatile;
        let vga_buf = 0xb8000 as *mut u16;
    	for (n, c) in s.iter().enumerate() {
    		write_volatile(vga_buf.offset(n as isize), 0x0200 + *c as u16);
    	}

    }

}

extern "C" {
    static mut pml4_table: Table;
    static mut pdp_table: Table;
    static mut pd_table: Table;
}

#[cold]
#[inline(always)]
#[naked]
unsafe fn create_page_tables() {
    // 3. if everything is okay, create the page tables and start long mode
    const HUGE_PAGE_SIZE: u64 = 2 * 1024 * 1024; // 2 MiB

    //-- map the PML4 and PDP tables -----------------------------------------
    // recursive map last PML4 entry
    pml4_table[511] = (&pml4_table as *const _ as u64) | 0b11;
    // map first PML4 entry to PDP table
    pml4_table[0] = (&pdp_table as *const _ as u64) | 0b11;
    // map first PDPT entry to PD table
    pdp_table[0] = (&pd_table as *const _ as u64) | 0b11;

    boot_write(b"3.1");

    //-- map the PD table ----------------------------------------------------
    for (number, entry) in pd_table.iter_mut().enumerate() {
        // set each PD entry equal to the start address of the page (the page
        // number times the page's size)
        let addr = number as u64 * HUGE_PAGE_SIZE;
        // with the appropriate flags (present + writable + huge)
        // TODO: do we want to do this using bitflags, or is that too
        //       heavyweight for the boot module?
        //          - eliza, 1/23/2017
        *entry = addr | 0b10000011;
    }

    boot_write(b"3.2");
}
#[cold]
#[inline(always)]
#[naked]
unsafe fn set_long_mode() {
    // load PML4 addr to cr3
    asm!("mov cr3, $0" :: "r"(&pml4_table) :: "intel");
    boot_write(b"3.3");

    // // enable PAE flag in cr4
    set_flags!(%cr4 |= 1 << 5 );
    boot_write(b"3.4");

    // set the long mode bit in EFER MSR (model specific register)
    asm!( "mov   ecx, 0xC0000080
           rdmsr
           or    eax, 1 << 8
           wrmsr"
        :::: "intel");
    boot_write(b"3.5");

    // enable paging in cr0
    set_flags!(%cr0 |= 1 << 31;
                    |= 1 << 16 );
}

/// Test whether or not this system supports Multiboot 2
#[cold]
#[inline(always)]
unsafe fn is_multiboot_supported() -> bool {
    let eax: usize;
    asm!("mov eax, $0" : "=r"(eax) ::: "intel");
    eax == 0x36d76289
}

#[cold]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn _start() {
    boot_write(b"0");
    asm!("cli");

    // 1. Move Multiboot info pointer to edi
    asm!("mov edi, ebx" :::: "intel");
    boot_write(b"1");

    // 2. make sure the system supports SOS
    // TODO: port this from boot.asm
    if !is_multiboot_supported() {
        loop { boot_write(b"ERROR: multiboot not supported!"); }
    }
    boot_write(b"2");

    create_page_tables();
    set_long_mode();

    // 4. load the 64-bit GDT
    GdtPointer::from(&GDT).load();
    boot_write(b"4");

    // 6. jump to the 64-bit boot subroutine.
    asm!("ljmpl $$8, $$long_mode_init");

}
<|endoftext|>


<commit_before>//! Draw rectangle

use current::{ Get, Modifier, Set };
use internal;
use triangulation;
use Context;
use BackEnd;
use ImageSize;
use Color;

/// Use x, y, half-width, half-height
pub fn centered(rect: internal::Rectangle) -> internal::Rectangle {
    let [cx, cy, rw, rh] = rect;
    [cx - rw, cy - rh, 2.0 * rw, 2.0 * rh]
}

/// Use centered square
pub fn centered_square(
    x: internal::Scalar,
    y: internal::Scalar,
    radius: internal::Scalar
) -> internal::Rectangle {
    [x - radius, y - radius, 2.0 * radius, 2.0 * radius]
}

/// Use square with x, y in upper left corner
pub fn square(
    x: internal::Scalar,
    y: internal::Scalar,
    size: internal::Scalar
) -> internal::Rectangle {
    [x, y, size, size]
}

/// The shape of the rectangle
pub enum Shape {
    /// Square corners
    Square,
    /// Round corners
    Round(internal::Radius),
    /// Bevel corners
    Bevel(internal::Radius),
}

/// Wrapper trait for `Get<Shape>`
pub trait GetShape: Get<Shape> {
    /// Get shape
    #[inline(always)]
    fn get_shape(&self) -> Shape {
        self.get()
    }
}

impl<T: Get<Shape>> GetShape for T {}

/// Wrapper trait for `Set<Shape>`
pub trait SetShape: Set<Shape> {
    /// Set shape
    #[inline(always)]
    fn set_shape(&mut self, val: Shape) {
        self.set_mut(val);
    }
}

impl<T: Set<Shape>> SetShape for T {}

/// The border of the rectangle
pub struct Border {
    /// The color of the border
    pub color: internal::Color,
    /// The radius of the border
    pub radius: internal::Radius,
}

/// Wrapper trait for `Get<Border>`
pub trait GetBorder: Get<Border> {
    /// Get border
    #[inline(always)]
    fn get_border(&self) -> Border {
        self.get()
    }
}

impl<T: Get<Border>> GetBorder for T {}

/// Wrapper trait for `Set<Border>`
pub trait SetBorder: Set<Border> {
    /// Set border
    #[inline(always)]
    fn set_border(&mut self, val: Border) {
        self.set_mut(val);
    }
}

impl<T: Set<Border>> SetBorder for T {}

/// Maybe border property
pub struct MaybeBorder(pub Option<Border>);

/// Wrapper trait for `Get<MaybeBorder>`
pub trait GetMaybeBorder: Get<MaybeBorder> {
    /// Get maybe border
    #[inline(always)]
    fn get_maybe_border(&self) -> MaybeBorder {
        self.get()
    }
}

impl<T: Get<MaybeBorder>> GetMaybeBorder for T {}

/// Wrapper trait for `Set<MaybeBorder>`
pub trait SetMaybeBorder: Set<MaybeBorder> {
    /// Set maybe border
    #[inline(always)]
    fn set_maybe_border(&mut self, val: MaybeBorder) {
        self.set_mut(val);
    }
}

impl<T: Set<MaybeBorder>> SetMaybeBorder for T {}

/// A filled rectangle
#[deriving(Copy)]
pub struct Rectangle {
    /// The rectangle color
    pub color: internal::Color,
    /// The roundness of the rectangle
    pub shape: Shape,
    /// The border
    pub border: Option<Border>,
}

impl Rectangle {
    /// Creates a new rectangle.
    pub fn new(color: internal::Color) -> Rectangle {
        Rectangle {
            color: color,
            shape: Shape::Square,
            border: None,
        }
    }

    /// Creates a new rectangle border.
    pub fn border(
        color: internal::Color,
        radius: internal::Radius
    ) -> Rectangle {
        Rectangle {
            color: [0.0, ..4],
            shape: Shape::Square,
            border: Some(Border {
                    color: color,
                    radius: radius
                })
        }
    }

    /// Draws the rectangle
    pub fn draw<B: BackEnd<I>, I: ImageSize>(
        &self,
        rectangle: internal::Rectangle,
        c: &Context,
        back_end: &mut B
    ) {
        if self.color[3] != 0.0 {
            back_end.color(self.color);
            match self.shape {
                Shape::Square => {
                    back_end.tri_list(
                        &triangulation::rect_tri_list_xy(c.transform, rectangle),
                    );
                }
                Shape::Round(round_radius) => {
                    triangulation::with_round_rectangle_tri_list(
                        32,
                        c.transform,
                        rectangle,
                        round_radius,
                        |vertices| back_end.tri_list(vertices)
                    );
                }
                Shape::Bevel(bevel_radius) => {
                    triangulation::with_round_rectangle_tri_list(
                        2,
                        c.transform,
                        rectangle,
                        bevel_radius,
                        |vertices| back_end.tri_list(vertices)
                    );
                }
            }
        }

        if let Some(Border { color, radius: border_radius }) = self.border {
            if color[3] == 0.0 { return; }
            back_end.color(color);
            match self.shape {
                Shape::Square => {
                    back_end.tri_list(
                        &triangulation::rect_border_tri_list_xy(
                            c.transform, rectangle, border_radius),
                    );
                }
                Shape::Round(round_radius) => {
                    triangulation::with_round_rectangle_border_tri_list(
                        128,
                        c.transform,
                        rectangle,
                        round_radius,
                        border_radius,
                        |vertices| back_end.tri_list(vertices)
                    );
                }
                Shape::Bevel(bevel_radius) => {
                    triangulation::with_round_rectangle_border_tri_list(
                        2,
                        c.transform,
                        rectangle,
                        bevel_radius,
                        border_radius,
                        |vertices| back_end.tri_list(vertices)
                    );
                }
            }
        }
    }
}

impl Modifier<Rectangle> for Color {
    #[inline(always)]
    fn modify(self, r: &mut Rectangle) {
        let Color(val) = self;
        r.color = val;
    }
}

impl Get<Color> for Rectangle {
    #[inline(always)]
    fn get(&self) -> Color {
        Color(self.color)
    }
}

impl Modifier<Rectangle> for Shape {
    #[inline(always)]
    fn modify(self, r: &mut Rectangle) {
        r.shape = self;
    }
}

impl Get<Shape> for Rectangle {
    #[inline(always)]
    fn get(&self) -> Shape {
        self.shape
    }
}

impl Modifier<Rectangle> for Border {
    #[inline(always)]
    fn modify(self, r: &mut Rectangle) {
        r.border = Some(self);
    }
}

impl Modifier<Rectangle> for MaybeBorder {
    #[inline(always)]
    fn modify(self, r: &mut Rectangle) {
        let MaybeBorder(val) = self;
        r.border = val;
    }
}

impl Get<MaybeBorder> for Rectangle {
    #[inline(always)]
    fn get(&self) -> MaybeBorder {
        MaybeBorder(self.border)
    }
}

#[cfg(test)]
mod test {
    use super::Rectangle;
    use super::Shape;
    use super::Border;
    use Color;
    use current::Set;

    #[test]
    fn test_rectangle() {
        let _rectangle = Rectangle::new([1.0, ..4])
            .set(Color([0.0, ..4]))
            .set(Shape::Round(10.0))
            .set(Border { color: [0.0, ..4], radius: 4.0 });
    }
}

<commit_msg>Reexported `margin`<commit_after>//! Draw rectangle

use current::{ Get, Modifier, Set };
use internal;
use triangulation;
use Context;
use BackEnd;
use ImageSize;
use Color;

pub use vecmath::margin_rectangle as margin;

/// Use x, y, half-width, half-height
pub fn centered(rect: internal::Rectangle) -> internal::Rectangle {
    let [cx, cy, rw, rh] = rect;
    [cx - rw, cy - rh, 2.0 * rw, 2.0 * rh]
}

/// Use centered square
pub fn centered_square(
    x: internal::Scalar,
    y: internal::Scalar,
    radius: internal::Scalar
) -> internal::Rectangle {
    [x - radius, y - radius, 2.0 * radius, 2.0 * radius]
}

/// Use square with x, y in upper left corner
pub fn square(
    x: internal::Scalar,
    y: internal::Scalar,
    size: internal::Scalar
) -> internal::Rectangle {
    [x, y, size, size]
}

/// The shape of the rectangle
pub enum Shape {
    /// Square corners
    Square,
    /// Round corners
    Round(internal::Radius),
    /// Bevel corners
    Bevel(internal::Radius),
}

/// Wrapper trait for `Get<Shape>`
pub trait GetShape: Get<Shape> {
    /// Get shape
    #[inline(always)]
    fn get_shape(&self) -> Shape {
        self.get()
    }
}

impl<T: Get<Shape>> GetShape for T {}

/// Wrapper trait for `Set<Shape>`
pub trait SetShape: Set<Shape> {
    /// Set shape
    #[inline(always)]
    fn set_shape(&mut self, val: Shape) {
        self.set_mut(val);
    }
}

impl<T: Set<Shape>> SetShape for T {}

/// The border of the rectangle
pub struct Border {
    /// The color of the border
    pub color: internal::Color,
    /// The radius of the border
    pub radius: internal::Radius,
}

/// Wrapper trait for `Get<Border>`
pub trait GetBorder: Get<Border> {
    /// Get border
    #[inline(always)]
    fn get_border(&self) -> Border {
        self.get()
    }
}

impl<T: Get<Border>> GetBorder for T {}

/// Wrapper trait for `Set<Border>`
pub trait SetBorder: Set<Border> {
    /// Set border
    #[inline(always)]
    fn set_border(&mut self, val: Border) {
        self.set_mut(val);
    }
}

impl<T: Set<Border>> SetBorder for T {}

/// Maybe border property
pub struct MaybeBorder(pub Option<Border>);

/// Wrapper trait for `Get<MaybeBorder>`
pub trait GetMaybeBorder: Get<MaybeBorder> {
    /// Get maybe border
    #[inline(always)]
    fn get_maybe_border(&self) -> MaybeBorder {
        self.get()
    }
}

impl<T: Get<MaybeBorder>> GetMaybeBorder for T {}

/// Wrapper trait for `Set<MaybeBorder>`
pub trait SetMaybeBorder: Set<MaybeBorder> {
    /// Set maybe border
    #[inline(always)]
    fn set_maybe_border(&mut self, val: MaybeBorder) {
        self.set_mut(val);
    }
}

impl<T: Set<MaybeBorder>> SetMaybeBorder for T {}

/// A filled rectangle
#[deriving(Copy)]
pub struct Rectangle {
    /// The rectangle color
    pub color: internal::Color,
    /// The roundness of the rectangle
    pub shape: Shape,
    /// The border
    pub border: Option<Border>,
}

impl Rectangle {
    /// Creates a new rectangle.
    pub fn new(color: internal::Color) -> Rectangle {
        Rectangle {
            color: color,
            shape: Shape::Square,
            border: None,
        }
    }

    /// Creates a new rectangle border.
    pub fn border(
        color: internal::Color,
        radius: internal::Radius
    ) -> Rectangle {
        Rectangle {
            color: [0.0, ..4],
            shape: Shape::Square,
            border: Some(Border {
                    color: color,
                    radius: radius
                })
        }
    }

    /// Draws the rectangle
    pub fn draw<B: BackEnd<I>, I: ImageSize>(
        &self,
        rectangle: internal::Rectangle,
        c: &Context,
        back_end: &mut B
    ) {
        if self.color[3] != 0.0 {
            back_end.color(self.color);
            match self.shape {
                Shape::Square => {
                    back_end.tri_list(
                        &triangulation::rect_tri_list_xy(c.transform, rectangle),
                    );
                }
                Shape::Round(round_radius) => {
                    triangulation::with_round_rectangle_tri_list(
                        32,
                        c.transform,
                        rectangle,
                        round_radius,
                        |vertices| back_end.tri_list(vertices)
                    );
                }
                Shape::Bevel(bevel_radius) => {
                    triangulation::with_round_rectangle_tri_list(
                        2,
                        c.transform,
                        rectangle,
                        bevel_radius,
                        |vertices| back_end.tri_list(vertices)
                    );
                }
            }
        }

        if let Some(Border { color, radius: border_radius }) = self.border {
            if color[3] == 0.0 { return; }
            back_end.color(color);
            match self.shape {
                Shape::Square => {
                    back_end.tri_list(
                        &triangulation::rect_border_tri_list_xy(
                            c.transform, rectangle, border_radius),
                    );
                }
                Shape::Round(round_radius) => {
                    triangulation::with_round_rectangle_border_tri_list(
                        128,
                        c.transform,
                        rectangle,
                        round_radius,
                        border_radius,
                        |vertices| back_end.tri_list(vertices)
                    );
                }
                Shape::Bevel(bevel_radius) => {
                    triangulation::with_round_rectangle_border_tri_list(
                        2,
                        c.transform,
                        rectangle,
                        bevel_radius,
                        border_radius,
                        |vertices| back_end.tri_list(vertices)
                    );
                }
            }
        }
    }
}

impl Modifier<Rectangle> for Color {
    #[inline(always)]
    fn modify(self, r: &mut Rectangle) {
        let Color(val) = self;
        r.color = val;
    }
}

impl Get<Color> for Rectangle {
    #[inline(always)]
    fn get(&self) -> Color {
        Color(self.color)
    }
}

impl Modifier<Rectangle> for Shape {
    #[inline(always)]
    fn modify(self, r: &mut Rectangle) {
        r.shape = self;
    }
}

impl Get<Shape> for Rectangle {
    #[inline(always)]
    fn get(&self) -> Shape {
        self.shape
    }
}

impl Modifier<Rectangle> for Border {
    #[inline(always)]
    fn modify(self, r: &mut Rectangle) {
        r.border = Some(self);
    }
}

impl Modifier<Rectangle> for MaybeBorder {
    #[inline(always)]
    fn modify(self, r: &mut Rectangle) {
        let MaybeBorder(val) = self;
        r.border = val;
    }
}

impl Get<MaybeBorder> for Rectangle {
    #[inline(always)]
    fn get(&self) -> MaybeBorder {
        MaybeBorder(self.border)
    }
}

#[cfg(test)]
mod test {
    use super::Rectangle;
    use super::Shape;
    use super::Border;
    use Color;
    use current::Set;

    #[test]
    fn test_rectangle() {
        let _rectangle = Rectangle::new([1.0, ..4])
            .set(Color([0.0, ..4]))
            .set(Shape::Round(10.0))
            .set(Border { color: [0.0, ..4], radius: 4.0 });
    }
}

<|endoftext|>


<commit_before>use hyper;
use serde;
use serde_json;
use std;

use Error;
use ErrorResponse;
use IntoViewPath;
use ViewResult;
use client::ClientState;
use action::{self, Action, Request, Response};
use error::EncodeErrorKind;

/// Action to execute a view.
///
/// # Errors
///
/// The following are some of the errors that may occur as a result of executing
/// this action:
///
/// * `Error::InternalServerError`: An error occurred when executing the view.
/// * `Error::NotFound`: The view does not exist.
/// * `Error::Unauthorized`: The client is unauthorized.
///
pub struct GetView<'a, P, K, V>
    where P: IntoViewPath,
          K: serde::Deserialize, // serialize needed for endkey and startkey
          V: serde::Deserialize
{
    client_state: &'a ClientState,
    path: P,

    reduce: Option<bool>,
    endkey: Option<K>,
    startkey: Option<K>,

    _phantom_key: std::marker::PhantomData<K>,
    _phantom_value: std::marker::PhantomData<V>,
}

impl<'a, P, K, V> GetView<'a, P, K, V>
    where P: IntoViewPath,
          K: serde::Deserialize + serde::Serialize,
          V: serde::Deserialize
{
    #[doc(hidden)]
    pub fn new(client_state: &'a ClientState, path: P) -> Self {
        GetView {
            client_state: client_state,
            path: path,
            reduce: None,
            endkey: None,
            startkey: None,
            _phantom_key: std::marker::PhantomData,
            _phantom_value: std::marker::PhantomData,
        }
    }

    /// Sets whether to run the `reduce` view function.
    pub fn reduce(mut self, v: bool) -> Self {
        self.reduce = Some(v);
        self
    }

    /// Sets the minimum key for rows contained within the result.
    pub fn endkey(mut self, key: K) -> Self {
        self.endkey = Some(key);
        self
    }

    /// Sets the maximum key for rows contained within the result.
    pub fn startkey(mut self, key: K) -> Self {
        self.startkey = Some(key);
        self
    }

    impl_action_public_methods!(ViewResult<K, V>);
}

impl<'a, P, K, V> Action for GetView<'a, P, K, V>
    where P: IntoViewPath,
          K: serde::Deserialize + serde::Serialize,
          V: serde::Deserialize
{
    type Output = ViewResult<K, V>;
    type State = ();

    fn make_request(self) -> Result<(Request, Self::State), Error> {

        let uri = {

            let mut uri = try!(self.path.into_view_path()).into_uri(self.client_state.uri.clone());

            {
                let mut query_pairs = Vec::<(&'static str, String)>::new();
                if self.reduce.is_some() {
                    match self.reduce.unwrap() {
                        true => query_pairs.push(("reduce", "true".to_string())),
                        false => query_pairs.push(("reduce", "false".to_string())),
                    };
                }
                if self.startkey.is_some() {
                    let x = try!(serde_json::to_string(&self.startkey.unwrap()).or_else(|e| {
                        Err(Error::Encode(EncodeErrorKind::Serde { cause: e }))
                    }));
                    query_pairs.push(("startkey", x));
                }
                if self.endkey.is_some() {
                    let x = try!(serde_json::to_string(&self.endkey.unwrap()).or_else(|e| {
                        Err(Error::Encode(EncodeErrorKind::Serde { cause: e }))
                    }));
                    query_pairs.push(("endkey", x));
                }
                if !query_pairs.is_empty() {
                    uri.set_query_from_pairs(query_pairs.iter()
                                                        .map(|&(k, ref v)| {
                                                            let x: (&str, &str) = (k, v);
                                                            x
                                                        }));
                }
            }

            uri
        };

        let request = Request::new(hyper::Get, uri).set_accept_application_json();
        Ok((request, ()))
    }

    fn take_response<R>(mut response: R, _state: Self::State) -> Result<Self::Output, Error>
        where R: Response
    {
        match response.status() {
            hyper::status::StatusCode::Ok => {
                try!(response.content_type_must_be_application_json());
                let view_result = try!(response.decode_json_all::<ViewResult<K, V>>());
                Ok(view_result)
            }
            hyper::status::StatusCode::BadRequest => Err(make_couchdb_error!(BadRequest, response)),
            hyper::status::StatusCode::Unauthorized => {
                Err(make_couchdb_error!(Unauthorized, response))
            }
            hyper::status::StatusCode::NotFound => Err(make_couchdb_error!(NotFound, response)),
            hyper::status::StatusCode::InternalServerError => {
                Err(make_couchdb_error!(InternalServerError, response))
            }
            _ => Err(Error::UnexpectedHttpStatus { got: response.status() }),
        }
    }
}

#[cfg(test)]
mod tests {

    use hyper;
    use serde_json;

    use DocumentId;
    use ViewPath;
    use ViewRow;
    use client::ClientState;
    use action::{Action, JsonResponse};
    use super::GetView;

    #[test]
    fn make_request_default() {
        let client_state = ClientState::new("http://example.com:1234/").unwrap();
        let action = GetView::<_, String, i32>::new(&client_state, "/foo/_design/bar/_view/qux");
        let (request, _) = action.make_request().unwrap();
        expect_request_method!(request, hyper::Get);
        expect_request_uri!(request, "http://example.com:1234/foo/_design/bar/_view/qux");
        expect_request_accept_application_json!(request);
    }

    #[test]
    fn make_request_reduce() {
        let client_state = ClientState::new("http://example.com:1234/").unwrap();
        let action = GetView::<_, String, i32>::new(&client_state, "/foo/_design/bar/_view/qux")
                         .reduce(true);
        let (request, _) = action.make_request().unwrap();
        expect_request_method!(request, hyper::Get);
        expect_request_uri!(request,
                            "http://example.com:1234/foo/_design/bar/_view/qux?reduce=true");
        expect_request_accept_application_json!(request);
    }

    #[test]
    fn make_request_startkey() {
        let client_state = ClientState::new("http://example.com:1234/").unwrap();
        let path = ViewPath::parse("/foo/_design/bar/_view/qux").unwrap();
        let action = GetView::<ViewPath, String, i32>::new(&client_state, path)
                         .startkey("baz".to_string());
        let (request, ()) = action.make_request().unwrap();
        expect_request_method!(request, hyper::Get);
        expect_request_uri!(request,
                            "http://example.com:1234/foo/_design/bar/_view/qux?startkey=\"baz\"");
        expect_request_accept_application_json!(request);
    }

    #[test]
    fn make_request_endkey() {
        let client_state = ClientState::new("http://example.com:1234/").unwrap();
        let path = ViewPath::parse("/foo/_design/bar/_view/qux").unwrap();
        let action = GetView::<ViewPath, String, i32>::new(&client_state, path)
                         .endkey("baz".to_string());
        let (request, _) = action.make_request().unwrap();
        expect_request_method!(request, hyper::Get);
        expect_request_uri!(request,
                            "http://example.com:1234/foo/_design/bar/_view/qux?endkey=\"baz\"");
        expect_request_accept_application_json!(request);
    }

    #[test]
    fn take_response_ok() {
        let source = serde_json::builder::ObjectBuilder::new()
                         .insert("offset", 17)
                         .insert_array("rows", |x| {
                             x.push_object(|x| {
                                 x.insert("id", "foo")
                                  .insert("key", "alpha")
                                  .insert("value", 5)
                             })
                         })
                         .insert("total_rows", 42)
                         .unwrap();
        let response = JsonResponse::new(hyper::Ok, &source);
        let got = GetView::<ViewPath, String, i32>::take_response(response, ()).unwrap();
        assert_eq!(got.total_rows, Some(42));
        assert_eq!(got.offset, Some(17));
        assert_eq!(got.rows,
                   vec![{
                            let mut x = ViewRow::new(5);
                            x.id = Some(DocumentId::Normal("foo".into()));
                            x.key = Some("alpha".to_string());
                            x
                        }]);
    }

    #[test]
    fn take_response_bad_request() {
        let source = serde_json::builder::ObjectBuilder::new()
                         .insert("error", "bad_request")
                         .insert("reason", "blah blah blah")
                         .unwrap();
        let response = JsonResponse::new(hyper::BadRequest, &source);
        let got = GetView::<ViewPath, String, i32>::take_response(response, ());
        expect_couchdb_error!(got, BadRequest);
    }

    #[test]
    fn take_response_internal_server_error() {
        let source = serde_json::builder::ObjectBuilder::new()
                         .insert("error", "internal_server_error")
                         .insert("reason", "blah blah blah")
                         .unwrap();
        let response = JsonResponse::new(hyper::status::StatusCode::InternalServerError, &source);
        let got = GetView::<ViewPath, String, i32>::take_response(response, ());
        expect_couchdb_error!(got, InternalServerError);
    }

    #[test]
    fn take_response_not_found() {
        let source = serde_json::builder::ObjectBuilder::new()
                         .insert("error", "not_found")
                         .insert("reason", "blah blah blah")
                         .unwrap();
        let response = JsonResponse::new(hyper::NotFound, &source);
        let got = GetView::<ViewPath, String, i32>::take_response(response, ());
        expect_couchdb_error!(got, NotFound);
    }

    #[test]
    fn take_response_unauthorized() {
        let source = serde_json::builder::ObjectBuilder::new()
                         .insert("error", "unauthorized")
                         .insert("reason", "blah blah blah")
                         .unwrap();
        let response = JsonResponse::new(hyper::status::StatusCode::Unauthorized, &source);
        let got = GetView::<ViewPath, String, i32>::take_response(response, ());
        expect_couchdb_error!(got, Unauthorized);
    }
}
<commit_msg>Separate query iteration for GetView action<commit_after>use hyper;
use serde;
use serde_json;
use std;

use Error;
use ErrorResponse;
use IntoViewPath;
use ViewResult;
use client::ClientState;
use action::{self, Action, Request, Response};
use error::EncodeErrorKind;

struct QueryParams<K>
    where K: serde::Serialize
{
    endkey: Option<K>,
    reduce: Option<bool>,
    startkey: Option<K>,
}

impl<K> Default for QueryParams<K> where K: serde::Serialize
{
    fn default() -> Self {
        QueryParams {
            endkey: Default::default(),
            reduce: Default::default(),
            startkey: Default::default(),
        }
    }
}

impl<K> QueryParams<K> where K: serde::Serialize
{
    fn is_default(&self) -> bool {
        self.endkey.is_none() && self.reduce.is_none() && self.startkey.is_none()
    }

    fn into_iter(self) -> Result<std::vec::IntoIter<(String, String)>, Error> {

        // It's possible to construct an iterator that doesn't use a vector or
        // other container, but it requires a lot more code and is less clear.

        let mut v = Vec::new();
        if let Some(x) = self.endkey {
            let s = try!(serde_json::to_string(&x)
                             .map_err(|e| Error::Encode(EncodeErrorKind::Serde { cause: e })));
            v.push(("endkey".to_string(), s));
        }
        if let Some(x) = self.reduce {
            v.push(("reduce".to_string(), x.to_string()));
        }
        if let Some(x) = self.startkey {
            let s = try!(serde_json::to_string(&x)
                             .map_err(|e| Error::Encode(EncodeErrorKind::Serde { cause: e })));
            v.push(("startkey".to_string(), s));
        }
        Ok(v.into_iter())
    }
}

/// Action to execute a view.
///
/// # Errors
///
/// The following are some of the errors that may occur as a result of executing
/// this action:
///
/// * `Error::InternalServerError`: An error occurred when executing the view.
/// * `Error::NotFound`: The view does not exist.
/// * `Error::Unauthorized`: The client is unauthorized.
///
pub struct GetView<'a, P, K, V>
    where P: IntoViewPath,
          K: serde::Deserialize + serde::Serialize,
          V: serde::Deserialize
{
    client_state: &'a ClientState,
    path: P,
    query: QueryParams<K>,
    _phantom_key: std::marker::PhantomData<K>,
    _phantom_value: std::marker::PhantomData<V>,
}

impl<'a, P, K, V> GetView<'a, P, K, V>
    where P: IntoViewPath,
          K: serde::Deserialize + serde::Serialize,
          V: serde::Deserialize
{
    #[doc(hidden)]
    pub fn new(client_state: &'a ClientState, path: P) -> Self {
        GetView {
            client_state: client_state,
            path: path,
            query: Default::default(),
            _phantom_key: std::marker::PhantomData,
            _phantom_value: std::marker::PhantomData,
        }
    }

    /// Sets the minimum key for rows contained within the result.
    pub fn endkey(mut self, key: K) -> Self {
        self.query.endkey = Some(key);
        self
    }

    /// Sets whether to run the `reduce` view function.
    pub fn reduce(mut self, v: bool) -> Self {
        self.query.reduce = Some(v);
        self
    }

    /// Sets the maximum key for rows contained within the result.
    pub fn startkey(mut self, key: K) -> Self {
        self.query.startkey = Some(key);
        self
    }

    impl_action_public_methods!(ViewResult<K, V>);
}

impl<'a, P, K, V> Action for GetView<'a, P, K, V>
    where P: IntoViewPath,
          K: serde::Deserialize + serde::Serialize,
          V: serde::Deserialize
{
    type Output = ViewResult<K, V>;
    type State = ();

    fn make_request(self) -> Result<(Request, Self::State), Error> {
        let uri = {
            let mut uri = try!(self.path.into_view_path()).into_uri(self.client_state.uri.clone());
            if !self.query.is_default() {
                uri.set_query_from_pairs(try!(self.query.into_iter()));
            }
            uri
        };
        let request = Request::new(hyper::Get, uri).set_accept_application_json();
        Ok((request, ()))
    }

    fn take_response<R>(mut response: R, _state: Self::State) -> Result<Self::Output, Error>
        where R: Response
    {
        match response.status() {
            hyper::status::StatusCode::Ok => {
                try!(response.content_type_must_be_application_json());
                let view_result = try!(response.decode_json_all::<ViewResult<K, V>>());
                Ok(view_result)
            }
            hyper::status::StatusCode::BadRequest => Err(make_couchdb_error!(BadRequest, response)),
            hyper::status::StatusCode::Unauthorized => {
                Err(make_couchdb_error!(Unauthorized, response))
            }
            hyper::status::StatusCode::NotFound => Err(make_couchdb_error!(NotFound, response)),
            hyper::status::StatusCode::InternalServerError => {
                Err(make_couchdb_error!(InternalServerError, response))
            }
            _ => Err(Error::UnexpectedHttpStatus { got: response.status() }),
        }
    }
}

#[cfg(test)]
mod tests {

    use hyper;
    use serde_json;
    use std;

    use DocumentId;
    use ViewPath;
    use ViewRow;
    use client::ClientState;
    use action::{Action, JsonResponse};
    use super::{GetView, QueryParams};

    #[test]
    fn query_iterator() {
        let query = QueryParams {
            endkey: Some("foo"),
            reduce: Some(true),
            startkey: Some("bar"),
        };
        let expected = vec![
            ("endkey".to_string(), "\"foo\"".to_string()),
            ("reduce".to_string(), "true".to_string()),
            ("startkey".to_string(), "\"bar\"".to_string()),
        ]
                           .into_iter()
                           .collect::<std::collections::BTreeMap<_, _>>();
        let got = query.into_iter().unwrap().collect();
        assert_eq!(expected, got);
    }

    #[test]
    fn make_request_default() {
        let client_state = ClientState::new("http://example.com:1234/").unwrap();
        let action = GetView::<_, String, i32>::new(&client_state, "/foo/_design/bar/_view/qux");
        let (request, _) = action.make_request().unwrap();
        expect_request_method!(request, hyper::Get);
        expect_request_uri!(request, "http://example.com:1234/foo/_design/bar/_view/qux");
        expect_request_accept_application_json!(request);
    }

    #[test]
    fn make_request_reduce() {
        let client_state = ClientState::new("http://example.com:1234/").unwrap();
        let action = GetView::<_, String, i32>::new(&client_state, "/foo/_design/bar/_view/qux")
                         .reduce(true);
        let (request, _) = action.make_request().unwrap();
        expect_request_method!(request, hyper::Get);
        expect_request_uri!(request,
                            "http://example.com:1234/foo/_design/bar/_view/qux?reduce=true");
        expect_request_accept_application_json!(request);
    }

    #[test]
    fn make_request_startkey() {
        let client_state = ClientState::new("http://example.com:1234/").unwrap();
        let path = ViewPath::parse("/foo/_design/bar/_view/qux").unwrap();
        let action = GetView::<ViewPath, String, i32>::new(&client_state, path)
                         .startkey("baz".to_string());
        let (request, ()) = action.make_request().unwrap();
        expect_request_method!(request, hyper::Get);
        expect_request_uri!(request,
                            "http://example.com:1234/foo/_design/bar/_view/qux?startkey=\"baz\"");
        expect_request_accept_application_json!(request);
    }

    #[test]
    fn make_request_endkey() {
        let client_state = ClientState::new("http://example.com:1234/").unwrap();
        let path = ViewPath::parse("/foo/_design/bar/_view/qux").unwrap();
        let action = GetView::<ViewPath, String, i32>::new(&client_state, path)
                         .endkey("baz".to_string());
        let (request, _) = action.make_request().unwrap();
        expect_request_method!(request, hyper::Get);
        expect_request_uri!(request,
                            "http://example.com:1234/foo/_design/bar/_view/qux?endkey=\"baz\"");
        expect_request_accept_application_json!(request);
    }

    #[test]
    fn take_response_ok() {
        let source = serde_json::builder::ObjectBuilder::new()
                         .insert("offset", 17)
                         .insert_array("rows", |x| {
                             x.push_object(|x| {
                                 x.insert("id", "foo")
                                  .insert("key", "alpha")
                                  .insert("value", 5)
                             })
                         })
                         .insert("total_rows", 42)
                         .unwrap();
        let response = JsonResponse::new(hyper::Ok, &source);
        let got = GetView::<ViewPath, String, i32>::take_response(response, ()).unwrap();
        assert_eq!(got.total_rows, Some(42));
        assert_eq!(got.offset, Some(17));
        assert_eq!(got.rows,
                   vec![{
                            let mut x = ViewRow::new(5);
                            x.id = Some(DocumentId::Normal("foo".into()));
                            x.key = Some("alpha".to_string());
                            x
                        }]);
    }

    #[test]
    fn take_response_bad_request() {
        let source = serde_json::builder::ObjectBuilder::new()
                         .insert("error", "bad_request")
                         .insert("reason", "blah blah blah")
                         .unwrap();
        let response = JsonResponse::new(hyper::BadRequest, &source);
        let got = GetView::<ViewPath, String, i32>::take_response(response, ());
        expect_couchdb_error!(got, BadRequest);
    }

    #[test]
    fn take_response_internal_server_error() {
        let source = serde_json::builder::ObjectBuilder::new()
                         .insert("error", "internal_server_error")
                         .insert("reason", "blah blah blah")
                         .unwrap();
        let response = JsonResponse::new(hyper::status::StatusCode::InternalServerError, &source);
        let got = GetView::<ViewPath, String, i32>::take_response(response, ());
        expect_couchdb_error!(got, InternalServerError);
    }

    #[test]
    fn take_response_not_found() {
        let source = serde_json::builder::ObjectBuilder::new()
                         .insert("error", "not_found")
                         .insert("reason", "blah blah blah")
                         .unwrap();
        let response = JsonResponse::new(hyper::NotFound, &source);
        let got = GetView::<ViewPath, String, i32>::take_response(response, ());
        expect_couchdb_error!(got, NotFound);
    }

    #[test]
    fn take_response_unauthorized() {
        let source = serde_json::builder::ObjectBuilder::new()
                         .insert("error", "unauthorized")
                         .insert("reason", "blah blah blah")
                         .unwrap();
        let response = JsonResponse::new(hyper::status::StatusCode::Unauthorized, &source);
        let got = GetView::<ViewPath, String, i32>::take_response(response, ());
        expect_couchdb_error!(got, Unauthorized);
    }
}
<|endoftext|>


<commit_before>// ignore-windows: No libc on Windows
// compile-flags: -Zmiri-disable-isolation

#![feature(rustc_private)]

extern crate libc;

#[cfg(not(target_os = "macos"))]
fn test_posix_fadvise() {
    use std::convert::TryInto;
    use std::env::temp_dir;
    use std::fs::{File, remove_file};
    use std::io::Write;
    use std::os::unix::io::AsRawFd;

    let path = temp_dir().join("miri_test_libc.txt");
    // Cleanup before test
    remove_file(&path).ok();

    // Set up an open file
    let mut file = File::create(&path).unwrap();
    let bytes = b"Hello, World!\n";
    file.write(bytes).unwrap();

    // Test calling posix_fadvise on a file.
    let result = unsafe {
        libc::posix_fadvise(
            file.as_raw_fd(),
            0,
            bytes.len().try_into().unwrap(),
            libc::POSIX_FADV_DONTNEED,
        )
    };
    drop(file);
    remove_file(&path).unwrap();
    assert_eq!(result, 0);
}

fn main() {
    #[cfg(not(target_os = "macos"))]
    test_posix_fadvise();
}
<commit_msg>Conditional compilation fix<commit_after>// ignore-windows: No libc on Windows
// compile-flags: -Zmiri-disable-isolation

#![feature(rustc_private)]

#[allow(unused)] // necessary on macos due to conditional compilation
extern crate libc;

#[cfg(not(target_os = "macos"))]
fn test_posix_fadvise() {
    use std::convert::TryInto;
    use std::env::temp_dir;
    use std::fs::{File, remove_file};
    use std::io::Write;
    use std::os::unix::io::AsRawFd;

    let path = temp_dir().join("miri_test_libc.txt");
    // Cleanup before test
    remove_file(&path).ok();

    // Set up an open file
    let mut file = File::create(&path).unwrap();
    let bytes = b"Hello, World!\n";
    file.write(bytes).unwrap();

    // Test calling posix_fadvise on a file.
    let result = unsafe {
        libc::posix_fadvise(
            file.as_raw_fd(),
            0,
            bytes.len().try_into().unwrap(),
            libc::POSIX_FADV_DONTNEED,
        )
    };
    drop(file);
    remove_file(&path).unwrap();
    assert_eq!(result, 0);
}

fn main() {
    #[cfg(not(target_os = "macos"))]
    test_posix_fadvise();
}
<|endoftext|>


<commit_before>//! Compute dominators of a control-flow graph.
//!
//! # The Dominance Relation
//!
//! In a directed graph with a root node **R**, a node **A** is said to *dominate* a
//! node **B** iff every path from **R** to **B** contains **A**.
//!
//! The node **A** is said to *strictly dominate* the node **B** iff **A** dominates
//! **B** and **A ≠ B**.
//!
//! The node **A** is said to be the *immediate dominator* of a node **B** iff it
//! strictly dominates **B** and there does not exist any node **C** where **A**
//! dominates **C** and **C** dominates **B**.

use std::collections::{HashMap, HashSet};
use std::hash::Hash;

use visit::{DfsPostOrder, GraphBase, IntoNeighbors, Visitable, Walker};

/// The dominance relation for some graph and root.
#[derive(Debug, Clone)]
pub struct Dominators<N>
    where N: Copy + Eq + Hash
{
    root: N,
    dominators: HashMap<N, N>,
}

impl<N> Dominators<N>
    where N: Copy + Eq + Hash
{
    /// Get the root node used to construct these dominance relations.
    pub fn root(&self) -> N {
        self.root
    }

    /// Get the immediate dominator of the given node.
    ///
    /// Returns `None` for any node that is not reachable from the root, and for
    /// the root itself.
    pub fn immediate_dominator(&self, node: N) -> Option<N> {
        if node == self.root {
            None
        } else {
            self.dominators.get(&node).cloned()
        }
    }

    /// Iterate over the given node's that strict dominators.
    ///
    /// If the given node is not reachable from the root, then `None` is
    /// returned.
    pub fn strict_dominators(&self, node: N) -> Option<DominatorsIter<N>> {
        if self.dominators.contains_key(&node) {
            Some(DominatorsIter {
                dominators: self,
                node: self.immediate_dominator(node),
            })
        } else {
            None
        }
    }

    /// Iterate over all of the given node's dominators (including the given
    /// node itself).
    ///
    /// If the given node is not reachable from the root, then `None` is
    /// returned.
    pub fn dominators(&self, node: N) -> Option<DominatorsIter<N>> {
        if self.dominators.contains_key(&node) {
            Some(DominatorsIter {
                dominators: self,
                node: Some(node),
            })
        } else {
            None
        }
    }
}

/// Iterator for a node's dominators.
pub struct DominatorsIter<'a, N>
    where N: 'a + Copy + Eq + Hash
{
    dominators: &'a Dominators<N>,
    node: Option<N>,
}

impl<'a, N> Iterator for DominatorsIter<'a, N>
    where N: 'a + Copy + Eq + Hash
{
    type Item = N;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.node.take();
        if let Some(next) = next {
            self.node = self.dominators.immediate_dominator(next);
        }
        next
    }
}

/// The undefined dominator sentinel, for when we have not yet discovered a
/// node's dominator.
const UNDEFINED: usize = ::std::usize::MAX;

/// This is an implementation of the engineered ["Simple, Fast Dominance
/// Algorithm"][0] discovered by Cooper et al.
///
/// This algorithm is **O(|V|²)**, and therefore has slower theoretical running time
/// than the Lengauer-Tarjan algorithm (which is **O(|E| log |V|)**. However,
/// Cooper et al found it to be faster in practice on control flow graphs of up
/// to ~30,000 vertices.
///
/// [0]: http://www.cs.rice.edu/~keith/EMBED/dom.pdf
pub fn simple_fast<G>(graph: G, root: G::NodeId) -> Dominators<G::NodeId>
    where G: IntoNeighbors + Visitable,
          <G as GraphBase>::NodeId: Eq + Hash
{
    let (post_order, predecessor_sets) = simple_fast_post_order(graph, root);
    let length = post_order.len();
    debug_assert!(length > 0);
    debug_assert!(post_order.last() == Some(&root));

    // From here on out we use indices into `post_order` instead of actual
    // `NodeId`s wherever possible. This greatly improves the performance of
    // this implementation, but we have to pay a little bit of upfront cost to
    // convert our data structures to play along first.

    // Maps a node to its index into `post_order`.
    let node_to_post_order_idx: HashMap<_, _> = post_order.iter()
        .enumerate()
        .map(|(idx, &node)| (node, idx))
        .collect();

    // Maps a node's `post_order` index to its set of predecessors's indices
    // into `post_order` (as a vec).
    let idx_to_predecessor_vec =
        predecessor_sets_to_idx_vecs(&post_order, &node_to_post_order_idx, predecessor_sets);

    let mut dominators = vec![UNDEFINED; length];
    dominators[length - 1] = length - 1;

    let mut changed = true;
    while changed {
        changed = false;

        // Iterate in reverse post order, skipping the root.

        for idx in (0..length - 1).rev() {
            debug_assert!(post_order[idx] != root);

            // Take the intersection of every predecessor's dominator set; that
            // is the current best guess at the immediate dominator for this
            // node.

            let new_idom_idx = {
                let mut predecessors =
                    idx_to_predecessor_vec[idx].iter().filter(|&&p| dominators[p] != UNDEFINED);
                let new_idom_idx = predecessors.next()
                    .expect("Because the root is initialized to dominate itself, and is the \
                             first node in every path, there must exist a predecessor to this \
                             node that also has a dominator");
                predecessors.fold(*new_idom_idx, |new_idom_idx, &predecessor_idx| {
                    intersect(&dominators, new_idom_idx, predecessor_idx)
                })
            };

            debug_assert!(new_idom_idx < length);

            if new_idom_idx != dominators[idx] {
                dominators[idx] = new_idom_idx;
                changed = true;
            }
        }
    }

    // All done! Translate the indices back into proper `G::NodeId`s.

    debug_assert!(!dominators.iter().any(|&dom| dom == UNDEFINED));

    Dominators {
        root: root,
        dominators: dominators.into_iter()
            .enumerate()
            .map(|(idx, dom_idx)| (post_order[idx], post_order[dom_idx]))
            .collect(),
    }
}

fn intersect(dominators: &[usize], mut finger1: usize, mut finger2: usize) -> usize {
    while finger1 != finger2 {
        if finger1 < finger2 {
            finger1 = dominators[finger1];
        } else if finger2 < finger1 {
            finger2 = dominators[finger2];
        }
    }
    finger1
}

fn predecessor_sets_to_idx_vecs<N>(post_order: &[N],
                                   node_to_post_order_idx: &HashMap<N, usize>,
                                   mut predecessor_sets: HashMap<N, HashSet<N>>)
                                   -> Vec<Vec<usize>>
    where N: Copy + Eq + Hash
{
    post_order.iter()
        .map(|node| {
            predecessor_sets.remove(node)
                .map(|predecessors| {
                    predecessors.into_iter()
                        .map(|p| *node_to_post_order_idx.get(&p).unwrap())
                        .collect()
                })
                .unwrap_or_else(Vec::new)
        })
        .collect()
}

fn simple_fast_post_order<G>(graph: G,
                             root: G::NodeId)
                             -> (Vec<G::NodeId>, HashMap<G::NodeId, HashSet<G::NodeId>>)
    where G: IntoNeighbors + Visitable,
          <G as GraphBase>::NodeId: Eq + Hash
{
    let mut post_order = vec![];
    let mut predecessor_sets = HashMap::new();

    for node in DfsPostOrder::new(graph, root).iter(graph) {
        post_order.push(node);

        for successor in graph.neighbors(node) {
            predecessor_sets.entry(successor)
                .or_insert_with(HashSet::new)
                .insert(node);
        }
    }

    (post_order, predecessor_sets)
}

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

    #[test]
    fn test_iter_dominators() {
        let doms: Dominators<u32> = Dominators {
            root: 0,
            dominators: [(2, 1), (1, 0), (0, 0)]
                .iter()
                .cloned()
                .collect(),
        };

        let all_doms: Vec<_> = doms.dominators(2).unwrap().collect();
        assert_eq!(vec![2, 1, 0], all_doms);

        assert_eq!(None::<()>, doms.dominators(99).map(|_| unreachable!()));

        let strict_doms: Vec<_> = doms.strict_dominators(2).unwrap().collect();
        assert_eq!(vec![1, 0], strict_doms);

        assert_eq!(None::<()>, doms.strict_dominators(99).map(|_| unreachable!()));
    }
}
<commit_msg>Fix typo in documentation<commit_after>//! Compute dominators of a control-flow graph.
//!
//! # The Dominance Relation
//!
//! In a directed graph with a root node **R**, a node **A** is said to *dominate* a
//! node **B** iff every path from **R** to **B** contains **A**.
//!
//! The node **A** is said to *strictly dominate* the node **B** iff **A** dominates
//! **B** and **A ≠ B**.
//!
//! The node **A** is said to be the *immediate dominator* of a node **B** iff it
//! strictly dominates **B** and there does not exist any node **C** where **A**
//! dominates **C** and **C** dominates **B**.

use std::collections::{HashMap, HashSet};
use std::hash::Hash;

use visit::{DfsPostOrder, GraphBase, IntoNeighbors, Visitable, Walker};

/// The dominance relation for some graph and root.
#[derive(Debug, Clone)]
pub struct Dominators<N>
    where N: Copy + Eq + Hash
{
    root: N,
    dominators: HashMap<N, N>,
}

impl<N> Dominators<N>
    where N: Copy + Eq + Hash
{
    /// Get the root node used to construct these dominance relations.
    pub fn root(&self) -> N {
        self.root
    }

    /// Get the immediate dominator of the given node.
    ///
    /// Returns `None` for any node that is not reachable from the root, and for
    /// the root itself.
    pub fn immediate_dominator(&self, node: N) -> Option<N> {
        if node == self.root {
            None
        } else {
            self.dominators.get(&node).cloned()
        }
    }

    /// Iterate over the given node's strict dominators.
    ///
    /// If the given node is not reachable from the root, then `None` is
    /// returned.
    pub fn strict_dominators(&self, node: N) -> Option<DominatorsIter<N>> {
        if self.dominators.contains_key(&node) {
            Some(DominatorsIter {
                dominators: self,
                node: self.immediate_dominator(node),
            })
        } else {
            None
        }
    }

    /// Iterate over all of the given node's dominators (including the given
    /// node itself).
    ///
    /// If the given node is not reachable from the root, then `None` is
    /// returned.
    pub fn dominators(&self, node: N) -> Option<DominatorsIter<N>> {
        if self.dominators.contains_key(&node) {
            Some(DominatorsIter {
                dominators: self,
                node: Some(node),
            })
        } else {
            None
        }
    }
}

/// Iterator for a node's dominators.
pub struct DominatorsIter<'a, N>
    where N: 'a + Copy + Eq + Hash
{
    dominators: &'a Dominators<N>,
    node: Option<N>,
}

impl<'a, N> Iterator for DominatorsIter<'a, N>
    where N: 'a + Copy + Eq + Hash
{
    type Item = N;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.node.take();
        if let Some(next) = next {
            self.node = self.dominators.immediate_dominator(next);
        }
        next
    }
}

/// The undefined dominator sentinel, for when we have not yet discovered a
/// node's dominator.
const UNDEFINED: usize = ::std::usize::MAX;

/// This is an implementation of the engineered ["Simple, Fast Dominance
/// Algorithm"][0] discovered by Cooper et al.
///
/// This algorithm is **O(|V|²)**, and therefore has slower theoretical running time
/// than the Lengauer-Tarjan algorithm (which is **O(|E| log |V|)**. However,
/// Cooper et al found it to be faster in practice on control flow graphs of up
/// to ~30,000 vertices.
///
/// [0]: http://www.cs.rice.edu/~keith/EMBED/dom.pdf
pub fn simple_fast<G>(graph: G, root: G::NodeId) -> Dominators<G::NodeId>
    where G: IntoNeighbors + Visitable,
          <G as GraphBase>::NodeId: Eq + Hash
{
    let (post_order, predecessor_sets) = simple_fast_post_order(graph, root);
    let length = post_order.len();
    debug_assert!(length > 0);
    debug_assert!(post_order.last() == Some(&root));

    // From here on out we use indices into `post_order` instead of actual
    // `NodeId`s wherever possible. This greatly improves the performance of
    // this implementation, but we have to pay a little bit of upfront cost to
    // convert our data structures to play along first.

    // Maps a node to its index into `post_order`.
    let node_to_post_order_idx: HashMap<_, _> = post_order.iter()
        .enumerate()
        .map(|(idx, &node)| (node, idx))
        .collect();

    // Maps a node's `post_order` index to its set of predecessors's indices
    // into `post_order` (as a vec).
    let idx_to_predecessor_vec =
        predecessor_sets_to_idx_vecs(&post_order, &node_to_post_order_idx, predecessor_sets);

    let mut dominators = vec![UNDEFINED; length];
    dominators[length - 1] = length - 1;

    let mut changed = true;
    while changed {
        changed = false;

        // Iterate in reverse post order, skipping the root.

        for idx in (0..length - 1).rev() {
            debug_assert!(post_order[idx] != root);

            // Take the intersection of every predecessor's dominator set; that
            // is the current best guess at the immediate dominator for this
            // node.

            let new_idom_idx = {
                let mut predecessors =
                    idx_to_predecessor_vec[idx].iter().filter(|&&p| dominators[p] != UNDEFINED);
                let new_idom_idx = predecessors.next()
                    .expect("Because the root is initialized to dominate itself, and is the \
                             first node in every path, there must exist a predecessor to this \
                             node that also has a dominator");
                predecessors.fold(*new_idom_idx, |new_idom_idx, &predecessor_idx| {
                    intersect(&dominators, new_idom_idx, predecessor_idx)
                })
            };

            debug_assert!(new_idom_idx < length);

            if new_idom_idx != dominators[idx] {
                dominators[idx] = new_idom_idx;
                changed = true;
            }
        }
    }

    // All done! Translate the indices back into proper `G::NodeId`s.

    debug_assert!(!dominators.iter().any(|&dom| dom == UNDEFINED));

    Dominators {
        root: root,
        dominators: dominators.into_iter()
            .enumerate()
            .map(|(idx, dom_idx)| (post_order[idx], post_order[dom_idx]))
            .collect(),
    }
}

fn intersect(dominators: &[usize], mut finger1: usize, mut finger2: usize) -> usize {
    while finger1 != finger2 {
        if finger1 < finger2 {
            finger1 = dominators[finger1];
        } else if finger2 < finger1 {
            finger2 = dominators[finger2];
        }
    }
    finger1
}

fn predecessor_sets_to_idx_vecs<N>(post_order: &[N],
                                   node_to_post_order_idx: &HashMap<N, usize>,
                                   mut predecessor_sets: HashMap<N, HashSet<N>>)
                                   -> Vec<Vec<usize>>
    where N: Copy + Eq + Hash
{
    post_order.iter()
        .map(|node| {
            predecessor_sets.remove(node)
                .map(|predecessors| {
                    predecessors.into_iter()
                        .map(|p| *node_to_post_order_idx.get(&p).unwrap())
                        .collect()
                })
                .unwrap_or_else(Vec::new)
        })
        .collect()
}

fn simple_fast_post_order<G>(graph: G,
                             root: G::NodeId)
                             -> (Vec<G::NodeId>, HashMap<G::NodeId, HashSet<G::NodeId>>)
    where G: IntoNeighbors + Visitable,
          <G as GraphBase>::NodeId: Eq + Hash
{
    let mut post_order = vec![];
    let mut predecessor_sets = HashMap::new();

    for node in DfsPostOrder::new(graph, root).iter(graph) {
        post_order.push(node);

        for successor in graph.neighbors(node) {
            predecessor_sets.entry(successor)
                .or_insert_with(HashSet::new)
                .insert(node);
        }
    }

    (post_order, predecessor_sets)
}

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

    #[test]
    fn test_iter_dominators() {
        let doms: Dominators<u32> = Dominators {
            root: 0,
            dominators: [(2, 1), (1, 0), (0, 0)]
                .iter()
                .cloned()
                .collect(),
        };

        let all_doms: Vec<_> = doms.dominators(2).unwrap().collect();
        assert_eq!(vec![2, 1, 0], all_doms);

        assert_eq!(None::<()>, doms.dominators(99).map(|_| unreachable!()));

        let strict_doms: Vec<_> = doms.strict_dominators(2).unwrap().collect();
        assert_eq!(vec![1, 0], strict_doms);

        assert_eq!(None::<()>, doms.strict_dominators(99).map(|_| unreachable!()));
    }
}
<|endoftext|>


<commit_before>extern crate inkwell;

use self::inkwell::context::Context;
use self::inkwell::module::Module;
use self::inkwell::targets::{
    ByteOrdering, CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetData,
    TargetMachine, TargetTriple,
};
use self::inkwell::OptimizationLevel;

#[test]
fn test_section_iterator() {
    Target::initialize_native(&InitializationConfig::default())
        .expect("Failed to initialize native target");
    let target_triple = TargetMachine::get_default_triple();
    let target = Target::from_triple(&target_triple).unwrap();
    let target_machine = target
        .create_target_machine(
            &target_triple,
            &TargetMachine::get_host_cpu_name().to_string(),
            &TargetMachine::get_host_cpu_features().to_string(),
            OptimizationLevel::None,
            RelocMode::Static,
            CodeModel::Small,
        )
        .unwrap();

    let context = Context::create();
    let mut module = context.create_module("my_module");
    module.set_inline_assembly(
        ".section A\n\
        .byte 1\n\
        .section B\n\
        .byte 2, 2\n\
        .section C\n\
        .byte 3, 3, 3",
    );
    module.set_triple(&target_triple);
    module.set_data_layout(&target_machine.get_target_data().get_data_layout());

    let memory_buffer = target_machine
        .write_to_memory_buffer(&mut module, FileType::Object)
        .unwrap();
    let object_file = memory_buffer.create_object_file().unwrap();

    let mut has_section_a = false;
    let mut has_section_b = false;
    let mut has_section_c = false;
    for (i, section) in object_file.get_sections().enumerate() {
        // TODO: the first section has no name, skip it.
        if i == 0 {
            continue;
        }
        match section.get_name().to_str().unwrap() {
            "A" => {
                assert!(!has_section_a);
                has_section_a = true;
                assert_eq!(section.size(), 1);
            }
            "B" => {
                assert!(!has_section_b);
                has_section_b = true;
                assert_eq!(section.size(), 2);
            }
            "C" => {
                assert!(!has_section_c);
                has_section_c = true;
                assert_eq!(section.size(), 3);
            }
            _ => {}
        }
    }
    assert!(has_section_a);
    assert!(has_section_b);
    assert!(has_section_c);
}
<commit_msg>Expand the tests to cover symbol and relocation iterators.<commit_after>extern crate inkwell;

use self::inkwell::context::Context;
use self::inkwell::module::Module;
use self::inkwell::targets::{
    ByteOrdering, CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetData,
    TargetMachine, TargetTriple,
};
use self::inkwell::values::BasicValue;
use self::inkwell::OptimizationLevel;

fn get_native_target_machine() -> TargetMachine {
    Target::initialize_native(&InitializationConfig::default())
        .expect("Failed to initialize native target");
    let target_triple = TargetMachine::get_default_triple();
    let target = Target::from_triple(&target_triple).unwrap();
    target
        .create_target_machine(
            &target_triple,
            &TargetMachine::get_host_cpu_name().to_string(),
            &TargetMachine::get_host_cpu_features().to_string(),
            OptimizationLevel::None,
            RelocMode::Static,
            CodeModel::Small,
        )
        .unwrap()
}

#[test]
fn test_section_iterator() {
    let target_machine = get_native_target_machine();

    let context = Context::create();
    let mut module = context.create_module("my_module");

    let gv_a = module.add_global(context.i8_type(), None, "a");
    gv_a.set_initializer(&context.i8_type().const_zero().as_basic_value_enum());
    gv_a.set_section("A");

    let gv_b = module.add_global(context.i16_type(), None, "b");
    gv_b.set_initializer(&context.i16_type().const_zero().as_basic_value_enum());
    gv_b.set_section("B");

    let gv_c = module.add_global(context.i32_type(), None, "c");
    gv_c.set_initializer(&context.i32_type().const_zero().as_basic_value_enum());
    gv_c.set_section("C");

    module.set_triple(&target_machine.get_triple());
    module.set_data_layout(&target_machine.get_target_data().get_data_layout());

    let memory_buffer = target_machine
        .write_to_memory_buffer(&mut module, FileType::Object)
        .unwrap();
    let object_file = memory_buffer.create_object_file().unwrap();

    let mut has_section_a = false;
    let mut has_section_b = false;
    let mut has_section_c = false;
    for (i, section) in object_file.get_sections().enumerate() {
        // TODO: the first section has no name, skip it.
        if i == 0 {
            continue;
        }
        match section.get_name().to_str().unwrap() {
            "A" => {
                assert!(!has_section_a);
                has_section_a = true;
                assert_eq!(section.size(), 1);
            }
            "B" => {
                assert!(!has_section_b);
                has_section_b = true;
                assert_eq!(section.size(), 2);
            }
            "C" => {
                assert!(!has_section_c);
                has_section_c = true;
                assert_eq!(section.size(), 4);
            }
            _ => {}
        }
    }
    assert!(has_section_a);
    assert!(has_section_b);
    assert!(has_section_c);
}

#[test]
fn test_symbol_iterator() {
    let target_machine = get_native_target_machine();

    let context = Context::create();
    let mut module = context.create_module("my_module");
    module
        .add_global(context.i8_type(), None, "a")
        .set_initializer(&context.i8_type().const_zero().as_basic_value_enum());
    module
        .add_global(context.i16_type(), None, "b")
        .set_initializer(&context.i16_type().const_zero().as_basic_value_enum());
    module
        .add_global(context.i32_type(), None, "c")
        .set_initializer(&context.i32_type().const_zero().as_basic_value_enum());
    module.set_triple(&target_machine.get_triple());
    module.set_data_layout(&target_machine.get_target_data().get_data_layout());

    let memory_buffer = target_machine
        .write_to_memory_buffer(&mut module, FileType::Object)
        .unwrap();
    let object_file = memory_buffer.create_object_file().unwrap();

    let mut has_symbol_a = false;
    let mut has_symbol_b = false;
    let mut has_symbol_c = false;
    for symbol in object_file.get_symbols() {
        match symbol.get_name().to_str().unwrap() {
            "a" => {
                assert!(!has_symbol_a);
                has_symbol_a = true;
                assert_eq!(symbol.size(), 1);
            }
            "b" => {
                assert!(!has_symbol_b);
                has_symbol_b = true;
                assert_eq!(symbol.size(), 2);
            }
            "c" => {
                assert!(!has_symbol_c);
                has_symbol_c = true;
                assert_eq!(symbol.size(), 4);
            }
            _ => {}
        }
    }
    assert!(has_symbol_a);
    assert!(has_symbol_b);
    assert!(has_symbol_c);
}

#[test]
fn test_reloc_iterator() {
    let target_machine = get_native_target_machine();

    let context = Context::create();
    let mut module = context.create_module("my_module");
    let x_ptr = module
        .add_global(context.i8_type(), None, "x")
        .as_pointer_value();
    let x_plus_4 = x_ptr
        .const_to_int(context.i64_type())
        .const_add(context.i64_type().const_int(4, false));
    module
        .add_global(context.i64_type(), None, "a")
        .set_initializer(&x_plus_4);

    module.set_triple(&target_machine.get_triple());
    module.set_data_layout(&target_machine.get_target_data().get_data_layout());

    let memory_buffer = target_machine
        .write_to_memory_buffer(&mut module, FileType::Object)
        .unwrap();
    let object_file = memory_buffer.create_object_file().unwrap();

    let mut found_relocation = false;
    for section in object_file.get_sections() {
        for reloc in section.get_relocations() {
            found_relocation = true;
            // We don't stop the traversal here, so as to exercise the iterators.
        }
    }
    assert!(found_relocation);
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

// The `Version` object is reexported from the `instance` module.

use std::{fmt, num::ParseIntError, str::FromStr};

/// Represents an API version of Vulkan.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Version {
    /// Major version number.
    pub major: u32,
    /// Minor version number.
    pub minor: u32,
    /// Patch version number.
    pub patch: u32,
}

impl Version {
    pub const V1_0: Version = Version::major_minor(1, 0);
    pub const V1_1: Version = Version::major_minor(1, 1);
    pub const V1_2: Version = Version::major_minor(1, 2);
    pub const V1_3: Version = Version::major_minor(1, 3);
    pub const V1_4: Version = Version::major_minor(1, 4);
    pub const V1_5: Version = Version::major_minor(1, 5);

    /// Constructs a `Version` from the given major and minor version numbers.
    #[inline]
    pub const fn major_minor(major: u32, minor: u32) -> Version {
        Version {
            major,
            minor,
            patch: 0,
        }
    }
}

impl Default for Version {
    fn default() -> Self {
        Self::V1_0
    }
}

impl From<u32> for Version {
    #[inline]
    fn from(val: u32) -> Self {
        Version {
            major: ash::vk::api_version_major(val),
            minor: ash::vk::api_version_minor(val),
            patch: ash::vk::api_version_patch(val),
        }
    }
}

impl TryFrom<Version> for u32 {
    type Error = ();

    #[inline]
    fn try_from(val: Version) -> Result<Self, Self::Error> {
        if val.major <= 0x3ff && val.minor <= 0x3ff && val.patch <= 0xfff {
            Ok(ash::vk::make_api_version(
                0, val.major, val.minor, val.patch,
            ))
        } else {
            Err(())
        }
    }
}

impl FromStr for Version {
    type Err = ParseIntError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut iter = s.splitn(3, '.');
        let major: u32 = iter.next().unwrap().parse()?;
        let minor: u32 = iter.next().map_or(Ok(0), |n| n.parse())?;
        let patch: u32 = iter.next().map_or(Ok(0), |n| n.parse())?;

        Ok(Version {
            major,
            minor,
            patch,
        })
    }
}

impl fmt::Debug for Version {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
    }
}

impl fmt::Display for Version {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, formatter)
    }
}

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

    #[test]
    fn into_vk_version() {
        let version = Version {
            major: 1,
            minor: 0,
            patch: 0,
        };
        assert_eq!(u32::try_from(version).unwrap(), 0x400000);
    }

    #[test]
    fn greater_major() {
        let v1 = Version {
            major: 1,
            minor: 0,
            patch: 0,
        };
        let v2 = Version {
            major: 2,
            minor: 0,
            patch: 0,
        };
        assert!(v2 > v1);
    }

    #[test]
    fn greater_minor() {
        let v1 = Version {
            major: 1,
            minor: 1,
            patch: 0,
        };
        let v2 = Version {
            major: 1,
            minor: 3,
            patch: 0,
        };
        assert!(v2 > v1);
    }

    #[test]
    fn greater_patch() {
        let v1 = Version {
            major: 1,
            minor: 0,
            patch: 4,
        };
        let v2 = Version {
            major: 1,
            minor: 0,
            patch: 5,
        };
        assert!(v2 > v1);
    }
}
<commit_msg>Add test for Version parsing (#1825)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

// The `Version` object is reexported from the `instance` module.

use std::{fmt, num::ParseIntError, str::FromStr};

/// Represents an API version of Vulkan.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Version {
    /// Major version number.
    pub major: u32,
    /// Minor version number.
    pub minor: u32,
    /// Patch version number.
    pub patch: u32,
}

impl Version {
    pub const V1_0: Version = Version::major_minor(1, 0);
    pub const V1_1: Version = Version::major_minor(1, 1);
    pub const V1_2: Version = Version::major_minor(1, 2);
    pub const V1_3: Version = Version::major_minor(1, 3);
    pub const V1_4: Version = Version::major_minor(1, 4);
    pub const V1_5: Version = Version::major_minor(1, 5);

    /// Constructs a `Version` from the given major and minor version numbers.
    #[inline]
    pub const fn major_minor(major: u32, minor: u32) -> Version {
        Version {
            major,
            minor,
            patch: 0,
        }
    }
}

impl Default for Version {
    fn default() -> Self {
        Self::V1_0
    }
}

impl From<u32> for Version {
    #[inline]
    fn from(val: u32) -> Self {
        Version {
            major: ash::vk::api_version_major(val),
            minor: ash::vk::api_version_minor(val),
            patch: ash::vk::api_version_patch(val),
        }
    }
}

impl TryFrom<Version> for u32 {
    type Error = ();

    #[inline]
    fn try_from(val: Version) -> Result<Self, Self::Error> {
        if val.major <= 0x3ff && val.minor <= 0x3ff && val.patch <= 0xfff {
            Ok(ash::vk::make_api_version(
                0, val.major, val.minor, val.patch,
            ))
        } else {
            Err(())
        }
    }
}

impl FromStr for Version {
    type Err = ParseIntError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut iter = s.splitn(3, '.');
        let major: u32 = iter.next().unwrap().parse()?;
        let minor: u32 = iter.next().map_or(Ok(0), |n| n.parse())?;
        let patch: u32 = iter.next().map_or(Ok(0), |n| n.parse())?;

        Ok(Version {
            major,
            minor,
            patch,
        })
    }
}

impl fmt::Debug for Version {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
    }
}

impl fmt::Display for Version {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, formatter)
    }
}

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

    #[test]
    fn into_vk_version() {
        let version = Version {
            major: 1,
            minor: 0,
            patch: 0,
        };
        assert_eq!(u32::try_from(version).unwrap(), 0x400000);
    }

    #[test]
    fn greater_major() {
        let v1 = Version {
            major: 1,
            minor: 0,
            patch: 0,
        };
        let v2 = Version {
            major: 2,
            minor: 0,
            patch: 0,
        };
        assert!(v2 > v1);
    }

    #[test]
    fn greater_minor() {
        let v1 = Version {
            major: 1,
            minor: 1,
            patch: 0,
        };
        let v2 = Version {
            major: 1,
            minor: 3,
            patch: 0,
        };
        assert!(v2 > v1);
    }

    #[test]
    fn greater_patch() {
        let v1 = Version {
            major: 1,
            minor: 0,
            patch: 4,
        };
        let v2 = Version {
            major: 1,
            minor: 0,
            patch: 5,
        };
        assert!(v2 > v1);
    }

    #[test]
    fn version_parse() {
        assert!(matches!(
            "1.1.1".parse::<Version>(),
            Ok(Version {
                major: 1,
                minor: 1,
                patch: 1,
            })
        ));
        assert!(matches!(
            "1.1".parse::<Version>(),
            Ok(Version {
                major: 1,
                minor: 1,
                patch: 0,
            })
        ));
        assert!(matches!(
            "1".parse::<Version>(),
            Ok(Version {
                major: 1,
                minor: 0,
                patch: 0,
            })
        ));

        assert!("".parse::<Version>().is_err());
        assert!("1.1.1.1".parse::<Version>().is_err());
        assert!("foobar".parse::<Version>().is_err());
        assert!("1.bar".parse::<Version>().is_err());
    }
}
<|endoftext|>


<commit_before>use futures_core::task::{Context, Poll};
use futures_io::AsyncWrite;
use futures_sink::Sink;
use std::fmt;
use std::io;
use std::pin::Pin;
use std::marker::Unpin;
use pin_utils::{unsafe_pinned, unsafe_unpinned};

/// Sink for the [`into_sink`](super::AsyncWriteExt::into_sink) method.
#[must_use = "sinks do nothing unless polled"]
pub struct IntoSink<W> {
    writer: W,
    /// An outstanding block for us to push into the underlying writer, along with an index of how
    /// far into the block we have written already.
    buffer: Option<(usize, Box<dyn AsRef<[u8]>>)>,
}

impl<W: Unpin> Unpin for IntoSink<W> {}

impl<W: AsyncWrite> IntoSink<W> {
    unsafe_pinned!(writer: W);
    unsafe_unpinned!(buffer: Option<(usize, Box<dyn AsRef<[u8]>>)>);

    pub(super) fn new(writer: W) -> Self {
        IntoSink { writer, buffer: None }
    }

    fn project<'a>(self: Pin<&'a mut Self>) -> (Pin<&'a mut W>, &'a mut Option<(usize, Box<dyn AsRef<[u8]>>)>) {
        unsafe {
            let this = self.get_unchecked_mut();
            (Pin::new_unchecked(&mut this.writer), &mut this.buffer)
        }
    }

    /// If we have an outstanding block in `buffer` attempt to push it into the writer, does _not_
    /// flush the writer after it succeeds in pushing the block into it.
    fn poll_flush_buffer(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), io::Error>>
    {
        let (mut writer, buffer) = self.project();
        if let Some((index, block)) = buffer {
            loop {
                let bytes = (**block).as_ref();
                let written = ready!(writer.as_mut().poll_write(cx, &bytes[*index..]))?;
                *index += written;
                if *index == bytes.len() {
                    break;
                }
            }
            *buffer = None;
        }
        Poll::Ready(Ok(()))
    }

}

impl<W: AsyncWrite, Item: AsRef<[u8]> + 'static> Sink<Item> for IntoSink<W> {
    type SinkError = io::Error;

    fn poll_ready(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), Self::SinkError>>
    {
        ready!(self.as_mut().poll_flush_buffer(cx))?;
        Poll::Ready(Ok(()))
    }

    fn start_send(
        mut self: Pin<&mut Self>,
        item: Item,
    ) -> Result<(), Self::SinkError>
    {
        debug_assert!(self.as_mut().buffer().is_none());
        *self.as_mut().buffer() = Some((0, Box::new(item)));
        Ok(())
    }

    fn poll_flush(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), Self::SinkError>>
    {
        ready!(self.as_mut().poll_flush_buffer(cx))?;
        ready!(self.as_mut().writer().poll_flush(cx))?;
        Poll::Ready(Ok(()))
    }

    fn poll_close(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), Self::SinkError>>
    {
        ready!(self.as_mut().poll_flush_buffer(cx))?;
        ready!(self.as_mut().writer().poll_close(cx))?;
        Poll::Ready(Ok(()))
    }
}

impl<W: fmt::Debug> fmt::Debug for IntoSink<W> {

    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let buffer = self.buffer.as_ref().map(|(size, block)| {
            (size, format!("[... {} bytes ...]", (**block).as_ref().len()))
        });
        f.debug_struct("IntoSink")
            .field("writer", &self.writer)
            .field("buffer", &buffer)
            .finish()?;
        Ok(())
    }
}
<commit_msg>Fix very complex type lint<commit_after>use futures_core::task::{Context, Poll};
use futures_io::AsyncWrite;
use futures_sink::Sink;
use std::fmt;
use std::io;
use std::pin::Pin;
use std::marker::Unpin;
use pin_utils::{unsafe_pinned, unsafe_unpinned};

struct Block {
    offset: usize,
    bytes: Box<dyn AsRef<[u8]>>,
}

/// Sink for the [`into_sink`](super::AsyncWriteExt::into_sink) method.
#[must_use = "sinks do nothing unless polled"]
#[derive(Debug)]
pub struct IntoSink<W> {
    writer: W,
    /// An outstanding block for us to push into the underlying writer, along with an offset of how
    /// far into this block we have written already.
    buffer: Option<Block>,
}

impl<W: Unpin> Unpin for IntoSink<W> {}

impl<W: AsyncWrite> IntoSink<W> {
    unsafe_pinned!(writer: W);
    unsafe_unpinned!(buffer: Option<Block>);

    pub(super) fn new(writer: W) -> Self {
        IntoSink { writer, buffer: None }
    }

    fn project<'a>(self: Pin<&'a mut Self>) -> (Pin<&'a mut W>, &'a mut Option<Block>) {
        unsafe {
            let this = self.get_unchecked_mut();
            (Pin::new_unchecked(&mut this.writer), &mut this.buffer)
        }
    }

    /// If we have an outstanding block in `buffer` attempt to push it into the writer, does _not_
    /// flush the writer after it succeeds in pushing the block into it.
    fn poll_flush_buffer(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), io::Error>>
    {
        let (mut writer, buffer) = self.project();
        if let Some(buffer) = buffer {
            loop {
                let bytes = (*buffer.bytes).as_ref();
                let written = ready!(writer.as_mut().poll_write(cx, &bytes[buffer.offset..]))?;
                buffer.offset += written;
                if buffer.offset == bytes.len() {
                    break;
                }
            }
        }
        *buffer = None;
        Poll::Ready(Ok(()))
    }

}

impl<W: AsyncWrite, Item: AsRef<[u8]> + 'static> Sink<Item> for IntoSink<W> {
    type SinkError = io::Error;

    fn poll_ready(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), Self::SinkError>>
    {
        ready!(self.as_mut().poll_flush_buffer(cx))?;
        Poll::Ready(Ok(()))
    }

    fn start_send(
        mut self: Pin<&mut Self>,
        item: Item,
    ) -> Result<(), Self::SinkError>
    {
        debug_assert!(self.as_mut().buffer().is_none());
        *self.as_mut().buffer() = Some(Block { offset: 0, bytes: Box::new(item)} );
        Ok(())
    }

    fn poll_flush(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), Self::SinkError>>
    {
        ready!(self.as_mut().poll_flush_buffer(cx))?;
        ready!(self.as_mut().writer().poll_flush(cx))?;
        Poll::Ready(Ok(()))
    }

    fn poll_close(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), Self::SinkError>>
    {
        ready!(self.as_mut().poll_flush_buffer(cx))?;
        ready!(self.as_mut().writer().poll_close(cx))?;
        Poll::Ready(Ok(()))
    }
}

impl fmt::Debug for Block {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "[... {}/{} bytes ...]", self.offset, (*self.bytes).as_ref().len())?;
        Ok(())
    }
}
<|endoftext|>