<commit_before>use std::collections::HashMap;
use std::marker::PhantomData;
use std::convert::AsRef;

use rocket::{Outcome, State};
use rocket::request::{self, Request, FromRequest, FlashMessage};
use serde::Serialize;

use meta::Metadata;
use nav::{MenuBuilder, Link, EMPTY_MENU};

#[derive(Debug, Serialize)]
pub struct TemplateContext<'s, T: Serialize> {
    meta: &'s Metadata,
    menus: HashMap<String, Vec<Link>>,
    data: T,
    alerts: Vec<Alert>,
}

// TODO add dynamically loadable data to TemplateBuilder (could also be done in route when needed)
// e.g. for sidebar

pub struct ContextBuilder<'s, T: Serialize> {
    meta: &'s Metadata,
    menu_builders: HashMap<String, MenuBuilder<'s>>,
    data: PhantomData<*const T>,
    alerts: Vec<Alert>,
}

impl<'a, 'r, T: Serialize> FromRequest<'a, 'r> for ContextBuilder<'a, T> {
    type Error = ();

    fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
        let meta = request.guard::<State<Metadata>>()?.inner();
        let flash = request.guard::<Option<FlashMessage>>()?;

        let mut cb = ContextBuilder::new(meta);

        if let Some(flash) = flash {
            cb.add_alert(flash.into());
        }

        Outcome::Success(cb)
    }
}

impl<'s, T: Serialize> ContextBuilder<'s, T> {
    /// Creates a new `TemplateBuilder` from the given [`Metadata`].
    ///
    /// [`Metadata`]: ../metadata/struct.Metadata.html
    pub fn new(meta: &'s Metadata) -> Self {
        ContextBuilder {
            meta,
            menu_builders: HashMap::new(),
            data: PhantomData,
            alerts: Vec::new(),
        }
    }

    /// Returns a mutable reference to the [`MenuBuilder`] with the given key or creates a new one
    /// if it doesn't exist.
    ///
    /// [`MenuBuilder`]: ../navigation/struct.MenuBuilder.html
    ///
    /// # Examples
    ///
    /// ```rust
    /// use context_builder::ContextBuilder;
    /// use context_builder::Metadata;
    ///
    /// let metadata = Metadata::new();
    /// let mut context_builder: ContextBuilder<()> = ContextBuilder::new(&metadata);
    ///
    /// {
    ///     let menu_builder = context_builder.menu_builder("main");
    ///     menu_builder.add_class("menu-item");
    /// }
    ///
    /// let context = context_builder.finalize_with_default();
    /// ```
    pub fn menu_builder(&mut self, key: &str) -> &mut MenuBuilder<'s> {
        let menus = self.meta.menus();
        self.menu_builders.entry(key.to_string()).or_insert_with(
            || {
                let menu: &[Link] = menus.get(key).map(|menu| menu.as_ref()).unwrap_or(
                    &EMPTY_MENU,
                );
                MenuBuilder::new(menu)
            },
        )
    }

    /// Adds an alert to the internal list.
    pub fn add_alert(&mut self, alert: Alert) {
        self.alerts.push(alert);
    }

    /// Finalizes the Context with the given data.
    pub fn finalize_with_data(mut self, data: T) -> TemplateContext<'s, T> {
        self.add_all_menu_builders();

        let menus = self.menu_builders
            .into_iter()
            .map(|(k, menu)| (k, menu.finalize()))
            .collect();

        TemplateContext {
            meta: self.meta,
            menus,
            data,
            alerts: self.alerts,
        }
    }

    fn add_all_menu_builders(&mut self) {
        for key in self.meta.menus().keys() {
            self.menu_builder(key);
        }
    }
}

impl<'s, T> ContextBuilder<'s, T>
where
    T: Serialize + Default,
{
    /// Like [`ContextBuilder.finalize_with_data`] but uses the `default` constructor of type `T`.
    /// [`ContextBuilder.finalize_with_data`]: #method.finalize_with_data
    pub fn finalize_with_default(self) -> TemplateContext<'s, T> {
        self.finalize_with_data(T::default())
    }
}

#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AlertType {
    Primary,
    Secondary,
    Success,
    Warning,
    #[serde(rename = "danger")]
    Error,
    Info,
    Dark,
    Light,
}

impl<T: AsRef<str>> From<T> for AlertType {
    fn from(name: T) -> AlertType {
        use self::AlertType::*;
        match name.as_ref() {
            "primary" => Primary,
            "secondary" => Secondary,
            "success" => Success,
            "warning" => Warning,
            "error" => Error,
            "info" => Info,
            "dark" => Dark,
            _ => Light,
        }
    }
}

// TODO maybe encapsulate Alert in an enum for easier deserialization
// something like Alert::Inline(AlertData...) or Alert::Cached(key).

#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Alert {
    raw: bool,
    #[serde(rename = "type")]
    typ: AlertType,
    heading: Option<String>,
    msg: String,
    strong: Option<String>,
    dismissible: bool,
}

impl From<FlashMessage> for Alert {
    fn from(flash: FlashMessage) -> Alert {
        lookup_flash_message(flash)
    }
}

// TODO create a lookup source for static alerts (maybe file or db)
// something like impl From<Cookie> for Alert;

fn lookup_flash_message(flash: FlashMessage) -> Alert {
    Alert {
        raw: false,
        typ: flash.name().into(),
        heading: None,
        msg: flash.msg().into(),
        strong: None,
        dismissible: true,
    }
}
<commit_msg>Renamed Alert.heading to header (which fixes error in templates)<commit_after>use std::collections::HashMap;
use std::marker::PhantomData;
use std::convert::AsRef;

use rocket::{Outcome, State};
use rocket::request::{self, Request, FromRequest, FlashMessage};
use serde::Serialize;

use meta::Metadata;
use nav::{MenuBuilder, Link, EMPTY_MENU};

#[derive(Debug, Serialize)]
pub struct TemplateContext<'s, T: Serialize> {
    meta: &'s Metadata,
    menus: HashMap<String, Vec<Link>>,
    data: T,
    alerts: Vec<Alert>,
}

// TODO add dynamically loadable data to TemplateBuilder (could also be done in route when needed)
// e.g. for sidebar

pub struct ContextBuilder<'s, T: Serialize> {
    meta: &'s Metadata,
    menu_builders: HashMap<String, MenuBuilder<'s>>,
    data: PhantomData<*const T>,
    alerts: Vec<Alert>,
}

impl<'a, 'r, T: Serialize> FromRequest<'a, 'r> for ContextBuilder<'a, T> {
    type Error = ();

    fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
        let meta = request.guard::<State<Metadata>>()?.inner();
        let flash = request.guard::<Option<FlashMessage>>()?;

        let mut cb = ContextBuilder::new(meta);

        if let Some(flash) = flash {
            cb.add_alert(flash.into());
        }

        Outcome::Success(cb)
    }
}

impl<'s, T: Serialize> ContextBuilder<'s, T> {
    /// Creates a new `TemplateBuilder` from the given [`Metadata`].
    ///
    /// [`Metadata`]: ../metadata/struct.Metadata.html
    pub fn new(meta: &'s Metadata) -> Self {
        ContextBuilder {
            meta,
            menu_builders: HashMap::new(),
            data: PhantomData,
            alerts: Vec::new(),
        }
    }

    /// Returns a mutable reference to the [`MenuBuilder`] with the given key or creates a new one
    /// if it doesn't exist.
    ///
    /// [`MenuBuilder`]: ../navigation/struct.MenuBuilder.html
    ///
    /// # Examples
    ///
    /// ```rust
    /// use context_builder::ContextBuilder;
    /// use context_builder::Metadata;
    ///
    /// let metadata = Metadata::new();
    /// let mut context_builder: ContextBuilder<()> = ContextBuilder::new(&metadata);
    ///
    /// {
    ///     let menu_builder = context_builder.menu_builder("main");
    ///     menu_builder.add_class("menu-item");
    /// }
    ///
    /// let context = context_builder.finalize_with_default();
    /// ```
    pub fn menu_builder(&mut self, key: &str) -> &mut MenuBuilder<'s> {
        let menus = self.meta.menus();
        self.menu_builders.entry(key.to_string()).or_insert_with(
            || {
                let menu: &[Link] = menus.get(key).map(|menu| menu.as_ref()).unwrap_or(
                    &EMPTY_MENU,
                );
                MenuBuilder::new(menu)
            },
        )
    }

    /// Adds an alert to the internal list.
    pub fn add_alert(&mut self, alert: Alert) {
        self.alerts.push(alert);
    }

    /// Finalizes the Context with the given data.
    pub fn finalize_with_data(mut self, data: T) -> TemplateContext<'s, T> {
        self.add_all_menu_builders();

        let menus = self.menu_builders
            .into_iter()
            .map(|(k, menu)| (k, menu.finalize()))
            .collect();

        TemplateContext {
            meta: self.meta,
            menus,
            data,
            alerts: self.alerts,
        }
    }

    fn add_all_menu_builders(&mut self) {
        for key in self.meta.menus().keys() {
            self.menu_builder(key);
        }
    }
}

impl<'s, T> ContextBuilder<'s, T>
where
    T: Serialize + Default,
{
    /// Like [`ContextBuilder.finalize_with_data`] but uses the `default` constructor of type `T`.
    /// [`ContextBuilder.finalize_with_data`]: #method.finalize_with_data
    pub fn finalize_with_default(self) -> TemplateContext<'s, T> {
        self.finalize_with_data(T::default())
    }
}

#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AlertType {
    Primary,
    Secondary,
    Success,
    Warning,
    #[serde(rename = "danger")]
    Error,
    Info,
    Dark,
    Light,
}

impl<T: AsRef<str>> From<T> for AlertType {
    fn from(name: T) -> AlertType {
        use self::AlertType::*;
        match name.as_ref() {
            "primary" => Primary,
            "secondary" => Secondary,
            "success" => Success,
            "warning" => Warning,
            "error" => Error,
            "info" => Info,
            "dark" => Dark,
            _ => Light,
        }
    }
}

// TODO maybe encapsulate Alert in an enum for easier deserialization
// something like Alert::Inline(AlertData...) or Alert::Cached(key).

#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Alert {
    raw: bool,
    #[serde(rename = "type")]
    typ: AlertType,
    header: Option<String>,
    msg: String,
    strong: Option<String>,
    dismissible: bool,
}

impl From<FlashMessage> for Alert {
    fn from(flash: FlashMessage) -> Alert {
        lookup_flash_message(flash)
    }
}

