<commit_before>//! Memory buffers

use std::error::Error;
use std::fmt;

use {IndexType, Backend};

/// An offset inside a buffer, in bytes.
pub type Offset = u64;

/// Error creating a buffer.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum CreationError {
    /// Required `Usage` is not supported.
    Usage(Usage),
    /// Some other problem.
    Other,
}

impl fmt::Display for CreationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let description = self.description();
        match *self {
            CreationError::Usage(usage) => write!(f, "{}: {:?}", description, usage),
            _ => write!(f, "{}", description)
        }
    }
}

impl Error for CreationError {
    fn description(&self) -> &str {
        match *self {
            CreationError::Usage(_) =>
                "Required `Usage` is not supported",
            CreationError::Other =>
                "Some other problem",
        }
    }
}

/// Error creating a `BufferView`.
#[derive(Clone, Debug, PartialEq)]
pub enum ViewError {
    /// The required usage flag is not present in the image.
    Usage(Usage),
    /// The backend refused for some reason.
    Unsupported,
}

impl fmt::Display for ViewError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let description = self.description();
        match *self {
            ViewError::Usage(usage) => write!(f, "{}: {:?}", description, usage),
            _ => write!(f, "{}", description)
        }
    }
}

impl Error for ViewError {
    fn description(&self) -> &str {
        match *self {
            ViewError::Usage(_) =>
                "The required usage flag is not present in the image",
            ViewError::Unsupported =>
                "The backend refused for some reason",
        }
    }
}

bitflags!(
    /// Buffer usage flags.
    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
    pub struct Usage: u16 {
        ///
        const TRANSFER_SRC  = 0x1;
        ///
        const TRANSFER_DST = 0x2;
        ///
        const UNIFORM = 0x4;
        ///
        const STORAGE = 0x8;
        ///
        const UNIFORM_TEXEL = 0x10;
        ///
        const STORAGE_TEXEL = 0x20;
        ///
        const INDEX = 0x40;
        ///
        const INDIRECT = 0x80;
        ///
        const VERTEX = 0x100;
    }
);

impl Usage {
    /// Can this buffer be used in transfer operations ?
    pub fn can_transfer(&self) -> bool {
        self.intersects(Usage::TRANSFER_SRC | Usage::TRANSFER_DST)
    }
}

bitflags!(
    /// Buffer state flags.
    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
    pub struct Access: u32 {
        ///
        const TRANSFER_READ          = 0x800;
        ///
        const TRANSFER_WRITE         = 0x1000;
        ///
        const INDEX_BUFFER_READ      = 0x02;
        ///
        const VERTEX_BUFFER_READ     = 0x04;
        ///
        const CONSTANT_BUFFER_READ   = 0x08;
        ///
        const INDIRECT_COMMAND_READ  = 0x01;
        ///
        const SHADER_READ = 0x20;
        ///
        const SHADER_WRITE = 0x40;
        ///
        const HOST_READ = 0x2000;
        ///
        const HOST_WRITE = 0x4000;
        ///
        const MEMORY_READ = 0x8000;
        ///
        const MEMORY_WRITE = 0x10000;
    }
);

/// Buffer state
pub type State = Access;

/// Index buffer view for `bind_index_buffer`, slightly
/// analogous to an index table into an array.
pub struct IndexBufferView<'a, B: Backend> {
    /// The buffer to bind.
    pub buffer: &'a B::Buffer,
    /// The offset into the buffer to start at.
    pub offset: u64,
    /// The type of the table elements (`u16` or `u32`).
    pub index_type: IndexType,
}
<commit_msg>Rearrange buffer access flags<commit_after>//! Memory buffers

use std::error::Error;
use std::fmt;

use {IndexType, Backend};

/// An offset inside a buffer, in bytes.
pub type Offset = u64;

/// Error creating a buffer.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum CreationError {
    /// Required `Usage` is not supported.
    Usage(Usage),
    /// Some other problem.
    Other,
}

impl fmt::Display for CreationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let description = self.description();
        match *self {
            CreationError::Usage(usage) => write!(f, "{}: {:?}", description, usage),
            _ => write!(f, "{}", description)
        }
    }
}

impl Error for CreationError {
    fn description(&self) -> &str {
        match *self {
            CreationError::Usage(_) =>
                "Required `Usage` is not supported",
            CreationError::Other =>
                "Some other problem",
        }
    }
}

/// Error creating a `BufferView`.
#[derive(Clone, Debug, PartialEq)]
pub enum ViewError {
    /// The required usage flag is not present in the image.
    Usage(Usage),
    /// The backend refused for some reason.
    Unsupported,
}

impl fmt::Display for ViewError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let description = self.description();
        match *self {
            ViewError::Usage(usage) => write!(f, "{}: {:?}", description, usage),
            _ => write!(f, "{}", description)
        }
    }
}

impl Error for ViewError {
    fn description(&self) -> &str {
        match *self {
            ViewError::Usage(_) =>
                "The required usage flag is not present in the image",
            ViewError::Unsupported =>
                "The backend refused for some reason",
        }
    }
}

bitflags!(
    /// Buffer usage flags.
    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
    pub struct Usage: u16 {
        ///
        const TRANSFER_SRC  = 0x1;
        ///
        const TRANSFER_DST = 0x2;
        ///
        const UNIFORM = 0x4;
        ///
        const STORAGE = 0x8;
        ///
        const UNIFORM_TEXEL = 0x10;
        ///
        const STORAGE_TEXEL = 0x20;
        ///
        const INDEX = 0x40;
        ///
        const INDIRECT = 0x80;
        ///
        const VERTEX = 0x100;
    }
);

impl Usage {
    /// Can this buffer be used in transfer operations ?
    pub fn can_transfer(&self) -> bool {
        self.intersects(Usage::TRANSFER_SRC | Usage::TRANSFER_DST)
    }
}

bitflags!(
    /// Buffer state flags.
    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
    pub struct Access: u32 {
        ///
        const INDIRECT_COMMAND_READ = 0x1;
        ///
        const INDEX_BUFFER_READ = 0x2;
        ///
        const VERTEX_BUFFER_READ = 0x4;
        ///
        const CONSTANT_BUFFER_READ = 0x8;
        ///
        const SHADER_READ = 0x20;
        ///
        const SHADER_WRITE = 0x40;
        ///
        const TRANSFER_READ = 0x800;
        ///
        const TRANSFER_WRITE = 0x1000;
        ///
        const HOST_READ = 0x2000;
        ///
        const HOST_WRITE = 0x4000;
        ///
        const MEMORY_READ = 0x8000;
        ///
        const MEMORY_WRITE = 0x10000;
    }
);

/// Buffer state
pub type State = Access;

/// Index buffer view for `bind_index_buffer`, slightly
/// analogous to an index table into an array.
pub struct IndexBufferView<'a, B: Backend> {
    /// The buffer to bind.
    pub buffer: &'a B::Buffer,
    /// The offset into the buffer to start at.
    pub offset: u64,
    /// The type of the table elements (`u16` or `u32`).
    pub index_type: IndexType,
}
<|endoftext|>


<commit_before>//! Windowing system interoperability
//!
//! Screen presentation (fullscreen or window) of images requires two objects:
//!
//! * [`Surface`] is the host abstraction of the native screen
//! * [`Swapchain`] is the device abstraction for a surface, containing multiple presentable images
//!
//! ## Window
//!
//! // DOC TODO
//!
//! ## Surface
//!
//! // DOC TODO
//!
//! ## Swapchain
//!
//! The most interesting part of a swapchain are the contained presentable images/backbuffers.
//! Presentable images are specialized images, which can be presented on the screen. They are
//! 2D color images with optionally associated depth-stencil images.
//!
//! The common steps for presentation of a frame are acquisition and presentation:
//!
//! ```no_run
//! # extern crate gfx_backend_empty as empty;
//! # extern crate gfx_hal;
//! # fn main() {
//! use gfx_hal::Device;
//! # use gfx_hal::{CommandQueue, Graphics, Swapchain};
//!
//! # let mut swapchain: empty::Swapchain = return;
//! # let device: empty::Device = return;
//! # let mut present_queue: CommandQueue<empty::Backend, Graphics> = return;
//! # unsafe {
//! let acquisition_semaphore = device.create_semaphore().unwrap();
//! let render_semaphore = device.create_semaphore().unwrap();
//!
//! let frame = swapchain.acquire_image(!0, Some(&acquisition_semaphore), None);
//! // render the scene..
//! // `render_semaphore` will be signalled once rendering has been finished
//! swapchain.present(&mut present_queue, 0, &[render_semaphore]);
//! # }}
//! ```
//!
//! Queues need to synchronize with the presentation engine, usually done via signalling a semaphore
//! once a frame is available for rendering and waiting on a separate semaphore until scene rendering
//! has finished.
//!
//! ### Recreation
//!
//! DOC TODO

use crate::device;
use crate::format::Format;
use crate::image;
use crate::queue::{Capability, CommandQueue};
use crate::Backend;

use std::any::Any;
use std::borrow::Borrow;
use std::cmp::{max, min};
use std::iter;
use std::ops::Range;

/// Error occurred during swapchain creation.
#[derive(Clone, Copy, Debug, Fail, PartialEq, Eq)]
pub enum CreationError {
    /// Out of either host or device memory.
    #[fail(display = "{}", _0)]
    OutOfMemory(device::OutOfMemory),
    /// Device is lost
    #[fail(display = "{}", _0)]
    DeviceLost(device::DeviceLost),
    /// Surface is lost
    #[fail(display = "{}", _0)]
    SurfaceLost(device::SurfaceLost),
    /// Window in use
    #[fail(display = "{}", _0)]
    WindowInUse(device::WindowInUse),
}

