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

#![allow(unsafe_code)]

//! A drop-in replacement for string_cache, but backed by Gecko `nsIAtom`s.

use gecko_bindings::bindings::Gecko_AddRefAtom;
use gecko_bindings::bindings::Gecko_Atomize;
use gecko_bindings::bindings::Gecko_Atomize16;
use gecko_bindings::bindings::Gecko_ReleaseAtom;
use gecko_bindings::structs::nsIAtom;
use nsstring::nsAString;
use precomputed_hash::PrecomputedHash;
use std::ascii::AsciiExt;
use std::borrow::{Cow, Borrow};
use std::char::{self, DecodeUtf16};
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
use std::iter::Cloned;
use std::mem;
use std::ops::Deref;
use std::slice;

#[macro_use]
#[allow(improper_ctypes, non_camel_case_types, missing_docs)]
pub mod atom_macro {
    include!(concat!(env!("OUT_DIR"), "/gecko/atom_macro.rs"));
}

#[macro_use]
pub mod namespace;

pub use self::namespace::{Namespace, WeakNamespace};

macro_rules! local_name {
    ($s: tt) => { atom!($s) }
}

/// A strong reference to a Gecko atom.
#[derive(PartialEq, Eq)]
pub struct Atom(*mut WeakAtom);

/// An atom *without* a strong reference.
///
/// Only usable as `&'a WeakAtom`,
/// where `'a` is the lifetime of something that holds a strong reference to that atom.
pub struct WeakAtom(nsIAtom);

/// A BorrowedAtom for Gecko is just a weak reference to a `nsIAtom`, that
/// hasn't been bumped.
pub type BorrowedAtom<'a> = &'a WeakAtom;

impl Deref for Atom {
    type Target = WeakAtom;

    #[inline]
    fn deref(&self) -> &WeakAtom {
        unsafe {
            &*self.0
        }
    }
}

impl PrecomputedHash for Atom {
    #[inline]
    fn precomputed_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl Borrow<WeakAtom> for Atom {
    #[inline]
    fn borrow(&self) -> &WeakAtom {
        self
    }
}

impl Eq for WeakAtom {}
impl PartialEq for WeakAtom {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        let weak: *const WeakAtom = self;
        let other: *const WeakAtom = other;
        weak == other
    }
}

unsafe impl Send for Atom {}
unsafe impl Sync for Atom {}
unsafe impl Sync for WeakAtom {}

impl WeakAtom {
    /// Construct a `WeakAtom` from a raw `nsIAtom`.
    #[inline]
    pub unsafe fn new<'a>(atom: *mut nsIAtom) -> &'a mut Self {
        &mut *(atom as *mut WeakAtom)
    }

    /// Clone this atom, bumping the refcount if the atom is not static.
    #[inline]
    pub fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }

    /// Get the atom hash.
    #[inline]
    pub fn get_hash(&self) -> u32 {
        self.0.mHash
    }

    /// Get the atom as a slice of utf-16 chars.
    #[inline]
    pub fn as_slice(&self) -> &[u16] {
        unsafe {
            slice::from_raw_parts((*self.as_ptr()).mString, self.len() as usize)
        }
    }

    // NOTE: don't expose this, since it's slow, and easy to be misused.
    fn chars(&self) -> DecodeUtf16<Cloned<slice::Iter<u16>>> {
        char::decode_utf16(self.as_slice().iter().cloned())
    }

    /// Execute `cb` with the string that this atom represents.
    ///
    /// Find alternatives to this function when possible, please, since it's
    /// pretty slow.
    pub fn with_str<F, Output>(&self, cb: F) -> Output
        where F: FnOnce(&str) -> Output
    {
        // FIXME(bholley): We should measure whether it makes more sense to
        // cache the UTF-8 version in the Gecko atom table somehow.
        let owned = self.to_string();
        cb(&owned)
    }

    /// Convert this Atom into a string, decoding the UTF-16 bytes.
    ///
    /// Find alternatives to this function when possible, please, since it's
    /// pretty slow.
    #[inline]
    pub fn to_string(&self) -> String {
        String::from_utf16(self.as_slice()).unwrap()
    }

    /// Returns whether this atom is static.
    #[inline]
    pub fn is_static(&self) -> bool {
        // FIXME(emilio): re-introduce bitfield accessors:
        //
        // https://github.com/servo/rust-bindgen/issues/519
        unsafe {
            ((*self.as_ptr())._bitfield_1 & (0x80000000 as u32)) != 0
        }
    }

    /// Returns the length of the atom string.
    #[inline]
    pub fn len(&self) -> u32 {
        // FIXME(emilio): re-introduce bitfield accessors:
        //
        // https://github.com/servo/rust-bindgen/issues/519
        unsafe {
            (*self.as_ptr())._bitfield_1 & 0x7FFFFFFF
        }
    }

    /// Returns whether this atom is the empty string.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the atom as a mutable pointer.
    #[inline]
    pub fn as_ptr(&self) -> *mut nsIAtom {
        let const_ptr: *const nsIAtom = &self.0;
        const_ptr as *mut nsIAtom
    }
}

impl fmt::Debug for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko WeakAtom({:p}, {})", self, self)
    }
}

impl fmt::Display for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        for c in self.chars() {
            try!(w.write_char(c.unwrap_or(char::REPLACEMENT_CHARACTER)))
        }
        Ok(())
    }
}

impl Atom {
    /// Execute a callback with the atom represented by `ptr`.
    pub unsafe fn with<F, R>(ptr: *mut nsIAtom, callback: F) -> R where F: FnOnce(&Atom) -> R {
        let atom = Atom(WeakAtom::new(ptr));
        let ret = callback(&atom);
        mem::forget(atom);
        ret
    }

    /// Creates an atom from an static atom pointer without checking in release
    /// builds.
    ///
    /// Right now it's only used by the atom macro, and ideally it should keep
    /// that way, now we have sugar for is_static, creating atoms using
    /// Atom::from should involve almost no overhead.
    #[inline]
    unsafe fn from_static(ptr: *mut nsIAtom) -> Self {
        let atom = Atom(ptr as *mut WeakAtom);
        debug_assert!(atom.is_static(),
                      "Called from_static for a non-static atom!");
        atom
    }

    /// Creates an atom from a dynamic atom pointer that has already had AddRef
    /// called on it.
    #[inline]
    pub unsafe fn from_addrefed(ptr: *mut nsIAtom) -> Self {
        debug_assert!(!ptr.is_null());
        unsafe {
            Atom(WeakAtom::new(ptr))
        }
    }

    /// Convert this atom into an addrefed nsIAtom pointer.
    #[inline]
    pub fn into_addrefed(self) -> *mut nsIAtom {
        let ptr = self.as_ptr();
        mem::forget(self);
        ptr
    }

    /// Return whether two atoms are ASCII-case-insensitive matches
    pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        if self == other {
            return true;
        }

        let a = self.as_slice();
        let b = other.as_slice();
        a.len() == b.len() && a.iter().zip(b).all(|(&a16, &b16)| {
            if a16 <= 0x7F && b16 <= 0x7F {
                (a16 as u8).eq_ignore_ascii_case(&(b16 as u8))
            } else {
                a16 == b16
            }
        })
    }

    /// Return whether this atom is an ASCII-case-insensitive match for the given string
    pub fn eq_str_ignore_ascii_case(&self, other: &str) -> bool {
        self.chars().map(|r| r.map(|c: char| c.to_ascii_lowercase()))
        .eq(other.chars().map(|c: char| Ok(c.to_ascii_lowercase())))
    }
}

impl Hash for Atom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Hash for WeakAtom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Clone for Atom {
    #[inline(always)]
    fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }
}

impl Drop for Atom {
    #[inline]
    fn drop(&mut self) {
        if !self.is_static() {
            unsafe {
                Gecko_ReleaseAtom(self.as_ptr());
            }
        }
    }
}

impl Default for Atom {
    #[inline]
    fn default() -> Self {
        atom!("")
    }
}

impl fmt::Debug for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko Atom({:p}, {})", self.0, self)
    }
}

impl fmt::Display for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            (&*self.0).fmt(w)
        }
    }
}

impl<'a> From<&'a str> for Atom {
    #[inline]
    fn from(string: &str) -> Atom {
        debug_assert!(string.len() <= u32::max_value() as usize);
        unsafe {
            Atom(WeakAtom::new(
                Gecko_Atomize(string.as_ptr() as *const _, string.len() as u32)
            ))
        }
    }
}

impl<'a> From<&'a nsAString> for Atom {
    #[inline]
    fn from(string: &nsAString) -> Atom {
        unsafe {
            Atom(WeakAtom::new(
                Gecko_Atomize16(string)
            ))
        }
    }
}

impl<'a> From<Cow<'a, str>> for Atom {
    #[inline]
    fn from(string: Cow<'a, str>) -> Atom {
        Atom::from(&*string)
    }
}

impl From<String> for Atom {
    #[inline]
    fn from(string: String) -> Atom {
        Atom::from(&*string)
    }
}

impl From<*mut nsIAtom> for Atom {
    #[inline]
    fn from(ptr: *mut nsIAtom) -> Atom {
        debug_assert!(!ptr.is_null());
        unsafe {
            let ret = Atom(WeakAtom::new(ptr));
            if !ret.is_static() {
                Gecko_AddRefAtom(ptr);
            }
            ret
        }
    }
}
<commit_msg>Auto merge of #17270 - emilio:bindgen-does-bitfields-sort-of, r=wafflespeanut<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![allow(unsafe_code)]

//! A drop-in replacement for string_cache, but backed by Gecko `nsIAtom`s.

use gecko_bindings::bindings::Gecko_AddRefAtom;
use gecko_bindings::bindings::Gecko_Atomize;
use gecko_bindings::bindings::Gecko_Atomize16;
use gecko_bindings::bindings::Gecko_ReleaseAtom;
use gecko_bindings::structs::nsIAtom;
use nsstring::nsAString;
use precomputed_hash::PrecomputedHash;
use std::ascii::AsciiExt;
use std::borrow::{Cow, Borrow};
use std::char::{self, DecodeUtf16};
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
use std::iter::Cloned;
use std::mem;
use std::ops::Deref;
use std::slice;

#[macro_use]
#[allow(improper_ctypes, non_camel_case_types, missing_docs)]
pub mod atom_macro {
    include!(concat!(env!("OUT_DIR"), "/gecko/atom_macro.rs"));
}

#[macro_use]
pub mod namespace;

pub use self::namespace::{Namespace, WeakNamespace};

macro_rules! local_name {
    ($s: tt) => { atom!($s) }
}

/// A strong reference to a Gecko atom.
#[derive(PartialEq, Eq)]
pub struct Atom(*mut WeakAtom);

/// An atom *without* a strong reference.
///
/// Only usable as `&'a WeakAtom`,
/// where `'a` is the lifetime of something that holds a strong reference to that atom.
pub struct WeakAtom(nsIAtom);

/// A BorrowedAtom for Gecko is just a weak reference to a `nsIAtom`, that
/// hasn't been bumped.
pub type BorrowedAtom<'a> = &'a WeakAtom;

impl Deref for Atom {
    type Target = WeakAtom;

    #[inline]
    fn deref(&self) -> &WeakAtom {
        unsafe {
            &*self.0
        }
    }
}

impl PrecomputedHash for Atom {
    #[inline]
    fn precomputed_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl Borrow<WeakAtom> for Atom {
    #[inline]
    fn borrow(&self) -> &WeakAtom {
        self
    }
}

impl Eq for WeakAtom {}
impl PartialEq for WeakAtom {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        let weak: *const WeakAtom = self;
        let other: *const WeakAtom = other;
        weak == other
    }
}