// TODO create a lookup source for static alerts (maybe file or db)
// something like impl From<Cookie> for Alert;

fn lookup_flash_message(flash: FlashMessage) -> Alert {
    Alert {
        raw: false,
        typ: flash.name().into(),
        header: None,
        msg: flash.msg().into(),
        strong: None,
        dismissible: false,
    }
}
<|endoftext|>


<commit_before>use super::branchify::generate_branchified_method;
use super::get_writer;
use std::io::IoResult;

pub fn generate(output_dir: &Path) -> IoResult<()> {
    let mut writer = get_writer(output_dir, "read_method.rs");
    try!(writer.write(b"\
// This automatically generated file is included in request.rs.
use std::io::{Stream, IoResult};
use method::{Method, Connect, Delete, Get, Head, Options, Patch, Post, Put, Trace, ExtensionMethod};
use server::request::MAX_METHOD_LEN;
use rfc2616::{SP, is_token_item};
use buffer::BufferedStream;

#[inline]
pub fn read_method<S: Stream>(stream: &mut BufferedStream<S>) -> IoResult<Method> {
"));

    try!(generate_branchified_method(
        writer,
        branchify!(case sensitive,
            "CONNECT" => Connect,
            "DELETE"  => Delete,
            "GET"     => Get,
            "HEAD"    => Head,
            "OPTIONS" => Options,
            "PATCH"   => Patch,
            "POST"    => Post,
            "PUT"     => Put,
            "TRACE"   => Trace
        ),
        1,
        "stream.read_byte()",
        "SP",
        "MAX_METHOD_LEN",
        "is_token_item(b)",
        "ExtensionMethod({})"));
    writer.write(b"}\n")
}
<commit_msg>Keep up with rust<commit_after>use super::branchify::generate_branchified_method;
use super::get_writer;
use std::io::IoResult;

pub fn generate(output_dir: &Path) -> IoResult<()> {
    let mut writer = get_writer(output_dir, "read_method.rs");
    try!(writer.write(b"\
// This automatically generated file is included in request.rs.
use std::io::{Stream, IoResult};
use method::{Method, Connect, Delete, Get, Head, Options, Patch, Post, Put, Trace, ExtensionMethod};
use server::request::MAX_METHOD_LEN;
use rfc2616::{SP, is_token_item};
use buffer::BufferedStream;

#[inline]
pub fn read_method<S: Stream>(stream: &mut BufferedStream<S>) -> IoResult<Method> {
"));

    try!(generate_branchified_method(
        &mut writer,
        branchify!(case sensitive,
            "CONNECT" => Connect,
            "DELETE"  => Delete,
            "GET"     => Get,
            "HEAD"    => Head,
            "OPTIONS" => Options,
            "PATCH"   => Patch,
            "POST"    => Post,
            "PUT"     => Put,
            "TRACE"   => Trace
        ),
        1,
        "stream.read_byte()",
        "SP",
        "MAX_METHOD_LEN",
        "is_token_item(b)",
        "ExtensionMethod({})"));
    writer.write(b"}\n")
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]

use core::prelude::*;

bitflags!(
	flags Features: u64 {
		const Fpu = 1 << 0,
		const Virtual8086 = 1 << 1,
		const DebugExtension = 1 << 2,
		const PageSizeExtension = 1 << 3,
		const TimeStampCounter = 1 << 4,
		const ModelSpecificRegister = 1 << 5,
		const PhysicalAddressExtension = 1 << 6,
		const MachineCheckException = 1 << 7,
		const Cx8 = 1 << 8, // CMPXCHG8
		const Apic = 1 << 9,
		const SysEnter = 1 << 11,
		const MemoryTypeRange = 1 << 12,
		const PageGlobal = 1 << 13,
		const MachineCheckArchitecture = 1 << 14,
		const CMov = 1 << 15,
		const PageAttributeTable = 1 << 16,
		const PageSizeExtension36 = 1 << 17,
		const ProcessorSerial = 1 << 18,
		const CacheFlush = 1 << 19,
		const DebugStore = 1 << 21,
		const Acpi = 1 << 22,
		const Mmx = 1 << 23,
		const FxSave = 1 << 24,
		const Sse = 1 << 25,
		const Sse2 = 1 << 26,
		const SelfSnoop = 1 << 27,
		const HyperThreading = 1 << 28,
		const ThermalMonitor = 1 << 29,
		const Ia64 = 1 << 30,
		const PendingBreak = 1 << 31,

		const Sse3 = 1 << (32 + 0),
		const PclMulQdq = 1 << (32 + 1), // what
		const DebugStore64 = 1 << (32 + 2),
		const Monitor = 1 << (32 + 3),
		const CplDebugStore = 1 << (32 + 4),
		const Vmx = 1 << (32 + 5),
		const SaferMode = 1 << (32 + 6),
		const EnhancedSpeedStep = 1 << (32 + 7),
		const ThermalMonitor2 = 1 << (32 + 8),
		const Ssse3 = 1 << (32 + 9),
		const L1ContextId = 1 << (32 + 10),
		const Fma = 1 << (32 + 12),
		const Cx16 = 1 << (32 + 13), // CMPXCHG16B
		const Xtpr = 1 << (32 + 14), // I have no idea what this is
		const PerformanceMonitor = 1 << (32 + 15),
		const ProcessContextId = 1 << (32 + 17),
		const DirectCache = 1 << (32 + 18),
		const Sse41 = 1 << (32 + 19),
		const Sse42 = 1 << (32 + 20),
		const X2Apic = 1 << (32 + 21),
		const MovBe = 1 << (32 + 22),
		const PopulationCount = 1 << (32 + 23),
		const TscDeadline = 1 << (32 + 24),
		const AesNi = 1 << (32 + 25),
		const XSave = 1 << (32 + 26),
		const OsXSave = 1 << (32 + 27),
		const Avx = 1 << (32 + 28),
		const HalfPrecision = 1 << (32 + 29),
		const HwRandom = 1 << (32 + 30)
	}
);

#[derive(Copy, Clone, PartialEq, Eq, FromPrimitive)]
pub enum Exception {
	DivisionByZero = 0,
	Debug = 1,
	Nmi = 2,
	Breakpoint = 3,
	Overflow = 4,
	Bounds = 5,
	InvalidOpcode = 6,
	NotAvailable = 7,
	DoubleFault = 8,
	CoprocessorSegment = 9,
	Tss = 10,
	NotPresent = 11,
	StackSegment = 12,
	GeneralProtection = 13,
	PageFault = 14,
	Fpu = 16,
	Alignment = 17,
	MachineCheck = 18,
	Simd = 19,
	Virtualization = 20,
	Security = 30
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Msr {
	ApicBase = 0x1B
}

#[inline(always)]
pub fn cpuid(function: u32) -> (u32, u32, u32, u32) {
	unsafe {
		let (eax, ebx, ecx, edx): (u32, u32, u32, u32);
		asm!("cpuid" : "={eax}"(eax), "={ebx}"(ebx), "={ecx}"(ecx), "={edx}"(edx) : "{eax}"(function));
		(eax, ebx, ecx, edx)
	}
}

#[inline(always)]
pub fn supports() -> Features {
	let (_, _, feature_ecx, feature_edx) = cpuid(1);
	Features {
		bits: ((feature_ecx as u64) << 32) | (feature_edx as u64)
	}
}

#[inline(always)]
pub unsafe fn read_msr(msr: Msr) -> u64 {
	let (r1, r2): (u32, u32);
	asm!("rdmsr" : "={eax}"(r1), "={edx}"(r2) : "{ecx}"(msr as u32) :: "intel");
	r1 as u64 | ((r2 as u64) << 32)
}

#[derive(Copy, Clone, PartialEq, Eq, FromPrimitive)]
pub enum PrivilegeLevel {
	Ring0 = 0,
	Ring1 = 1,
	Ring2 = 2,
	Ring3 = 3,
}

#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(C, packed)]
pub struct SegmentSelector {
	data: u16
}

impl SegmentSelector {
	#[inline(always)]
	pub fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector {
		SegmentSelector {
			data: index << 3 | rpl as u16
		}
	}

	pub fn bits(&self) -> u16 {
		self.data
	}
}

#[inline(always)]
pub unsafe fn set_tr(selector: SegmentSelector) {
	asm!("ltr $0" :: "r"(selector.bits()) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn set_ss(selector: SegmentSelector) {
	asm!("mov ss, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn set_ds(selector: SegmentSelector) {
	asm!("mov ds, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn set_es(selector: SegmentSelector) {
	asm!("mov es, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn set_gs(selector: SegmentSelector) {
	asm!("mov gs, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn set_fs(selector: SegmentSelector) {
	asm!("mov fs, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn set_cs(selector: SegmentSelector) {
	asm!("push $0;
		push $$1f
		lret;
		1:" :: "ri"(selector.bits() as usize) :: "volatile");
}

#[inline(always)]
pub unsafe fn enable_interrupts() {
	asm!("sti" :::: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn disable_interrupts() {
	asm!("cli" :::: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn halt() {
	asm!("hlt" :::: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn out8(port: u16, value: u8) {
	asm!("out $0, $1" :: "{dx}"(port), "{al}"(value) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn out16(port: u16, value: u16) {
	asm!("out $0, $1" :: "{dx}"(port), "{ax}"(value) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn out32(port: u16, value: u32) {
	asm!("out $0, $1" :: "{dx}"(port), "{eax}"(value) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn outs8(port: u16, buf: &[u8]) {
	asm!("rep outsb dx, [esi]" :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}

#[inline(always)]
pub unsafe fn outs16(port: u16, buf: &[u16]) {
	asm!("rep outsw dx, [esi]" :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}

#[inline(always)]
pub unsafe fn outs32(port: u16, buf: &[u32]) {
	asm!("rep outsd dx, [esi]" :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}

#[inline(always)]
pub unsafe fn in8(port: u16) -> u8 {
	let r: u8;
	asm!("in $0, $1" : "={al}"(r) : "{dx}"(port) :: "intel");
	r
}

#[inline(always)]
pub unsafe fn in16(port: u16) -> u16 {
	let r: u16;
	asm!("in $0, $1" : "={ax}"(r) : "{dx}"(port) :: "intel");
	r
}

#[inline(always)]
pub unsafe fn in32(port: u16) -> u32 {
	let r: u32;
	asm!("in $0, $1" : "={eax}"(r) : "{dx}"(port) :: "intel");
	r
}

#[inline(always)]
pub unsafe fn ins8(port: u16, buf: &mut [u8]) {
	asm!("rep insb [edi], dx" :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}

#[inline(always)]
pub unsafe fn ins16(port: u16, buf: &mut [u16]) {
	asm!("rep insw [edi], dx" :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}

#[inline(always)]
pub unsafe fn ins32(port: u16, buf: &mut [u32]) {
	asm!("rep insd [edi], dx" :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}
<commit_msg>Update to deal with the removal of FromPrimitive<commit_after>#![allow(non_upper_case_globals)]

use core::prelude::*;

bitflags!(
	flags Features: u64 {
		const Fpu = 1 << 0,
		const Virtual8086 = 1 << 1,
		const DebugExtension = 1 << 2,
		const PageSizeExtension = 1 << 3,
		const TimeStampCounter = 1 << 4,
		const ModelSpecificRegister = 1 << 5,
		const PhysicalAddressExtension = 1 << 6,
		const MachineCheckException = 1 << 7,
		const Cx8 = 1 << 8, // CMPXCHG8
		const Apic = 1 << 9,
		const SysEnter = 1 << 11,
		const MemoryTypeRange = 1 << 12,
		const PageGlobal = 1 << 13,
		const MachineCheckArchitecture = 1 << 14,
		const CMov = 1 << 15,
		const PageAttributeTable = 1 << 16,
		const PageSizeExtension36 = 1 << 17,
		const ProcessorSerial = 1 << 18,
		const CacheFlush = 1 << 19,
		const DebugStore = 1 << 21,
		const Acpi = 1 << 22,
		const Mmx = 1 << 23,
		const FxSave = 1 << 24,
		const Sse = 1 << 25,
		const Sse2 = 1 << 26,
		const SelfSnoop = 1 << 27,
		const HyperThreading = 1 << 28,
		const ThermalMonitor = 1 << 29,
		const Ia64 = 1 << 30,
		const PendingBreak = 1 << 31,

		const Sse3 = 1 << (32 + 0),
		const PclMulQdq = 1 << (32 + 1), // what
		const DebugStore64 = 1 << (32 + 2),
		const Monitor = 1 << (32 + 3),
		const CplDebugStore = 1 << (32 + 4),
		const Vmx = 1 << (32 + 5),
		const SaferMode = 1 << (32 + 6),
		const EnhancedSpeedStep = 1 << (32 + 7),
		const ThermalMonitor2 = 1 << (32 + 8),
		const Ssse3 = 1 << (32 + 9),
		const L1ContextId = 1 << (32 + 10),
		const Fma = 1 << (32 + 12),
		const Cx16 = 1 << (32 + 13), // CMPXCHG16B
		const Xtpr = 1 << (32 + 14), // I have no idea what this is
		const PerformanceMonitor = 1 << (32 + 15),
		const ProcessContextId = 1 << (32 + 17),
		const DirectCache = 1 << (32 + 18),
		const Sse41 = 1 << (32 + 19),
		const Sse42 = 1 << (32 + 20),
		const X2Apic = 1 << (32 + 21),
		const MovBe = 1 << (32 + 22),
		const PopulationCount = 1 << (32 + 23),
		const TscDeadline = 1 << (32 + 24),
		const AesNi = 1 << (32 + 25),
		const XSave = 1 << (32 + 26),
		const OsXSave = 1 << (32 + 27),
		const Avx = 1 << (32 + 28),
		const HalfPrecision = 1 << (32 + 29),
		const HwRandom = 1 << (32 + 30)
	}
);

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Exception {
	DivisionByZero = 0,
	Debug = 1,
	Nmi = 2,
	Breakpoint = 3,
	Overflow = 4,
	Bounds = 5,
	InvalidOpcode = 6,
	NotAvailable = 7,
	DoubleFault = 8,
	CoprocessorSegment = 9,
	Tss = 10,
	NotPresent = 11,
	StackSegment = 12,
	GeneralProtection = 13,
	PageFault = 14,
	Fpu = 16,
	Alignment = 17,
	MachineCheck = 18,
	Simd = 19,
	Virtualization = 20,
	Security = 30
}

impl Exception {
	pub fn from_code(code: u32) -> Option<Exception> {
		Some(match code {
			0 => Exception::DivisionByZero,
			1 => Exception::Debug,
			2 => Exception::Nmi,
			3 => Exception::Breakpoint,
			4 => Exception::Overflow,
			5 => Exception::Bounds,
			6 => Exception::InvalidOpcode,
			7 => Exception::NotAvailable,
			8 => Exception::DoubleFault,
			9 => Exception::CoprocessorSegment,
			10 => Exception::Tss,
			11 => Exception::NotPresent,
			12 => Exception::StackSegment,
			13 => Exception::GeneralProtection,
			14 => Exception::PageFault,
			16 => Exception::Fpu,
			17 => Exception::Alignment,
			18 => Exception::MachineCheck,
			19 => Exception::Simd,
			20 => Exception::Virtualization,
			30 => Exception::Security,

			_ => return None
		})
	}
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Msr {
	ApicBase = 0x1B
}

#[inline(always)]
pub fn cpuid(function: u32) -> (u32, u32, u32, u32) {
	unsafe {
		let (eax, ebx, ecx, edx): (u32, u32, u32, u32);
		asm!("cpuid" : "={eax}"(eax), "={ebx}"(ebx), "={ecx}"(ecx), "={edx}"(edx) : "{eax}"(function));
		(eax, ebx, ecx, edx)
	}
}

#[inline(always)]
pub fn supports() -> Features {
	let (_, _, feature_ecx, feature_edx) = cpuid(1);
	Features {
		bits: ((feature_ecx as u64) << 32) | (feature_edx as u64)
	}
}

#[inline(always)]
pub unsafe fn read_msr(msr: Msr) -> u64 {
	let (r1, r2): (u32, u32);
	asm!("rdmsr" : "={eax}"(r1), "={edx}"(r2) : "{ecx}"(msr as u32) :: "intel");
	r1 as u64 | ((r2 as u64) << 32)
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum PrivilegeLevel {
	Ring0 = 0,
	Ring1 = 1,
	Ring2 = 2,
	Ring3 = 3,
}

#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(C, packed)]
pub struct SegmentSelector {
	data: u16
}

impl SegmentSelector {
	#[inline(always)]
	pub fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector {
		SegmentSelector {
			data: index << 3 | rpl as u16
		}
	}

	pub fn bits(&self) -> u16 {
		self.data
	}
}

#[inline(always)]
pub unsafe fn set_tr(selector: SegmentSelector) {
	asm!("ltr $0" :: "r"(selector.bits()) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn set_ss(selector: SegmentSelector) {
	asm!("mov ss, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn set_ds(selector: SegmentSelector) {
	asm!("mov ds, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn set_es(selector: SegmentSelector) {
	asm!("mov es, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn set_gs(selector: SegmentSelector) {
	asm!("mov gs, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn set_fs(selector: SegmentSelector) {
	asm!("mov fs, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn set_cs(selector: SegmentSelector) {
	asm!("push $0;
		push $$1f
		lret;
		1:" :: "ri"(selector.bits() as usize) :: "volatile");
}

#[inline(always)]
pub unsafe fn enable_interrupts() {
	asm!("sti" :::: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn disable_interrupts() {
	asm!("cli" :::: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn halt() {
	asm!("hlt" :::: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn out8(port: u16, value: u8) {
	asm!("out $0, $1" :: "{dx}"(port), "{al}"(value) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn out16(port: u16, value: u16) {
	asm!("out $0, $1" :: "{dx}"(port), "{ax}"(value) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn out32(port: u16, value: u32) {
	asm!("out $0, $1" :: "{dx}"(port), "{eax}"(value) :: "volatile", "intel");
}

#[inline(always)]
pub unsafe fn outs8(port: u16, buf: &[u8]) {
	asm!("rep outsb dx, [esi]" :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}

#[inline(always)]
pub unsafe fn outs16(port: u16, buf: &[u16]) {
	asm!("rep outsw dx, [esi]" :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}

#[inline(always)]
pub unsafe fn outs32(port: u16, buf: &[u32]) {
	asm!("rep outsd dx, [esi]" :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}

#[inline(always)]
pub unsafe fn in8(port: u16) -> u8 {
	let r: u8;
	asm!("in $0, $1" : "={al}"(r) : "{dx}"(port) :: "intel");
	r
}

#[inline(always)]
pub unsafe fn in16(port: u16) -> u16 {
	let r: u16;
	asm!("in $0, $1" : "={ax}"(r) : "{dx}"(port) :: "intel");
	r
}

#[inline(always)]
pub unsafe fn in32(port: u16) -> u32 {
	let r: u32;
	asm!("in $0, $1" : "={eax}"(r) : "{dx}"(port) :: "intel");
	r
}

#[inline(always)]
pub unsafe fn ins8(port: u16, buf: &mut [u8]) {
	asm!("rep insb [edi], dx" :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}

#[inline(always)]
pub unsafe fn ins16(port: u16, buf: &mut [u16]) {
	asm!("rep insw [edi], dx" :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}

#[inline(always)]
pub unsafe fn ins32(port: u16, buf: &mut [u32]) {
	asm!("rep insd [edi], dx" :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}
<|endoftext|>


<commit_before>//! The `style` element.

use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::*;
use crate::session::Session;
use crate::xml::Attributes;

/// Represents the syntax used in the <style> node.
///
/// Currently only "text/css" is supported.
///
/// <https://www.w3.org/TR/SVG11/styling.html#StyleElementTypeAttribute>
/// <https://www.w3.org/TR/SVG11/styling.html#ContentStyleTypeAttribute>
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum StyleType {
    TextCss,
}

enum_default!(StyleType, StyleType::TextCss);

impl StyleType {
    fn parse(value: &str) -> Result<StyleType, ValueErrorKind> {
        // https://html.spec.whatwg.org/multipage/semantics.html#the-style-element
        //
        // 4. If element's type attribute is present and its value is
        // neither the empty string nor an ASCII case-insensitive
        // match for "text/css", then return.

        if value.eq_ignore_ascii_case("text/css") {
            Ok(StyleType::TextCss)
        } else {
            Err(ValueErrorKind::parse_error(
                "invalid value for type attribute in style element",
            ))
        }
    }
}

/// Represents a <style> node.
///
/// It does not render itself, and just holds CSS stylesheet information for the rest of
/// the code to use.
#[derive(Default)]
pub struct Style {
    type_: StyleType,
}

impl Style {
    pub fn style_type(&self) -> StyleType {
        self.type_
    }
}

impl SetAttributes for Style {
    fn set_attributes(&mut self, attrs: &Attributes, _session: &Session) -> ElementResult {
        for (attr, value) in attrs.iter() {
            if attr.expanded() == expanded_name!("", "type") {
                self.type_ = StyleType::parse(value).attribute(attr)?;
            }
        }

        Ok(())
    }
}

impl Draw for Style {}

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

    #[test]
    fn parses_style_type() {
        assert_eq!(StyleType::parse("text/css").unwrap(), StyleType::TextCss);
    }

    #[test]
    fn invalid_style_type_yields_error() {
        assert!(StyleType::parse("").is_err());
        assert!(StyleType::parse("some-other-stylesheet-language").is_err());
    }
}
<commit_msg>style.rs: use set_attribute()<commit_after>//! The `style` element.

use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::element::{set_attribute, Draw, ElementResult, SetAttributes};
use crate::error::*;
use crate::session::Session;
use crate::xml::Attributes;

/// Represents the syntax used in the <style> node.
///
/// Currently only "text/css" is supported.
///
/// <https://www.w3.org/TR/SVG11/styling.html#StyleElementTypeAttribute>
/// <https://www.w3.org/TR/SVG11/styling.html#ContentStyleTypeAttribute>
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum StyleType {
    TextCss,
}

enum_default!(StyleType, StyleType::TextCss);

impl StyleType {
    fn parse(value: &str) -> Result<StyleType, ValueErrorKind> {
        // https://html.spec.whatwg.org/multipage/semantics.html#the-style-element
        //
        // 4. If element's type attribute is present and its value is
        // neither the empty string nor an ASCII case-insensitive
        // match for "text/css", then return.

        if value.eq_ignore_ascii_case("text/css") {
            Ok(StyleType::TextCss)
        } else {
            Err(ValueErrorKind::parse_error(
                "invalid value for type attribute in style element",
            ))
        }
    }
}

/// Represents a <style> node.
///
/// It does not render itself, and just holds CSS stylesheet information for the rest of
/// the code to use.
#[derive(Default)]
pub struct Style {
    type_: StyleType,
}

impl Style {
    pub fn style_type(&self) -> StyleType {
        self.type_
    }
}

impl SetAttributes for Style {
    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) -> ElementResult {
        for (attr, value) in attrs.iter() {
            if attr.expanded() == expanded_name!("", "type") {
                set_attribute(
                    &mut self.type_,
                    StyleType::parse(value).attribute(attr),
                    session,
                );
            }
        }

        Ok(())
    }
}

impl Draw for Style {}

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

    #[test]
    fn parses_style_type() {
        assert_eq!(StyleType::parse("text/css").unwrap(), StyleType::TextCss);
    }

    #[test]
    fn invalid_style_type_yields_error() {
        assert!(StyleType::parse("").is_err());
        assert!(StyleType::parse("some-other-stylesheet-language").is_err());
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::io::{self, Write};
use std::{ops, str};

use rustc::hir::def_id::DefId;
use rustc::mir::{self, BasicBlock, Body, Location};
use rustc_index::bit_set::{BitSet, HybridBitSet};
use rustc_index::vec::Idx;

use crate::util::graphviz_safe_def_name;
use super::{Analysis, Results, ResultsRefCursor};

pub struct Formatter<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    body: &'a Body<'tcx>,
    def_id: DefId,

    // This must be behind a `RefCell` because `dot::Labeller` takes `&self`.
    block_formatter: RefCell<BlockFormatter<'a, 'tcx, A>>,
}

impl Formatter<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    pub fn new(
        body: &'a Body<'tcx>,
        def_id: DefId,
        results: &'a Results<'tcx, A>,
    ) -> Self {
        let block_formatter = BlockFormatter {
            bg: Background::Light,
            prev_state: BitSet::new_empty(results.analysis.bits_per_block(body)),
            results: ResultsRefCursor::new(body, results),
        };

        Formatter {
            body,
            def_id,
            block_formatter: RefCell::new(block_formatter),
        }
    }
}

/// A pair of a basic block and an index into that basic blocks `successors`.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct CfgEdge {
    source: BasicBlock,
    index: usize,
}

fn outgoing_edges(body: &Body<'_>, bb: BasicBlock) -> Vec<CfgEdge> {
    body[bb]
        .terminator()
        .successors()
        .enumerate()
        .map(|(index, _)| CfgEdge { source: bb, index })
        .collect()
}

impl dot::Labeller<'_> for Formatter<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    type Node = BasicBlock;
    type Edge = CfgEdge;

    fn graph_id(&self) -> dot::Id<'_> {
        let name = graphviz_safe_def_name(self.def_id);
        dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap()
    }

    fn node_id(&self, n: &Self::Node) -> dot::Id<'_> {
        dot::Id::new(format!("bb_{}", n.index())).unwrap()
    }

    fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
        let mut label = Vec::new();
        self.block_formatter
            .borrow_mut()
            .write_node_label(&mut label, self.body, *block)
            .unwrap();
        dot::LabelText::html(String::from_utf8(label).unwrap())
    }

    fn node_shape(&self, _n: &Self::Node) -> Option<dot::LabelText<'_>> {
        Some(dot::LabelText::label("none"))
    }

    fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> {
        let label = &self.body
            [e.source]
            .terminator()
            .kind
            .fmt_successor_labels()
            [e.index];
        dot::LabelText::label(label.clone())
    }
}

impl dot::GraphWalk<'a> for Formatter<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    type Node = BasicBlock;
    type Edge = CfgEdge;

    fn nodes(&self) -> dot::Nodes<'_, Self::Node> {
        self.body
            .basic_blocks()
            .indices()
            .collect::<Vec<_>>()
            .into()
    }

    fn edges(&self) -> dot::Edges<'_, Self::Edge> {
        self.body
            .basic_blocks()
            .indices()
            .flat_map(|bb| outgoing_edges(self.body, bb))
            .collect::<Vec<_>>()
            .into()
    }

    fn source(&self, edge: &Self::Edge) -> Self::Node {
        edge.source
    }

    fn target(&self, edge: &Self::Edge) -> Self::Node {
        self.body
            [edge.source]
            .terminator()
            .successors()
            .nth(edge.index)
            .copied()
            .unwrap()
    }
}

struct BlockFormatter<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    prev_state: BitSet,
    results: ResultsRefCursor<'a, 'a, 'tcx, A>,
    bg: Background,
}

impl BlockFormatter<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    fn toggle_background(&mut self) -> Background {
        let bg = self.bg;
        self.bg = !bg;
        bg
    }

    fn write_node_label(
        &mut self,
        w: &mut impl io::Write,
        body: &'a Body<'tcx>,
        block: BasicBlock,
    ) -> io::Result<()> {
        //   Sample output:
        //   +-+--------------------------------------------------+
        // A |                         bb4                        |
        //   +-+----------------------------------+---------------+
        // B |               MIR                  |     STATE     |
        //   +-+----------------------------------+---------------+
        // C | | (on entry)                       | {_0,_2,_3}    |
        //   +-+----------------------------------+---------------+
        // D |0|  0: StorageLive(_7)              |               |
        //   +-+----------------------------------+---------------+
        //   |1|  1: StorageLive(_8)              |               |
        //   +-+----------------------------------+---------------+
        //   |2|  2: _8 = &mut _1                 | +_8           |
        //   +-+----------------------------------+---------------+
        // E |T| _7 = const Foo::twiddle(move _8) | -_8           |
        //   +-+----------------------------------+---------------+
        // F | | (on unwind)                      | {_0,_2,_3,_7} |
        //   +-+----------------------------------+---------------+
        //   | | (on successful return)           | +_7           |
        //   +-+----------------------------------+---------------+

        write!(
            w,
            r#"
"#,
        )?;

        // A: Block info
        write!(
            w,
            r#"

                 bb{block_id}

"#,
            num_headers = 3,
            block_id = block.index(),
        )?;

        // B: Column headings
        write!(
            w,
            r#"

                 MIR
                 STATE

"#,
            fmt = r##"bgcolor="#a0a0a0" sides="tl""##,
        )?;

        // C: Entry state
        self.bg = Background::Light;
        self.results.seek_to_block_start(block);
        self.write_row_with_curr_state(w, "", "(on entry)")?;
        self.prev_state.overwrite(self.results.get());

        // D: Statement transfer functions
        for (i, statement) in body[block].statements.iter().enumerate() {
            let location = Location { block, statement_index: i };

            let mir_col = format!("{:?}", statement);
            let i_col = i.to_string();

            self.results.seek_after(location);
            self.write_row_with_curr_diff(w, &i_col, &mir_col)?;
            self.prev_state.overwrite(self.results.get());
        }

        // E: Terminator transfer function
        let terminator = body[block].terminator();
        let location = body.terminator_loc(block);

        let mut mir_col = String::new();
        terminator.kind.fmt_head(&mut mir_col).unwrap();

        self.results.seek_after(location);
        self.write_row_with_curr_diff(w, "T", &mir_col)?;
        self.prev_state.overwrite(self.results.get());

        // F: Exit state
        if let mir::TerminatorKind::Call { destination: Some(_), ..  } = &terminator.kind {
            self.write_row_with_curr_state(w, "", "(on unwind)")?;

            self.results.seek_after_assume_call_returns(location);
            self.write_row_with_curr_diff(w, "", "(on successful return)")?;
        } else {
            self.write_row_with_curr_state(w, "", "(on exit)")?;
        }

        write!(w, "
")
    }

    fn write_row_with_curr_state(
        &mut self,
        w: &mut impl io::Write,
        i: &str,
        mir: &str,
    ) -> io::Result<()> {
        let bg = self.toggle_background();

        let mut out = Vec::new();
        write!(&mut out, "{{")?;
        pretty_print_state_elems(&mut out, self.results.analysis(), self.results.get().iter())?;
        write!(&mut out, "}}")?;

        write!(
            w,
            r#"

                 {i}
                 {mir}
                 {state}

"#,
            fmt = &["sides=\"tl\"", bg.attr()].join(" "),
            i = i,
            mir = dot::escape_html(mir),
            state = dot::escape_html(str::from_utf8(&out).unwrap()),
        )
    }

    fn write_row_with_curr_diff(
        &mut self,
        w: &mut impl io::Write,
        i: &str,
        mir: &str,
    ) -> io::Result<()> {
        let bg = self.toggle_background();
        let analysis = self.results.analysis();

        let diff = BitSetDiff::compute(&self.prev_state, self.results.get());

        let mut set = Vec::new();
        pretty_print_state_elems(&mut set, analysis, diff.set.iter())?;

        let mut clear = Vec::new();
        pretty_print_state_elems(&mut clear, analysis, diff.clear.iter())?;

        write!(
            w,
            r#"

                 {i}
                 {mir}
                 "#,
            i = i,
            fmt = &["sides=\"tl\"", bg.attr()].join(" "),
            mir = dot::escape_html(mir),
        )?;

        if !set.is_empty() {
            write!(
                w,
                r#"+{}"#,
                dot::escape_html(str::from_utf8(&set).unwrap()),
            )?;
        }

        if !set.is_empty() && !clear.is_empty() {
            write!(w, "  ")?;
        }

        if !clear.is_empty() {
            write!(
                w,
                r#"-{}"#,
                dot::escape_html(str::from_utf8(&clear).unwrap()),
            )?;
        }

        write!(w, "
")
    }
}

/// The operations required to transform one `BitSet` into another.
struct BitSetDiff<T: Idx> {
    set: HybridBitSet<T>,
    clear: HybridBitSet<T>,
}

impl<T: Idx> BitSetDiff<T> {
    fn compute(from: &BitSet<T>, to: &BitSet<T>) -> Self {
        assert_eq!(from.domain_size(), to.domain_size());
        let len = from.domain_size();

        let mut set = HybridBitSet::new_empty(len);
        let mut clear = HybridBitSet::new_empty(len);

        // FIXME: This could be made faster if `BitSet::xor` were implemented.
        for i in (0..len).map(|i| T::new(i)) {
            match (from.contains(i), to.contains(i)) {
                (false, true) => set.insert(i),
                (true, false) => clear.insert(i),
                _ => continue,
            };
        }

        BitSetDiff {
            set,
            clear,
        }
    }
}

/// Formats each `elem` using the pretty printer provided by `analysis` into a comma-separated
/// list.
fn pretty_print_state_elems(
    w: &mut impl io::Write,
    analysis: &A,
    elems: impl Iterator<Item = A::Idx>,
) -> io::Result<()>
where
    A: Analysis<'tcx>,
{
    let mut first = true;
    for idx in elems {
        if first {
            first = false;
        } else {
            write!(w, ",")?;
        }

        analysis.pretty_print_idx(w, idx)?;
    }

    Ok(())
}

/// The background color used for zebra-striping the table.
#[derive(Clone, Copy)]
enum Background {
    Light,
    Dark,
}

impl Background {
    fn attr(self) -> &'static str {
        match self {
            Self::Dark => "bgcolor=\"#f0f0f0\"",
            Self::Light => "",
        }
    }
}

impl ops::Not for Background {
    type Output = Self;

    fn not(self) -> Self {
        match self {
            Self::Light => Self::Dark,
            Self::Dark => Self::Light,
        }
    }
}
<commit_msg>Update example table to match current output<commit_after>use std::cell::RefCell;
use std::io::{self, Write};
use std::{ops, str};

use rustc::hir::def_id::DefId;
use rustc::mir::{self, BasicBlock, Body, Location};
use rustc_index::bit_set::{BitSet, HybridBitSet};
use rustc_index::vec::Idx;

use crate::util::graphviz_safe_def_name;
use super::{Analysis, Results, ResultsRefCursor};

pub struct Formatter<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    body: &'a Body<'tcx>,
    def_id: DefId,

    // This must be behind a `RefCell` because `dot::Labeller` takes `&self`.
    block_formatter: RefCell<BlockFormatter<'a, 'tcx, A>>,
}

impl Formatter<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    pub fn new(
        body: &'a Body<'tcx>,
        def_id: DefId,
        results: &'a Results<'tcx, A>,
    ) -> Self {
        let block_formatter = BlockFormatter {
            bg: Background::Light,
            prev_state: BitSet::new_empty(results.analysis.bits_per_block(body)),
            results: ResultsRefCursor::new(body, results),
        };

        Formatter {
            body,
            def_id,
            block_formatter: RefCell::new(block_formatter),
        }
    }
}

/// A pair of a basic block and an index into that basic blocks `successors`.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct CfgEdge {
    source: BasicBlock,
    index: usize,
}

fn outgoing_edges(body: &Body<'_>, bb: BasicBlock) -> Vec<CfgEdge> {
    body[bb]
        .terminator()
        .successors()
        .enumerate()
        .map(|(index, _)| CfgEdge { source: bb, index })
        .collect()
}

impl dot::Labeller<'_> for Formatter<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    type Node = BasicBlock;
    type Edge = CfgEdge;

    fn graph_id(&self) -> dot::Id<'_> {
        let name = graphviz_safe_def_name(self.def_id);
        dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap()
    }

    fn node_id(&self, n: &Self::Node) -> dot::Id<'_> {
        dot::Id::new(format!("bb_{}", n.index())).unwrap()
    }

    fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
        let mut label = Vec::new();
        self.block_formatter
            .borrow_mut()
            .write_node_label(&mut label, self.body, *block)
            .unwrap();
        dot::LabelText::html(String::from_utf8(label).unwrap())
    }

    fn node_shape(&self, _n: &Self::Node) -> Option<dot::LabelText<'_>> {
        Some(dot::LabelText::label("none"))
    }

    fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> {
        let label = &self.body
            [e.source]
            .terminator()
            .kind
            .fmt_successor_labels()
            [e.index];
        dot::LabelText::label(label.clone())
    }
}

impl dot::GraphWalk<'a> for Formatter<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    type Node = BasicBlock;
    type Edge = CfgEdge;

    fn nodes(&self) -> dot::Nodes<'_, Self::Node> {
        self.body
            .basic_blocks()
            .indices()
            .collect::<Vec<_>>()
            .into()
    }

    fn edges(&self) -> dot::Edges<'_, Self::Edge> {
        self.body
            .basic_blocks()
            .indices()
            .flat_map(|bb| outgoing_edges(self.body, bb))
            .collect::<Vec<_>>()
            .into()
    }

    fn source(&self, edge: &Self::Edge) -> Self::Node {
        edge.source
    }

    fn target(&self, edge: &Self::Edge) -> Self::Node {
        self.body
            [edge.source]
            .terminator()
            .successors()
            .nth(edge.index)
            .copied()
            .unwrap()
    }
}

struct BlockFormatter<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    prev_state: BitSet,
    results: ResultsRefCursor<'a, 'a, 'tcx, A>,
    bg: Background,
}

impl BlockFormatter<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    fn toggle_background(&mut self) -> Background {
        let bg = self.bg;
        self.bg = !bg;
        bg
    }

    fn write_node_label(
        &mut self,
        w: &mut impl io::Write,
        body: &'a Body<'tcx>,
        block: BasicBlock,
    ) -> io::Result<()> {
        //   Sample output:
        //   +-+-----------------------------------------------+
        // A |                      bb4                        |
        //   +-+----------------------------------+------------+
        // B |                MIR                 |   STATE    |
        //   +-+----------------------------------+------------+
        // C | | (on entry)                       | {_0,_2,_3} |
        //   +-+----------------------------------+------------+
        // D |0| StorageLive(_7)                  |            |
        //   +-+----------------------------------+------------+
        //   |1| StorageLive(_8)                  |            |
        //   +-+----------------------------------+------------+
        //   |2| _8 = &mut _1                     | +_8        |
        //   +-+----------------------------------+------------+
        // E |T| _4 = const Foo::twiddle(move _2) | -_2        |
        //   +-+----------------------------------+------------+
        // F | | (on unwind)                      | {_0,_3,_8} |
        //   +-+----------------------------------+------------+
        //   | | (on successful return)           | +_4        |
        //   +-+----------------------------------+------------+

        write!(
            w,
            r#"
"#,
        )?;

        // A: Block info
        write!(
            w,
            r#"

                 bb{block_id}

"#,
            num_headers = 3,
            block_id = block.index(),
        )?;

        // B: Column headings
        write!(
            w,
            r#"

                 MIR
                 STATE

"#,
            fmt = r##"bgcolor="#a0a0a0" sides="tl""##,
        )?;

        // C: Entry state
        self.bg = Background::Light;
        self.results.seek_to_block_start(block);
        self.write_row_with_curr_state(w, "", "(on entry)")?;
        self.prev_state.overwrite(self.results.get());

        // D: Statement transfer functions
        for (i, statement) in body[block].statements.iter().enumerate() {
            let location = Location { block, statement_index: i };

            let mir_col = format!("{:?}", statement);
            let i_col = i.to_string();

            self.results.seek_after(location);
            self.write_row_with_curr_diff(w, &i_col, &mir_col)?;
            self.prev_state.overwrite(self.results.get());
        }

        // E: Terminator transfer function
        let terminator = body[block].terminator();
        let location = body.terminator_loc(block);

        let mut mir_col = String::new();
        terminator.kind.fmt_head(&mut mir_col).unwrap();

        self.results.seek_after(location);
        self.write_row_with_curr_diff(w, "T", &mir_col)?;
        self.prev_state.overwrite(self.results.get());

        // F: Exit state
        if let mir::TerminatorKind::Call { destination: Some(_), ..  } = &terminator.kind {
            self.write_row_with_curr_state(w, "", "(on unwind)")?;

            self.results.seek_after_assume_call_returns(location);
            self.write_row_with_curr_diff(w, "", "(on successful return)")?;
        } else {
            self.write_row_with_curr_state(w, "", "(on exit)")?;
        }

        write!(w, "
")
    }

    fn write_row_with_curr_state(
        &mut self,
        w: &mut impl io::Write,
        i: &str,
        mir: &str,
    ) -> io::Result<()> {
        let bg = self.toggle_background();

        let mut out = Vec::new();
        write!(&mut out, "{{")?;
        pretty_print_state_elems(&mut out, self.results.analysis(), self.results.get().iter())?;
        write!(&mut out, "}}")?;

        write!(
            w,
            r#"

                 {i}
                 {mir}
                 {state}

"#,
            fmt = &["sides=\"tl\"", bg.attr()].join(" "),
            i = i,
            mir = dot::escape_html(mir),
            state = dot::escape_html(str::from_utf8(&out).unwrap()),
        )
    }

    fn write_row_with_curr_diff(
        &mut self,
        w: &mut impl io::Write,
        i: &str,
        mir: &str,
    ) -> io::Result<()> {
        let bg = self.toggle_background();
        let analysis = self.results.analysis();

        let diff = BitSetDiff::compute(&self.prev_state, self.results.get());

        let mut set = Vec::new();
        pretty_print_state_elems(&mut set, analysis, diff.set.iter())?;

        let mut clear = Vec::new();
        pretty_print_state_elems(&mut clear, analysis, diff.clear.iter())?;

        write!(
            w,
            r#"

                 {i}
                 {mir}
                 "#,
            i = i,
            fmt = &["sides=\"tl\"", bg.attr()].join(" "),
            mir = dot::escape_html(mir),
        )?;

        if !set.is_empty() {
            write!(
                w,
                r#"+{}"#,
                dot::escape_html(str::from_utf8(&set).unwrap()),
            )?;
        }

        if !set.is_empty() && !clear.is_empty() {
            write!(w, "  ")?;
        }

        if !clear.is_empty() {
            write!(
                w,
                r#"-{}"#,
                dot::escape_html(str::from_utf8(&clear).unwrap()),
            )?;
        }

        write!(w, "
")
    }
}

/// The operations required to transform one `BitSet` into another.
struct BitSetDiff<T: Idx> {
    set: HybridBitSet<T>,
    clear: HybridBitSet<T>,
}

impl<T: Idx> BitSetDiff<T> {
    fn compute(from: &BitSet<T>, to: &BitSet<T>) -> Self {
        assert_eq!(from.domain_size(), to.domain_size());
        let len = from.domain_size();

        let mut set = HybridBitSet::new_empty(len);
        let mut clear = HybridBitSet::new_empty(len);

        // FIXME: This could be made faster if `BitSet::xor` were implemented.
        for i in (0..len).map(|i| T::new(i)) {
            match (from.contains(i), to.contains(i)) {
                (false, true) => set.insert(i),
                (true, false) => clear.insert(i),
                _ => continue,
            };
        }

        BitSetDiff {
            set,
            clear,
        }
    }
}

/// Formats each `elem` using the pretty printer provided by `analysis` into a comma-separated
/// list.
fn pretty_print_state_elems(
    w: &mut impl io::Write,
    analysis: &A,
    elems: impl Iterator<Item = A::Idx>,
) -> io::Result<()>
where
    A: Analysis<'tcx>,
{
    let mut first = true;
    for idx in elems {
        if first {
            first = false;
        } else {
            write!(w, ",")?;
        }

        analysis.pretty_print_idx(w, idx)?;
    }

    Ok(())
}

/// The background color used for zebra-striping the table.
#[derive(Clone, Copy)]
enum Background {
    Light,
    Dark,
}

impl Background {
    fn attr(self) -> &'static str {
        match self {
            Self::Dark => "bgcolor=\"#f0f0f0\"",
            Self::Light => "",
        }
    }
}

impl ops::Not for Background {
    type Output = Self;

    fn not(self) -> Self {
        match self {
            Self::Light => Self::Dark,
            Self::Dark => Self::Light,
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests;

use num::{Integer, ToPrimitive};

use std::slice::SliceConcatExt;
use std::convert::AsRef;
use std::fmt::Debug;
// use std::iter::Iterator;

use ::crypto::Hash;
use ::messages::{Precommit, Propose, Message};

mod leveldb;
mod memorydb;
mod map_table;
mod list_table;
mod merkle_table;
mod fields;
mod db;
mod merkle_patricia_table;

pub use leveldb::options::Options as LevelDBOptions;
pub use leveldb::database::cache::Cache as LevelDBCache;

pub use self::leveldb::LevelDB;
pub use self::db::{Database, Patch, Fork, Change};
pub use self::memorydb::MemoryDB;
pub use self::map_table::MapTable;
pub use self::list_table::ListTable;
pub use self::merkle_table::MerkleTable;
pub use self::fields::StorageValue;
pub use self::merkle_patricia_table::MerklePatriciaTable;

pub trait Storage<D: Database, T: Message + StorageValue> {
    fn db(&self) -> &D;
    fn db_mut(&mut self) -> &mut D;

    fn fork(&self) -> Fork<D> {
        self.db().fork()
    }

    // TODO: remove ellided lifetimes

    fn transactions<'a>(&'a mut self) -> MapTable<'a, D, Hash, T> {
        self.db_mut().map(vec![00])
    }

    fn proposes<'a>(&'a mut self) -> MapTable<'a, D, Hash, Propose> {
        self.db_mut().map(vec![01])
    }

    fn heights<'a>(&'a mut self) -> ListTable<MapTable<'a, D, [u8], Vec<u8>>, u64, Hash> {
        self.db_mut().list(vec![02])
    }

    fn last_hash(&mut self) -> Result<Option<Hash>, Error> {
        self.heights().last()
    }

    fn last_propose(&mut self) -> Result<Option<Propose>, Error> {
        Ok(match self.last_hash()? {
            Some(hash) => Some(self.proposes().get(&hash)?.unwrap()),
            None => None,
        })

    }

    fn precommits<'a>(&'a mut self,
                          hash: &'a Hash)
                          -> ListTable<MapTable<'a, D, [u8], Vec<u8>>, u32, Precommit> {
        self.db_mut().list([&[03], hash.as_ref()].concat())
    }

    fn merge(&mut self, patch: Patch) -> Result<(), Error> {
        self.db_mut().merge(patch)
    }
}

pub trait Blockchain : Sized {
    type Database: Database;
    type Transaction: Message + StorageValue;

    fn db(&self) -> &Self::Database;
    fn db_mut(&mut self) -> &mut Self::Database;
}

impl<T, Tx, Db> Storage<Db, Tx> for T where T: Blockchain<Database=Db, Transaction=Tx>,
                                            Db: Database,
                                            Tx: Message + StorageValue {
    fn db(&self) -> &Db {
        Blockchain::db(self)
    }

    fn db_mut(&mut self) -> &mut Db {
        Blockchain::db_mut(self)
    }
}

impl<'a, Tx, Db> Storage<Fork<'a, Db>, Tx> for Fork<'a, Db> where Db: Database,
                                                                  Tx: Message + StorageValue {
    fn db(&self) -> &Fork<'a, Db> {
        self
    }

    fn db_mut(&mut self) -> &mut Fork<'a, Db> {
        self
    }
}

pub type Error = Box<Debug>;

// TODO We need to understand how to finish them
// pub trait Iterable {
//     type Iter: Iterator;

//     fn iter(self) -> Self::Iter;
// }

// pub trait Seekable<'a> {
//     type Item;
//     type Key: ?Sized;

//     fn seek(&mut self, key: &Self::Key) -> Option<Self::Item>;
// }

pub trait Map<K: ?Sized, V> {
    fn get(&self, key: &K) -> Result<Option<V>, Error>;
    fn put(&mut self, key: &K, value: V) -> Result<(), Error>;
    fn delete(&mut self, key: &K) -> Result<(), Error>;
    fn find_key(&self, key: &K) -> Result<Option<Vec<u8>>, Error>;
}

pub trait List<K: Integer + Copy + Clone + ToPrimitive, V> {
    fn append(&mut self, value: V) -> Result<(), Error>;
    fn extend<I: IntoIterator<Item = V>>(&mut self, iter: I) -> Result<(), Error>;
    fn get(&self, index: K) -> Result<Option<V>, Error>;
    fn last(&self) -> Result<Option<V>, Error>;
    fn is_empty(&self) -> Result<bool, Error>;
    fn len(&self) -> Result<K, Error>;
}

pub trait MapExt: Map<[u8], Vec<u8>> + Sized {
    fn list<'a, K, V>(&'a mut self,
                      prefix: Vec<u8>)
                      -> ListTable<MapTable<'a, Self, [u8], Vec<u8>>, K, V>
        where K: Integer + Copy + Clone + ToPrimitive + StorageValue,
              V: StorageValue;

    fn map<'a, K: ?Sized, V>(&'a mut self, prefix: Vec<u8>) -> MapTable<'a, Self, K, V>;
    fn merkle_list<'a, K, V>(&'a mut self,
                             prefix: Vec<u8>)
                             -> MerkleTable<MapTable<'a, Self, [u8], Vec<u8>>, K, V>
        where K: Integer + Copy + Clone + ToPrimitive + StorageValue,
              V: StorageValue;
    fn merkle_map<'a, K: ?Sized, V>
        (&'a mut self,
         prefix: Vec<u8>)
         -> MerklePatriciaTable<MapTable<'a, Self, [u8], Vec<u8>>, K, V>
        where K: AsRef<[u8]>,
              V: StorageValue;
}

// TODO MapExt looks too complex. Find more simple way.
impl<T> MapExt for T
    where T: Map<[u8], Vec<u8>> + Sized
{
    fn list<'a, K, V>(&'a mut self,
                      prefix: Vec<u8>)
                      -> ListTable<MapTable<'a, Self, [u8], Vec<u8>>, K, V>
        where K: Integer + Copy + Clone + ToPrimitive + StorageValue,
              V: StorageValue
    {
        ListTable::new(self.map(prefix))
    }

    fn map<'a, K: ?Sized, V>(&'a mut self, prefix: Vec<u8>) -> MapTable<'a, Self, K, V> {
        MapTable::new(prefix, self)
    }
    fn merkle_list<'a, K, V>(&'a mut self,
                             prefix: Vec<u8>)
                             -> MerkleTable<MapTable<'a, Self, [u8], Vec<u8>>, K, V>
        where K: Integer + Copy + Clone + ToPrimitive + StorageValue,
              V: StorageValue
    {
        MerkleTable::new(self.map(prefix))
    }
    fn merkle_map<'a, K: ?Sized, V>
        (&'a mut self,
         prefix: Vec<u8>)
         -> MerklePatriciaTable<MapTable<'a, Self, [u8], Vec<u8>>, K, V>
        where K: AsRef<[u8]>,
              V: StorageValue
    {
        let map_table = self.map(prefix);
        MerklePatriciaTable::new(map_table)
    }
}
<commit_msg>Simplifying storage: reduce ellided lifetimes, remove MapExt<commit_after>#[cfg(test)]
mod tests;

use num::{Integer, ToPrimitive};

use std::slice::SliceConcatExt;
use std::convert::AsRef;
use std::fmt::Debug;
// use std::iter::Iterator;

use ::crypto::Hash;
use ::messages::{Precommit, Propose, Message};

mod leveldb;
mod memorydb;
mod map_table;
mod list_table;
mod merkle_table;
mod fields;
mod db;
mod merkle_patricia_table;

pub use leveldb::options::Options as LevelDBOptions;
pub use leveldb::database::cache::Cache as LevelDBCache;

pub use self::leveldb::LevelDB;
pub use self::db::{Database, Patch, Fork, Change};
pub use self::memorydb::MemoryDB;
pub use self::map_table::MapTable;
pub use self::list_table::ListTable;
pub use self::merkle_table::MerkleTable;
pub use self::fields::StorageValue;
pub use self::merkle_patricia_table::MerklePatriciaTable;

pub trait Storage<D: Database, T: Message + StorageValue> {
    fn db(&self) -> &D;
    fn db_mut(&mut self) -> &mut D;

    fn fork(&self) -> Fork<D> {
        self.db().fork()
    }

    fn transactions(&mut self) -> MapTable<D, Hash, T> {
        MapTable::new(vec![00], self.db_mut())
    }

    fn proposes(&mut self) -> MapTable<D, Hash, Propose> {
        MapTable::new(vec![01], self.db_mut())
    }

    fn heights(&mut self) -> ListTable<MapTable<D, [u8], Vec<u8>>, u64, Hash> {
        ListTable::new(MapTable::new(vec![02], self.db_mut()))
    }

    fn last_hash(&mut self) -> Result<Option<Hash>, Error> {
        self.heights().last()
    }

    fn last_propose(&mut self) -> Result<Option<Propose>, Error> {
        Ok(match self.last_hash()? {
            Some(hash) => Some(self.proposes().get(&hash)?.unwrap()),
            None => None,
        })

    }

    fn precommits(&mut self, hash: &Hash)
        -> ListTable<MapTable<D, [u8], Vec<u8>>, u32, Precommit> {
        ListTable::new(MapTable::new([&[03], hash.as_ref()].concat(), self.db_mut()))
    }

    fn merge(&mut self, patch: Patch) -> Result<(), Error> {
        self.db_mut().merge(patch)
    }
}

pub trait Blockchain : Sized {
    type Database: Database;
    type Transaction: Message + StorageValue;

    fn db(&self) -> &Self::Database;
    fn db_mut(&mut self) -> &mut Self::Database;
}

impl<T, Tx, Db> Storage<Db, Tx> for T where T: Blockchain<Database=Db, Transaction=Tx>,
                                            Db: Database,
                                            Tx: Message + StorageValue {
    fn db(&self) -> &Db {
        Blockchain::db(self)
    }

    fn db_mut(&mut self) -> &mut Db {
        Blockchain::db_mut(self)
    }
}

impl<'a, Tx, Db> Storage<Fork<'a, Db>, Tx> for Fork<'a, Db> where Db: Database,
                                                                  Tx: Message + StorageValue {
    fn db(&self) -> &Fork<'a, Db> {
        self
    }

    fn db_mut(&mut self) -> &mut Fork<'a, Db> {
        self
    }
}

pub type Error = Box<Debug>;

// TODO We need to understand how to finish them
// pub trait Iterable {
//     type Iter: Iterator;

//     fn iter(self) -> Self::Iter;
// }

// pub trait Seekable<'a> {
//     type Item;
//     type Key: ?Sized;

//     fn seek(&mut self, key: &Self::Key) -> Option<Self::Item>;
// }

pub trait Map<K: ?Sized, V> {
    fn get(&self, key: &K) -> Result<Option<V>, Error>;
    fn put(&mut self, key: &K, value: V) -> Result<(), Error>;
    fn delete(&mut self, key: &K) -> Result<(), Error>;
    fn find_key(&self, key: &K) -> Result<Option<Vec<u8>>, Error>;
}

pub trait List<K: Integer + Copy + Clone + ToPrimitive, V> {
    fn append(&mut self, value: V) -> Result<(), Error>;
    fn extend<I: IntoIterator<Item = V>>(&mut self, iter: I) -> Result<(), Error>;
    fn get(&self, index: K) -> Result<Option<V>, Error>;
    fn last(&self) -> Result<Option<V>, Error>;
    fn is_empty(&self) -> Result<bool, Error>;
    fn len(&self) -> Result<K, Error>;
}
<|endoftext|>


<commit_before>use color::Color;
use game::Piece;

use std::ops::Range;

#[derive(Debug, PartialEq, Eq)]
pub struct Board {
    color_matrix: Vec<Vec<Option<Color>>>,
}

impl Board {
    pub fn new(width: usize, height: usize) -> Board {
        Board {
            color_matrix: vec![vec![None; width]; height],
        }
    }

    fn height(&self) -> usize {
        self.color_matrix.len()
    }

    fn width(&self) -> usize {
        self.color_matrix.get(0).unwrap_or(&vec![]).len()
    }

    pub fn set(&mut self, row: usize, col: usize, color: Color) {
        self.color_matrix.get_mut(row).unwrap()[col] = Some(color);
    }

    pub fn get(&self, row: usize, col:usize) -> Option<Color> {
        self.color_matrix.get(row)
            .unwrap_or(&vec![])
            .get(col)
            .unwrap_or(&None)
            .clone()
    }

    pub fn get_pieces(&self) -> Vec<Piece> {
        self.color_matrix.iter()
            .enumerate()
            .flat_map(|(row_num, col)| {
                let pieces: Vec<Piece> = col.iter()
                    .enumerate()
                    .filter_map(|(col_num, color)| {
                        if let Some(c) = color.clone() {
                            Some(Piece { row: row_num, col: col_num, color: c })
                        } else {
                            None
                        }
                    }).collect();
                pieces
            })
            .collect()
    }

    fn get_sequences_in_coordinate_list(
        &self,
        coordinates: Vec<(usize, usize)>
    ) -> Vec<Vec<Piece>>
        {

        let sequence_clear_len = 4;

        let mut sequences: Vec<Vec<Piece>> = vec![];

        let mut sequence: Vec<Piece> = vec![];

        for (row, col) in coordinates {
            let color = self.get(row, col);

            let prev_color = match sequence.last() {
                Some(piece) => Some(piece.color()),
                _ => None,
            };

            match (color, prev_color) {
                (Some(ref c1), Some(ref c2)) if c1 == c2 => {
                    sequence.push(Piece {row: row, col: col, color: c1.clone() });
                },
                (Some(c1), None) => {
                    if sequence.len() >= sequence_clear_len {
                        sequences.push(sequence.clone());
                    }

                    sequence.clear();
                    sequence.push(Piece {row: row, col: col, color: c1.clone() });
                },
                _ => {
                    if sequence.len() >= sequence_clear_len {
                        sequences.push(sequence.clone());
                    }

                    sequence.clear();
                }
            }
        }

        if sequence.len() >= sequence_clear_len {
            sequences.push(sequence);
        }

        sequences
    }

    pub fn get_sequences_to_clear(&self) -> Vec<Vec<Piece>> {
        let mut sequences: Vec<Vec<Piece>> = vec![];

        // vertical
        for col in 0..self.width() {
            let mut coordinates = vec![];

            for row in 0..self.height() {
                coordinates.push((row, col));
            }

            let new_sequences = self.get_sequences_in_coordinate_list(
                coordinates
            );

            for s in new_sequences {
                sequences.push(s);
            }
        }

        // horizontal
        for row in 0..self.height() {
            let mut coordinates = vec![];

            for col in 0..self.width() {
                coordinates.push((row, col));
            }

            let new_sequences = self.get_sequences_in_coordinate_list(
                coordinates
            );

            for s in new_sequences {
                sequences.push(s);
            }
        }

        // diagonal up by row, looks like /
        for starting_row in 0..self.height() {
            let mut coordinates = vec![];

            for (row, col) in (0...starting_row).rev().zip(0..self.width()) {
                coordinates.push((row, col));
            }

            let new_sequences = self.get_sequences_in_coordinate_list(
                coordinates
            );

            for s in new_sequences {
                sequences.push(s);
            }
        }

        // diagonal up by col, looks like /
        for starting_col in 1..self.width() {
            let mut coordinates = vec![];

            for (row, col) in (0...(self.height() - 1)).rev().zip(starting_col..self.width()) {
                coordinates.push((row, col));
            }

            let new_sequences = self.get_sequences_in_coordinate_list(
                coordinates
            );

            for s in new_sequences {
                sequences.push(s);
            }
        }

        sequences
    }

    pub fn clear_all(&mut self, pieces: Vec<Piece>) {
    }

    pub fn get_lowest_free_row_in_col(&self, col: usize) -> usize {
        self.color_matrix.iter()
            .rposition(|row| row.get(col).unwrap_or(&None).is_none())
            .unwrap()
    }
}

#[cfg(test)]
mod tests {
    use board::Board;
    use color::Color::*;
    use game::Piece;

    #[test]
    fn get_sequences_to_clear_diagonal_up() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, Some(Red) ],
                vec![ None, None, Some(Red), None ],
                vec![ None, Some(Red), None, None ],
                vec![ Some(Red), None, None, None ],
            ],
        };

        let mut expected_sequences_to_clear = vec![vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 1, col: 2, color: Red },
            Piece { row: 0, col: 3, color: Red },
        ]];

        let mut sequences_to_clear = board.get_sequences_to_clear();

        expected_sequences_to_clear.sort();
        sequences_to_clear.sort();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn get_sequences_to_clear_diagonal_up_off_center_up() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, Some(Red), None, None, None ],
                vec![ Some(Red), None, None, None, None ],
                vec![ None, None, None, None, None ],
            ],
        };

        let mut expected_sequences_to_clear = vec![vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 1, col: 2, color: Red },
            Piece { row: 0, col: 3, color: Red },
        ]];

        let mut sequences_to_clear = board.get_sequences_to_clear();

        expected_sequences_to_clear.sort();
        sequences_to_clear.sort();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn get_sequences_to_clear_diagonal_up_off_center_down() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None, None ],
                vec![ None, None, None, None, Some(Red) ],
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, Some(Red), None, None, None ],
            ],
        };

        let mut expected_sequences_to_clear = vec![vec![
            Piece { row: 4, col: 1, color: Red },
            Piece { row: 3, col: 2, color: Red },
            Piece { row: 2, col: 3, color: Red },
            Piece { row: 1, col: 4, color: Red },
        ]];

        let mut sequences_to_clear = board.get_sequences_to_clear();

        expected_sequences_to_clear.sort();
        sequences_to_clear.sort();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn get_sequences_to_clear_horizontal() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None ],
                vec![ None, None, None, None ],
                vec![ Some(Red), Some(Red), Some(Red), Some(Red) ],
                vec![ None, None, None, None ],
            ],
        };

        let expected_sequences_to_clear = vec![vec![
            Piece { row: 2, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 2, col: 3, color: Red },
        ]];

        let sequences_to_clear = board.get_sequences_to_clear();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn get_sequences_to_clear_vertical() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Yellow), None ],
            ],
        };

        let expected_sequences_to_clear = vec![vec![
            Piece { row: 0, col: 0, color: Red },
            Piece { row: 1, col: 0, color: Red },
            Piece { row: 2, col: 0, color: Red },
            Piece { row: 3, col: 0, color: Red },
        ]];

        let sequences_to_clear = board.get_sequences_to_clear();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn get_sequences_to_clear_vertical_none_eligible() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None ],
                vec![ Some(Blue), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
            ],
        };

        let expected_sequences_to_clear: Vec<Vec<Piece>> = vec![];

        let sequences_to_clear = board.get_sequences_to_clear();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn set_a_color() {
        let mut board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Red) ],
                vec![ Some(Red), Some(Red) ],
            ],
        };

        board.set(1, 1, Yellow);

        let expected_board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Red) ],
                vec![ Some(Red), Some(Yellow) ],
            ],
        };

        assert_eq!(expected_board, board);
    }

    #[test]
    fn get_a_color() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Blue) ],
                vec![ Some(Red), Some(Yellow) ],
            ],
        };

        let color = board.get(0, 1);

        let expected_color = Some(Blue);

        assert_eq!(expected_color, color);
    }

    #[test]
    fn get_lowest_free_row_in_col() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None ],
                vec![ None, None ],
            ],
        };

        let row = board.get_lowest_free_row_in_col(0);
        let expected_row = 1;

        assert_eq!(expected_row, row);
    }

    #[test]
    fn get_lowest_free_row_in_col_with_another_existing_piece() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None ],
                vec![ Some(Red), None ],
            ],
        };

        let row = board.get_lowest_free_row_in_col(0);
        let expected_row = 0;

        assert_eq!(expected_row, row);
    }
}
<commit_msg>unused use<commit_after>use color::Color;
use game::Piece;