impl From<device::OutOfMemory> for CreationError {
    fn from(error: device::OutOfMemory) -> Self {
        CreationError::OutOfMemory(error)
    }
}

impl From<device::DeviceLost> for CreationError {
    fn from(error: device::DeviceLost) -> Self {
        CreationError::DeviceLost(error)
    }
}

impl From<device::SurfaceLost> for CreationError {
    fn from(error: device::SurfaceLost) -> Self {
        CreationError::SurfaceLost(error)
    }
}

impl From<device::WindowInUse> for CreationError {
    fn from(error: device::WindowInUse) -> Self {
        CreationError::WindowInUse(error)
    }
}

/// An extent describes the size of a rectangle, such as
/// a window or texture. It is not used for referring to a
/// sub-rectangle; for that see `command::Rect`.
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Extent2D {
    /// Width
    pub width: image::Size,
    /// Height
    pub height: image::Size,
}

impl From<image::Extent> for Extent2D {
    fn from(ex: image::Extent) -> Self {
        Extent2D {
            width: ex.width,
            height: ex.height,
        }
    }
}

impl Extent2D {
    /// Convert into a regular image extent.
    pub fn to_extent(&self) -> image::Extent {
        image::Extent {
            width: self.width,
            height: self.height,
            depth: 1,
        }
    }
}

/// Describes information about what a `Surface`'s properties are.
/// Fetch this with `surface.capabilities_and_formats(device)`.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SurfaceCapabilities {
    /// Number of presentable images supported by the adapter for a swapchain
    /// created from this surface.
    ///
    /// - `image_count.start` must be at least 1.
    /// - `image_count.end` must be larger of equal to `image_count.start`.
    pub image_count: Range<SwapImageIndex>,

    /// Current extent of the surface.
    ///
    /// `None` if the surface has no explicit size, depending on the swapchain extent.
    pub current_extent: Option<Extent2D>,

    /// Range of supported extents.
    ///
    /// `current_extent` must be inside this range.
    pub extents: Range<Extent2D>,

    /// Maximum number of layers supported for presentable images.
    ///
    /// Must be at least 1.
    pub max_image_layers: image::Layer,

    /// Supported image usage flags.
    pub usage: image::Usage,

    /// A bitmask of supported alpha composition modes.
    pub composite_alpha: CompositeAlpha,
}

/// A `Surface` abstracts the surface of a native window, which will be presented
/// on the display.
pub trait Surface<B: Backend>: Any + Send + Sync {
    /// Retrieve the surface image kind.
    fn kind(&self) -> image::Kind;

    /// Check if the queue family supports presentation to this surface.
    ///
    /// # Examples
    ///
    /// ```no_run
    ///
    /// ```
    fn supports_queue_family(&self, family: &B::QueueFamily) -> bool;

    /// Query surface capabilities, formats, and present modes for this physical device.
    ///
    /// Use this function for configuring swapchain creation.
    ///
    /// Returns a tuple of surface capabilities and formats.
    /// If formats is `None` than the surface has no preferred format and the
    /// application may use any desired format.
    fn compatibility(
        &self,
        physical_device: &B::PhysicalDevice,
    ) -> (SurfaceCapabilities, Option<Vec<Format>>, Vec<PresentMode>);
}

/// Index of an image in the swapchain.
///
/// The swapchain is a series of one or more images, usually
/// with one being drawn on while the other is displayed by
/// the GPU (aka double-buffering). A `SwapImageIndex` refers
/// to a particular image in the swapchain.
pub type SwapImageIndex = u32;

/// Specifies the mode regulating how a swapchain presents frames.
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum PresentMode {
    /// Don't ever wait for v-sync.
    Immediate = 0,
    /// Wait for v-sync, overwrite the last rendered frame.
    Mailbox = 1,
    /// Present frames in the same order they are rendered.
    Fifo = 2,
    /// Don't wait for the next v-sync if we just missed it.
    Relaxed = 3,
}

bitflags!(
    /// Specifies how the alpha channel of the images should be handled during
    /// compositing.
    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
    pub struct CompositeAlpha: u32 {
        /// The alpha channel, if it exists, of the images is ignored in the
        /// compositing process. Instead, the image is treated as if it has a
        /// constant alpha of 1.0.
        const OPAQUE = 0x1;
        /// The alpha channel, if it exists, of the images is respected in the
        /// compositing process. The non-alpha channels of the image are
        /// expected to already be multiplied by the alpha channel by the
        /// application.
        const PREMULTIPLIED = 0x2;
        /// The alpha channel, if it exists, of the images is respected in the
        /// compositing process. The non-alpha channels of the image are not
        /// expected to already be multiplied by the alpha channel by the
        /// application; instead, the compositor will multiply the non-alpha
        /// channels of the image by the alpha channel during compositing.
        const POSTMULTIPLIED = 0x4;
        /// The way in which the presentation engine treats the alpha channel in
        /// the images is unknown to gfx-hal. Instead, the application is
        /// responsible for setting the composite alpha blending mode using
        /// native window system commands. If the application does not set the
        /// blending mode using native window system commands, then a
        /// platform-specific default will be used.
        const INHERIT = 0x8;
    }
);

/// Contains all the data necessary to create a new `Swapchain`:
/// color, depth, and number of images.
///
/// # Examples
///
/// This type implements the builder pattern, method calls can be
/// easily chained.
///
/// ```no_run
/// # extern crate gfx_hal;
/// # fn main() {
/// # use gfx_hal::{SwapchainConfig};
/// # use gfx_hal::format::Format;
/// let config = SwapchainConfig::new(100, 100, Format::Bgra8Unorm, 2);
/// # }
/// ```
#[derive(Debug, Clone)]
pub struct SwapchainConfig {
    /// Presentation mode.
    pub present_mode: PresentMode,
    /// Alpha composition mode.
    pub composite_alpha: CompositeAlpha,
    /// Format of the backbuffer images.
    pub format: Format,
    /// Requested image extent. Must be in
    /// `SurfaceCapabilities::extents` range.
    pub extent: Extent2D,
    /// Number of images in the swapchain. Must be in
    /// `SurfaceCapabilities::image_count` range.
    pub image_count: SwapImageIndex,
    /// Number of image layers. Must be lower or equal to
    /// `SurfaceCapabilities::max_image_layers`.
    pub image_layers: image::Layer,
    /// Image usage of the backbuffer images.
    pub image_usage: image::Usage,
}

impl SwapchainConfig {
    /// Create a new default configuration (color images only).
    ///
    /// # Examples
    ///
    /// ```no_run
    ///
    /// ```
    pub fn new(width: u32, height: u32, format: Format, image_count: SwapImageIndex) -> Self {
        SwapchainConfig {
            present_mode: PresentMode::Fifo,
            composite_alpha: CompositeAlpha::OPAQUE,
            format,
            extent: Extent2D { width, height },
            image_count,
            image_layers: 1,
            image_usage: image::Usage::COLOR_ATTACHMENT,
        }
    }

    /// Create a swapchain configuration based on the capabilities
    /// returned from a physical device query. If the surface does not
    /// specify a current size, default_extent is clamped and used instead.
    pub fn from_caps(caps: &SurfaceCapabilities, format: Format, default_extent: Extent2D) -> Self {
        let clamped_extent = match caps.current_extent {
            Some(current) => current,
            None => {
                let (min_width, max_width) = (caps.extents.start.width, caps.extents.end.width - 1);
                let (min_height, max_height) =
                    (caps.extents.start.height, caps.extents.end.height - 1);

                // clamp the default_extent to within the allowed surface sizes
                let width = min(max_width, max(default_extent.width, min_width));
                let height = min(max_height, max(default_extent.height, min_height));

                Extent2D { width, height }
            }
        };

        let composite_alpha = if caps.composite_alpha.contains(CompositeAlpha::INHERIT) {
            CompositeAlpha::INHERIT
        } else if caps.composite_alpha.contains(CompositeAlpha::OPAQUE) {
            CompositeAlpha::OPAQUE
        } else {
            unreachable!("neither INHERIT or OPAQUE CompositeAlpha modes are supported")
        };

        SwapchainConfig {
            present_mode: PresentMode::Fifo,
            composite_alpha,
            format,
            extent: clamped_extent,
            image_count: caps.image_count.start,
            image_layers: 1,
            image_usage: image::Usage::COLOR_ATTACHMENT,
        }
    }

    /// Specify the presentation mode.
    ///
    /// # Examples
    ///
    /// ```no_run
    ///
    /// ```
    pub fn with_mode(mut self, mode: PresentMode) -> Self {
        self.present_mode = mode;
        self
    }

    /// Specify the usage of backbuffer images.
    ///
    /// # Examples
    ///
    /// ```no_run
    ///
    /// ```
    pub fn with_image_usage(mut self, usage: image::Usage) -> Self {
        self.image_usage = usage;
        self
    }

    // TODO: depth-only, stencil-only, swapchain size, present modes, etc.
}

/// Swapchain backbuffer type
#[derive(Debug)]
pub enum Backbuffer<B: Backend> {
    /// Color image chain
    Images(Vec<B::Image>),
    /// A single opaque framebuffer
    Framebuffer(B::Framebuffer),
}