unsafe impl Send for Atom {}
unsafe impl Sync for Atom {}
unsafe impl Sync for WeakAtom {}

impl WeakAtom {
    /// Construct a `WeakAtom` from a raw `nsIAtom`.
    #[inline]
    pub unsafe fn new<'a>(atom: *mut nsIAtom) -> &'a mut Self {
        &mut *(atom as *mut WeakAtom)
    }

    /// Clone this atom, bumping the refcount if the atom is not static.
    #[inline]
    pub fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }

    /// Get the atom hash.
    #[inline]
    pub fn get_hash(&self) -> u32 {
        self.0.mHash
    }

    /// Get the atom as a slice of utf-16 chars.
    #[inline]
    pub fn as_slice(&self) -> &[u16] {
        unsafe {
            slice::from_raw_parts((*self.as_ptr()).mString, self.len() as usize)
        }
    }

    // NOTE: don't expose this, since it's slow, and easy to be misused.
    fn chars(&self) -> DecodeUtf16<Cloned<slice::Iter<u16>>> {
        char::decode_utf16(self.as_slice().iter().cloned())
    }

    /// Execute `cb` with the string that this atom represents.
    ///
    /// Find alternatives to this function when possible, please, since it's
    /// pretty slow.
    pub fn with_str<F, Output>(&self, cb: F) -> Output
        where F: FnOnce(&str) -> Output
    {
        // FIXME(bholley): We should measure whether it makes more sense to
        // cache the UTF-8 version in the Gecko atom table somehow.
        let owned = self.to_string();
        cb(&owned)
    }

    /// Convert this Atom into a string, decoding the UTF-16 bytes.
    ///
    /// Find alternatives to this function when possible, please, since it's
    /// pretty slow.
    #[inline]
    pub fn to_string(&self) -> String {
        String::from_utf16(self.as_slice()).unwrap()
    }

    /// Returns whether this atom is static.
    #[inline]
    pub fn is_static(&self) -> bool {
        unsafe {
            (*self.as_ptr()).mIsStatic() != 0
        }
    }

    /// Returns the length of the atom string.
    #[inline]
    pub fn len(&self) -> u32 {
        // FIXME(emilio): re-introduce bitfield accessors:
        //
        // https://github.com/servo/rust-bindgen/issues/519
        unsafe {
            (*self.as_ptr())._bitfield_1 & 0x7FFFFFFF
        }
    }

    /// Returns whether this atom is the empty string.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the atom as a mutable pointer.
    #[inline]
    pub fn as_ptr(&self) -> *mut nsIAtom {
        let const_ptr: *const nsIAtom = &self.0;
        const_ptr as *mut nsIAtom
    }
}

impl fmt::Debug for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko WeakAtom({:p}, {})", self, self)
    }
}

impl fmt::Display for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        for c in self.chars() {
            try!(w.write_char(c.unwrap_or(char::REPLACEMENT_CHARACTER)))
        }
        Ok(())
    }
}

impl Atom {
    /// Execute a callback with the atom represented by `ptr`.
    pub unsafe fn with<F, R>(ptr: *mut nsIAtom, callback: F) -> R where F: FnOnce(&Atom) -> R {
        let atom = Atom(WeakAtom::new(ptr));
        let ret = callback(&atom);
        mem::forget(atom);
        ret
    }

    /// Creates an atom from an static atom pointer without checking in release
    /// builds.
    ///
    /// Right now it's only used by the atom macro, and ideally it should keep
    /// that way, now we have sugar for is_static, creating atoms using
    /// Atom::from should involve almost no overhead.
    #[inline]
    unsafe fn from_static(ptr: *mut nsIAtom) -> Self {
        let atom = Atom(ptr as *mut WeakAtom);
        debug_assert!(atom.is_static(),
                      "Called from_static for a non-static atom!");
        atom
    }

    /// Creates an atom from a dynamic atom pointer that has already had AddRef
    /// called on it.
    #[inline]
    pub unsafe fn from_addrefed(ptr: *mut nsIAtom) -> Self {
        debug_assert!(!ptr.is_null());
        unsafe {
            Atom(WeakAtom::new(ptr))
        }
    }

    /// Convert this atom into an addrefed nsIAtom pointer.
    #[inline]
    pub fn into_addrefed(self) -> *mut nsIAtom {
        let ptr = self.as_ptr();
        mem::forget(self);
        ptr
    }

    /// Return whether two atoms are ASCII-case-insensitive matches
    pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        if self == other {
            return true;
        }

        let a = self.as_slice();
        let b = other.as_slice();
        a.len() == b.len() && a.iter().zip(b).all(|(&a16, &b16)| {
            if a16 <= 0x7F && b16 <= 0x7F {
                (a16 as u8).eq_ignore_ascii_case(&(b16 as u8))
            } else {
                a16 == b16
            }
        })
    }

    /// Return whether this atom is an ASCII-case-insensitive match for the given string
    pub fn eq_str_ignore_ascii_case(&self, other: &str) -> bool {
        self.chars().map(|r| r.map(|c: char| c.to_ascii_lowercase()))
        .eq(other.chars().map(|c: char| Ok(c.to_ascii_lowercase())))
    }
}

impl Hash for Atom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Hash for WeakAtom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Clone for Atom {
    #[inline(always)]
    fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }
}

impl Drop for Atom {
    #[inline]
    fn drop(&mut self) {
        if !self.is_static() {
            unsafe {
                Gecko_ReleaseAtom(self.as_ptr());
            }
        }
    }
}

impl Default for Atom {
    #[inline]
    fn default() -> Self {
        atom!("")
    }
}

impl fmt::Debug for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko Atom({:p}, {})", self.0, self)
    }
}

impl fmt::Display for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            (&*self.0).fmt(w)
        }
    }
}

impl<'a> From<&'a str> for Atom {
    #[inline]
    fn from(string: &str) -> Atom {
        debug_assert!(string.len() <= u32::max_value() as usize);
        unsafe {
            Atom(WeakAtom::new(
                Gecko_Atomize(string.as_ptr() as *const _, string.len() as u32)
            ))
        }
    }
}

impl<'a> From<&'a nsAString> for Atom {
    #[inline]
    fn from(string: &nsAString) -> Atom {
        unsafe {
            Atom(WeakAtom::new(
                Gecko_Atomize16(string)
            ))
        }
    }
}

impl<'a> From<Cow<'a, str>> for Atom {
    #[inline]
    fn from(string: Cow<'a, str>) -> Atom {
        Atom::from(&*string)
    }
}

impl From<String> for Atom {
    #[inline]
    fn from(string: String) -> Atom {
        Atom::from(&*string)
    }
}

impl From<*mut nsIAtom> for Atom {
    #[inline]
    fn from(ptr: *mut nsIAtom) -> Atom {
        debug_assert!(!ptr.is_null());
        unsafe {
            let ret = Atom(WeakAtom::new(ptr));
            if !ret.is_static() {
                Gecko_AddRefAtom(ptr);
            }
            ret
        }
    }
}
<|endoftext|>


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

//! Specified types for CSS values related to tables.

/// Specified values for the `caption-side` property.
///
/// Note that despite having "physical" names, these are actually interpreted
/// according to the table's writing-mode: Top and Bottom are treated as
/// block-start and -end respectively, and Left and Right are treated as
/// line-start and -end.
///
/// https://drafts.csswg.org/css-tables/#propdef-caption-side
#[allow(missing_docs)]
#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    FromPrimitive,
    MallocSizeOf,
    Ord,
    Parse,
    PartialEq,
    PartialOrd,
    SpecifiedValueInfo,
    ToComputedValue,
    ToCss,
    ToResolvedValue,
    ToShmem,
)]
#[repr(u8)]
pub enum CaptionSide {
    Top,
    Bottom,
    #[cfg(feature = "gecko")]
    Right,
    #[cfg(feature = "gecko")]
    Left,
    #[cfg(feature = "gecko")]
    TopOutside,
    #[cfg(feature = "gecko")]
    BottomOutside,
}
<commit_msg>style: Hide non-standard values of caption-side.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

//! Specified types for CSS values related to tables.

use crate::parser::ParserContext;

/// Specified values for the `caption-side` property.
///
/// Note that despite having "physical" names, these are actually interpreted
/// according to the table's writing-mode: Top and Bottom are treated as
/// block-start and -end respectively, and Left and Right are treated as
/// line-start and -end.
///
/// https://drafts.csswg.org/css-tables/#propdef-caption-side
#[cfg(feature = "gecko")]
fn caption_side_non_standard_enabled(_context: &ParserContext) -> bool {
    static_prefs::pref!("layout.css.caption-side-non-standard.enabled")
}

#[allow(missing_docs)]
#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    FromPrimitive,
    MallocSizeOf,
    Ord,
    Parse,
    PartialEq,
    PartialOrd,
    SpecifiedValueInfo,
    ToComputedValue,
    ToCss,
    ToResolvedValue,
    ToShmem,
)]
#[repr(u8)]
pub enum CaptionSide {
    Top,
    Bottom,
    #[cfg(feature = "gecko")]
    #[parse(condition = "caption_side_non_standard_enabled")]
    Right,
    #[cfg(feature = "gecko")]
    #[parse(condition = "caption_side_non_standard_enabled")]
    Left,
    #[cfg(feature = "gecko")]
    #[parse(condition = "caption_side_non_standard_enabled")]
    TopOutside,
    #[cfg(feature = "gecko")]
    #[parse(condition = "caption_side_non_standard_enabled")]
    BottomOutside,
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Graphics commands encoder.

#![deny(missing_docs)]

use draw_state::target::{Depth, Stencil};
use std::error::Error;
use std::any::Any;
use std::{fmt, mem};

use core::{Device, IndexType, Resources, VertexCount};
use core::{command, format, handle, texture};
use core::memory::{self, cast_slice, Typed, Pod, Usage};
use slice;
use pso;

/// An error occuring in memory copies.
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq)]
pub enum CopyError {
    OutOfSrcBounds {
        size: usize,
        copy_end: usize,
    },
    OutOfDstBounds {
        size: usize,
        copy_end: usize,
    },
    Overlap {
        src_offset: usize,
        dst_offset: usize,
        size: usize,
    },
    NoSrcBindFlag,
    NoDstBindFlag,
}

pub type CopyResult = Result<(), CopyError>;

impl fmt::Display for CopyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::CopyError::*;
        match *self {
            OutOfSrcBounds { ref size, ref copy_end } =>
                write!(f, "{}: {} / {}", self.description(), copy_end, size),
            OutOfDstBounds { ref size, ref copy_end } =>
                write!(f, "{}: {} / {}", self.description(), copy_end, size),
            Overlap { ref src_offset, ref dst_offset, ref size } =>
                write!(f, "{}: [{} - {}] to [{} - {}]",
                       self.description(),
                       src_offset, src_offset + size,
                       dst_offset, dst_offset + size),
            _ => write!(f, "{}", self.description())
        }
    }
}

impl Error for CopyError {
    fn description(&self) -> &str {
        use self::CopyError::*;
        match *self {
            OutOfSrcBounds {..} => "Copy source is out of bounds",
            OutOfDstBounds {..} => "Copy destination is out of bounds",
            Overlap {..} => "Copy source and destination are overlapping",
            NoSrcBindFlag => "Copy source is missing `TRANSFER_SRC`",
            NoDstBindFlag => "Copy destination is missing `TRANSFER_DST`",
        }
    }
}