#[derive(Debug, PartialEq, Eq)]
pub struct Board {
    color_matrix: Vec<Vec<Option<Color>>>,
}

impl Board {
    pub fn new(width: usize, height: usize) -> Board {
        Board {
            color_matrix: vec![vec![None; width]; height],
        }
    }

    fn height(&self) -> usize {
        self.color_matrix.len()
    }

    fn width(&self) -> usize {
        self.color_matrix.get(0).unwrap_or(&vec![]).len()
    }

    pub fn set(&mut self, row: usize, col: usize, color: Color) {
        self.color_matrix.get_mut(row).unwrap()[col] = Some(color);
    }

    pub fn get(&self, row: usize, col:usize) -> Option<Color> {
        self.color_matrix.get(row)
            .unwrap_or(&vec![])
            .get(col)
            .unwrap_or(&None)
            .clone()
    }

    pub fn get_pieces(&self) -> Vec<Piece> {
        self.color_matrix.iter()
            .enumerate()
            .flat_map(|(row_num, col)| {
                let pieces: Vec<Piece> = col.iter()
                    .enumerate()
                    .filter_map(|(col_num, color)| {
                        if let Some(c) = color.clone() {
                            Some(Piece { row: row_num, col: col_num, color: c })
                        } else {
                            None
                        }
                    }).collect();
                pieces
            })
            .collect()
    }