/// Error on acquiring the next image from a swapchain.
#[derive(Debug, Clone)]
pub enum AcquireError {
    /// No image was ready after the specified timeout expired.
    NotReady,
    /// The swapchain is no longer in sync with the surface, needs to be re-created.
    OutOfDate,
    /// The surface was lost, and the swapchain is no longer usable.
    SurfaceLost(device::SurfaceLost),
}

/// The `Swapchain` is the backend representation of the surface.
/// It consists of multiple buffers, which will be presented on the surface.
pub trait Swapchain<B: Backend>: Any + Send + Sync {
    /// Acquire a new swapchain image for rendering. This needs to be called before presenting.
    ///
    /// May fail according to one of the reasons indicated in `AcquireError` enum.
    ///
    /// # Synchronization
    ///
    /// The acquired image will not be immediately available when the function returns.
    /// Once available the provided [`Semaphore`](../trait.Resources.html#associatedtype.Semaphore)
    /// and [`Fence`](../trait.Resources.html#associatedtype.Fence) will be signaled.
    ///
    /// # Examples
    ///
    /// ```no_run
    ///
    /// ```
    unsafe fn acquire_image(
        &mut self,
        timeout_ns: u64,
        semaphore: Option<&B::Semaphore>,
        fence: Option<&B::Fence>,
    ) -> Result<SwapImageIndex, AcquireError>;

    /// Present one acquired image.
    ///
    /// # Safety
    ///
    /// The passed queue _must_ support presentation on the surface, which is
    /// used for creating this swapchain.
    ///
    /// # Examples
    ///
    /// ```no_run
    ///
    /// ```
    unsafe fn present<'a, C, S, Iw>(
        &'a self,
        present_queue: &mut CommandQueue<B, C>,
        image_index: SwapImageIndex,
        wait_semaphores: Iw,
    ) -> Result<(), ()>
    where
        Self: 'a + Sized + Borrow<B::Swapchain>,
        C: Capability,
        S: 'a + Borrow<B::Semaphore>,
        Iw: IntoIterator<Item = &'a S>,
    {
        present_queue.present(iter::once((self, image_index)), wait_semaphores)
    }

    /// Present one acquired image without any semaphore synchronization.
    unsafe fn present_nosemaphores<'a, C>(
        &'a self,
        present_queue: &mut CommandQueue<B, C>,
        image_index: SwapImageIndex,
    ) -> Result<(), ()>
    where
        Self: 'a + Sized + Borrow<B::Swapchain>,
        C: Capability,
    {
        self.present::<_, B::Semaphore, _>(present_queue, image_index, iter::empty())
    }
}
<commit_msg>Fix doc error<commit_after>//! Windowing system interoperability
//!
//! Screen presentation (fullscreen or window) of images requires two objects:
//!
//! * [`Surface`] is the host abstraction of the native screen
//! * [`Swapchain`] is the device abstraction for a surface, containing multiple presentable images
//!
//! ## Window
//!
//! // DOC TODO
//!
//! ## Surface
//!
//! // DOC TODO
//!
//! ## Swapchain
//!
//! The most interesting part of a swapchain are the contained presentable images/backbuffers.
//! Presentable images are specialized images, which can be presented on the screen. They are
//! 2D color images with optionally associated depth-stencil images.
//!
//! The common steps for presentation of a frame are acquisition and presentation:
//!
//! ```no_run
//! # extern crate gfx_backend_empty as empty;
//! # extern crate gfx_hal;
//! # fn main() {
//! use gfx_hal::Device;
//! # use gfx_hal::{CommandQueue, Graphics, Swapchain};
//!
//! # let mut swapchain: empty::Swapchain = return;
//! # let device: empty::Device = return;
//! # let mut present_queue: CommandQueue<empty::Backend, Graphics> = return;
//! # unsafe {
//! let acquisition_semaphore = device.create_semaphore().unwrap();
//! let render_semaphore = device.create_semaphore().unwrap();
//!
//! let frame = swapchain.acquire_image(!0, Some(&acquisition_semaphore), None);
//! // render the scene..
//! // `render_semaphore` will be signalled once rendering has been finished
//! swapchain.present(&mut present_queue, 0, &[render_semaphore]);
//! # }}
//! ```
//!
//! Queues need to synchronize with the presentation engine, usually done via signalling a semaphore
//! once a frame is available for rendering and waiting on a separate semaphore until scene rendering
//! has finished.
//!
//! ### Recreation
//!
//! DOC TODO

use crate::device;
use crate::format::Format;
use crate::image;
use crate::queue::{Capability, CommandQueue};
use crate::Backend;

use std::any::Any;
use std::borrow::Borrow;
use std::cmp::{max, min};
use std::iter;
use std::ops::Range;

/// Error occurred during swapchain creation.
#[derive(Clone, Copy, Debug, Fail, PartialEq, Eq)]
pub enum CreationError {
    /// Out of either host or device memory.
    #[fail(display = "{}", _0)]
    OutOfMemory(device::OutOfMemory),
    /// Device is lost
    #[fail(display = "{}", _0)]
    DeviceLost(device::DeviceLost),
    /// Surface is lost
    #[fail(display = "{}", _0)]
    SurfaceLost(device::SurfaceLost),
    /// Window in use
    #[fail(display = "{}", _0)]
    WindowInUse(device::WindowInUse),
}

impl From<device::OutOfMemory> for CreationError {
    fn from(error: device::OutOfMemory) -> Self {
        CreationError::OutOfMemory(error)
    }
}

impl From<device::DeviceLost> for CreationError {
    fn from(error: device::DeviceLost) -> Self {
        CreationError::DeviceLost(error)
    }
}

impl From<device::SurfaceLost> for CreationError {
    fn from(error: device::SurfaceLost) -> Self {
        CreationError::SurfaceLost(error)
    }
}

impl From<device::WindowInUse> for CreationError {
    fn from(error: device::WindowInUse) -> Self {
        CreationError::WindowInUse(error)
    }
}

/// An extent describes the size of a rectangle, such as
/// a window or texture. It is not used for referring to a
/// sub-rectangle; for that see `command::Rect`.
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Extent2D {
    /// Width
    pub width: image::Size,
    /// Height
    pub height: image::Size,
}

impl From<image::Extent> for Extent2D {
    fn from(ex: image::Extent) -> Self {
        Extent2D {
            width: ex.width,
            height: ex.height,
        }
    }
}

impl Extent2D {
    /// Convert into a regular image extent.
    pub fn to_extent(&self) -> image::Extent {
        image::Extent {
            width: self.width,
            height: self.height,
            depth: 1,
        }
    }
}

/// Describes information about what a `Surface`'s properties are.
/// Fetch this with `surface.compatibility(device)`.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SurfaceCapabilities {
    /// Number of presentable images supported by the adapter for a swapchain
    /// created from this surface.
    ///
    /// - `image_count.start` must be at least 1.
    /// - `image_count.end` must be larger of equal to `image_count.start`.
    pub image_count: Range<SwapImageIndex>,

    /// Current extent of the surface.
    ///
    /// `None` if the surface has no explicit size, depending on the swapchain extent.
    pub current_extent: Option<Extent2D>,

    /// Range of supported extents.
    ///
    /// `current_extent` must be inside this range.
    pub extents: Range<Extent2D>,

    /// Maximum number of layers supported for presentable images.
    ///
    /// Must be at least 1.
    pub max_image_layers: image::Layer,

    /// Supported image usage flags.
    pub usage: image::Usage,

    /// A bitmask of supported alpha composition modes.
    pub composite_alpha: CompositeAlpha,
}

/// A `Surface` abstracts the surface of a native window, which will be presented
/// on the display.
pub trait Surface<B: Backend>: Any + Send + Sync {
    /// Retrieve the surface image kind.
    fn kind(&self) -> image::Kind;

    /// Check if the queue family supports presentation to this surface.
    ///
    /// # Examples
    ///
    /// ```no_run
    ///
    /// ```
    fn supports_queue_family(&self, family: &B::QueueFamily) -> bool;

    /// Query surface capabilities, formats, and present modes for this physical device.
    ///
    /// Use this function for configuring swapchain creation.
    ///
    /// Returns a tuple of surface capabilities and formats.
    /// If formats is `None` than the surface has no preferred format and the
    /// application may use any desired format.
    fn compatibility(
        &self,
        physical_device: &B::PhysicalDevice,
    ) -> (SurfaceCapabilities, Option<Vec<Format>>, Vec<PresentMode>);
}

/// Index of an image in the swapchain.
///
/// The swapchain is a series of one or more images, usually
/// with one being drawn on while the other is displayed by
/// the GPU (aka double-buffering). A `SwapImageIndex` refers
/// to a particular image in the swapchain.
pub type SwapImageIndex = u32;

/// Specifies the mode regulating how a swapchain presents frames.
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum PresentMode {
    /// Don't ever wait for v-sync.
    Immediate = 0,
    /// Wait for v-sync, overwrite the last rendered frame.
    Mailbox = 1,
    /// Present frames in the same order they are rendered.
    Fifo = 2,
    /// Don't wait for the next v-sync if we just missed it.
    Relaxed = 3,
}