/// An error occuring in buffer/texture updates.
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq)]
pub enum UpdateError<T> {
    OutOfBounds {
        target: T,
        source: T,
    },
    UnitCountMismatch {
        target: usize,
        slice: usize,
    },
    InvalidUsage(Usage),
}

fn check_update_usage<T>(usage: Usage) -> Result<(), UpdateError<T>> {
    if usage == Usage::Dynamic {
        Ok(())
    } else {
        Err(UpdateError::InvalidUsage(usage))
    }
}

impl<T: Any + fmt::Debug + fmt::Display> fmt::Display for UpdateError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            UpdateError::OutOfBounds {ref target, ref source} =>
                write!(f, "Write to {} from {} is out of bounds", target, source),
            UpdateError::UnitCountMismatch {ref target, ref slice} =>
                write!(f, "{}: expected {}, found {}", self.description(), target, slice),
            UpdateError::InvalidUsage(usage) =>
                write!(f, "{}: {:?}", self.description(), usage),
        }
    }
}

impl<T: Any + fmt::Debug + fmt::Display> Error for UpdateError<T> {
    fn description(&self) -> &str {
        match *self {
            UpdateError::OutOfBounds {..} => "Write to data is out of bounds",
            UpdateError::UnitCountMismatch {..} => "Unit count mismatch",
            UpdateError::InvalidUsage(_) => "This memory usage does not allow updates",
        }
    }
}

/// Graphics Command Encoder
///
/// # Overview
/// The `Encoder` is a wrapper structure around a `CommandBuffer`. It is responsible for sending
/// commands to the `CommandBuffer`.
///
/// # Construction & Handling
/// The `Encoder` implements `From<CommandBuffer>`, which is how it is constructed. There is no
/// cross-API way to create a `CommandBuffer`, however, an API back-end should expose a function to
/// create one in its `Factory` type. See the specific back-end for details on how to construct a
/// `CommandBuffer`.
///
/// The encoder exposes multiple functions that add commands to its internal `CommandBuffer`. To
/// submit these commands to the GPU so they can be rendered, call `flush`.
pub struct Encoder<R: Resources, C> {
    command_buffer: C,
    raw_pso_data: pso::RawDataSet<R>,
    access_info: pso::AccessInfo<R>,
    handles: handle::Manager<R>,
}

impl<R: Resources, C> From<C> for Encoder<R, C> {
    fn from(combuf: C) -> Encoder<R, C> {
        Encoder {
            command_buffer: combuf,
            raw_pso_data: pso::RawDataSet::new(),
            access_info: pso::AccessInfo::new(),
            handles: handle::Manager::new(),
        }
    }
}

impl<R: Resources, C: command::Buffer<R>> Encoder<R, C> {
    /// Submits the commands in this `Encoder`'s internal `CommandBuffer` to the GPU, so they can
    /// be executed.
    ///
    /// Calling `flush` before swapping buffers is critical as without it the commands of the
    /// internal ´CommandBuffer´ will not be sent to the GPU, and as a result they will not be
    /// processed. Calling flush too often however will result in a performance hit. It is
    /// generally recommended to call flush once per frame, when all draw calls have been made.
    pub fn flush<D>(&mut self, device: &mut D) where
        D: Device<Resources=R, CommandBuffer=C>
    {
        device.pin_submitted_resources(&self.handles);
        device.submit(&mut self.command_buffer, &self.access_info);
        self.command_buffer.reset();
        self.access_info.clear();
        self.handles.clear();
    }

    /// Copy part of a buffer to another
    pub fn copy_buffer<T: Pod>(&mut self, src: &handle::Buffer<R, T>, dst: &handle::Buffer<R, T>,
                               src_offset: usize, dst_offset: usize, size: usize) -> CopyResult {
        if !src.get_info().bind.contains(memory::TRANSFER_SRC) {
            return Err(CopyError::NoSrcBindFlag);
        }
        if !dst.get_info().bind.contains(memory::TRANSFER_DST) {
            return Err(CopyError::NoDstBindFlag);
        }
        let size_bytes = mem::size_of::<T>() * size;
        let src_offset_bytes = mem::size_of::<T>() * src_offset;
        let src_copy_end = src_offset_bytes + size_bytes;
        if src_copy_end > src.get_info().size {
            return Err(CopyError::OutOfSrcBounds {
                size: src.get_info().size,
                copy_end: src_copy_end,
            });
        }
        let dst_offset_bytes = mem::size_of::<T>() * dst_offset;
        let dst_copy_end = dst_offset_bytes + size_bytes;
        if dst_copy_end > dst.get_info().size {
            return Err(CopyError::OutOfDstBounds {
                size: dst.get_info().size,
                copy_end: dst_copy_end,
            });
        }
        if src == dst &&
           src_offset_bytes < dst_copy_end &&
           dst_offset_bytes < src_copy_end
        {
            return Err(CopyError::Overlap {
                src_offset: src_offset_bytes,
                dst_offset: dst_offset_bytes,
                size: size_bytes,
            });
        }
        // TODO: should we use an HashSet instead of a Vec ?
        if src.raw().is_mapped() {
            self.access_info.mapped_reads.push(src.raw().clone());
        }
        if dst.raw().is_mapped() {
            self.access_info.mapped_writes.push(dst.raw().clone());
        }
        self.command_buffer.copy_buffer(
            self.handles.ref_buffer(src.raw()).clone(),
            self.handles.ref_buffer(dst.raw()).clone(),
            src_offset_bytes, dst_offset_bytes, size_bytes);
        Ok(())
    }

    /// Update a buffer with a slice of data.
    pub fn update_buffer<T: Pod>(&mut self, buf: &handle::Buffer<R, T>,
                         data: &[T], offset_elements: usize)
                         -> Result<(), UpdateError<usize>>
    {
        if data.is_empty() { return Ok(()); }
        try!(check_update_usage(buf.raw().get_info().usage));

        let elem_size = mem::size_of::<T>();
        let offset_bytes = elem_size * offset_elements;
        let bound = data.len().wrapping_mul(elem_size) + offset_bytes;
        if bound <= buf.get_info().size {
            self.command_buffer.update_buffer(
                self.handles.ref_buffer(buf.raw()).clone(),
                cast_slice(data), offset_bytes);
            Ok(())
        } else {
            Err(UpdateError::OutOfBounds {
                target: bound,
                source: buf.get_info().size,
            })
        }
    }

    /// Update a buffer with a single structure.
    pub fn update_constant_buffer<T: Copy>(&mut self, buf: &handle::Buffer<R, T>, data: &T) {
        use std::slice;

        check_update_usage::<usize>(buf.raw().get_info().usage).unwrap();

        let slice = unsafe {
            slice::from_raw_parts(data as *const T as *const u8, mem::size_of::<T>())
        };
        self.command_buffer.update_buffer(
            self.handles.ref_buffer(buf.raw()).clone(), slice, 0);
    }

    /// Update the contents of a texture.
    pub fn update_texture<S, T>(&mut self, tex: &handle::Texture<R, T::Surface>,
                          face: Option<texture::CubeFace>,
                          img: texture::NewImageInfo, data: &[S::DataType])
                          -> Result<(), UpdateError<[texture::Size; 3]>>
    where
        S: format::SurfaceTyped,
        S::DataType: Copy,
        T: format::Formatted<Surface = S>,
    {
        if data.is_empty() { return Ok(()); }
        try!(check_update_usage(tex.raw().get_info().usage));

        let target_count = img.get_texel_count();
        if target_count != data.len() {
            return Err(UpdateError::UnitCountMismatch {
                target: target_count,
                slice: data.len(),
            })
        }

        let dim = tex.get_info().kind.get_dimensions();
        if !img.is_inside(dim) {
            let (w, h, d, _) = dim;
            return Err(UpdateError::OutOfBounds {
                target: [
                    img.xoffset + img.width,
                    img.yoffset + img.height,
                    img.zoffset + img.depth,
                ],
                source: [w, h, d],
            })
        }

        self.command_buffer.update_texture(
            self.handles.ref_texture(tex.raw()).clone(),
            tex.get_info().kind, face, cast_slice(data),
            img.convert(T::get_format()));
        Ok(())
    }

    fn draw_indexed<T>(&mut self, buf: &handle::Buffer<R, T>, ty: IndexType,
                    slice: &slice::Slice<R>, base: VertexCount,
                    instances: Option<command::InstanceParams>) {
        self.command_buffer.bind_index(self.handles.ref_buffer(buf.raw()).clone(), ty);
        self.command_buffer.call_draw_indexed(slice.start, slice.end - slice.start, base, instances);
    }

    fn draw_slice(&mut self, slice: &slice::Slice<R>, instances: Option<command::InstanceParams>) {
        match slice.buffer {
            slice::IndexBuffer::Auto => self.command_buffer.call_draw(
                slice.start + slice.base_vertex, slice.end - slice.start, instances),
            slice::IndexBuffer::Index16(ref buf) =>
                self.draw_indexed(buf, IndexType::U16, slice, slice.base_vertex, instances),
            slice::IndexBuffer::Index32(ref buf) =>
                self.draw_indexed(buf, IndexType::U32, slice, slice.base_vertex, instances),
        }
    }

    /// Clears the supplied `RenderTargetView` to the supplied `ClearColor`.
    pub fn clear<T: format::RenderFormat>(&mut self,
                 view: &handle::RenderTargetView<R, T>, value: T::View)
    where T::View: Into<command::ClearColor> {
        let target = self.handles.ref_rtv(view.raw()).clone();
        self.command_buffer.clear_color(target, value.into())
    }
    /// Clear a depth view with a specified value.
    pub fn clear_depth<T: format::DepthFormat>(&mut self,
                       view: &handle::DepthStencilView<R, T>, depth: Depth) {
        let target = self.handles.ref_dsv(view.raw()).clone();
        self.command_buffer.clear_depth_stencil(target, Some(depth), None)
    }

    /// Clear a stencil view with a specified value.
    pub fn clear_stencil<T: format::StencilFormat>(&mut self,
                         view: &handle::DepthStencilView<R, T>, stencil: Stencil) {
        let target = self.handles.ref_dsv(view.raw()).clone();
        self.command_buffer.clear_depth_stencil(target, None, Some(stencil))
    }

    /// Draws a `slice::Slice` using a pipeline state object, and its matching `Data` structure.
    pub fn draw<D: pso::PipelineData<R>>(&mut self, slice: &slice::Slice<R>,
                pipeline: &pso::PipelineState<R, D::Meta>, user_data: &D)
    {
        let (pso, _) = self.handles.ref_pso(pipeline.get_handle());
        //TODO: make `raw_data` a member to this struct, to re-use the heap allocation
        self.raw_pso_data.clear();
        user_data.bake_to(&mut self.raw_pso_data, pipeline.get_meta(), &mut self.handles, &mut self.access_info);
        self.command_buffer.bind_pixel_targets(self.raw_pso_data.pixel_targets.clone());
        self.command_buffer.bind_pipeline_state(pso.clone());
        self.command_buffer.bind_vertex_buffers(self.raw_pso_data.vertex_buffers.clone());
        self.command_buffer.set_ref_values(self.raw_pso_data.ref_values);
        self.command_buffer.set_scissor(self.raw_pso_data.scissor);
        self.command_buffer.bind_constant_buffers(&self.raw_pso_data.constant_buffers);
        for &(location, value) in &self.raw_pso_data.global_constants {
            self.command_buffer.bind_global_constant(location, value);
        }
        self.command_buffer.bind_unordered_views(&self.raw_pso_data.unordered_views);
        //Note: it's important to bind RTV, DSV, and UAV before SRV
        self.command_buffer.bind_resource_views(&self.raw_pso_data.resource_views);
        self.command_buffer.bind_samplers(&self.raw_pso_data.samplers);
        self.draw_slice(slice, slice.instances);
    }
}
<commit_msg>Tracking the index buffer mapping<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Graphics commands encoder.