    fn get_sequences_in_coordinate_list(
        &self,
        coordinates: Vec<(usize, usize)>
    ) -> Vec<Vec<Piece>>
        {

        let sequence_clear_len = 4;

        let mut sequences: Vec<Vec<Piece>> = vec![];

        let mut sequence: Vec<Piece> = vec![];

        for (row, col) in coordinates {
            let color = self.get(row, col);

            let prev_color = match sequence.last() {
                Some(piece) => Some(piece.color()),
                _ => None,
            };

            match (color, prev_color) {
                (Some(ref c1), Some(ref c2)) if c1 == c2 => {
                    sequence.push(Piece {row: row, col: col, color: c1.clone() });
                },
                (Some(c1), None) => {
                    if sequence.len() >= sequence_clear_len {
                        sequences.push(sequence.clone());
                    }

                    sequence.clear();
                    sequence.push(Piece {row: row, col: col, color: c1.clone() });
                },
                _ => {
                    if sequence.len() >= sequence_clear_len {
                        sequences.push(sequence.clone());
                    }

                    sequence.clear();
                }
            }
        }

        if sequence.len() >= sequence_clear_len {
            sequences.push(sequence);
        }

        sequences
    }

    pub fn get_sequences_to_clear(&self) -> Vec<Vec<Piece>> {
        let mut sequences: Vec<Vec<Piece>> = vec![];

        // vertical
        for col in 0..self.width() {
            let mut coordinates = vec![];

            for row in 0..self.height() {
                coordinates.push((row, col));
            }

            let new_sequences = self.get_sequences_in_coordinate_list(
                coordinates
            );

            for s in new_sequences {
                sequences.push(s);
            }
        }

        // horizontal
        for row in 0..self.height() {
            let mut coordinates = vec![];

            for col in 0..self.width() {
                coordinates.push((row, col));
            }

            let new_sequences = self.get_sequences_in_coordinate_list(
                coordinates
            );

            for s in new_sequences {
                sequences.push(s);
            }
        }

        // diagonal up by row, looks like /
        for starting_row in 0..self.height() {
            let mut coordinates = vec![];

            for (row, col) in (0...starting_row).rev().zip(0..self.width()) {
                coordinates.push((row, col));
            }

            let new_sequences = self.get_sequences_in_coordinate_list(
                coordinates
            );

            for s in new_sequences {
                sequences.push(s);
            }
        }

        // diagonal up by col, looks like /
        for starting_col in 1..self.width() {
            let mut coordinates = vec![];

            for (row, col) in (0...(self.height() - 1)).rev().zip(starting_col..self.width()) {
                coordinates.push((row, col));
            }

            let new_sequences = self.get_sequences_in_coordinate_list(
                coordinates
            );

            for s in new_sequences {
                sequences.push(s);
            }
        }

        sequences
    }