bitflags!(
    /// Specifies how the alpha channel of the images should be handled during
    /// compositing.
    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
    pub struct CompositeAlpha: u32 {
        /// The alpha channel, if it exists, of the images is ignored in the
        /// compositing process. Instead, the image is treated as if it has a
        /// constant alpha of 1.0.
        const OPAQUE = 0x1;
        /// The alpha channel, if it exists, of the images is respected in the
        /// compositing process. The non-alpha channels of the image are
        /// expected to already be multiplied by the alpha channel by the
        /// application.
        const PREMULTIPLIED = 0x2;
        /// The alpha channel, if it exists, of the images is respected in the
        /// compositing process. The non-alpha channels of the image are not
        /// expected to already be multiplied by the alpha channel by the
        /// application; instead, the compositor will multiply the non-alpha
        /// channels of the image by the alpha channel during compositing.
        const POSTMULTIPLIED = 0x4;
        /// The way in which the presentation engine treats the alpha channel in
        /// the images is unknown to gfx-hal. Instead, the application is
        /// responsible for setting the composite alpha blending mode using
        /// native window system commands. If the application does not set the
        /// blending mode using native window system commands, then a
        /// platform-specific default will be used.
        const INHERIT = 0x8;
    }
);

/// Contains all the data necessary to create a new `Swapchain`:
/// color, depth, and number of images.
///
/// # Examples
///
/// This type implements the builder pattern, method calls can be
/// easily chained.
///
/// ```no_run
/// # extern crate gfx_hal;
/// # fn main() {
/// # use gfx_hal::{SwapchainConfig};
/// # use gfx_hal::format::Format;
/// let config = SwapchainConfig::new(100, 100, Format::Bgra8Unorm, 2);
/// # }
/// ```
#[derive(Debug, Clone)]
pub struct SwapchainConfig {
    /// Presentation mode.
    pub present_mode: PresentMode,
    /// Alpha composition mode.
    pub composite_alpha: CompositeAlpha,
    /// Format of the backbuffer images.
    pub format: Format,
    /// Requested image extent. Must be in
    /// `SurfaceCapabilities::extents` range.
    pub extent: Extent2D,
    /// Number of images in the swapchain. Must be in
    /// `SurfaceCapabilities::image_count` range.
    pub image_count: SwapImageIndex,
    /// Number of image layers. Must be lower or equal to
    /// `SurfaceCapabilities::max_image_layers`.
    pub image_layers: image::Layer,
    /// Image usage of the backbuffer images.
    pub image_usage: image::Usage,
}

impl SwapchainConfig {
    /// Create a new default configuration (color images only).
    ///
    /// # Examples
    ///
    /// ```no_run
    ///
    /// ```
    pub fn new(width: u32, height: u32, format: Format, image_count: SwapImageIndex) -> Self {
        SwapchainConfig {
            present_mode: PresentMode::Fifo,
            composite_alpha: CompositeAlpha::OPAQUE,
            format,
            extent: Extent2D { width, height },
            image_count,
            image_layers: 1,
            image_usage: image::Usage::COLOR_ATTACHMENT,
        }
    }

    /// Create a swapchain configuration based on the capabilities
    /// returned from a physical device query. If the surface does not
    /// specify a current size, default_extent is clamped and used instead.
    pub fn from_caps(caps: &SurfaceCapabilities, format: Format, default_extent: Extent2D) -> Self {
        let clamped_extent = match caps.current_extent {
            Some(current) => current,
            None => {
                let (min_width, max_width) = (caps.extents.start.width, caps.extents.end.width - 1);
                let (min_height, max_height) =
                    (caps.extents.start.height, caps.extents.end.height - 1);

                // clamp the default_extent to within the allowed surface sizes
                let width = min(max_width, max(default_extent.width, min_width));
                let height = min(max_height, max(default_extent.height, min_height));

                Extent2D { width, height }
            }
        };

        let composite_alpha = if caps.composite_alpha.contains(CompositeAlpha::INHERIT) {
            CompositeAlpha::INHERIT
        } else if caps.composite_alpha.contains(CompositeAlpha::OPAQUE) {
            CompositeAlpha::OPAQUE
        } else {
            unreachable!("neither INHERIT or OPAQUE CompositeAlpha modes are supported")
        };

        SwapchainConfig {
            present_mode: PresentMode::Fifo,
            composite_alpha,
            format,
            extent: clamped_extent,
            image_count: caps.image_count.start,
            image_layers: 1,
            image_usage: image::Usage::COLOR_ATTACHMENT,
        }
    }

    /// Specify the presentation mode.
    ///
    /// # Examples
    ///
    /// ```no_run
    ///
    /// ```
    pub fn with_mode(mut self, mode: PresentMode) -> Self {
        self.present_mode = mode;
        self
    }

    /// Specify the usage of backbuffer images.
    ///
    /// # Examples
    ///
    /// ```no_run
    ///
    /// ```
    pub fn with_image_usage(mut self, usage: image::Usage) -> Self {
        self.image_usage = usage;
        self
    }

    // TODO: depth-only, stencil-only, swapchain size, present modes, etc.
}

/// Swapchain backbuffer type
#[derive(Debug)]
pub enum Backbuffer<B: Backend> {
    /// Color image chain
    Images(Vec<B::Image>),
    /// A single opaque framebuffer
    Framebuffer(B::Framebuffer),
}

/// Error on acquiring the next image from a swapchain.
#[derive(Debug, Clone)]
pub enum AcquireError {
    /// No image was ready after the specified timeout expired.
    NotReady,
    /// The swapchain is no longer in sync with the surface, needs to be re-created.
    OutOfDate,
    /// The surface was lost, and the swapchain is no longer usable.
    SurfaceLost(device::SurfaceLost),
}

/// The `Swapchain` is the backend representation of the surface.
/// It consists of multiple buffers, which will be presented on the surface.
pub trait Swapchain<B: Backend>: Any + Send + Sync {
    /// Acquire a new swapchain image for rendering. This needs to be called before presenting.
    ///
    /// May fail according to one of the reasons indicated in `AcquireError` enum.
    ///
    /// # Synchronization
    ///
    /// The acquired image will not be immediately available when the function returns.
    /// Once available the provided [`Semaphore`](../trait.Resources.html#associatedtype.Semaphore)
    /// and [`Fence`](../trait.Resources.html#associatedtype.Fence) will be signaled.
    ///
    /// # Examples
    ///
    /// ```no_run
    ///
    /// ```
    unsafe fn acquire_image(
        &mut self,
        timeout_ns: u64,
        semaphore: Option<&B::Semaphore>,
        fence: Option<&B::Fence>,
    ) -> Result<SwapImageIndex, AcquireError>;

    /// Present one acquired image.
    ///
    /// # Safety
    ///
    /// The passed queue _must_ support presentation on the surface, which is
    /// used for creating this swapchain.
    ///
    /// # Examples
    ///
    /// ```no_run
    ///
    /// ```
    unsafe fn present<'a, C, S, Iw>(
        &'a self,
        present_queue: &mut CommandQueue<B, C>,
        image_index: SwapImageIndex,
        wait_semaphores: Iw,
    ) -> Result<(), ()>
    where
        Self: 'a + Sized + Borrow<B::Swapchain>,
        C: Capability,
        S: 'a + Borrow<B::Semaphore>,
        Iw: IntoIterator<Item = &'a S>,
    {
        present_queue.present(iter::once((self, image_index)), wait_semaphores)
    }

    /// Present one acquired image without any semaphore synchronization.
    unsafe fn present_nosemaphores<'a, C>(
        &'a self,
        present_queue: &mut CommandQueue<B, C>,
        image_index: SwapImageIndex,
    ) -> Result<(), ()>
    where
        Self: 'a + Sized + Borrow<B::Swapchain>,
        C: Capability,
    {
        self.present::<_, B::Semaphore, _>(present_queue, image_index, iter::empty())
    }
}
<|endoftext|>


<commit_before>//! Defines a BRDF that describes specular reflection

use std::num::Float;
use collect::enum_set::EnumSet;

use linalg::Vector;
use film::Colorf;
use bxdf;
use bxdf::{BxDF, BxDFType, fresnel};

/// Specular reflection BRDF that implements a specularly reflective material model
pub struct SpecularReflection {
    /// Color of the reflective material
    reflectance: Colorf,
    /// Fresnel term for the reflection model
    fresnel: Box<fresnel::Fresnel + Send + Sync>
}

impl SpecularReflection {
    /// Create a specularly reflective BRDF with the reflective color and Fresnel term
    pub fn new(c: &Colorf, fresnel: Box<fresnel::Fresnel + Send + Sync>) -> SpecularReflection {
        SpecularReflection { reflectance: *c, fresnel: fresnel }
    }
}

impl BxDF for SpecularReflection {
    fn bxdf_type(&self) -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Specular);
        e.insert(BxDFType::Reflection);
        e
    }
    /// We'll never exactly hit the specular reflection direction with some pair
    /// so this just returns black. Use `sample` instead
    fn eval(&self, _: &Vector, _: &Vector) -> Colorf { Colorf::broadcast(0.0) }
    /// Sampling the specular BRDF just returns the specular reflection direction
    /// for the light leaving along `w_o`
    fn sample(&self, w_o: &Vector) -> (Colorf, Vector) {
        let w_i = Vector::new(-w_o.x, -w_o.y, w_o.z);
        let c = self.fresnel.fresnel(bxdf::cos_theta(w_o)) * self.reflectance / Float::abs(bxdf::cos_theta(&w_i));
        (c, w_i)
    }
}

<commit_msg>Clean up imports in specular reflection<commit_after>//! Defines a BRDF that describes specular reflection