#![deny(missing_docs)]

use draw_state::target::{Depth, Stencil};
use std::error::Error;
use std::any::Any;
use std::{fmt, mem};

use core::{Device, IndexType, Resources, VertexCount};
use core::{command, format, handle, texture};
use core::memory::{self, cast_slice, Typed, Pod, Usage};
use slice;
use pso;

/// An error occuring in memory copies.
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq)]
pub enum CopyError {
    OutOfSrcBounds {
        size: usize,
        copy_end: usize,
    },
    OutOfDstBounds {
        size: usize,
        copy_end: usize,
    },
    Overlap {
        src_offset: usize,
        dst_offset: usize,
        size: usize,
    },
    NoSrcBindFlag,
    NoDstBindFlag,
}

pub type CopyResult = Result<(), CopyError>;

impl fmt::Display for CopyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::CopyError::*;
        match *self {
            OutOfSrcBounds { ref size, ref copy_end } =>
                write!(f, "{}: {} / {}", self.description(), copy_end, size),
            OutOfDstBounds { ref size, ref copy_end } =>
                write!(f, "{}: {} / {}", self.description(), copy_end, size),
            Overlap { ref src_offset, ref dst_offset, ref size } =>
                write!(f, "{}: [{} - {}] to [{} - {}]",
                       self.description(),
                       src_offset, src_offset + size,
                       dst_offset, dst_offset + size),
            _ => write!(f, "{}", self.description())
        }
    }
}

impl Error for CopyError {
    fn description(&self) -> &str {
        use self::CopyError::*;
        match *self {
            OutOfSrcBounds {..} => "Copy source is out of bounds",
            OutOfDstBounds {..} => "Copy destination is out of bounds",
            Overlap {..} => "Copy source and destination are overlapping",
            NoSrcBindFlag => "Copy source is missing `TRANSFER_SRC`",
            NoDstBindFlag => "Copy destination is missing `TRANSFER_DST`",
        }
    }
}

/// An error occuring in buffer/texture updates.
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq)]
pub enum UpdateError<T> {
    OutOfBounds {
        target: T,
        source: T,
    },
    UnitCountMismatch {
        target: usize,
        slice: usize,
    },
    InvalidUsage(Usage),
}

fn check_update_usage<T>(usage: Usage) -> Result<(), UpdateError<T>> {
    if usage == Usage::Dynamic {
        Ok(())
    } else {
        Err(UpdateError::InvalidUsage(usage))
    }
}

impl<T: Any + fmt::Debug + fmt::Display> fmt::Display for UpdateError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            UpdateError::OutOfBounds {ref target, ref source} =>
                write!(f, "Write to {} from {} is out of bounds", target, source),
            UpdateError::UnitCountMismatch {ref target, ref slice} =>
                write!(f, "{}: expected {}, found {}", self.description(), target, slice),
            UpdateError::InvalidUsage(usage) =>
                write!(f, "{}: {:?}", self.description(), usage),
        }
    }
}

impl<T: Any + fmt::Debug + fmt::Display> Error for UpdateError<T> {
    fn description(&self) -> &str {
        match *self {
            UpdateError::OutOfBounds {..} => "Write to data is out of bounds",
            UpdateError::UnitCountMismatch {..} => "Unit count mismatch",
            UpdateError::InvalidUsage(_) => "This memory usage does not allow updates",
        }
    }
}

/// Graphics Command Encoder
///
/// # Overview
/// The `Encoder` is a wrapper structure around a `CommandBuffer`. It is responsible for sending
/// commands to the `CommandBuffer`.
///
/// # Construction & Handling
/// The `Encoder` implements `From<CommandBuffer>`, which is how it is constructed. There is no
/// cross-API way to create a `CommandBuffer`, however, an API back-end should expose a function to
/// create one in its `Factory` type. See the specific back-end for details on how to construct a
/// `CommandBuffer`.
///
/// The encoder exposes multiple functions that add commands to its internal `CommandBuffer`. To
/// submit these commands to the GPU so they can be rendered, call `flush`.
pub struct Encoder<R: Resources, C> {
    command_buffer: C,
    raw_pso_data: pso::RawDataSet<R>,
    access_info: pso::AccessInfo<R>,
    handles: handle::Manager<R>,
}

impl<R: Resources, C> From<C> for Encoder<R, C> {
    fn from(combuf: C) -> Encoder<R, C> {
        Encoder {
            command_buffer: combuf,
            raw_pso_data: pso::RawDataSet::new(),
            access_info: pso::AccessInfo::new(),
            handles: handle::Manager::new(),
        }
    }
}

impl<R: Resources, C: command::Buffer<R>> Encoder<R, C> {
    /// Submits the commands in this `Encoder`'s internal `CommandBuffer` to the GPU, so they can
    /// be executed.
    ///
    /// Calling `flush` before swapping buffers is critical as without it the commands of the
    /// internal ´CommandBuffer´ will not be sent to the GPU, and as a result they will not be
    /// processed. Calling flush too often however will result in a performance hit. It is
    /// generally recommended to call flush once per frame, when all draw calls have been made.
    pub fn flush<D>(&mut self, device: &mut D) where
        D: Device<Resources=R, CommandBuffer=C>
    {
        device.pin_submitted_resources(&self.handles);
        device.submit(&mut self.command_buffer, &self.access_info);
        self.command_buffer.reset();
        self.access_info.clear();
        self.handles.clear();
    }

    /// Copy part of a buffer to another
    pub fn copy_buffer<T: Pod>(&mut self, src: &handle::Buffer<R, T>, dst: &handle::Buffer<R, T>,
                               src_offset: usize, dst_offset: usize, size: usize) -> CopyResult {
        if !src.get_info().bind.contains(memory::TRANSFER_SRC) {
            return Err(CopyError::NoSrcBindFlag);
        }
        if !dst.get_info().bind.contains(memory::TRANSFER_DST) {
            return Err(CopyError::NoDstBindFlag);
        }

        let size_bytes = mem::size_of::<T>() * size;
        let src_offset_bytes = mem::size_of::<T>() * src_offset;
        let src_copy_end = src_offset_bytes + size_bytes;
        if src_copy_end > src.get_info().size {
            return Err(CopyError::OutOfSrcBounds {
                size: src.get_info().size,
                copy_end: src_copy_end,
            });
        }
        let dst_offset_bytes = mem::size_of::<T>() * dst_offset;
        let dst_copy_end = dst_offset_bytes + size_bytes;
        if dst_copy_end > dst.get_info().size {
            return Err(CopyError::OutOfDstBounds {
                size: dst.get_info().size,
                copy_end: dst_copy_end,
            });
        }
        if src == dst &&
           src_offset_bytes < dst_copy_end &&
           dst_offset_bytes < src_copy_end
        {
            return Err(CopyError::Overlap {
                src_offset: src_offset_bytes,
                dst_offset: dst_offset_bytes,
                size: size_bytes,
            });
        }
        // TODO: should we use an HashSet instead of a Vec ?
        self.access_info.buffer_read(src.raw());
        self.access_info.buffer_write(dst.raw());

        self.command_buffer.copy_buffer(
            self.handles.ref_buffer(src.raw()).clone(),
            self.handles.ref_buffer(dst.raw()).clone(),
            src_offset_bytes, dst_offset_bytes, size_bytes);
        Ok(())
    }

    /// Update a buffer with a slice of data.
    pub fn update_buffer<T: Pod>(&mut self, buf: &handle::Buffer<R, T>,
                         data: &[T], offset_elements: usize)
                         -> Result<(), UpdateError<usize>>
    {
        if data.is_empty() { return Ok(()); }
        try!(check_update_usage(buf.raw().get_info().usage));

        let elem_size = mem::size_of::<T>();
        let offset_bytes = elem_size * offset_elements;
        let bound = data.len().wrapping_mul(elem_size) + offset_bytes;
        if bound <= buf.get_info().size {
            self.command_buffer.update_buffer(
                self.handles.ref_buffer(buf.raw()).clone(),
                cast_slice(data), offset_bytes);
            Ok(())
        } else {
            Err(UpdateError::OutOfBounds {
                target: bound,
                source: buf.get_info().size,
            })
        }
    }

    /// Update a buffer with a single structure.
    pub fn update_constant_buffer<T: Copy>(&mut self, buf: &handle::Buffer<R, T>, data: &T) {
        use std::slice;

        check_update_usage::<usize>(buf.raw().get_info().usage).unwrap();

        let slice = unsafe {
            slice::from_raw_parts(data as *const T as *const u8, mem::size_of::<T>())
        };
        self.command_buffer.update_buffer(
            self.handles.ref_buffer(buf.raw()).clone(), slice, 0);
    }

    /// Update the contents of a texture.
    pub fn update_texture<S, T>(&mut self, tex: &handle::Texture<R, T::Surface>,
                          face: Option<texture::CubeFace>,
                          img: texture::NewImageInfo, data: &[S::DataType])
                          -> Result<(), UpdateError<[texture::Size; 3]>>
    where
        S: format::SurfaceTyped,
        S::DataType: Copy,
        T: format::Formatted<Surface = S>,
    {
        if data.is_empty() { return Ok(()); }
        try!(check_update_usage(tex.raw().get_info().usage));

        let target_count = img.get_texel_count();
        if target_count != data.len() {
            return Err(UpdateError::UnitCountMismatch {
                target: target_count,
                slice: data.len(),
            })
        }

        let dim = tex.get_info().kind.get_dimensions();
        if !img.is_inside(dim) {
            let (w, h, d, _) = dim;
            return Err(UpdateError::OutOfBounds {
                target: [
                    img.xoffset + img.width,
                    img.yoffset + img.height,
                    img.zoffset + img.depth,
                ],
                source: [w, h, d],
            })
        }

        self.command_buffer.update_texture(
            self.handles.ref_texture(tex.raw()).clone(),
            tex.get_info().kind, face, cast_slice(data),
            img.convert(T::get_format()));
        Ok(())
    }

    fn draw_indexed<T>(&mut self, buf: &handle::Buffer<R, T>, ty: IndexType,
                    slice: &slice::Slice<R>, base: VertexCount,
                    instances: Option<command::InstanceParams>) {
        self.access_info.buffer_read(buf.raw());
        self.command_buffer.bind_index(self.handles.ref_buffer(buf.raw()).clone(), ty);
        self.command_buffer.call_draw_indexed(slice.start, slice.end - slice.start, base, instances);
    }

    fn draw_slice(&mut self, slice: &slice::Slice<R>, instances: Option<command::InstanceParams>) {
        match slice.buffer {
            slice::IndexBuffer::Auto => self.command_buffer.call_draw(
                slice.start + slice.base_vertex, slice.end - slice.start, instances),
            slice::IndexBuffer::Index16(ref buf) =>
                self.draw_indexed(buf, IndexType::U16, slice, slice.base_vertex, instances),
            slice::IndexBuffer::Index32(ref buf) =>
                self.draw_indexed(buf, IndexType::U32, slice, slice.base_vertex, instances),
        }
    }