    pub fn clear_all(&mut self, pieces: Vec<Piece>) {
    }

    pub fn get_lowest_free_row_in_col(&self, col: usize) -> usize {
        self.color_matrix.iter()
            .rposition(|row| row.get(col).unwrap_or(&None).is_none())
            .unwrap()
    }
}

#[cfg(test)]
mod tests {
    use board::Board;
    use color::Color::*;
    use game::Piece;

    #[test]
    fn get_sequences_to_clear_diagonal_up() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, Some(Red) ],
                vec![ None, None, Some(Red), None ],
                vec![ None, Some(Red), None, None ],
                vec![ Some(Red), None, None, None ],
            ],
        };

        let mut expected_sequences_to_clear = vec![vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 1, col: 2, color: Red },
            Piece { row: 0, col: 3, color: Red },
        ]];

        let mut sequences_to_clear = board.get_sequences_to_clear();

        expected_sequences_to_clear.sort();
        sequences_to_clear.sort();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn get_sequences_to_clear_diagonal_up_off_center_up() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, Some(Red), None, None, None ],
                vec![ Some(Red), None, None, None, None ],
                vec![ None, None, None, None, None ],
            ],
        };

        let mut expected_sequences_to_clear = vec![vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 1, col: 2, color: Red },
            Piece { row: 0, col: 3, color: Red },
        ]];

        let mut sequences_to_clear = board.get_sequences_to_clear();

        expected_sequences_to_clear.sort();
        sequences_to_clear.sort();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn get_sequences_to_clear_diagonal_up_off_center_down() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None, None ],
                vec![ None, None, None, None, Some(Red) ],
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, Some(Red), None, None, None ],
            ],
        };

        let mut expected_sequences_to_clear = vec![vec![
            Piece { row: 4, col: 1, color: Red },
            Piece { row: 3, col: 2, color: Red },
            Piece { row: 2, col: 3, color: Red },
            Piece { row: 1, col: 4, color: Red },
        ]];

        let mut sequences_to_clear = board.get_sequences_to_clear();

        expected_sequences_to_clear.sort();
        sequences_to_clear.sort();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn get_sequences_to_clear_horizontal() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None ],
                vec![ None, None, None, None ],
                vec![ Some(Red), Some(Red), Some(Red), Some(Red) ],
                vec![ None, None, None, None ],
            ],
        };

        let expected_sequences_to_clear = vec![vec![
            Piece { row: 2, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 2, col: 3, color: Red },
        ]];

        let sequences_to_clear = board.get_sequences_to_clear();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn get_sequences_to_clear_vertical() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Yellow), None ],
            ],
        };

        let expected_sequences_to_clear = vec![vec![
            Piece { row: 0, col: 0, color: Red },
            Piece { row: 1, col: 0, color: Red },
            Piece { row: 2, col: 0, color: Red },
            Piece { row: 3, col: 0, color: Red },
        ]];

        let sequences_to_clear = board.get_sequences_to_clear();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn get_sequences_to_clear_vertical_none_eligible() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None ],
                vec![ Some(Blue), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
            ],
        };

        let expected_sequences_to_clear: Vec<Vec<Piece>> = vec![];

        let sequences_to_clear = board.get_sequences_to_clear();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn set_a_color() {
        let mut board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Red) ],
                vec![ Some(Red), Some(Red) ],
            ],
        };

        board.set(1, 1, Yellow);

        let expected_board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Red) ],
                vec![ Some(Red), Some(Yellow) ],
            ],
        };

        assert_eq!(expected_board, board);
    }

    #[test]
    fn get_a_color() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Blue) ],
                vec![ Some(Red), Some(Yellow) ],
            ],
        };

        let color = board.get(0, 1);

        let expected_color = Some(Blue);

        assert_eq!(expected_color, color);
    }

    #[test]
    fn get_lowest_free_row_in_col() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None ],
                vec![ None, None ],
            ],
        };

        let row = board.get_lowest_free_row_in_col(0);
        let expected_row = 1;

        assert_eq!(expected_row, row);
    }

    #[test]
    fn get_lowest_free_row_in_col_with_another_existing_piece() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None ],
                vec![ Some(Red), None ],
            ],
        };

        let row = board.get_lowest_free_row_in_col(0);
        let expected_row = 0;

        assert_eq!(expected_row, row);
    }
}
<|endoftext|>


<commit_before>use super::start;

use std::sync::{Arc, Mutex};

#[test]
fn empty_handler() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |_| {
        let mut lock = finished_copy.lock().unwrap();
        *lock = true;

        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}
<commit_msg>Add `contain_panics` test.<commit_after>use super::start;

use std::sync::{Arc, Mutex};

#[test]
fn empty_handler() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |_| {
        let mut lock = finished_copy.lock().unwrap();
        *lock = true;

        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn contain_panics() {
    let finished_ok = Arc::new(Mutex::new(false));

    start(move |_| {
        panic!()
    });

    assert!(!*finished_ok.lock().unwrap());
}
<|endoftext|>