use std::num::Float;
use collect::enum_set::EnumSet;

use linalg::Vector;
use film::Colorf;
use bxdf;
use bxdf::{BxDF, BxDFType};
use bxdf::fresnel::Fresnel;

/// Specular reflection BRDF that implements a specularly reflective material model
pub struct SpecularReflection {
    /// Color of the reflective material
    reflectance: Colorf,
    /// Fresnel term for the reflection model
    fresnel: Box<Fresnel + Send + Sync>
}

impl SpecularReflection {
    /// Create a specularly reflective BRDF with the reflective color and Fresnel term
    pub fn new(c: &Colorf, fresnel: Box<Fresnel + Send + Sync>) -> SpecularReflection {
        SpecularReflection { reflectance: *c, fresnel: fresnel }
    }
}

impl BxDF for SpecularReflection {
    fn bxdf_type(&self) -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Specular);
        e.insert(BxDFType::Reflection);
        e
    }
    /// We'll never exactly hit the specular reflection direction with some pair
    /// so this just returns black. Use `sample` instead
    fn eval(&self, _: &Vector, _: &Vector) -> Colorf { Colorf::broadcast(0.0) }
    /// Sampling the specular BRDF just returns the specular reflection direction
    /// for the light leaving along `w_o`
    fn sample(&self, w_o: &Vector) -> (Colorf, Vector) {
        let w_i = Vector::new(-w_o.x, -w_o.y, w_o.z);
        let c = self.fresnel.fresnel(bxdf::cos_theta(w_o)) * self.reflectance / Float::abs(bxdf::cos_theta(&w_i));
        (c, w_i)
    }
}

<|endoftext|>


<commit_before>use ast::Block;
use error::ParseError;
use super::format::Format;
use super::builder::{Builder, Output};

///
/// # Example
///
/// ```
/// use squid::generator::html::{Generator, DefaultFormat};
/// use squid::ast::{Block, HeadingLevel};
///
/// let blocks = vec![
///     Ok(Block::Heading {
///         level: HeadingLevel::Level1,
///         content: "Hello World".to_string(),
///     }),
/// ];
///
/// let mut generator = Generator::new(&DefaultFormat, blocks.into_iter());
///
/// for node in generator {
///     println!("{}", node.unwrap());
/// }
/// ```
///
/// ## Output
/// ```text
/// <h1>hello world</h1>
/// ```
///
pub struct Generator<'a, 'b, F, I>
where
    F: Format + 'static,
    // TODO: use own error type
    I: Iterator<Item = Result<Block, ParseError>>,
{
    format: &'a F,
    input: I,
    _marker: ::std::marker::PhantomData<&'b ()>,
}

impl<'a, 'b, F, I> Generator<'a, 'b, F, I>
where
    F: Format + 'static,
    I: Iterator<Item = Result<Block, ParseError>>,
{
    pub fn new(format: &'a F, input: I) -> Self {
        Generator {
            format,
            input,
            _marker: ::std::marker::PhantomData,
        }
    }
}

impl<'a, 'b, F, I> Iterator for Generator<'a, 'b, F, I>
where
    F: Format + 'static,
    I: Iterator<Item = Result<Block, ParseError>>,
{
    type Item = Result<Output<'b>, ParseError>;

    fn next(&mut self) -> Option<Self::Item> {
        let node = self.input.next()?.and_then(|block| {
            let mut builder = Builder::new();

            match block {
                Block::Heading { level, content } => {
                    self.format.heading(&mut builder, level, content)
                }
                _ => unimplemented!(),
            }

            Ok(builder.consume())
        });

        Some(node)
    }
}<commit_msg>Fix generator example<commit_after>use ast::Block;
use error::ParseError;
use super::format::Format;
use super::builder::{Builder, Output};

///
/// # Example
///
/// ```
/// use squid::html::{Generator, DefaultFormat};
/// use squid::ast::{Block, HeadingLevel};
///
/// let blocks = vec![
///     Ok(Block::Heading {
///         level: HeadingLevel::Level1,
///         content: "Hello World".to_string(),
///     }),
/// ];
///
/// let mut generator = Generator::new(&DefaultFormat, blocks.into_iter());
///
/// for node in generator {
///     println!("{}", node.unwrap());
/// }
/// ```
///
/// ## Output
/// ```text
/// <h1>hello world</h1>
/// ```
///
pub struct Generator<'a, 'b, F, I>
where
    F: Format + 'static,
    // TODO: use own error type
    I: Iterator<Item = Result<Block, ParseError>>,
{
    format: &'a F,
    input: I,
    _marker: ::std::marker::PhantomData<&'b ()>,
}

impl<'a, 'b, F, I> Generator<'a, 'b, F, I>
where
    F: Format + 'static,
    I: Iterator<Item = Result<Block, ParseError>>,
{
    pub fn new(format: &'a F, input: I) -> Self {
        Generator {
            format,
            input,
            _marker: ::std::marker::PhantomData,
        }
    }
}

impl<'a, 'b, F, I> Iterator for Generator<'a, 'b, F, I>
where
    F: Format + 'static,
    I: Iterator<Item = Result<Block, ParseError>>,
{
    type Item = Result<Output<'b>, ParseError>;

    fn next(&mut self) -> Option<Self::Item> {
        let node = self.input.next()?.and_then(|block| {
            let mut builder = Builder::new();

            match block {
                Block::Heading { level, content } => {
                    self.format.heading(&mut builder, level, content)
                }
                _ => unimplemented!(),
            }

            Ok(builder.consume())
        });

        Some(node)
    }
}<|endoftext|>


<commit_before>use std::net;
use uuid::Uuid;

use frame::frame_result::{RowsMetadata, ColType, ColSpec, BodyResResultRows, ColTypeOptionValue};
use types::{CBytes, IntoRustByName};
use types::data_serialization_types::*;
use types::list::List;
use types::map::Map;
use types::udt::UDT;
use error::Result;
use std::io;

#[derive(Debug)]
pub struct Row {
    metadata: RowsMetadata,
    row_content: Vec<CBytes>,
}

impl Row {
    pub fn from_frame_body(body: BodyResResultRows) -> Vec<Row> {
        return body.rows_content
            .iter()
            .map(|row| {
                Row {
                    metadata: body.metadata.clone(),
                    row_content: row.clone(),
                }
            })
            .collect();
    }

    fn get_col_by_name(&self, name: &str) -> Option<(&ColType, &CBytes)> {
        let i_opt = self.metadata.col_specs.iter().position(|spec| spec.name.as_str() == name);
        if !i_opt.is_some() {
            return None;
        }
        let i = i_opt.unwrap();
        let ref data: CBytes = self.row_content[i];
        let ref cassandra_type: ColType = self.metadata.col_specs[i].col_type.id;
        return Some((cassandra_type, data));
    }

    fn get_col_spec_by_name(&self, name: &str) -> Option<(&ColSpec, &CBytes)> {
        let i_opt = self.metadata.col_specs.iter().position(|spec| spec.name.as_str() == name);
        if !i_opt.is_some() {
            return None;
        }
        let i = i_opt.unwrap();
        let ref data: CBytes = self.row_content[i];
        let ref cassandra_type: ColSpec = self.metadata.col_specs[i];
        return Some((cassandra_type, data));
    }
}