    /// Clears the supplied `RenderTargetView` to the supplied `ClearColor`.
    pub fn clear<T: format::RenderFormat>(&mut self,
                 view: &handle::RenderTargetView<R, T>, value: T::View)
    where T::View: Into<command::ClearColor> {
        let target = self.handles.ref_rtv(view.raw()).clone();
        self.command_buffer.clear_color(target, value.into())
    }
    /// Clear a depth view with a specified value.
    pub fn clear_depth<T: format::DepthFormat>(&mut self,
                       view: &handle::DepthStencilView<R, T>, depth: Depth) {
        let target = self.handles.ref_dsv(view.raw()).clone();
        self.command_buffer.clear_depth_stencil(target, Some(depth), None)
    }

    /// Clear a stencil view with a specified value.
    pub fn clear_stencil<T: format::StencilFormat>(&mut self,
                         view: &handle::DepthStencilView<R, T>, stencil: Stencil) {
        let target = self.handles.ref_dsv(view.raw()).clone();
        self.command_buffer.clear_depth_stencil(target, None, Some(stencil))
    }

    /// Draws a `slice::Slice` using a pipeline state object, and its matching `Data` structure.
    pub fn draw<D: pso::PipelineData<R>>(&mut self, slice: &slice::Slice<R>,
                pipeline: &pso::PipelineState<R, D::Meta>, user_data: &D)
    {
        let (pso, _) = self.handles.ref_pso(pipeline.get_handle());
        //TODO: make `raw_data` a member to this struct, to re-use the heap allocation
        self.raw_pso_data.clear();
        user_data.bake_to(&mut self.raw_pso_data, pipeline.get_meta(), &mut self.handles, &mut self.access_info);
        self.command_buffer.bind_pixel_targets(self.raw_pso_data.pixel_targets.clone());
        self.command_buffer.bind_pipeline_state(pso.clone());
        self.command_buffer.bind_vertex_buffers(self.raw_pso_data.vertex_buffers.clone());
        self.command_buffer.set_ref_values(self.raw_pso_data.ref_values);
        self.command_buffer.set_scissor(self.raw_pso_data.scissor);
        self.command_buffer.bind_constant_buffers(&self.raw_pso_data.constant_buffers);
        for &(location, value) in &self.raw_pso_data.global_constants {
            self.command_buffer.bind_global_constant(location, value);
        }
        self.command_buffer.bind_unordered_views(&self.raw_pso_data.unordered_views);
        //Note: it's important to bind RTV, DSV, and UAV before SRV
        self.command_buffer.bind_resource_views(&self.raw_pso_data.resource_views);
        self.command_buffer.bind_samplers(&self.raw_pso_data.samplers);
        self.draw_slice(slice, slice.instances);
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};

use crate::{
    ast::{Definition, Document, Fragment, FragmentSpread, Operation},
    parser::Spanning,
    validation::{ValidatorContext, Visitor},
    value::ScalarValue,
};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Scope<'a> {
    Operation(Option<&'a str>),
    Fragment(&'a str),
}

pub fn factory<'a>() -> NoUnusedFragments<'a> {
    NoUnusedFragments {
        spreads: HashMap::new(),
        defined_fragments: HashSet::new(),
        current_scope: None,
    }
}

pub struct NoUnusedFragments<'a> {
    spreads: HashMap<Scope<'a>, Vec<&'a str>>,
    defined_fragments: HashSet<Spanning<&'a str>>,
    current_scope: Option<Scope<'a>>,
}

impl<'a> NoUnusedFragments<'a> {
    fn find_reachable_fragments(&'a self, from: &Scope<'a>, result: &mut HashSet<&'a str>) {
        let mut to_visit = Vec::new();
        if let Scope::Fragment(name) = *from {
            to_visit.push(name);
        }

        while let Some(from) = to_visit.pop() {
            if let Some(next) = self.find_reachable_fragments_inner(from, result) {
                to_visit.extend(next);
            }
        }
    }