impl IntoRustByName<Vec<u8>> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<Vec<u8>>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();
            let converted = match cassandra_type {
                &ColType::Blob => decode_blob(bytes),
                _ => unreachable!(),
            };
            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<String> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<String>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();

            let converted = match cassandra_type {
                &ColType::Custom => decode_custom(bytes),
                &ColType::Ascii => decode_ascii(bytes),
                &ColType::Varchar => decode_varchar(bytes),
                // TODO: clarify when to use decode_text.
                // it's not mentioned in
                // https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L582
                // &ColType::XXX => decode_text(bytes).ok(),
                _ => unreachable!(),
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<bool> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<bool>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();

            let converted = match cassandra_type {
                &ColType::Boolean => decode_boolean(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (bool ) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<i64> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<i64>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();
            let converted = match cassandra_type {
                &ColType::Int => decode_bigint(bytes),
                &ColType::Bigint => decode_bigint(bytes),
                &ColType::Timestamp => decode_timestamp(bytes),
                &ColType::Time => decode_time(bytes),
                &ColType::Varint => decode_varint(bytes),
                &ColType::Float => decode_varint(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (Int,Bigint,Timestamp,Time,Varint,Float ) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<i32> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<i32>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();

            let converted = match cassandra_type {
                &ColType::Int => decode_int(bytes),
                &ColType::Date => decode_date(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (Int,date ) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<i16> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<i16>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();

            let converted = match cassandra_type {
                &ColType::Smallint => decode_smallint(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (Smallint) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };
            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<f64> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<f64>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();

            let converted = match cassandra_type {
                &ColType::Double => decode_double(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (Double) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<f32> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<f32>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();

            let converted = match cassandra_type {
                &ColType::Decimal => decode_decimal(bytes),
                &ColType::Float => decode_float(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (Float,Decimal) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<net::IpAddr> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<net::IpAddr>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();

            let converted = match cassandra_type {
                &ColType::Inet => decode_inet(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (Inet) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<Uuid> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<Uuid>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();

            let converted = match cassandra_type {
                &ColType::Uuid => decode_timeuuid(bytes),
                &ColType::Timeuuid => decode_timeuuid(bytes),
                _ => unreachable!(),
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<List> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<List>> {
        return self.get_col_spec_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();

            return match cassandra_type.col_type.id {
                // in fact, both decode_list and decode_set return Ok
                ColType::List => {
                    Ok(List::new(decode_list(bytes).unwrap(), cassandra_type.col_type.clone()))
                }
                ColType::Set => {
                    Ok(List::new(decode_set(bytes).unwrap(), cassandra_type.col_type.clone()))
                }
                _ => unreachable!(),
            };
        });
    }
}

impl IntoRustByName<Map> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<Map>> {
        return self.get_col_spec_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();

            return match cassandra_type.col_type.id {
                // in fact, both decode_map and decode_set return Ok
                ColType::Map => {
                    Ok(Map::new(decode_map(bytes).unwrap(), cassandra_type.col_type.clone()))
                }
                _ => unreachable!(),
            };
        });
    }
}

impl IntoRustByName<UDT> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<UDT>> {
        return self.get_col_spec_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();
            let cudt = match cassandra_type.col_type.value {
                Some(ColTypeOptionValue::UdtType(ref t)) => t,
                _ => unreachable!(),
            };

            return match cassandra_type.col_type.id {
                ColType::Map => Ok(UDT::new(decode_udt(bytes).unwrap(), cudt)),
                _ => unreachable!(),
            };
        });
    }
}

// TODO: add uuid
<commit_msg>Refactoring. Avoid clones 2<commit_after>use std::net;
use uuid::Uuid;

use frame::frame_result::{RowsMetadata, ColType, ColSpec, BodyResResultRows, ColTypeOptionValue};
use types::{CBytes, IntoRustByName};
use types::data_serialization_types::*;
use types::list::List;
use types::map::Map;
use types::udt::UDT;
use error::Result;
use std::io;

#[derive(Debug)]
pub struct Row {
    metadata: RowsMetadata,
    row_content: Vec<CBytes>,
}

impl Row {
    pub fn from_frame_body(body: BodyResResultRows) -> Vec<Row> {
        return body.rows_content
            .iter()
            .map(|row| {
                Row {
                    metadata: body.metadata.clone(),
                    row_content: row.clone(),
                }
            })
            .collect();
    }

    fn get_col_by_name(&self, name: &str) -> Option<(&ColType, &CBytes)> {
        let i_opt = self.metadata.col_specs.iter().position(|spec| spec.name.as_str() == name);
        if !i_opt.is_some() {
            return None;
        }
        let i = i_opt.unwrap();
        let ref data: CBytes = self.row_content[i];
        let ref cassandra_type: ColType = self.metadata.col_specs[i].col_type.id;
        return Some((cassandra_type, data));
    }

    fn get_col_spec_by_name(&self, name: &str) -> Option<(&ColSpec, &CBytes)> {
        let i_opt = self.metadata.col_specs.iter().position(|spec| spec.name.as_str() == name);
        if !i_opt.is_some() {
            return None;
        }
        let i = i_opt.unwrap();
        let ref data: CBytes = self.row_content[i];
        let ref cassandra_type: ColSpec = self.metadata.col_specs[i];
        return Some((cassandra_type, data));
    }
}

impl IntoRustByName<Vec<u8>> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<Vec<u8>>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();
            let converted = match cassandra_type {
                &ColType::Blob => decode_blob(bytes),
                _ => unreachable!(),
            };
            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<String> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<String>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();

            let converted = match cassandra_type {
                &ColType::Custom => decode_custom(bytes),
                &ColType::Ascii => decode_ascii(bytes),
                &ColType::Varchar => decode_varchar(bytes),
                // TODO: clarify when to use decode_text.
                // it's not mentioned in
                // https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L582
                // &ColType::XXX => decode_text(bytes).ok(),
                _ => unreachable!(),
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<bool> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<bool>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();

            let converted = match cassandra_type {
                &ColType::Boolean => decode_boolean(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (bool ) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<i64> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<i64>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();
            let converted = match cassandra_type {
                &ColType::Int => decode_bigint(bytes),
                &ColType::Bigint => decode_bigint(bytes),
                &ColType::Timestamp => decode_timestamp(bytes),
                &ColType::Time => decode_time(bytes),
                &ColType::Varint => decode_varint(bytes),
                &ColType::Float => decode_varint(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (Int,Bigint,Timestamp,Time,Varint,Float ) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<i32> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<i32>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();

            let converted = match cassandra_type {
                &ColType::Int => decode_int(bytes),
                &ColType::Date => decode_date(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (Int,date ) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<i16> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<i16>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();

            let converted = match cassandra_type {
                &ColType::Smallint => decode_smallint(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (Smallint) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };
            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<f64> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<f64>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();

            let converted = match cassandra_type {
                &ColType::Double => decode_double(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (Double) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<f32> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<f32>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();

            let converted = match cassandra_type {
                &ColType::Decimal => decode_decimal(bytes),
                &ColType::Float => decode_float(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (Float,Decimal) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<net::IpAddr> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<net::IpAddr>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();

            let converted = match cassandra_type {
                &ColType::Inet => decode_inet(bytes),
                _ => {
                    let io_err =
                        io::Error::new(io::ErrorKind::NotFound,
                                       format!("Unsupported type of converter. {:?} got, but
                    (Inet) is only supported.",
                                               cassandra_type));
                    Err(io_err)
                }
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<Uuid> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<Uuid>> {
        return self.get_col_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();

            let converted = match cassandra_type {
                &ColType::Uuid => decode_timeuuid(bytes),
                &ColType::Timeuuid => decode_timeuuid(bytes),
                _ => unreachable!(),
            };

            return converted.map_err(|err| err.into());
        });
    }
}

impl IntoRustByName<List> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<List>> {
        return self.get_col_spec_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();

            return match cassandra_type.col_type.id {
                // in fact, both decode_list and decode_set return Ok
                ColType::List => {
                    Ok(List::new(decode_list(bytes).unwrap(), cassandra_type.col_type.clone()))
                }
                ColType::Set => {
                    Ok(List::new(decode_set(bytes).unwrap(), cassandra_type.col_type.clone()))
                }
                _ => unreachable!(),
            };
        });
    }
}

impl IntoRustByName<Map> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<Map>> {
        return self.get_col_spec_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain().clone();

            return match cassandra_type.col_type.id {
                // in fact, both decode_map and decode_set return Ok
                ColType::Map => {
                    Ok(Map::new(decode_map(bytes).unwrap(), cassandra_type.col_type.clone()))
                }
                _ => unreachable!(),
            };
        });
    }
}

impl IntoRustByName<UDT> for Row {
    fn get_by_name(&self, name: &str) -> Option<Result<UDT>> {
        return self.get_col_spec_by_name(name).map(|(cassandra_type, cbytes)| {
            let bytes = cbytes.as_plain();
            let cudt = match cassandra_type.col_type.value {
                Some(ColTypeOptionValue::UdtType(ref t)) => t,
                _ => unreachable!(),
            };

            return match cassandra_type.col_type.id {
                ColType::Map => Ok(UDT::new(decode_udt(bytes).unwrap(), cudt)),
                _ => unreachable!(),
            };
        });
    }
}

// TODO: add uuid
<|endoftext|>


<commit_before>use std::{thread, time};
use std::fs;
use std::process::Command;

pub struct Python {
    user: String,
    subject: String,
}

pub struct Scala {
    user: String,
    subject: String,
}

pub trait Lang {
    fn new(user: String, subject: String) -> Self;
    fn run_test(&self);
}

impl Lang for Python {
    fn new(user: String, subject: String) -> Python {
        Python { user: user, subject: subject}
    }

    fn run_test(&self) {
        let from = format!("/home/{}/Code-Fight/python/{}", self.user, self.subject);
        let to = format!("/test/{}/Code-Fight/python/{}", self.user, self.subject);
        println!("from => {}, to => {}", &from, &to);
        fs::copy(&from, &to);

        let result = Command::new("nosetests")
               .arg(&to)
               .output()
               .expect("cat error to start");

        println!(&result);
        //let sleep_time = time::Duration::new(10, 0);;
        //thread::sleep(sleep_time);
    }
}

impl Lang for Scala {
    fn new(user: String, subject: String) -> Scala {
        Scala { user: user, subject: subject}
    }

    fn run_test(&self) {
        let from = format!("/home/{}/Code-Fight/scala/{}", self.user, self.subject);
        let to = format!("/test/{}/Code-Fight/scala/{}", self.user, self.subject);
        println!("from => {}, to => {}", &from, &to);

        fs::copy(&from, &to);
        //Command::new("nosetests")
        //       .arg(&to)
        //       .spawn()
        //       .expect("cat error to start");

        let sleep_time = time::Duration::new(10, 0);;
        thread::sleep(sleep_time);

    }
}
<commit_msg>fix bug<commit_after>use std::{thread, time};
use std::fs;
use std::process::Command;

pub struct Python {
    user: String,
    subject: String,
}

pub struct Scala {
    user: String,
    subject: String,
}

pub trait Lang {
    fn new(user: String, subject: String) -> Self;
    fn run_test(&self);
}

impl Lang for Python {
    fn new(user: String, subject: String) -> Python {
        Python { user: user, subject: subject}
    }

    fn run_test(&self) {
        let from = format!("/home/{}/Code-Fight/python/{}", self.user, self.subject);
        let to = format!("/test/{}/Code-Fight/python/{}", self.user, self.subject);
        println!("from => {}, to => {}", &from, &to);
        fs::copy(&from, &to);

        let result = Command::new("nosetests")
               .arg(&to)
               .output()
               .expect("cat error to start");

        println!("result: {:?}", &result);
        //let sleep_time = time::Duration::new(10, 0);;
        //thread::sleep(sleep_time);
    }
}

impl Lang for Scala {
    fn new(user: String, subject: String) -> Scala {
        Scala { user: user, subject: subject}
    }

    fn run_test(&self) {
        let from = format!("/home/{}/Code-Fight/scala/{}", self.user, self.subject);
        let to = format!("/test/{}/Code-Fight/scala/{}", self.user, self.subject);
        println!("from => {}, to => {}", &from, &to);

        fs::copy(&from, &to);
        //Command::new("nosetests")
        //       .arg(&to)
        //       .spawn()
        //       .expect("cat error to start");

        let sleep_time = time::Duration::new(10, 0);;
        thread::sleep(sleep_time);

    }
}
<|endoftext|>


<commit_before>use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::FnKind;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::mir::{BasicBlock, Body, ReadOnlyBodyAndCache, TerminatorKind, START_BLOCK};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
use std::collections::VecDeque;

crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &ReadOnlyBodyAndCache<'_, 'tcx>, def_id: DefId) {
    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();

    if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) {
        check_fn_for_unconditional_recursion(tcx, fn_like_node.kind(), body, def_id);
    }
}

fn check_fn_for_unconditional_recursion<'tcx>(
    tcx: TyCtxt<'tcx>,
    fn_kind: FnKind<'_>,
    body: &ReadOnlyBodyAndCache<'_, 'tcx>,
    def_id: DefId,
) {
    if let FnKind::Closure(_) = fn_kind {
        // closures can't recur, so they don't matter.
        return;
    }

    let self_calls = find_blocks_calling_self(tcx, &body, def_id);
    let mut results = IndexVec::from_elem_n(vec![], body.basic_blocks().len());
    let mut queue: VecDeque<_> = self_calls.iter().collect();

    while let Some(bb) = queue.pop_front() {
        if !results[bb].is_empty() {
            // Already propagated.
            continue;
        }

        let locations = if self_calls.contains(bb) {
            // `bb` *is* a self-call.
            vec![bb]
        } else {
            // If *all* successors of `bb` lead to a self-call, emit notes at all of their
            // locations.

            // Converging successors without unwind paths.
            let terminator = body[bb].terminator();
            let relevant_successors = match &terminator.kind {
                TerminatorKind::Call { destination: Some((_, dest)), .. } => {
                    Some(dest).into_iter().chain(&[])
                }
                TerminatorKind::Call { destination: None, .. } => None.into_iter().chain(&[]),
                TerminatorKind::SwitchInt { targets, .. } => None.into_iter().chain(targets),
                TerminatorKind::Goto { target }
                | TerminatorKind::Drop { target, .. }
                | TerminatorKind::DropAndReplace { target, .. }
                | TerminatorKind::Assert { target, .. } => Some(target).into_iter().chain(&[]),
                TerminatorKind::Yield { .. } | TerminatorKind::GeneratorDrop => {
                    None.into_iter().chain(&[])
                }
                TerminatorKind::FalseEdges { real_target, .. }
                | TerminatorKind::FalseUnwind { real_target, .. } => {
                    Some(real_target).into_iter().chain(&[])
                }
                TerminatorKind::Resume
                | TerminatorKind::Abort
                | TerminatorKind::Return
                | TerminatorKind::Unreachable => {
                    unreachable!("unexpected terminator {:?}", terminator.kind)
                }
            };

            let all_are_self_calls =
                relevant_successors.clone().all(|&succ| !results[succ].is_empty());

            if all_are_self_calls {
                relevant_successors.flat_map(|&succ| results[succ].iter().copied()).collect()
            } else {
                vec![]
            }
        };

        if !locations.is_empty() {
            // This is a newly confirmed-to-always-reach-self-call block.
            results[bb] = locations;

            // Propagate backwards through the CFG.
            debug!("propagate loc={:?} in {:?} -> {:?}", results[bb], bb, body.predecessors()[bb]);
            queue.extend(body.predecessors()[bb].iter().copied());
        }
    }

    debug!("unconditional recursion results: {:?}", results);

    let self_call_locations = &mut results[START_BLOCK];
    self_call_locations.sort();
    self_call_locations.dedup();

    if !self_call_locations.is_empty() {
        let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
        let sp = tcx.sess.source_map().guess_head_span(tcx.hir().span(hir_id));
        tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| {
            let mut db = lint.build("function cannot return without recursing");
            db.span_label(sp, "cannot return without recursing");
            // offer some help to the programmer.
            for bb in self_call_locations {
                let span = body.basic_blocks()[*bb].terminator().source_info.span;
                db.span_label(span, "recursive call site");
            }
            db.help("a `loop` may express intention better if this is on purpose");
            db.emit();
        });
    }
}

/// Finds blocks with `Call` terminators that would end up calling back into the same method.
fn find_blocks_calling_self<'tcx>(
    tcx: TyCtxt<'tcx>,
    body: &Body<'tcx>,
    def_id: DefId,
) -> BitSet<BasicBlock> {
    let param_env = tcx.param_env(def_id);
    let trait_substs_count = match tcx.opt_associated_item(def_id) {
        Some(AssocItem { container: AssocItemContainer::TraitContainer(trait_def_id), .. }) => {
            tcx.generics_of(trait_def_id).count()
        }
        _ => 0,
    };
    let caller_substs = &InternalSubsts::identity_for_item(tcx, def_id)[..trait_substs_count];

    let mut self_calls = BitSet::new_empty(body.basic_blocks().len());

    for (bb, data) in body.basic_blocks().iter_enumerated() {
        if let TerminatorKind::Call { func, .. } = &data.terminator().kind {
            let func_ty = func.ty(body, tcx);

            if let ty::FnDef(fn_def_id, substs) = func_ty.kind {
                let (call_fn_id, call_substs) =
                    if let Some(instance) = Instance::resolve(tcx, param_env, fn_def_id, substs) {
                        (instance.def_id(), instance.substs)
                    } else {
                        (fn_def_id, substs)
                    };

                // FIXME(#57965): Make this work across function boundaries

                let is_self_call =
                    call_fn_id == def_id && &call_substs[..caller_substs.len()] == caller_substs;

                if is_self_call {
                    self_calls.insert(bb);
                }
            }
        }
    }

    self_calls
}
<commit_msg>Move closure check upwards<commit_after>use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::FnKind;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::mir::{BasicBlock, Body, ReadOnlyBodyAndCache, TerminatorKind, START_BLOCK};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
use std::collections::VecDeque;

crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &ReadOnlyBodyAndCache<'_, 'tcx>, def_id: DefId) {
    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();

    if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) {
        if let FnKind::Closure(_) = fn_like_node.kind() {
            // closures can't recur, so they don't matter.
            return;
        }

        check_fn_for_unconditional_recursion(tcx, body, def_id);
    }
}

fn check_fn_for_unconditional_recursion<'tcx>(
    tcx: TyCtxt<'tcx>,
    body: &ReadOnlyBodyAndCache<'_, 'tcx>,
    def_id: DefId,
) {
    let self_calls = find_blocks_calling_self(tcx, &body, def_id);
    let mut results = IndexVec::from_elem_n(vec![], body.basic_blocks().len());
    let mut queue: VecDeque<_> = self_calls.iter().collect();

    while let Some(bb) = queue.pop_front() {
        if !results[bb].is_empty() {
            // Already propagated.
            continue;
        }

        let locations = if self_calls.contains(bb) {
            // `bb` *is* a self-call.
            vec![bb]
        } else {
            // If *all* successors of `bb` lead to a self-call, emit notes at all of their
            // locations.

            // Converging successors without unwind paths.
            let terminator = body[bb].terminator();
            let relevant_successors = match &terminator.kind {
                TerminatorKind::Call { destination: Some((_, dest)), .. } => {
                    Some(dest).into_iter().chain(&[])
                }
                TerminatorKind::Call { destination: None, .. } => None.into_iter().chain(&[]),
                TerminatorKind::SwitchInt { targets, .. } => None.into_iter().chain(targets),
                TerminatorKind::Goto { target }
                | TerminatorKind::Drop { target, .. }
                | TerminatorKind::DropAndReplace { target, .. }
                | TerminatorKind::Assert { target, .. } => Some(target).into_iter().chain(&[]),
                TerminatorKind::Yield { .. } | TerminatorKind::GeneratorDrop => {
                    None.into_iter().chain(&[])
                }
                TerminatorKind::FalseEdges { real_target, .. }
                | TerminatorKind::FalseUnwind { real_target, .. } => {
                    Some(real_target).into_iter().chain(&[])
                }
                TerminatorKind::Resume
                | TerminatorKind::Abort
                | TerminatorKind::Return
                | TerminatorKind::Unreachable => {
                    unreachable!("unexpected terminator {:?}", terminator.kind)
                }
            };

            let all_are_self_calls =
                relevant_successors.clone().all(|&succ| !results[succ].is_empty());

            if all_are_self_calls {
                relevant_successors.flat_map(|&succ| results[succ].iter().copied()).collect()
            } else {
                vec![]
            }
        };

        if !locations.is_empty() {
            // This is a newly confirmed-to-always-reach-self-call block.
            results[bb] = locations;

            // Propagate backwards through the CFG.
            debug!("propagate loc={:?} in {:?} -> {:?}", results[bb], bb, body.predecessors()[bb]);
            queue.extend(body.predecessors()[bb].iter().copied());
        }
    }

    debug!("unconditional recursion results: {:?}", results);

    let self_call_locations = &mut results[START_BLOCK];
    self_call_locations.sort();
    self_call_locations.dedup();

    if !self_call_locations.is_empty() {
        let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
        let sp = tcx.sess.source_map().guess_head_span(tcx.hir().span(hir_id));
        tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| {
            let mut db = lint.build("function cannot return without recursing");
            db.span_label(sp, "cannot return without recursing");
            // offer some help to the programmer.
            for bb in self_call_locations {
                let span = body.basic_blocks()[*bb].terminator().source_info.span;
                db.span_label(span, "recursive call site");
            }
            db.help("a `loop` may express intention better if this is on purpose");
            db.emit();
        });
    }
}

/// Finds blocks with `Call` terminators that would end up calling back into the same method.
fn find_blocks_calling_self<'tcx>(
    tcx: TyCtxt<'tcx>,
    body: &Body<'tcx>,
    def_id: DefId,
) -> BitSet<BasicBlock> {
    let param_env = tcx.param_env(def_id);
    let trait_substs_count = match tcx.opt_associated_item(def_id) {
        Some(AssocItem { container: AssocItemContainer::TraitContainer(trait_def_id), .. }) => {
            tcx.generics_of(trait_def_id).count()
        }
        _ => 0,
    };
    let caller_substs = &InternalSubsts::identity_for_item(tcx, def_id)[..trait_substs_count];

    let mut self_calls = BitSet::new_empty(body.basic_blocks().len());

    for (bb, data) in body.basic_blocks().iter_enumerated() {
        if let TerminatorKind::Call { func, .. } = &data.terminator().kind {
            let func_ty = func.ty(body, tcx);

            if let ty::FnDef(fn_def_id, substs) = func_ty.kind {
                let (call_fn_id, call_substs) =
                    if let Some(instance) = Instance::resolve(tcx, param_env, fn_def_id, substs) {
                        (instance.def_id(), instance.substs)
                    } else {
                        (fn_def_id, substs)
                    };

                // FIXME(#57965): Make this work across function boundaries

                let is_self_call =
                    call_fn_id == def_id && &call_substs[..caller_substs.len()] == caller_substs;

                if is_self_call {
                    self_calls.insert(bb);
                }
            }
        }
    }

    self_calls
}
<|endoftext|>