    /// This function should be called only inside
    /// [`Self::find_reachable_fragments()`], as it's a recursive function using
    /// heap instead of a stack. So, instead of the recursive call, we return a
    /// [`Vec`] that is visited inside [`Self::find_reachable_fragments()`].
    fn find_reachable_fragments_inner(
        &'a self,
        from: &'a str,
        result: &mut HashSet<&'a str>,
    ) -> Option<&'a Vec<&'a str>> {
        if result.contains(from) {
            return None;
        } else {
            result.insert(from);
        }

        self.spreads.get(&Scope::Fragment(from))
    }
}

impl<'a, S> Visitor<'a, S> for NoUnusedFragments<'a>
where
    S: ScalarValue,
{
    fn exit_document(&mut self, ctx: &mut ValidatorContext<'a, S>, defs: &'a Document<S>) {
        let mut reachable = HashSet::new();

        for def in defs {
            if let Definition::Operation(Spanning {
                item: Operation { ref name, .. },
                ..
            }) = *def
            {
                let op_name = name.as_ref().map(|s| s.item);
                self.find_reachable_fragments(&Scope::Operation(op_name), &mut reachable);
            }
        }

        for fragment in &self.defined_fragments {
            if !reachable.contains(&fragment.item) {
                ctx.report_error(&error_message(fragment.item), &[fragment.start]);
            }
        }
    }

    fn enter_operation_definition(
        &mut self,
        _: &mut ValidatorContext<'a, S>,
        op: &'a Spanning<Operation<S>>,
    ) {
        let op_name = op.item.name.as_ref().map(|s| s.item);
        self.current_scope = Some(Scope::Operation(op_name));
    }

    fn enter_fragment_definition(
        &mut self,
        _: &mut ValidatorContext<'a, S>,
        f: &'a Spanning<Fragment<S>>,
    ) {
        self.current_scope = Some(Scope::Fragment(f.item.name.item));
        self.defined_fragments
            .insert(Spanning::start_end(&f.start, &f.end, f.item.name.item));
    }

    fn enter_fragment_spread(
        &mut self,
        _: &mut ValidatorContext<'a, S>,
        spread: &'a Spanning<FragmentSpread<S>>,
    ) {
        if let Some(ref scope) = self.current_scope {
            self.spreads
                .entry(scope.clone())
                .or_insert_with(Vec::new)
                .push(spread.item.name.item);
        }
    }
}

fn error_message(frag_name: &str) -> String {
    format!(r#"Fragment "{frag_name}" is never used"#)
}

#[cfg(test)]
mod tests {
    use super::{error_message, factory};

    use crate::{
        parser::SourcePosition,
        validation::{expect_fails_rule, expect_passes_rule, RuleError},
        value::DefaultScalarValue,
    };

    #[test]
    fn all_fragment_names_are_used() {
        expect_passes_rule::<_, _, DefaultScalarValue>(
            factory,
            r#"
          {
            human(id: 4) {
              ...HumanFields1
              ... on Human {
                ...HumanFields2
              }
            }
          }
          fragment HumanFields1 on Human {
            name
            ...HumanFields3
          }
          fragment HumanFields2 on Human {
            name
          }
          fragment HumanFields3 on Human {
            name
          }
        "#,
        );
    }

    #[test]
    fn all_fragment_names_are_used_by_multiple_operations() {
        expect_passes_rule::<_, _, DefaultScalarValue>(
            factory,
            r#"
          query Foo {
            human(id: 4) {
              ...HumanFields1
            }
          }
          query Bar {
            human(id: 4) {
              ...HumanFields2
            }
          }
          fragment HumanFields1 on Human {
            name
            ...HumanFields3
          }
          fragment HumanFields2 on Human {
            name
          }
          fragment HumanFields3 on Human {
            name
          }
        "#,
        );
    }

    #[test]
    fn contains_unknown_fragments() {
        expect_fails_rule::<_, _, DefaultScalarValue>(
            factory,
            r#"
          query Foo {
            human(id: 4) {
              ...HumanFields1
            }
          }
          query Bar {
            human(id: 4) {
              ...HumanFields2
            }
          }
          fragment HumanFields1 on Human {
            name
            ...HumanFields3
          }
          fragment HumanFields2 on Human {
            name
          }
          fragment HumanFields3 on Human {
            name
          }
          fragment Unused1 on Human {
            name
          }
          fragment Unused2 on Human {
            name
          }
        "#,
            &[
                RuleError::new(
                    &error_message("Unused1"),
                    &[SourcePosition::new(465, 21, 10)],
                ),
                RuleError::new(
                    &error_message("Unused2"),
                    &[SourcePosition::new(532, 24, 10)],
                ),
            ],
        );
    }

    #[test]
    fn contains_unknown_fragments_with_ref_cycle() {
        expect_fails_rule::<_, _, DefaultScalarValue>(
            factory,
            r#"
          query Foo {
            human(id: 4) {
              ...HumanFields1
            }
          }
          query Bar {
            human(id: 4) {
              ...HumanFields2
            }
          }
          fragment HumanFields1 on Human {
            name
            ...HumanFields3
          }
          fragment HumanFields2 on Human {
            name
          }
          fragment HumanFields3 on Human {
            name
          }
          fragment Unused1 on Human {
            name
            ...Unused2
          }
          fragment Unused2 on Human {
            name
            ...Unused1
          }
        "#,
            &[
                RuleError::new(
                    &error_message("Unused1"),
                    &[SourcePosition::new(465, 21, 10)],
                ),
                RuleError::new(
                    &error_message("Unused2"),
                    &[SourcePosition::new(555, 25, 10)],
                ),
            ],
        );
    }

    #[test]
    fn contains_unknown_and_undef_fragments() {
        expect_fails_rule::<_, _, DefaultScalarValue>(
            factory,
            r#"
          query Foo {
            human(id: 4) {
              ...bar
            }
          }
          fragment foo on Human {
            name
          }
        "#,
            &[RuleError::new(
                &error_message("foo"),
                &[SourcePosition::new(107, 6, 10)],
            )],
        );
    }
}
<commit_msg>Fix `NoUnusedFragments` validation rule<commit_after>use std::collections::{HashMap, HashSet};

use crate::{
    ast::{Definition, Document, Fragment, FragmentSpread, Operation},
    parser::Spanning,
    validation::{ValidatorContext, Visitor},
    value::ScalarValue,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Scope<'a> {
    Operation(Option<&'a str>),
    Fragment(&'a str),
}

pub fn factory<'a>() -> NoUnusedFragments<'a> {
    NoUnusedFragments {
        spreads: HashMap::new(),
        defined_fragments: HashSet::new(),
        current_scope: None,
    }
}

pub struct NoUnusedFragments<'a> {
    spreads: HashMap<Scope<'a>, Vec<&'a str>>,
    defined_fragments: HashSet<Spanning<&'a str>>,
    current_scope: Option<Scope<'a>>,
}

impl<'a> NoUnusedFragments<'a> {
    fn find_reachable_fragments(&'a self, from: Scope<'a>, result: &mut HashSet<&'a str>) {
        let mut to_visit = Vec::new();
        to_visit.push(from);

        while let Some(from) = to_visit.pop() {
            if let Some(next) = self.find_reachable_fragments_inner(from, result) {
                to_visit.extend(next.iter().map(|s| Scope::Fragment(s)));
            }
        }
    }

    /// This function should be called only inside
    /// [`Self::find_reachable_fragments()`], as it's a recursive function using
    /// heap instead of a stack. So, instead of the recursive call, we return a
    /// [`Vec`] that is visited inside [`Self::find_reachable_fragments()`].
    fn find_reachable_fragments_inner(
        &'a self,
        from: Scope<'a>,
        result: &mut HashSet<&'a str>,
    ) -> Option<&'a Vec<&'a str>> {
        if let Scope::Fragment(name) = from {
            if result.contains(name) {
                return None;
            } else {
                result.insert(name);
            }
        }

        self.spreads.get(&from)
    }
}

impl<'a, S> Visitor<'a, S> for NoUnusedFragments<'a>
where
    S: ScalarValue,
{
    fn exit_document(&mut self, ctx: &mut ValidatorContext<'a, S>, defs: &'a Document<S>) {
        let mut reachable = HashSet::new();

        for def in defs {
            if let Definition::Operation(Spanning {
                item: Operation { ref name, .. },
                ..
            }) = *def
            {
                let op_name = name.as_ref().map(|s| s.item);
                self.find_reachable_fragments(Scope::Operation(op_name), &mut reachable);
            }
        }

        for fragment in &self.defined_fragments {
            if !reachable.contains(&fragment.item) {
                ctx.report_error(&error_message(fragment.item), &[fragment.start]);
            }
        }
    }

    fn enter_operation_definition(
        &mut self,
        _: &mut ValidatorContext<'a, S>,
        op: &'a Spanning<Operation<S>>,
    ) {
        let op_name = op.item.name.as_ref().map(|s| s.item);
        self.current_scope = Some(Scope::Operation(op_name));
    }

    fn enter_fragment_definition(
        &mut self,
        _: &mut ValidatorContext<'a, S>,
        f: &'a Spanning<Fragment<S>>,
    ) {
        self.current_scope = Some(Scope::Fragment(f.item.name.item));
        self.defined_fragments
            .insert(Spanning::start_end(&f.start, &f.end, f.item.name.item));
    }

    fn enter_fragment_spread(
        &mut self,
        _: &mut ValidatorContext<'a, S>,
        spread: &'a Spanning<FragmentSpread<S>>,
    ) {
        if let Some(ref scope) = self.current_scope {
            self.spreads
                .entry(scope.clone())
                .or_insert_with(Vec::new)
                .push(spread.item.name.item);
        }
    }
}

fn error_message(frag_name: &str) -> String {
    format!(r#"Fragment "{frag_name}" is never used"#)
}

#[cfg(test)]
mod tests {
    use super::{error_message, factory};

    use crate::{
        parser::SourcePosition,
        validation::{expect_fails_rule, expect_passes_rule, RuleError},
        value::DefaultScalarValue,
    };

    #[test]
    fn all_fragment_names_are_used() {
        expect_passes_rule::<_, _, DefaultScalarValue>(
            factory,
            r#"
          {
            human(id: 4) {
              ...HumanFields1
              ... on Human {
                ...HumanFields2
              }
            }
          }
          fragment HumanFields1 on Human {
            name
            ...HumanFields3
          }
          fragment HumanFields2 on Human {
            name
          }
          fragment HumanFields3 on Human {
            name
          }
        "#,
        );
    }

    #[test]
    fn all_fragment_names_are_used_by_multiple_operations() {
        expect_passes_rule::<_, _, DefaultScalarValue>(
            factory,
            r#"
          query Foo {
            human(id: 4) {
              ...HumanFields1
            }
          }
          query Bar {
            human(id: 4) {
              ...HumanFields2
            }
          }
          fragment HumanFields1 on Human {
            name
            ...HumanFields3
          }
          fragment HumanFields2 on Human {
            name
          }
          fragment HumanFields3 on Human {
            name
          }
        "#,
        );
    }

    #[test]
    fn contains_unknown_fragments() {
        expect_fails_rule::<_, _, DefaultScalarValue>(
            factory,
            r#"
          query Foo {
            human(id: 4) {
              ...HumanFields1
            }
          }
          query Bar {
            human(id: 4) {
              ...HumanFields2
            }
          }
          fragment HumanFields1 on Human {
            name
            ...HumanFields3
          }
          fragment HumanFields2 on Human {
            name
          }
          fragment HumanFields3 on Human {
            name
          }
          fragment Unused1 on Human {
            name
          }
          fragment Unused2 on Human {
            name
          }
        "#,
            &[
                RuleError::new(
                    &error_message("Unused1"),
                    &[SourcePosition::new(465, 21, 10)],
                ),
                RuleError::new(
                    &error_message("Unused2"),
                    &[SourcePosition::new(532, 24, 10)],
                ),
            ],
        );
    }

    #[test]
    fn contains_unknown_fragments_with_ref_cycle() {
        expect_fails_rule::<_, _, DefaultScalarValue>(
            factory,
            r#"
          query Foo {
            human(id: 4) {
              ...HumanFields1
            }
          }
          query Bar {
            human(id: 4) {
              ...HumanFields2
            }
          }
          fragment HumanFields1 on Human {
            name
            ...HumanFields3
          }
          fragment HumanFields2 on Human {
            name
          }
          fragment HumanFields3 on Human {
            name
          }
          fragment Unused1 on Human {
            name
            ...Unused2
          }
          fragment Unused2 on Human {
            name
            ...Unused1
          }
        "#,
            &[
                RuleError::new(
                    &error_message("Unused1"),
                    &[SourcePosition::new(465, 21, 10)],
                ),
                RuleError::new(
                    &error_message("Unused2"),
                    &[SourcePosition::new(555, 25, 10)],
                ),
            ],
        );
    }

    #[test]
    fn contains_unknown_and_undef_fragments() {
        expect_fails_rule::<_, _, DefaultScalarValue>(
            factory,
            r#"
          query Foo {
            human(id: 4) {
              ...bar
            }
          }
          fragment foo on Human {
            name
          }
        "#,
            &[RuleError::new(
                &error_message("foo"),
                &[SourcePosition::new(107, 6, 10)],
            )],
        );
    }
}
<|endoftext|>


<commit_before>extern crate cv;

use cv::*;
use cv::objdetect::ObjectDetect;

mod utils;
use utils::*;

#[test]
fn detect_lenna() {
    let mat = load_lenna();
    let cascade = load_frontal_face();
    let result = cascade.detect(&mat);
    assert_eq!(result.len(), 1);
    assert!(close_rect(
        result[0].0,
        Rect {
            x: 219,
            y: 203,
            width: 170,
            height: 170,
        },
        2,
    ));
}
<commit_msg>Update expected lenna location<commit_after>extern crate cv;

use cv::*;
use cv::objdetect::ObjectDetect;

mod utils;
use utils::*;

#[test]
fn detect_lenna() {
    let mat = load_lenna();
    let cascade = load_frontal_face();
    let result = cascade.detect(&mat);
    assert_eq!(result.len(), 1);
    assert!(close_rect(
        result[0].0,
        Rect {
            x: 220,
            y: 204,
            width: 168,
            height: 168,
        },
        3,
    ));
}
<|endoftext|>


<commit_before>#![allow(unstable)]
extern crate sss;
extern crate test;

use std::collections::VecMap;
use std::rand::ChaChaRng;
use test::Bencher;

#[bench]
fn bench_combine(b: &mut Bencher) {
    let mut expected: VecMap<Vec<u8>> = VecMap::new();
    expected.insert(1, vec![118, 163, 66, 80, 187]);
    expected.insert(2, vec![239, 91, 129, 172, 98]);
    expected.insert(3, vec![152, 250, 192, 248, 220]);

    b.iter(|| {
        sss::combine(&expected)
    })
}

#[bench]
fn bench_split(b: &mut Bencher) {
    let mut rng = ChaChaRng::new_unseeded();
    let input = vec![1, 2, 3, 4, 5];

    b.iter(|| {
        sss::split(5, 3, &input, &mut rng);
    })
}
<commit_msg>Make sure the bench loop isn't elided.<commit_after>#![allow(unstable)]
extern crate sss;
extern crate test;

use std::collections::VecMap;
use std::rand::ChaChaRng;
use test::Bencher;

#[bench]
fn bench_combine(b: &mut Bencher) {
    let mut expected: VecMap<Vec<u8>> = VecMap::new();
    expected.insert(1, vec![118, 163, 66, 80, 187]);
    expected.insert(2, vec![239, 91, 129, 172, 98]);
    expected.insert(3, vec![152, 250, 192, 248, 220]);

    b.iter(|| {
        sss::combine(&expected)
    })
}

#[bench]
fn bench_split(b: &mut Bencher) {
    let mut rng = ChaChaRng::new_unseeded();
    let input = vec![1, 2, 3, 4, 5];

    b.iter(|| {
        sss::split(5, 3, &input, &mut rng)
    })
}
<|endoftext|>


<commit_before>use crate::cdsl::operands::{Operand, OperandKind};

use std::collections::{HashMap, HashSet};
use std::fmt;
use std::slice;

use cranelift_entity::{entity_impl, PrimaryMap};

/// An immediate field in an instruction format.
///
/// This corresponds to a single member of a variant of the `InstructionData`
/// data type.
#[derive(Debug)]
pub struct FormatField {
    /// Immediate operand number in parent.
    immnum: usize,

    /// Immediate operand kind.
    pub kind: OperandKind,

    /// Member name in InstructionData variant.
    pub member: &'static str,
}

/// Every instruction opcode has a corresponding instruction format which determines the number of
/// operands and their kinds. Instruction formats are identified structurally, i.e., the format of
/// an instruction is derived from the kinds of operands used in its declaration.
///
/// The instruction format stores two separate lists of operands: Immediates and values. Immediate
/// operands (including entity references) are represented as explicit members in the
/// `InstructionData` variants. The value operands are stored differently, depending on how many
/// there are.  Beyond a certain point, instruction formats switch to an external value list for
/// storing value arguments. Value lists can hold an arbitrary number of values.
///
/// All instruction formats must be predefined in the meta shared/formats.rs module.
#[derive(Debug)]
pub struct InstructionFormat {
    /// Instruction format name in CamelCase. This is used as a Rust variant name in both the
    /// `InstructionData` and `InstructionFormat` enums.
    pub name: &'static str,

    pub num_value_operands: usize,

    pub has_value_list: bool,

    pub imm_fields: Vec<FormatField>,

    /// Index of the value input operand that is used to infer the controlling type variable. By
    /// default, this is `0`, the first `value` operand. The index is relative to the values only,
    /// ignoring immediate operands.
    pub typevar_operand: Option<usize>,
}

impl fmt::Display for InstructionFormat {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let args = self
            .imm_fields
            .iter()
            .map(|field| format!("{}: {}", field.member, field.kind.name))
            .collect::<Vec<_>>()
            .join(", ");
        fmt.write_fmt(format_args!(
            "{}(imms=({}), vals={})",
            self.name, args, self.num_value_operands
        ))?;
        Ok(())
    }
}

impl InstructionFormat {
    pub fn imm_by_name(&self, name: &'static str) -> &FormatField {
        self.imm_fields
            .iter()
            .find(|&field| field.member == name)
            .unwrap_or_else(|| {
                panic!(
                    "unexpected immediate field named {} in instruction format {}",
                    name, self.name
                )
            })
    }
}

pub struct InstructionFormatBuilder {
    name: &'static str,
    num_value_operands: usize,
    has_value_list: bool,
    imm_fields: Vec<FormatField>,
    typevar_operand: Option<usize>,
}

impl InstructionFormatBuilder {
    pub fn new(name: &'static str) -> Self {
        Self {
            name,
            num_value_operands: 0,
            has_value_list: false,
            imm_fields: Vec::new(),
            typevar_operand: None,
        }
    }

    pub fn value(mut self) -> Self {
        self.num_value_operands += 1;
        self
    }

    pub fn varargs(mut self) -> Self {
        self.has_value_list = true;
        self
    }

    pub fn imm(mut self, operand_kind: &OperandKind) -> Self {
        let field = FormatField {
            immnum: self.imm_fields.len(),
            kind: operand_kind.clone(),
            member: operand_kind.default_member.unwrap(),
        };
        self.imm_fields.push(field);
        self
    }

    pub fn imm_with_name(mut self, member: &'static str, operand_kind: &OperandKind) -> Self {
        let field = FormatField {
            immnum: self.imm_fields.len(),
            kind: operand_kind.clone(),
            member,
        };
        self.imm_fields.push(field);
        self
    }

    pub fn typevar_operand(mut self, operand_index: usize) -> Self {
        assert!(self.typevar_operand.is_none());
        assert!(self.has_value_list || operand_index < self.num_value_operands);
        self.typevar_operand = Some(operand_index);
        self
    }

    pub fn build(self) -> InstructionFormat {
        let typevar_operand = if self.typevar_operand.is_some() {
            self.typevar_operand
        } else if self.has_value_list || self.num_value_operands > 0 {
            // Default to the first value operand, if there's one.
            Some(0)
        } else {
            None
        };

        InstructionFormat {
            name: self.name,
            num_value_operands: self.num_value_operands,
            has_value_list: self.has_value_list,
            imm_fields: self.imm_fields,
            typevar_operand,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct InstructionFormatIndex(u32);
entity_impl!(InstructionFormatIndex);

pub struct FormatRegistry {
    /// Map (immediate kinds names, number of values, has varargs) to an instruction format index
    /// in the actual map.
    sig_to_index: HashMap<(Vec<String>, usize, bool), InstructionFormatIndex>,
    map: PrimaryMap<InstructionFormatIndex, InstructionFormat>,
    name_set: HashSet<&'static str>,
}

impl FormatRegistry {
    pub fn new() -> Self {
        Self {
            sig_to_index: HashMap::new(),
            map: PrimaryMap::new(),
            name_set: HashSet::new(),
        }
    }

    /// Find an existing instruction format that matches the given lists of instruction inputs and
    /// outputs.
    pub fn lookup(&self, operands_in: &Vec<Operand>) -> InstructionFormatIndex {
        let mut imm_keys = Vec::new();
        let mut num_values = 0;
        let mut has_varargs = false;

        for operand in operands_in.iter() {
            if operand.is_value() {
                num_values += 1;
            }
            if !has_varargs {
                has_varargs = operand.is_varargs();
            }
            if let Some(imm_key) = operand.kind.imm_key() {
                imm_keys.push(imm_key);
            }
        }

        let sig = (imm_keys, num_values, has_varargs);
        *self
            .sig_to_index
            .get(&sig)
            .expect("unknown InstructionFormat; please define it in shared/formats.rs first")
    }

    pub fn by_name(&self, name: &str) -> InstructionFormatIndex {
        self.map
            .iter()
            .find(|(_key, value)| value.name == name)
            .unwrap_or_else(|| panic!("format with name '{}' doesn't exist", name))
            .0
    }

    pub fn get(&self, index: InstructionFormatIndex) -> &InstructionFormat {
        self.map.get(index).unwrap()
    }

    pub fn insert(&mut self, inst_format: InstructionFormatBuilder) {
        let name = &inst_format.name;
        if !self.name_set.insert(name) {
            panic!(
                "Trying to add an InstructionFormat named {}, but it already exists!",
                name
            );
        }

        let format = inst_format.build();

        // Compute key.
        let imm_keys = format
            .imm_fields
            .iter()
            .map(|field| field.kind.imm_key().unwrap())
            .collect();
        let key = (imm_keys, format.num_value_operands, format.has_value_list);

        let index = self.map.push(format);
        if let Some(already_inserted) = self.sig_to_index.insert(key, index) {
            panic!(
                "duplicate InstructionFormat: trying to insert '{}' while '{}' already has the same structure.",
                self.map.get(index).unwrap().name,
                self.map.get(already_inserted).unwrap().name
            );
        }
    }

    pub fn iter(&self) -> slice::Iter<InstructionFormat> {
        self.map.values()
    }
}
<commit_msg>[meta] Remove unused immfield index in the FormatField;<commit_after>use crate::cdsl::operands::{Operand, OperandKind};

use std::collections::{HashMap, HashSet};
use std::fmt;
use std::slice;

use cranelift_entity::{entity_impl, PrimaryMap};

/// An immediate field in an instruction format.
///
/// This corresponds to a single member of a variant of the `InstructionData`
/// data type.
#[derive(Debug)]
pub struct FormatField {
    /// Immediate operand kind.
    pub kind: OperandKind,

    /// Member name in InstructionData variant.
    pub member: &'static str,
}

/// Every instruction opcode has a corresponding instruction format which determines the number of
/// operands and their kinds. Instruction formats are identified structurally, i.e., the format of
/// an instruction is derived from the kinds of operands used in its declaration.
///
/// The instruction format stores two separate lists of operands: Immediates and values. Immediate
/// operands (including entity references) are represented as explicit members in the
/// `InstructionData` variants. The value operands are stored differently, depending on how many
/// there are.  Beyond a certain point, instruction formats switch to an external value list for
/// storing value arguments. Value lists can hold an arbitrary number of values.
///
/// All instruction formats must be predefined in the meta shared/formats.rs module.
#[derive(Debug)]
pub struct InstructionFormat {
    /// Instruction format name in CamelCase. This is used as a Rust variant name in both the
    /// `InstructionData` and `InstructionFormat` enums.
    pub name: &'static str,

    pub num_value_operands: usize,

    pub has_value_list: bool,

    pub imm_fields: Vec<FormatField>,

    /// Index of the value input operand that is used to infer the controlling type variable. By
    /// default, this is `0`, the first `value` operand. The index is relative to the values only,
    /// ignoring immediate operands.
    pub typevar_operand: Option<usize>,
}

impl fmt::Display for InstructionFormat {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let imm_args = self
            .imm_fields
            .iter()
            .map(|field| format!("{}: {}", field.member, field.kind.name))
            .collect::<Vec<_>>()
            .join(", ");
        fmt.write_fmt(format_args!(
            "{}(imms=({}), vals={})",
            self.name, imm_args, self.num_value_operands
        ))?;
        Ok(())
    }
}

impl InstructionFormat {
    pub fn imm_by_name(&self, name: &'static str) -> &FormatField {
        self.imm_fields
            .iter()
            .find(|&field| field.member == name)
            .unwrap_or_else(|| {
                panic!(
                    "unexpected immediate field named {} in instruction format {}",
                    name, self.name
                )
            })
    }
}

pub struct InstructionFormatBuilder {
    name: &'static str,
    num_value_operands: usize,
    has_value_list: bool,
    imm_fields: Vec<FormatField>,
    typevar_operand: Option<usize>,
}

impl InstructionFormatBuilder {
    pub fn new(name: &'static str) -> Self {
        Self {
            name,
            num_value_operands: 0,
            has_value_list: false,
            imm_fields: Vec::new(),
            typevar_operand: None,
        }
    }

    pub fn value(mut self) -> Self {
        self.num_value_operands += 1;
        self
    }

    pub fn varargs(mut self) -> Self {
        self.has_value_list = true;
        self
    }

    pub fn imm(mut self, operand_kind: &OperandKind) -> Self {
        let field = FormatField {
            kind: operand_kind.clone(),
            member: operand_kind.default_member.unwrap(),
        };
        self.imm_fields.push(field);
        self
    }

    pub fn imm_with_name(mut self, member: &'static str, operand_kind: &OperandKind) -> Self {
        let field = FormatField {
            kind: operand_kind.clone(),
            member,
        };
        self.imm_fields.push(field);
        self
    }

    pub fn typevar_operand(mut self, operand_index: usize) -> Self {
        assert!(self.typevar_operand.is_none());
        assert!(self.has_value_list || operand_index < self.num_value_operands);
        self.typevar_operand = Some(operand_index);
        self
    }

    pub fn build(self) -> InstructionFormat {
        let typevar_operand = if self.typevar_operand.is_some() {
            self.typevar_operand
        } else if self.has_value_list || self.num_value_operands > 0 {
            // Default to the first value operand, if there's one.
            Some(0)
        } else {
            None
        };

        InstructionFormat {
            name: self.name,
            num_value_operands: self.num_value_operands,
            has_value_list: self.has_value_list,
            imm_fields: self.imm_fields,
            typevar_operand,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct InstructionFormatIndex(u32);
entity_impl!(InstructionFormatIndex);

pub struct FormatRegistry {
    /// Map (immediate kinds names, number of values, has varargs) to an instruction format index
    /// in the actual map.
    sig_to_index: HashMap<(Vec<String>, usize, bool), InstructionFormatIndex>,
    map: PrimaryMap<InstructionFormatIndex, InstructionFormat>,
    name_set: HashSet<&'static str>,
}

impl FormatRegistry {
    pub fn new() -> Self {
        Self {
            sig_to_index: HashMap::new(),
            map: PrimaryMap::new(),
            name_set: HashSet::new(),
        }
    }

    /// Find an existing instruction format that matches the given lists of instruction inputs and
    /// outputs.
    pub fn lookup(&self, operands_in: &Vec<Operand>) -> InstructionFormatIndex {
        let mut imm_keys = Vec::new();
        let mut num_values = 0;
        let mut has_varargs = false;

        for operand in operands_in.iter() {
            if operand.is_value() {
                num_values += 1;
            }
            if !has_varargs {
                has_varargs = operand.is_varargs();
            }
            if let Some(imm_key) = operand.kind.imm_key() {
                imm_keys.push(imm_key);
            }
        }

        let sig = (imm_keys, num_values, has_varargs);
        *self
            .sig_to_index
            .get(&sig)
            .expect("unknown InstructionFormat; please define it in shared/formats.rs first")
    }

    pub fn by_name(&self, name: &str) -> InstructionFormatIndex {
        self.map
            .iter()
            .find(|(_key, value)| value.name == name)
            .unwrap_or_else(|| panic!("format with name '{}' doesn't exist", name))
            .0
    }

    pub fn get(&self, index: InstructionFormatIndex) -> &InstructionFormat {
        self.map.get(index).unwrap()
    }

    pub fn insert(&mut self, inst_format: InstructionFormatBuilder) {
        let name = &inst_format.name;
        if !self.name_set.insert(name) {
            panic!(
                "Trying to add an InstructionFormat named {}, but it already exists!",
                name
            );
        }

        let format = inst_format.build();

        // Compute key.
        let imm_keys = format
            .imm_fields
            .iter()
            .map(|field| field.kind.imm_key().unwrap())
            .collect();
        let key = (imm_keys, format.num_value_operands, format.has_value_list);

        let index = self.map.push(format);
        if let Some(already_inserted) = self.sig_to_index.insert(key, index) {
            panic!(
                "duplicate InstructionFormat: trying to insert '{}' while '{}' already has the same structure.",
                self.map.get(index).unwrap().name,
                self.map.get(already_inserted).unwrap().name
            );
        }
    }

    pub fn iter(&self) -> slice::Iter<InstructionFormat> {
        self.map.values()
    }
}
<|endoftext|>


<commit_before>use cairo;
use cairo::MatrixTrait;

use rect::RectangleExt;

#[derive(Debug, Copy, Clone)]
pub struct BoundingBox {
    pub affine: cairo::Matrix,
    pub rect: Option<cairo::Rectangle>,     // without stroke
    pub ink_rect: Option<cairo::Rectangle>, // with stroke
}

impl BoundingBox {
    pub fn new(affine: &cairo::Matrix) -> BoundingBox {
        BoundingBox {
            affine: *affine,
            rect: None,
            ink_rect: None,
        }
    }

    pub fn with_rect(self, rect: Option<cairo::Rectangle>) -> BoundingBox {
        BoundingBox { rect, ..self }
    }

    pub fn with_extents(self, extents: (f64, f64, f64, f64)) -> BoundingBox {
        let rect = rect_from_extents(extents);
        BoundingBox { rect, ..self }
    }

    pub fn with_ink_extents(self, extents: (f64, f64, f64, f64)) -> BoundingBox {
        let ink_rect = rect_from_extents(extents);
        BoundingBox { ink_rect, ..self }
    }

    fn combine(&mut self, src: &BoundingBox, clip: bool) {
        if src.rect.is_none() && src.ink_rect.is_none() {
            return;
        }

        let mut affine = self.affine;

        // this will panic!() if it's not invertible... should we check on our own?
        affine.invert();
        affine = cairo::Matrix::multiply(&src.affine, &affine);

        self.rect = combine_rects(self.rect, src.rect, &affine, clip);
        self.ink_rect = combine_rects(self.ink_rect, src.ink_rect, &affine, clip);
    }

    pub fn insert(&mut self, src: &BoundingBox) {
        self.combine(src, false);
    }

    pub fn clip(&mut self, src: &BoundingBox) {
        self.combine(src, true);
    }
}

fn rect_from_extents((x1, y1, x2, y2): (f64, f64, f64, f64)) -> Option<cairo::Rectangle> {
    Some(cairo::Rectangle {
        x: x1,
        y: y1,
        width: x2 - x1,
        height: y2 - y1,
    })
}

fn combine_rects(
    r1: Option<cairo::Rectangle>,
    r2: Option<cairo::Rectangle>,
    affine: &cairo::Matrix,
    clip: bool,
) -> Option<cairo::Rectangle> {
    match (r1, r2, clip) {
        (r1, None, _) => r1,
        (None, Some(r2), _) => Some(r2.transform(&affine)),
        (Some(r1), Some(r2), true) => Some(r2.transform(&affine).intersect(&r1)),
        (Some(r1), Some(r2), false) => Some(r2.transform(&affine).union(&r1)),
    }
}
<commit_msg>BoundingBox::with_ink_rect() - new method, analogous to with_ink_extents()<commit_after>use cairo;
use cairo::MatrixTrait;

use rect::RectangleExt;

#[derive(Debug, Copy, Clone)]
pub struct BoundingBox {
    pub affine: cairo::Matrix,
    pub rect: Option<cairo::Rectangle>,     // without stroke
    pub ink_rect: Option<cairo::Rectangle>, // with stroke
}

impl BoundingBox {
    pub fn new(affine: &cairo::Matrix) -> BoundingBox {
        BoundingBox {
            affine: *affine,
            rect: None,
            ink_rect: None,
        }
    }

    pub fn with_rect(self, rect: Option<cairo::Rectangle>) -> BoundingBox {
        BoundingBox { rect, ..self }
    }

    pub fn with_ink_rect(self, ink_rect: Option<cairo::Rectangle>) -> BoundingBox {
        BoundingBox { ink_rect, ..self }
    }

    pub fn with_extents(self, extents: (f64, f64, f64, f64)) -> BoundingBox {
        self.with_rect(rect_from_extents(extents))
    }

    pub fn with_ink_extents(self, extents: (f64, f64, f64, f64)) -> BoundingBox {
        self.with_ink_rect(rect_from_extents(extents))
    }

    fn combine(&mut self, src: &BoundingBox, clip: bool) {
        if src.rect.is_none() && src.ink_rect.is_none() {
            return;
        }

        let mut affine = self.affine;

        // this will panic!() if it's not invertible... should we check on our own?
        affine.invert();
        affine = cairo::Matrix::multiply(&src.affine, &affine);

        self.rect = combine_rects(self.rect, src.rect, &affine, clip);
        self.ink_rect = combine_rects(self.ink_rect, src.ink_rect, &affine, clip);
    }

    pub fn insert(&mut self, src: &BoundingBox) {
        self.combine(src, false);
    }

    pub fn clip(&mut self, src: &BoundingBox) {
        self.combine(src, true);
    }
}

fn rect_from_extents((x1, y1, x2, y2): (f64, f64, f64, f64)) -> Option<cairo::Rectangle> {
    Some(cairo::Rectangle {
        x: x1,
        y: y1,
        width: x2 - x1,
        height: y2 - y1,
    })
}

fn combine_rects(
    r1: Option<cairo::Rectangle>,
    r2: Option<cairo::Rectangle>,
    affine: &cairo::Matrix,
    clip: bool,
) -> Option<cairo::Rectangle> {
    match (r1, r2, clip) {
        (r1, None, _) => r1,
        (None, Some(r2), _) => Some(r2.transform(&affine)),
        (Some(r1), Some(r2), true) => Some(r2.transform(&affine).intersect(&r1)),
        (Some(r1), Some(r2), false) => Some(r2.transform(&affine).union(&r1)),
    }
}
<|endoftext|>


<commit_before>pub mod fx32;

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

	#[test]
	fn it_works() {
		let a = Fx32::new (5000);
		let b = Fx32::new (4000);

		assert! (a == a, "eq");
		assert! (b == b, "eq");
		assert! (a != b, "eq");

		assert! ((a + b).x == 9000, "Fx32 add failed");
		assert! ((a - b).x == 1000, "Fx32 sub failed");
		assert! (-a.x == -5000, "Fx32 neg failed");

		assert_eq! (65536, super::fx32::DENOMINATOR, "Denominator is wrong");
		assert_eq! (65536, Fx32::from_float (1.0f32).x, "Denominator applied wrong");

		let half = Fx32::from_float (0.5f32);
		let quarter = Fx32::from_float (0.25f32);
		let three_quarters = Fx32::from_float (0.75f32);

		assert! (half + quarter == three_quarters, "from_float / add failed");

		assert! (half * half == quarter, "mul");
		assert! (Fx32::from_float (1.0f32 / 256.0f32) * Fx32::from_float (512.0f32) == Fx32::from_float (2.0f32), "mul");

		assert! (Fx32::from_float (181.0f32) * Fx32::from_float (181.0f32) == Fx32::from_float (181.0f32 * 181.0f32), "big * big mul");

		assert! (Fx32::from_float (1.0f32 / 256.0f32) * Fx32::from_float (1.0f32 / 128.0f32) == Fx32::from_float (1.0f32 / 128.0f32 / 256.0f32), "small * small mul");

		assert! (Fx32::mul_precise (Fx32::from_float (1.0f32 / 1024.0f32), Fx32::from_float (1024.0f32)) == Fx32::from_float (1.0f32), "small * big mul");

		/*
		Remember, i32 is signed, so our 16.16 is really 15.16
		plus one sign bit
		If we scale this to meters, we have no more than
		32 km negative and positive, with 1/65 millimeter granularity.
		For my plan, this is fine, if I stay within 10 km each way the
		math should be fine and that's a bigger world than I could create.
		*/
		assert! (Fx32::mul_64 (Fx32::from_float (1.0f32 / 16384.0f32), Fx32::from_float (16384.0f32)) == Fx32::from_float (1.0f32), "mul_64");

		assert! (Fx32::mul_small (Fx32::from_float (1.0f32 / 8192.0f32), Fx32::from_float (0.5f32)) == Fx32::from_float (1.0f32 / 16384.0f32), "mul_small");

		assert! (Fx32::mul_small (Fx32::from_float (1.0f32), Fx32::from_float (1.5f32)) == Fx32::from_float (1.5f32), "mul_small");
    }
}
<commit_msg>Switching to assert_eq in a few places<commit_after>pub mod fx32;

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

	#[test]
	fn it_works() {
		let a = Fx32::new (5000);
		let b = Fx32::new (4000);

		assert! (a == a, "eq");
		assert! (b == b, "eq");
		assert! (a != b, "eq");

		assert_eq! ((a + b).x, 9000, "Fx32 add failed");
		assert_eq! ((a - b).x, 1000, "Fx32 sub failed");
		assert_eq! (-a.x, -5000, "Fx32 neg failed");

		assert_eq! (65536, super::fx32::DENOMINATOR, "Denominator is wrong");
		assert_eq! (65536, Fx32::from_float (1.0f32).x, "Denominator applied wrong");

		let half = Fx32::from_float (0.5f32);
		let quarter = Fx32::from_float (0.25f32);
		let three_quarters = Fx32::from_float (0.75f32);

		assert! (half + quarter == three_quarters, "from_float / add failed");

		assert! (half * half == quarter, "mul");
		assert! (Fx32::from_float (1.0f32 / 256.0f32) * Fx32::from_float (512.0f32) == Fx32::from_float (2.0f32), "mul");

		assert! (Fx32::from_float (181.0f32) * Fx32::from_float (181.0f32) == Fx32::from_float (181.0f32 * 181.0f32), "big * big mul");

		assert! (Fx32::from_float (1.0f32 / 256.0f32) * Fx32::from_float (1.0f32 / 128.0f32) == Fx32::from_float (1.0f32 / 128.0f32 / 256.0f32), "small * small mul");

		assert! (Fx32::mul_precise (Fx32::from_float (1.0f32 / 1024.0f32), Fx32::from_float (1024.0f32)) == Fx32::from_float (1.0f32), "small * big mul");

		/*
		Remember, i32 is signed, so our 16.16 is really 15.16
		plus one sign bit
		If we scale this to meters, we have no more than
		32 km negative and positive, with 1/65 millimeter granularity.
		For my plan, this is fine, if I stay within 10 km each way the
		math should be fine and that's a bigger world than I could create.
		*/
		assert! (Fx32::mul_64 (Fx32::from_float (1.0f32 / 16384.0f32), Fx32::from_float (16384.0f32)) == Fx32::from_float (1.0f32), "mul_64");

		assert! (Fx32::mul_small (Fx32::from_float (1.0f32 / 8192.0f32), Fx32::from_float (0.5f32)) == Fx32::from_float (1.0f32 / 16384.0f32), "mul_small");

		assert! (Fx32::mul_small (Fx32::from_float (1.0f32), Fx32::from_float (1.5f32)) == Fx32::from_float (1.5f32), "mul_small");
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate nadezhda;

use nadezhda::grammar::Program;

trait Length {
    fn length(&self) -> i32;
}

impl Length for Program {
    fn length(&self) -> i32 {
        1 + match *self {
            Program::Forward(ref contained_program) => {
                contained_program.length()
            },
            Program::Backward(ref contained_program) => {
                contained_program.length()
            },
            Program::Stop => 0

        }
    }
}

fn main() {
    let program: Program = rand::random();

    println!("length of program is {}", program.length());
}

<commit_msg>Demonstrate the average length of a program<commit_after>extern crate rand;
extern crate nadezhda;

use std::collections::HashMap;
use nadezhda::grammar::Program;

trait Length {
    fn length(&self) -> i32;
}

impl Length for Program {
    fn length(&self) -> i32 {
        1 + match *self {
            Program::Forward(ref contained_program) => {
                contained_program.length()
            },
            Program::Backward(ref contained_program) => {
                contained_program.length()
            },
            Program::Stop => 0

        }
    }
}

fn main() {
    let mut length_frequency = HashMap::new();
    let number_of_loops = 10_000;
    for _ in 0..number_of_loops {
        let program: Program = rand::random();
        let length = program.length();

        let count = match length_frequency.get(&length) {
            Some(last_value) => last_value + 1,
            None => 1
        };
        length_frequency.insert(length, count);
    }

    let mut lengths: Vec<&i32> = length_frequency.keys().collect();
    lengths.sort();
    let mut weighted_sum = 0;
    for length in lengths {
        let frequency = length_frequency.get(length).unwrap();
        weighted_sum += length * frequency;
        println!("{}: {}", length, frequency );
    }
    println!("averge {}", (weighted_sum as f32) / (number_of_loops as f32));
}

<|endoftext|>