<commit_before>
pub( crate ) mod private
{
  use crate::command::*;
  use crate::instruction::*;
  use wtools::meta::*;
  use wtools::error::*;
  use wtools::former::Former;

  ///
  /// Commands aggregator.
  ///

  /*
     Dmytro : owned types are used because Former does not work with combination of links and
     containers
   */

  #[ derive( Debug, PartialEq ) ]
  #[ derive( Former ) ]
  #[ allow( missing_docs ) ]
  pub struct CommandsAggregator
  {
    pub base_path : Option<std::path::PathBuf>,
    #[ default( "".to_string() ) ]
    pub command_prefix : String,
    #[ default( vec![ ".".to_string(), " ".to_string() ] ) ]
    pub delimeter : Vec< String >,
    #[ default( ";".to_string() ) ]
    pub command_explicit_delimeter : String,
    #[ default( " ".to_string() ) ]
    pub command_implicit_delimeter : String,
    #[ default( true ) ]
    pub commands_explicit_delimiting : bool,
    #[ default( false ) ]
    pub commands_implicit_delimiting : bool,
    #[ default( false ) ]
    pub properties_map_parsing : bool,
    #[ default( true ) ]
    pub several_values : bool,
    #[ default( true ) ]
    pub with_help : bool,
    #[ default( true ) ]
    pub changing_exit_code : bool,
    // logger : Option<Logger>, /* qqq : implement */
    pub commands : std::collections::HashMap< String, Command >,
    // pub vocabulary : Option<Logger>, /* qqq : implement */
  }

  impl CommandsAggregator
  {
    /// Perform instructions queue as single program.
    pub fn program_perform( &self, _program : &str ) -> Result< (), BasicError >
    {
      unimplemented!( "not implemented" );
      // let parsed = program_parse( program );
    }

    /// Perform instruction.
    pub fn instruction_perform( &self, instruction : &str ) -> Result< (), BasicError >
    {
      let parsed : Instruction = instruction_parse()
      .instruction( instruction )
      .perform();

      let result = match self.command_resolve( &parsed )
      {
        Some( command ) =>
        {
          command.perform( &parsed )
        },
        None =>
        {
          if self.with_help
          {
            self.print_help();
          }
          if self.changing_exit_code
          {
            std::process::exit( 1 );
          }
          Ok( () )
        },
      };

      result
    }

    /// Print help information.
    fn print_help( &self )
    {
      println!( "Illformed command" );
      for ( command_name, command_descriptor ) in self.commands.iter()
      {
        println!( "{} - {}", command_name, command_descriptor.hint );
      }
    }

    /// Find command in dictionary.
    fn command_resolve( &self, instruction : &Instruction ) -> Option<&Command>
    {
      self.commands.get( &instruction.command_name )
    }
  }

  //

  ///
  /// Get instruction parser builder.
  ///

  pub fn commands_aggregator() -> CommandsAggregatorFormer
  {
    CommandsAggregator::former()
  }

}

/// Protected namespace of the module.
pub mod protected
{
  pub use super::private::CommandsAggregator;
  pub use super::private::commands_aggregator;
}

pub use protected::*;

/// Exposed namespace of the module.
pub mod exposed
{
  pub use super::prelude::*;
}

/// Namespace of the module to include with `use module::*`.
pub mod prelude
{
  pub use super::private::CommandsAggregator;
  pub use super::private::commands_aggregator;
}

<commit_msg>Extend routine `instruction_perform`, provide options to parse routine<commit_after>
pub( crate ) mod private
{
  use crate::command::*;
  use crate::instruction::*;
  use wtools::meta::*;
  use wtools::error::*;
  use wtools::former::Former;

  ///
  /// Commands aggregator.
  ///

  /*
     Dmytro : owned types are used because Former does not work with combination of links and
     containers
   */

  #[ derive( Debug, PartialEq ) ]
  #[ derive( Former ) ]
  #[ allow( missing_docs ) ]
  pub struct CommandsAggregator
  {
    pub base_path : Option<std::path::PathBuf>,
    #[ default( "".to_string() ) ]
    pub command_prefix : String,
    #[ default( vec![ ".".to_string(), " ".to_string() ] ) ]
    pub delimeter : Vec< String >,
    #[ default( ";".to_string() ) ]
    pub command_explicit_delimeter : String,
    #[ default( " ".to_string() ) ]
    pub command_implicit_delimeter : String,
    #[ default( true ) ]
    pub commands_explicit_delimiting : bool,
    #[ default( false ) ]
    pub commands_implicit_delimiting : bool,
    #[ default( false ) ]
    pub properties_map_parsing : bool,
    #[ default( true ) ]
    pub several_values : bool,
    #[ default( true ) ]
    pub with_help : bool,
    #[ default( true ) ]
    pub changing_exit_code : bool,
    // logger : Option<Logger>, /* qqq : implement */
    pub commands : std::collections::HashMap< String, Command >,
    // pub vocabulary : Option<vocabulary>, /* qqq : implement */
  }

  impl CommandsAggregator
  {
    /// Perform instructions queue as single program.
    pub fn program_perform( &self, _program : &str ) -> Result< (), BasicError >
    {
      unimplemented!( "not implemented" );
      // let parsed = program_parse( program );
    }

    /// Perform instruction.
    pub fn instruction_perform( &self, instruction : impl AsRef< str > ) -> Result< (), BasicError >
    {
      let parsed : Instruction = instruction_parse()
      .instruction( instruction.as_ref() )
      .several_values( self.several_values )
      .properties_map_parsing( self.properties_map_parsing )
      .quoting( true )
      .unquoting( true )
      .perform();

      let result = match self.command_resolve( &parsed )
      {
        Some( command ) =>
        {
          command.perform( &parsed )
        },
        None =>
        {
          if self.with_help
          {
            self.print_help();
          }
          if self.changing_exit_code
          {
            std::process::exit( 1 );
          }
          Ok( () )
        },
      };

      result
    }

    /// Print help information.
    fn print_help( &self )
    {
      println!( "Illformed command" );
      for ( command_name, command_descriptor ) in self.commands.iter()
      {
        println!( "{} - {}", command_name, command_descriptor.hint );
      }
    }

    /// Find command in dictionary.
    fn command_resolve( &self, instruction : &Instruction ) -> Option<&Command>
    {
      self.commands.get( &instruction.command_name )
    }
  }

  //

  ///
  /// Get instruction parser builder.
  ///

  pub fn commands_aggregator() -> CommandsAggregatorFormer
  {
    CommandsAggregator::former()
  }

}

/// Protected namespace of the module.
pub mod protected
{
  pub use super::private::CommandsAggregator;
  pub use super::private::commands_aggregator;
}

pub use protected::*;

/// Exposed namespace of the module.
pub mod exposed
{
  pub use super::prelude::*;
}

/// Namespace of the module to include with `use module::*`.
pub mod prelude
{
  pub use super::private::CommandsAggregator;
  pub use super::private::commands_aggregator;
}

<|endoftext|>