<commit_before>use time::precise_time_ns;

use std::sync::mpsc::{sync_channel, SyncSender};
use std::thread::Thread;

use search;

use super::types::{Cmd, Response, ID_DATA};
use super::state::{State, Mode};
use self::time_start::time_start;

mod go_param;
mod time_start;
mod pos;

pub fn process(state: &mut State,
               cmd: Cmd,
               output: &SyncSender<Response>,
               cmd_tx: &SyncSender<Cmd>) {
    match cmd {
        Cmd::Debug(val) => {
            // TODO set debug
            debug!("debug is now {:?}", val);
            state.search_tx.as_ref().map(|tx| {
                tx.send(search::Cmd::Stop)
                  .ok().expect("state.search_tx closed") } );
        },
        Cmd::IsReady => {
            output.send(Response::ReadyOk)
                  .ok().expect("output channel closed");
        },
        Cmd::Register(..) => {
            // TODO register
            unimplemented!();
        },
        cmd => {
            match state.mode {
                Mode::Init => {
                    if cmd == Cmd::Uci {
                        for x in ID_DATA.iter() {
                            output.send(Response::Id(x.clone()))
                                  .ok().expect("output channel closed");
                        }
                        // TODO print option list
                        output.send(Response::UciOk)
                              .ok().expect("output channel closed");
                        state.mode = Mode::Wait;
                    }
                },
                Mode::Wait => {
                    match cmd {
                        Cmd::SetOption(..) => {
                            // TODO maybe initialize
                            // TODO set options
                            unimplemented!();
                        },
                        Cmd::UciNewGame => {
                            *state = State {
                                mode: Mode::NewGame,
                                ucinewgame_support: true,
                                ..State::new()
                            };
                        },
                        Cmd::SetupPosition(pos, from_to_vec) => {
                            if state.ucinewgame_support {
                                pos::setup_same(&mut state.search_state, pos, from_to_vec);
                                state.mode = Mode::Ready;
                            } else {
                                process(state, Cmd::UciNewGame, output, cmd_tx);
                                state.ucinewgame_support = false;
                                process(state, Cmd::SetupPosition(pos, from_to_vec),
                                        output, cmd_tx);
                            }
                        },
                        _ => {},
                    }
                },
                Mode::NewGame => {
                    if let Cmd::SetupPosition(pos, from_to_vec) = cmd {
                        pos::setup_new(&mut state.search_state, pos, from_to_vec);
                        state.mode = Mode::Ready;
                    }
                },
                Mode::Ready => {
                    assert!(state.search_state.is_some());
                    if let Cmd::Go(param) = cmd {
                        go_param::setup(state, param);
                        let (search_tx, search_rx) = sync_channel::<search::Cmd>(0);
                        let search_state = state.search_state.as_ref().unwrap().clone();
                        let output = output.clone();
                        let temp = Thread::scoped(move ||
                                                  search::start(search_state, search_rx, output));

                        state.search_tx = Some(search_tx);
                        state.search_guard = Some(temp);

                        if !state.search_state.as_ref().unwrap().param.ponder {
                            time_start(state, cmd_tx.clone());
                        }

                        state.mode = Mode::Search;
                    }
                },
                Mode::Search => {
                    assert!(state.search_state.is_some());
                    assert!(state.search_guard.is_some());
                    assert!(state.search_tx.is_some());
                    match cmd {
                        Cmd::PonderHit => {
                            if !state.search_state.as_ref().unwrap().param.ponder {
                                return;
                            }
                            state.search_tx.as_ref().unwrap().send(search::Cmd::PonderHit)
                                 .ok().expect("state.search_tx was closed");
                            state.search_state.as_mut().unwrap().param.ponder = false;
                            state.start_move_time = Some(precise_time_ns());
                            time_start(state, cmd_tx.clone());
                        },
                        Cmd::Stop => {
                            state.search_tx.as_ref().unwrap().send(search::Cmd::Stop)
                                 .ok().expect("state.search_tx was closed");
                            state.search_guard.take().unwrap().join()
                                 .ok().expect("search thread is panicking");
                            state.search_tx = None;
                            state.start_search_time = None;
                            state.start_move_time = None;
                            state.time_data = None;
                            if let Some(time_kill_tx) = state.time_kill_tx.take() {
                                let _ = time_kill_tx.send(());
                            }
                            state.mode = Mode::Wait;
                        },
                        _ => {},
                    }
                },
            }
        },
    }
}
<commit_msg>Send the right command for debug<commit_after>use time::precise_time_ns;

use std::sync::mpsc::{sync_channel, SyncSender};
use std::thread::Thread;

use search;

use super::types::{Cmd, Response, ID_DATA};
use super::state::{State, Mode};
use self::time_start::time_start;

mod go_param;
mod time_start;
mod pos;

pub fn process(state: &mut State,
               cmd: Cmd,
               output: &SyncSender<Response>,
               cmd_tx: &SyncSender<Cmd>) {
    match cmd {
        Cmd::Debug(val) => {
            // TODO set debug
            debug!("debug is now {:?}", val);
            state.search_tx.as_ref().map(|tx| {
                tx.send(search::Cmd::SetDebug(val))
                  .ok().expect("state.search_tx closed") } );
        },
        Cmd::IsReady => {
            output.send(Response::ReadyOk)
                  .ok().expect("output channel closed");
        },
        Cmd::Register(..) => {
            // TODO register
            unimplemented!();
        },
        cmd => {
            match state.mode {
                Mode::Init => {
                    if cmd == Cmd::Uci {
                        for x in ID_DATA.iter() {
                            output.send(Response::Id(x.clone()))
                                  .ok().expect("output channel closed");
                        }
                        // TODO print option list
                        output.send(Response::UciOk)
                              .ok().expect("output channel closed");
                        state.mode = Mode::Wait;
                    }
                },
                Mode::Wait => {
                    match cmd {
                        Cmd::SetOption(..) => {
                            // TODO maybe initialize
                            // TODO set options
                            unimplemented!();
                        },
                        Cmd::UciNewGame => {
                            *state = State {
                                mode: Mode::NewGame,
                                ucinewgame_support: true,
                                ..State::new()
                            };
                        },
                        Cmd::SetupPosition(pos, from_to_vec) => {
                            if state.ucinewgame_support {
                                pos::setup_same(&mut state.search_state, pos, from_to_vec);
                                state.mode = Mode::Ready;
                            } else {
                                process(state, Cmd::UciNewGame, output, cmd_tx);
                                state.ucinewgame_support = false;
                                process(state, Cmd::SetupPosition(pos, from_to_vec),
                                        output, cmd_tx);
                            }
                        },
                        _ => {},
                    }
                },
                Mode::NewGame => {
                    if let Cmd::SetupPosition(pos, from_to_vec) = cmd {
                        pos::setup_new(&mut state.search_state, pos, from_to_vec);
                        state.mode = Mode::Ready;
                    }
                },
                Mode::Ready => {
                    assert!(state.search_state.is_some());
                    if let Cmd::Go(param) = cmd {
                        go_param::setup(state, param);
                        let (search_tx, search_rx) = sync_channel::<search::Cmd>(0);
                        let search_state = state.search_state.as_ref().unwrap().clone();
                        let output = output.clone();
                        let temp = Thread::scoped(move ||
                                                  search::start(search_state, search_rx, output));

                        state.search_tx = Some(search_tx);
                        state.search_guard = Some(temp);

                        if !state.search_state.as_ref().unwrap().param.ponder {
                            time_start(state, cmd_tx.clone());
                        }

                        state.mode = Mode::Search;
                    }
                },
                Mode::Search => {
                    assert!(state.search_state.is_some());
                    assert!(state.search_guard.is_some());
                    assert!(state.search_tx.is_some());
                    match cmd {
                        Cmd::PonderHit => {
                            if !state.search_state.as_ref().unwrap().param.ponder {
                                return;
                            }
                            state.search_tx.as_ref().unwrap().send(search::Cmd::PonderHit)
                                 .ok().expect("state.search_tx was closed");
                            state.search_state.as_mut().unwrap().param.ponder = false;
                            state.start_move_time = Some(precise_time_ns());
                            time_start(state, cmd_tx.clone());
                        },
                        Cmd::Stop => {
                            state.search_tx.as_ref().unwrap().send(search::Cmd::Stop)
                                 .ok().expect("state.search_tx was closed");
                            state.search_guard.take().unwrap().join()
                                 .ok().expect("search thread is panicking");
                            state.search_tx = None;
                            state.start_search_time = None;
                            state.start_move_time = None;
                            state.time_data = None;
                            if let Some(time_kill_tx) = state.time_kill_tx.take() {
                                let _ = time_kill_tx.send(());
                            }
                            state.mode = Mode::Wait;
                        },
                        _ => {},
                    }
                },
            }
        },
    }
}
<|endoftext|>


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

use std::ops::BitOr;

/// Describes how a buffer is going to be used. This is **not** just an optimization.
///
/// If you try to use a buffer in a way that you didn't declare, a panic will happen.
///
/// Some methods are provided to build `BufferUsage` structs for some common situations. However
/// there is no restriction in the combination of BufferUsages that can be enabled.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct BufferUsage {
    pub transfer_source: bool,
    pub transfer_destination: bool,
    pub uniform_texel_buffer: bool,
    pub storage_texel_buffer: bool,
    pub uniform_buffer: bool,
    pub storage_buffer: bool,
    pub index_buffer: bool,
    pub vertex_buffer: bool,
    pub indirect_buffer: bool,
    /// Requires the `buffer_device_address` feature. If that feature is not enabled, this will
    /// be silently ignored.
    pub device_address: bool,
}

impl BufferUsage {
    /// Builds a `BufferUsage` with all values set to false.
    #[inline]
    pub const fn none() -> BufferUsage {
        BufferUsage {
            transfer_source: false,
            transfer_destination: false,
            uniform_texel_buffer: false,
            storage_texel_buffer: false,
            uniform_buffer: false,
            storage_buffer: false,
            index_buffer: false,
            vertex_buffer: false,
            indirect_buffer: false,
            device_address: false,
        }
    }

    /// Builds a `BufferUsage` with all values set to true. Can be used for quick prototyping.
    #[inline]
    pub const fn all() -> BufferUsage {
        BufferUsage {
            transfer_source: true,
            transfer_destination: true,
            uniform_texel_buffer: true,
            storage_texel_buffer: true,
            uniform_buffer: true,
            storage_buffer: true,
            index_buffer: true,
            vertex_buffer: true,
            indirect_buffer: true,
            device_address: true,
        }
    }

    /// Builds a `BufferUsage` with `transfer_source` set to true and the rest to false.
    #[inline]
    pub const fn transfer_source() -> BufferUsage {
        BufferUsage {
            transfer_source: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `transfer_destination` set to true and the rest to false.
    #[inline]
    pub const fn transfer_destination() -> BufferUsage {
        BufferUsage {
            transfer_destination: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `vertex_buffer` set to true and the rest to false.
    #[inline]
    pub const fn vertex_buffer() -> BufferUsage {
        BufferUsage {
            vertex_buffer: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `vertex_buffer` and `transfer_destination` set to true and the rest
    /// to false.
    #[inline]
    pub const fn vertex_buffer_transfer_destination() -> BufferUsage {
        BufferUsage {
            vertex_buffer: true,
            transfer_destination: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `index_buffer` set to true and the rest to false.
    #[inline]
    pub const fn index_buffer() -> BufferUsage {
        BufferUsage {
            index_buffer: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `index_buffer` and `transfer_destination` set to true and the rest to false.
    #[inline]
    pub const fn index_buffer_transfer_destination() -> BufferUsage {
        BufferUsage {
            index_buffer: true,
            transfer_destination: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `uniform_buffer` set to true and the rest to false.
    #[inline]
    pub const fn uniform_buffer() -> BufferUsage {
        BufferUsage {
            uniform_buffer: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `uniform_buffer` and `transfer_destination` set to true and the rest
    /// to false.
    #[inline]
    pub const fn uniform_buffer_transfer_destination() -> BufferUsage {
        BufferUsage {
            uniform_buffer: true,
            transfer_destination: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `indirect_buffer` set to true and the rest to false.
    #[inline]
    pub const fn indirect_buffer() -> BufferUsage {
        BufferUsage {
            indirect_buffer: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `indirect_buffer` and `transfer_destination` set to true and the rest
    /// to false.
    #[inline]
    pub const fn indirect_buffer_transfer_destination() -> BufferUsage {
        BufferUsage {
            indirect_buffer: true,
            transfer_destination: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `device_address` set to true and the rest to false.
    #[inline]
    pub const fn device_address() -> BufferUsage {
        BufferUsage {
            device_address: true,
            ..BufferUsage::none()
        }
    }
}

impl From<BufferUsage> for ash::vk::BufferUsageFlags {
    fn from(val: BufferUsage) -> Self {
        let mut result = ash::vk::BufferUsageFlags::empty();
        if val.transfer_source {
            result |= ash::vk::BufferUsageFlags::TRANSFER_SRC;
        }
        if val.transfer_destination {
            result |= ash::vk::BufferUsageFlags::TRANSFER_DST;
        }
        if val.uniform_texel_buffer {
            result |= ash::vk::BufferUsageFlags::UNIFORM_TEXEL_BUFFER;
        }
        if val.storage_texel_buffer {
            result |= ash::vk::BufferUsageFlags::STORAGE_TEXEL_BUFFER;
        }
        if val.uniform_buffer {
            result |= ash::vk::BufferUsageFlags::UNIFORM_BUFFER;
        }
        if val.storage_buffer {
            result |= ash::vk::BufferUsageFlags::STORAGE_BUFFER;
        }
        if val.index_buffer {
            result |= ash::vk::BufferUsageFlags::INDEX_BUFFER;
        }
        if val.vertex_buffer {
            result |= ash::vk::BufferUsageFlags::VERTEX_BUFFER;
        }
        if val.indirect_buffer {
            result |= ash::vk::BufferUsageFlags::INDIRECT_BUFFER;
        }
        if val.device_address {
            result |= ash::vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS;
        }
        result
    }
}

impl BitOr for BufferUsage {
    type Output = Self;

    #[inline]
    fn bitor(self, rhs: Self) -> Self {
        BufferUsage {
            transfer_source: self.transfer_source || rhs.transfer_source,
            transfer_destination: self.transfer_destination || rhs.transfer_destination,
            uniform_texel_buffer: self.uniform_texel_buffer || rhs.uniform_texel_buffer,
            storage_texel_buffer: self.storage_texel_buffer || rhs.storage_texel_buffer,
            uniform_buffer: self.uniform_buffer || rhs.uniform_buffer,
            storage_buffer: self.storage_buffer || rhs.storage_buffer,
            index_buffer: self.index_buffer || rhs.index_buffer,
            vertex_buffer: self.vertex_buffer || rhs.vertex_buffer,
            indirect_buffer: self.indirect_buffer || rhs.indirect_buffer,
            device_address: self.device_address || rhs.device_address,
        }
    }
}
<commit_msg>add: missing method `vulkano::buffer::BufferUsage::storage_buffer()` (#1676)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::ops::BitOr;

/// Describes how a buffer is going to be used. This is **not** just an optimization.
///
/// If you try to use a buffer in a way that you didn't declare, a panic will happen.
///
/// Some methods are provided to build `BufferUsage` structs for some common situations. However
/// there is no restriction in the combination of BufferUsages that can be enabled.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct BufferUsage {
    pub transfer_source: bool,
    pub transfer_destination: bool,
    pub uniform_texel_buffer: bool,
    pub storage_texel_buffer: bool,
    pub uniform_buffer: bool,
    pub storage_buffer: bool,
    pub index_buffer: bool,
    pub vertex_buffer: bool,
    pub indirect_buffer: bool,
    /// Requires the `buffer_device_address` feature. If that feature is not enabled, this will
    /// be silently ignored.
    pub device_address: bool,
}

impl BufferUsage {
    /// Builds a `BufferUsage` with all values set to false.
    #[inline]
    pub const fn none() -> BufferUsage {
        BufferUsage {
            transfer_source: false,
            transfer_destination: false,
            uniform_texel_buffer: false,
            storage_texel_buffer: false,
            uniform_buffer: false,
            storage_buffer: false,
            index_buffer: false,
            vertex_buffer: false,
            indirect_buffer: false,
            device_address: false,
        }
    }

    /// Builds a `BufferUsage` with all values set to true. Can be used for quick prototyping.
    #[inline]
    pub const fn all() -> BufferUsage {
        BufferUsage {
            transfer_source: true,
            transfer_destination: true,
            uniform_texel_buffer: true,
            storage_texel_buffer: true,
            uniform_buffer: true,
            storage_buffer: true,
            index_buffer: true,
            vertex_buffer: true,
            indirect_buffer: true,
            device_address: true,
        }
    }

    /// Builds a `BufferUsage` with `transfer_source` set to true and the rest to false.
    #[inline]
    pub const fn transfer_source() -> BufferUsage {
        BufferUsage {
            transfer_source: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `transfer_destination` set to true and the rest to false.
    #[inline]
    pub const fn transfer_destination() -> BufferUsage {
        BufferUsage {
            transfer_destination: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `vertex_buffer` set to true and the rest to false.
    #[inline]
    pub const fn vertex_buffer() -> BufferUsage {
        BufferUsage {
            vertex_buffer: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `vertex_buffer` and `transfer_destination` set to true and the rest
    /// to false.
    #[inline]
    pub const fn vertex_buffer_transfer_destination() -> BufferUsage {
        BufferUsage {
            vertex_buffer: true,
            transfer_destination: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `index_buffer` set to true and the rest to false.
    #[inline]
    pub const fn index_buffer() -> BufferUsage {
        BufferUsage {
            index_buffer: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `index_buffer` and `transfer_destination` set to true and the rest to false.
    #[inline]
    pub const fn index_buffer_transfer_destination() -> BufferUsage {
        BufferUsage {
            index_buffer: true,
            transfer_destination: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `uniform_buffer` set to true and the rest to false.
    #[inline]
    pub const fn uniform_buffer() -> BufferUsage {
        BufferUsage {
            uniform_buffer: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with only `storage_buffer` set, while rest are not
    #[inline]
    pub const fn storage_buffer() -> BufferUsage {
        BufferUsage {
            storage_buffer: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `uniform_buffer` and `transfer_destination` set to true and the rest
    /// to false.
    #[inline]
    pub const fn uniform_buffer_transfer_destination() -> BufferUsage {
        BufferUsage {
            uniform_buffer: true,
            transfer_destination: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `indirect_buffer` set to true and the rest to false.
    #[inline]
    pub const fn indirect_buffer() -> BufferUsage {
        BufferUsage {
            indirect_buffer: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `indirect_buffer` and `transfer_destination` set to true and the rest
    /// to false.
    #[inline]
    pub const fn indirect_buffer_transfer_destination() -> BufferUsage {
        BufferUsage {
            indirect_buffer: true,
            transfer_destination: true,
            ..BufferUsage::none()
        }
    }

    /// Builds a `BufferUsage` with `device_address` set to true and the rest to false.
    #[inline]
    pub const fn device_address() -> BufferUsage {
        BufferUsage {
            device_address: true,
            ..BufferUsage::none()
        }
    }
}

impl From<BufferUsage> for ash::vk::BufferUsageFlags {
    fn from(val: BufferUsage) -> Self {
        let mut result = ash::vk::BufferUsageFlags::empty();
        if val.transfer_source {
            result |= ash::vk::BufferUsageFlags::TRANSFER_SRC;
        }
        if val.transfer_destination {
            result |= ash::vk::BufferUsageFlags::TRANSFER_DST;
        }
        if val.uniform_texel_buffer {
            result |= ash::vk::BufferUsageFlags::UNIFORM_TEXEL_BUFFER;
        }
        if val.storage_texel_buffer {
            result |= ash::vk::BufferUsageFlags::STORAGE_TEXEL_BUFFER;
        }
        if val.uniform_buffer {
            result |= ash::vk::BufferUsageFlags::UNIFORM_BUFFER;
        }
        if val.storage_buffer {
            result |= ash::vk::BufferUsageFlags::STORAGE_BUFFER;
        }
        if val.index_buffer {
            result |= ash::vk::BufferUsageFlags::INDEX_BUFFER;
        }
        if val.vertex_buffer {
            result |= ash::vk::BufferUsageFlags::VERTEX_BUFFER;
        }
        if val.indirect_buffer {
            result |= ash::vk::BufferUsageFlags::INDIRECT_BUFFER;
        }
        if val.device_address {
            result |= ash::vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS;
        }
        result
    }
}

impl BitOr for BufferUsage {
    type Output = Self;

    #[inline]
    fn bitor(self, rhs: Self) -> Self {
        BufferUsage {
            transfer_source: self.transfer_source || rhs.transfer_source,
            transfer_destination: self.transfer_destination || rhs.transfer_destination,
            uniform_texel_buffer: self.uniform_texel_buffer || rhs.uniform_texel_buffer,
            storage_texel_buffer: self.storage_texel_buffer || rhs.storage_texel_buffer,
            uniform_buffer: self.uniform_buffer || rhs.uniform_buffer,
            storage_buffer: self.storage_buffer || rhs.storage_buffer,
            index_buffer: self.index_buffer || rhs.index_buffer,
            vertex_buffer: self.vertex_buffer || rhs.vertex_buffer,
            indirect_buffer: self.indirect_buffer || rhs.indirect_buffer,
            device_address: self.device_address || rhs.device_address,
        }
    }
}
<|endoftext|>


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

use std::any::Any;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;

use buffer::Buffer;
use device::Queue;
use format::ClearValue;
use format::Format;
use image::Dimensions;
use image::ImageDimensions;
use image::sys::Layout;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use sampler::Sampler;
use sync::AccessFlagBits;
use sync::PipelineStages;
use sync::Fence;
use sync::Semaphore;

use VulkanObject;

/// Trait for types that represent images.
// TODO: remove 'static + Send + Sync
pub unsafe trait Image: 'static + Send + Sync {
    /// Returns the inner unsafe image object used by this image.
    fn inner(&self) -> &UnsafeImage;

    /// Returns the format of this image.
    #[inline]
    fn format(&self) -> Format {
        self.inner().format()
    }

    /// Returns the number of samples of this image.
    #[inline]
    fn samples(&self) -> u32 {
        self.inner().samples()
    }

    /// Returns the dimensions of the image.
    #[inline]
    fn dimensions(&self) -> ImageDimensions {
        self.inner().dimensions()
    }

    /// Returns true if the image can be used as a source for blits.
    #[inline]
    fn supports_blit_source(&self) -> bool {
        self.inner().supports_blit_source()
    }

    /// Returns true if the image can be used as a destination for blits.
    #[inline]
    fn supports_blit_destination(&self) -> bool {
        self.inner().supports_blit_destination()
    }
}

/// Extension trait for `Image`. Types that implement this can be used in a `StdCommandBuffer`.
///
/// Each buffer and image used in a `StdCommandBuffer` have an associated state which is
/// represented by the `CommandListState` associated type of this trait. You can make multiple
/// buffers or images share the same state by making `is_same` return true.
pub unsafe trait TrackedImage: Image {
    /// State of the image in a list of commands.
    ///
    /// The `Any` bound is here for stupid reasons, sorry.
    // TODO: remove Any bound
    type CommandListState: Any + CommandListState<FinishedState = Self::FinishedState>;
    /// State of the buffer in a finished list of commands.
    type FinishedState: CommandBufferState;

    /// Returns true if TODO.
    ///
    /// If `is_same` returns true, then the type of `CommandListState` must be the same as for the
    /// other buffer. Otherwise a panic will occur.
    #[inline]
    fn is_same_buffer<B>(&self, other: &B) -> bool where B: Buffer {
        false
    }

    /// Returns true if TODO.
    ///
    /// If `is_same` returns true, then the type of `CommandListState` must be the same as for the
    /// other image. Otherwise a panic will occur.
    #[inline]
    fn is_same_image<I>(&self, other: &I) -> bool where I: Image {
        self.inner().internal_object() == other.inner().internal_object()
    }

    /// Returns the state of the image when it has not yet been used.
    fn initial_state(&self) -> Self::CommandListState;
}

/// Trait for objects that represent the state of a slice of the image in a list of commands.
pub trait CommandListState {
    type FinishedState: CommandBufferState;

    /// Returns a new state that corresponds to the moment after a slice of the image has been
    /// used in the pipeline. The parameters indicate in which way it has been used.
    ///
    /// If the transition should result in a pipeline barrier, then it must be returned by this
    /// function.
    fn transition(self, num_command: usize, image: &UnsafeImage, first_mipmap: u32,
                  num_mipmaps: u32, first_layer: u32, num_layers: u32, write: bool, layout: Layout,
                  stage: PipelineStages, access: AccessFlagBits)
                  -> (Self, Option<PipelineBarrierRequest>)
        where Self: Sized;

    /// Function called when the command buffer builder is turned into a real command buffer.
    ///
    /// This function can return an additional pipeline barrier that will be applied at the end
    /// of the command buffer.
    fn finish(self) -> (Self::FinishedState, Option<PipelineBarrierRequest>);
}

/// Requests that a pipeline barrier is created.
pub struct PipelineBarrierRequest {
    /// The number of the command after which the barrier should be placed. Must usually match
    /// the number that was passed to the previous call to `transition`, or 0 if the image hasn't
    /// been used yet.
    pub after_command_num: usize,

    /// The source pipeline stages of the transition.
    pub source_stage: PipelineStages,

    /// The destination pipeline stages of the transition.
    pub destination_stages: PipelineStages,

    /// If true, the pipeliner barrier is by region.
    pub by_region: bool,

    /// An optional memory barrier. See the docs of `PipelineMemoryBarrierRequest`.
    pub memory_barrier: Option<PipelineMemoryBarrierRequest>,
}

/// Requests that a memory barrier is created as part of the pipeline barrier.
///
/// By default, a pipeline barrier only guarantees that the source operations are executed before
/// the destination operations, but it doesn't make memory writes made by source operations visible
/// to the destination operations. In order to make so, you have to add a memory barrier.
///
/// The memory barrier always concerns the image that is currently being processed. You can't add
/// a memory barrier that concerns another resource.
pub struct PipelineMemoryBarrierRequest {
    pub first_mipmap: u32,
    pub num_mipmaps: u32,
    pub first_layer: u32,
    pub num_layers: u32,

    pub old_layout: Layout,
    pub new_layout: Layout,

    /// Source accesses.
    pub source_access: AccessFlagBits,
    /// Destination accesses.
    pub destination_access: AccessFlagBits,
}

/// Trait for objects that represent the state of the image in a command buffer.
pub trait CommandBufferState {
    /// Called right before the command buffer is submitted.
    // TODO: function should be unsafe because it must be guaranteed that a cb is submitted
    fn on_submit<I, F>(&self, image: &I, queue: &Arc<Queue>, fence: F) -> SubmitInfos
        where I: Image, F: FnOnce() -> Arc<Fence>;
}

pub struct SubmitInfos {
    pub pre_semaphore: Option<(Receiver<Arc<Semaphore>>, PipelineStages)>,
    pub post_semaphore: Option<Sender<Arc<Semaphore>>>,
    pub pre_barrier: Option<PipelineBarrierRequest>,
    pub post_barrier: Option<PipelineBarrierRequest>,
}

/// Extension trait for images. Checks whether the value `T` can be used as a clear value for the
/// given image.
// TODO: isn't that for image views instead?
pub unsafe trait ImageClearValue<T>: Image {
    fn decode(&self, T) -> Option<ClearValue>;
}

pub unsafe trait ImageContent<P>: Image {
    /// Checks whether pixels of type `P` match the format of the image.
    fn matches_format(&self) -> bool;
}

/// Trait for types that represent image views.
// TODO: remove 'static + Send + Sync
pub unsafe trait ImageView: 'static + Send + Sync {
    fn parent(&self) -> &Image;

    fn parent_arc(&Arc<Self>) -> Arc<Image> where Self: Sized;

    /// Returns the dimensions of the image view.
    fn dimensions(&self) -> Dimensions;

    /// Returns the inner unsafe image view object used by this image view.
    fn inner(&self) -> &UnsafeImageView;

    /// Returns the blocks of the parent image this image view overlaps.
    fn blocks(&self) -> Vec<(u32, u32)>;

    /// Returns the format of this view. This can be different from the parent's format.
    #[inline]
    fn format(&self) -> Format {
        self.inner().format()
    }

    #[inline]
    fn samples(&self) -> u32 {
        self.parent().samples()
    }

    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_storage_image_layout(&self) -> Layout;
    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout;
    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_sampled_image_layout(&self) -> Layout;
    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_input_attachment_layout(&self) -> Layout;

    /// Returns true if the view doesn't use components swizzling.
    ///
    /// Must be true when the view is used as a framebuffer attachment or TODO: I don't remember
    /// the other thing.
    fn identity_swizzle(&self) -> bool;

    /// Returns true if the given sampler can be used with this image view.
    ///
    /// This method should check whether the sampler's configuration can be used with the format
    /// of the view.
    // TODO: return a Result
    fn can_be_sampled(&self, sampler: &Sampler) -> bool { true /* FIXME */ }

    //fn usable_as_render_pass_attachment(&self, ???) -> Result<(), ???>;
}

unsafe impl<T> ImageView for Arc<T> where T: ImageView {
    #[inline]
    fn parent(&self) -> &Image {
        (**self).parent()
    }

    #[inline]
    fn parent_arc(me: &Arc<Self>) -> Arc<Image> {
        ImageView::parent_arc(&**me)
    }

    #[inline]
    fn inner(&self) -> &UnsafeImageView {
        (**self).inner()
    }

    #[inline]
    fn blocks(&self) -> Vec<(u32, u32)> {
        (**self).blocks()
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> Layout {
        (**self).descriptor_set_storage_image_layout()
    }
    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
        (**self).descriptor_set_combined_image_sampler_layout()
    }
    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> Layout {
        (**self).descriptor_set_sampled_image_layout()
    }
    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> Layout {
        (**self).descriptor_set_input_attachment_layout()
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        (**self).identity_swizzle()
    }

    #[inline]
    fn can_be_sampled(&self, sampler: &Sampler) -> bool {
        (**self).can_be_sampled(sampler)
    }
}

pub unsafe trait TrackedImageView: ImageView {
    type Image: TrackedImage;

    fn image(&self) -> &Self::Image;
}

unsafe impl<T> TrackedImageView for Arc<T> where T: TrackedImageView {
    type Image = T::Image;

    #[inline]
    fn image(&self) -> &Self::Image {
        (**self).image()
    }
}

pub unsafe trait AttachmentImageView: ImageView {
    fn accept(&self, initial_layout: Layout, final_layout: Layout) -> bool;
}
<commit_msg>Fix build after rebase<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::any::Any;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;

use buffer::Buffer;
use device::Queue;
use format::ClearValue;
use format::Format;
use image::Dimensions;
use image::ImageDimensions;
use image::sys::Layout;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use sampler::Sampler;
use sync::AccessFlagBits;
use sync::PipelineStages;
use sync::Fence;
use sync::Semaphore;

use VulkanObject;

/// Trait for types that represent images.
// TODO: remove 'static + Send + Sync
pub unsafe trait Image: 'static + Send + Sync {
    /// Returns the inner unsafe image object used by this image.
    fn inner(&self) -> &UnsafeImage;

    /// Returns the format of this image.
    #[inline]
    fn format(&self) -> Format {
        self.inner().format()
    }

    /// Returns the number of samples of this image.
    #[inline]
    fn samples(&self) -> u32 {
        self.inner().samples()
    }

    /// Returns the dimensions of the image.
    #[inline]
    fn dimensions(&self) -> ImageDimensions {
        self.inner().dimensions()
    }

    /// Returns true if the image can be used as a source for blits.
    #[inline]
    fn supports_blit_source(&self) -> bool {
        self.inner().supports_blit_source()
    }

    /// Returns true if the image can be used as a destination for blits.
    #[inline]
    fn supports_blit_destination(&self) -> bool {
        self.inner().supports_blit_destination()
    }
}

/// Extension trait for `Image`. Types that implement this can be used in a `StdCommandBuffer`.
///
/// Each buffer and image used in a `StdCommandBuffer` have an associated state which is
/// represented by the `CommandListState` associated type of this trait. You can make multiple
/// buffers or images share the same state by making `is_same` return true.
pub unsafe trait TrackedImage: Image {
    /// State of the image in a list of commands.
    ///
    /// The `Any` bound is here for stupid reasons, sorry.
    // TODO: remove Any bound
    type CommandListState: Any + CommandListState<FinishedState = Self::FinishedState>;
    /// State of the buffer in a finished list of commands.
    type FinishedState: CommandBufferState;

    /// Returns true if TODO.
    ///
    /// If `is_same` returns true, then the type of `CommandListState` must be the same as for the
    /// other buffer. Otherwise a panic will occur.
    #[inline]
    fn is_same_buffer<B>(&self, other: &B) -> bool where B: Buffer {
        false
    }

    /// Returns true if TODO.
    ///
    /// If `is_same` returns true, then the type of `CommandListState` must be the same as for the
    /// other image. Otherwise a panic will occur.
    #[inline]
    fn is_same_image<I>(&self, other: &I) -> bool where I: Image {
        self.inner().internal_object() == other.inner().internal_object()
    }

    /// Returns the state of the image when it has not yet been used.
    fn initial_state(&self) -> Self::CommandListState;
}

/// Trait for objects that represent the state of a slice of the image in a list of commands.
pub trait CommandListState {
    type FinishedState: CommandBufferState;

    /// Returns a new state that corresponds to the moment after a slice of the image has been
    /// used in the pipeline. The parameters indicate in which way it has been used.
    ///
    /// If the transition should result in a pipeline barrier, then it must be returned by this
    /// function.
    fn transition(self, num_command: usize, image: &UnsafeImage, first_mipmap: u32,
                  num_mipmaps: u32, first_layer: u32, num_layers: u32, write: bool, layout: Layout,
                  stage: PipelineStages, access: AccessFlagBits)
                  -> (Self, Option<PipelineBarrierRequest>)
        where Self: Sized;

    /// Function called when the command buffer builder is turned into a real command buffer.
    ///
    /// This function can return an additional pipeline barrier that will be applied at the end
    /// of the command buffer.
    fn finish(self) -> (Self::FinishedState, Option<PipelineBarrierRequest>);
}

/// Requests that a pipeline barrier is created.
pub struct PipelineBarrierRequest {
    /// The number of the command after which the barrier should be placed. Must usually match
    /// the number that was passed to the previous call to `transition`, or 0 if the image hasn't
    /// been used yet.
    pub after_command_num: usize,

    /// The source pipeline stages of the transition.
    pub source_stage: PipelineStages,

    /// The destination pipeline stages of the transition.
    pub destination_stages: PipelineStages,

    /// If true, the pipeliner barrier is by region.
    pub by_region: bool,

    /// An optional memory barrier. See the docs of `PipelineMemoryBarrierRequest`.
    pub memory_barrier: Option<PipelineMemoryBarrierRequest>,
}

/// Requests that a memory barrier is created as part of the pipeline barrier.
///
/// By default, a pipeline barrier only guarantees that the source operations are executed before
/// the destination operations, but it doesn't make memory writes made by source operations visible
/// to the destination operations. In order to make so, you have to add a memory barrier.
///
/// The memory barrier always concerns the image that is currently being processed. You can't add
/// a memory barrier that concerns another resource.
pub struct PipelineMemoryBarrierRequest {
    pub first_mipmap: u32,
    pub num_mipmaps: u32,
    pub first_layer: u32,
    pub num_layers: u32,

    pub old_layout: Layout,
    pub new_layout: Layout,

    /// Source accesses.
    pub source_access: AccessFlagBits,
    /// Destination accesses.
    pub destination_access: AccessFlagBits,
}

/// Trait for objects that represent the state of the image in a command buffer.
pub trait CommandBufferState {
    /// Called right before the command buffer is submitted.
    // TODO: function should be unsafe because it must be guaranteed that a cb is submitted
    fn on_submit<I, F>(&self, image: &I, queue: &Arc<Queue>, fence: F) -> SubmitInfos
        where I: Image, F: FnOnce() -> Arc<Fence>;
}

pub struct SubmitInfos {
    pub pre_semaphore: Option<(Receiver<Arc<Semaphore>>, PipelineStages)>,
    pub post_semaphore: Option<Sender<Arc<Semaphore>>>,
    pub pre_barrier: Option<PipelineBarrierRequest>,
    pub post_barrier: Option<PipelineBarrierRequest>,
}

/// Extension trait for images. Checks whether the value `T` can be used as a clear value for the
/// given image.
// TODO: isn't that for image views instead?
pub unsafe trait ImageClearValue<T>: Image {
    fn decode(&self, T) -> Option<ClearValue>;
}

pub unsafe trait ImageContent<P>: Image {
    /// Checks whether pixels of type `P` match the format of the image.
    fn matches_format(&self) -> bool;
}

/// Trait for types that represent image views.
// TODO: remove 'static + Send + Sync
pub unsafe trait ImageView: 'static + Send + Sync {
    fn parent(&self) -> &Image;

    fn parent_arc(&Arc<Self>) -> Arc<Image> where Self: Sized;

    /// Returns the dimensions of the image view.
    fn dimensions(&self) -> Dimensions;

    /// Returns the inner unsafe image view object used by this image view.
    fn inner(&self) -> &UnsafeImageView;

    /// Returns the blocks of the parent image this image view overlaps.
    fn blocks(&self) -> Vec<(u32, u32)>;

    /// Returns the format of this view. This can be different from the parent's format.
    #[inline]
    fn format(&self) -> Format {
        self.inner().format()
    }

    #[inline]
    fn samples(&self) -> u32 {
        self.parent().samples()
    }

    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_storage_image_layout(&self) -> Layout;
    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout;
    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_sampled_image_layout(&self) -> Layout;
    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_input_attachment_layout(&self) -> Layout;

    /// Returns true if the view doesn't use components swizzling.
    ///
    /// Must be true when the view is used as a framebuffer attachment or TODO: I don't remember
    /// the other thing.
    fn identity_swizzle(&self) -> bool;

    /// Returns true if the given sampler can be used with this image view.
    ///
    /// This method should check whether the sampler's configuration can be used with the format
    /// of the view.
    // TODO: return a Result
    fn can_be_sampled(&self, sampler: &Sampler) -> bool { true /* FIXME */ }

    //fn usable_as_render_pass_attachment(&self, ???) -> Result<(), ???>;
}

unsafe impl<T> ImageView for Arc<T> where T: ImageView {
    #[inline]
    fn parent(&self) -> &Image {
        (**self).parent()
    }

    #[inline]
    fn parent_arc(me: &Arc<Self>) -> Arc<Image> {
        ImageView::parent_arc(&**me)
    }

    #[inline]
    fn inner(&self) -> &UnsafeImageView {
        (**self).inner()
    }

    #[inline]
    fn dimensions(&self) -> Dimensions {
        (**self).dimensions()
    }

    #[inline]
    fn blocks(&self) -> Vec<(u32, u32)> {
        (**self).blocks()
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> Layout {
        (**self).descriptor_set_storage_image_layout()
    }
    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
        (**self).descriptor_set_combined_image_sampler_layout()
    }
    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> Layout {
        (**self).descriptor_set_sampled_image_layout()
    }
    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> Layout {
        (**self).descriptor_set_input_attachment_layout()
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        (**self).identity_swizzle()
    }

    #[inline]
    fn can_be_sampled(&self, sampler: &Sampler) -> bool {
        (**self).can_be_sampled(sampler)
    }
}

pub unsafe trait TrackedImageView: ImageView {
    type Image: TrackedImage;

    fn image(&self) -> &Self::Image;
}

unsafe impl<T> TrackedImageView for Arc<T> where T: TrackedImageView {
    type Image = T::Image;

    #[inline]
    fn image(&self) -> &Self::Image {
        (**self).image()
    }
}

pub unsafe trait AttachmentImageView: ImageView {
    fn accept(&self, initial_layout: Layout, final_layout: Layout) -> bool;
}
<|endoftext|>


<commit_before>
use crate::{Incoming};
use super::{IntoNeighbors, IntoNeighborsDirected, Visitable, VisitMap};
use super::{GraphRef, Reversed, IntoNodeIdentifiers};
use std::collections::VecDeque;

/// Visit nodes of a graph in a depth-first-search (DFS) emitting nodes in
/// preorder (when they are first discovered).
///
/// The traversal starts at a given node and only traverses nodes reachable
/// from it.
///
/// `Dfs` is not recursive.
///
/// `Dfs` does not itself borrow the graph, and because of this you can run
/// a traversal over a graph while still retaining mutable access to it, if you
/// use it like the following example:
///
/// ```
/// use petgraph::Graph;
/// use petgraph::visit::Dfs;
///
/// let mut graph = Graph::<_,()>::new();
/// let a = graph.add_node(0);
///
/// let mut dfs = Dfs::new(&graph, a);
/// while let Some(nx) = dfs.next(&graph) {
///     // we can access `graph` mutably here still
///     graph[nx] += 1;
/// }
///
/// assert_eq!(graph[a], 1);
/// ```
///
/// **Note:** The algorithm may not behave correctly if nodes are removed
/// during iteration. It may not necessarily visit added nodes or edges.
#[derive(Clone, Debug)]
pub struct Dfs<N, VM> {
    /// The stack of nodes to visit
    pub stack: Vec<N>,
    /// The map of discovered nodes
    pub discovered: VM,
}

impl<N, VM> Dfs<N, VM>
    where N: Copy + PartialEq,
          VM: VisitMap<N>,
{
    /// Create a new **Dfs**, using the graph's visitor map, and put **start**
    /// in the stack of nodes to visit.
    pub fn new<G>(graph: G, start: N) -> Self
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        let mut dfs = Dfs::empty(graph);
        dfs.move_to(start);
        dfs
    }

    /// Create a `Dfs` from a vector and a visit map
    pub fn from_parts(stack: Vec<N>, discovered: VM) -> Self {
        Dfs {
            stack: stack,
            discovered: discovered,
        }
    }

    /// Clear the visit state
    pub fn reset<G>(&mut self, graph: G)
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        graph.reset_map(&mut self.discovered);
        self.stack.clear();
    }

    /// Create a new **Dfs** using the graph's visitor map, and no stack.
    pub fn empty<G>(graph: G) -> Self
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        Dfs {
            stack: Vec::new(),
            discovered: graph.visit_map(),
        }
    }

    /// Keep the discovered map, but clear the visit stack and restart
    /// the dfs from a particular node.
    pub fn move_to(&mut self, start: N)
    {
        self.discovered.visit(start);
        self.stack.clear();
        self.stack.push(start);
    }

    /// Return the next node in the dfs, or **None** if the traversal is done.
    pub fn next<G>(&mut self, graph: G) -> Option<N>
        where G: IntoNeighbors<NodeId=N>,
    {
        if let Some(node) = self.stack.pop() {
            for succ in graph.neighbors(node) {
                if self.discovered.visit(succ) {
                    self.stack.push(succ);
                }
            }

            return Some(node);
        }
        None
    }
}

/// Visit nodes in a depth-first-search (DFS) emitting nodes in postorder
/// (each node after all its descendants have been emitted).
///
/// `DfsPostOrder` is not recursive.
///
/// The traversal starts at a given node and only traverses nodes reachable
/// from it.
#[derive(Clone, Debug)]
pub struct DfsPostOrder<N, VM> {
    /// The stack of nodes to visit
    pub stack: Vec<N>,
    /// The map of discovered nodes
    pub discovered: VM,
    /// The map of finished nodes
    pub finished: VM,
}

impl<N, VM> DfsPostOrder<N, VM>
    where N: Copy + PartialEq,
          VM: VisitMap<N>,
{
    /// Create a new `DfsPostOrder` using the graph's visitor map, and put
    /// `start` in the stack of nodes to visit.
    pub fn new<G>(graph: G, start: N) -> Self
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        let mut dfs = Self::empty(graph);
        dfs.move_to(start);
        dfs
    }

    /// Create a new `DfsPostOrder` using the graph's visitor map, and no stack.
    pub fn empty<G>(graph: G) -> Self
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        DfsPostOrder {
            stack: Vec::new(),
            discovered: graph.visit_map(),
            finished: graph.visit_map(),
        }
    }

    /// Clear the visit state
    pub fn reset<G>(&mut self, graph: G)
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        graph.reset_map(&mut self.discovered);
        graph.reset_map(&mut self.finished);
        self.stack.clear();
    }

    /// Keep the discovered and finished map, but clear the visit stack and restart
    /// the dfs from a particular node.
    pub fn move_to(&mut self, start: N)
    {
        self.stack.clear();
        self.stack.push(start);
    }

    /// Return the next node in the traversal, or `None` if the traversal is done.
    pub fn next<G>(&mut self, graph: G) -> Option<N>
        where G: IntoNeighbors<NodeId=N>,
    {
        while let Some(&nx) = self.stack.last() {
            if self.discovered.visit(nx) {
                // First time visiting `nx`: Push neighbors, don't pop `nx`
                for succ in graph.neighbors(nx) {
                    if !self.discovered.is_visited(&succ) {
                        self.stack.push(succ);
                    }
                }
            } else {
                self.stack.pop();
                if self.finished.visit(nx) {
                    // Second time: All reachable nodes must have been finished
                    return Some(nx);
                }
            }
        }
        None
    }
}

/// A breadth first search (BFS) of a graph.
///
/// The traversal starts at a given node and only traverses nodes reachable
/// from it.
///
/// `Bfs` is not recursive.
///
/// `Bfs` does not itself borrow the graph, and because of this you can run
/// a traversal over a graph while still retaining mutable access to it, if you
/// use it like the following example:
///
/// ```
/// use petgraph::Graph;
/// use petgraph::visit::Bfs;
///
/// let mut graph = Graph::<_,()>::new();
/// let a = graph.add_node(0);
///
/// let mut bfs = Bfs::new(&graph, a);
/// while let Some(nx) = bfs.next(&graph) {
///     // we can access `graph` mutably here still
///     graph[nx] += 1;
/// }
///
/// assert_eq!(graph[a], 1);
/// ```
///
/// **Note:** The algorithm may not behave correctly if nodes are removed
/// during iteration. It may not necessarily visit added nodes or edges.
#[derive(Clone)]
pub struct Bfs<N, VM> {
    /// The queue of nodes to visit
    pub stack: VecDeque<N>,
    /// The map of discovered nodes
    pub discovered: VM,
}

impl<N, VM> Bfs<N, VM>
    where N: Copy + PartialEq,
          VM: VisitMap<N>,
{
    /// Create a new **Bfs**, using the graph's visitor map, and put **start**
    /// in the stack of nodes to visit.
    pub fn new<G>(graph: G, start: N) -> Self
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        let mut discovered = graph.visit_map();
        discovered.visit(start);
        let mut stack = VecDeque::new();
        stack.push_front(start);
        Bfs {
            stack: stack,
            discovered: discovered,
        }
    }

    /// Return the next node in the bfs, or **None** if the traversal is done.
    pub fn next<G>(&mut self, graph: G) -> Option<N>
        where G: IntoNeighbors<NodeId=N>
    {
        if let Some(node) = self.stack.pop_front() {
            for succ in graph.neighbors(node) {
                if self.discovered.visit(succ) {
                    self.stack.push_back(succ);
                }
            }

            return Some(node);
        }
        None
    }

}

/// A topological order traversal for a graph.
///
/// **Note** that `Topo` only visits nodes that are not part of cycles,
/// i.e. nodes in a true DAG. Use other visitors like `DfsPostOrder` or
/// algorithms like kosaraju_scc to handle graphs with possible cycles.
#[derive(Clone)]
pub struct Topo<N, VM> {
    tovisit: Vec<N>,
    ordered: VM,
}

impl<N, VM> Topo<N, VM>
    where N: Copy + PartialEq,
          VM: VisitMap<N>,
{
    /// Create a new `Topo`, using the graph's visitor map, and put all
    /// initial nodes in the to visit list.
    pub fn new<G>(graph: G) -> Self
        where G: IntoNodeIdentifiers + IntoNeighborsDirected + Visitable<NodeId=N, Map=VM>,
    {
        let mut topo = Self::empty(graph);
        topo.extend_with_initials(graph);
        topo
    }

    fn extend_with_initials<G>(&mut self, g: G)
        where G: IntoNodeIdentifiers + IntoNeighborsDirected<NodeId=N>,
    {
        // find all initial nodes (nodes without incoming edges)
        self.tovisit.extend(g.node_identifiers()
                             .filter(move |&a| g.neighbors_directed(a, Incoming).next().is_none()));
    }

    /* Private until it has a use */
    /// Create a new `Topo`, using the graph's visitor map with *no* starting
    /// index specified.
    fn empty<G>(graph: G) -> Self
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        Topo {
            ordered: graph.visit_map(),
            tovisit: Vec::new(),
        }
    }

    /// Clear visited state, and put all initial nodes in the to visit list.
    pub fn reset<G>(&mut self, graph: G)
        where G: IntoNodeIdentifiers + IntoNeighborsDirected + Visitable<NodeId=N, Map=VM>,
    {
        graph.reset_map(&mut self.ordered);
        self.tovisit.clear();
        self.extend_with_initials(graph);
    }

    /// Return the next node in the current topological order traversal, or
    /// `None` if the traversal is at the end.
    ///
    /// *Note:* The graph may not have a complete topological order, and the only
    /// way to know is to run the whole traversal and make sure it visits every node.
    pub fn next<G>(&mut self, g: G) -> Option<N>
        where G: IntoNeighborsDirected + Visitable<NodeId=N, Map=VM>,
    {
        // Take an unvisited element and find which of its neighbors are next
        while let Some(nix) = self.tovisit.pop() {
            if self.ordered.is_visited(&nix) {
                continue;
            }
            self.ordered.visit(nix);
            for neigh in g.neighbors(nix) {
                // Look at each neighbor, and those that only have incoming edges
                // from the already ordered list, they are the next to visit.
                if Reversed(g).neighbors(neigh).all(|b| self.ordered.is_visited(&b)) {
                    self.tovisit.push(neigh);
                }
            }
            return Some(nix);
        }
        None
    }
}

/// A walker is a traversal state, but where part of the traversal
/// information is supplied manually to each next call.
///
/// This for example allows graph traversals that don't hold a borrow of the
/// graph they are traversing.
pub trait Walker<Context> {
    type Item;
    /// Advance to the next item
    fn walk_next(&mut self, context: Context) -> Option<Self::Item>;

    /// Create an iterator out of the walker and given `context`.
    fn iter(self, context: Context) -> WalkerIter<Self, Context>
        where Self: Sized,
              Context: Clone,
    {
        WalkerIter {
            walker: self,
            context: context,
        }
    }
}

/// A walker and its context wrapped into an iterator.
#[derive(Clone, Debug)]
pub struct WalkerIter<W, C> {
    walker: W,
    context: C,
}

impl<W, C> WalkerIter<W, C>
    where W: Walker<C>,
          C: Clone,
{
    pub fn context(&self) -> C {
        self.context.clone()
    }

    pub fn inner_ref(&self) -> &W {
        &self.walker
    }

    pub fn inner_mut(&mut self) -> &mut W {
        &mut self.walker
    }
}

impl<W, C> Iterator for WalkerIter<W, C>
    where W: Walker<C>,
          C: Clone,
{
    type Item = W::Item;
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.walk_next(self.context.clone())
    }
}

impl<'a, C, W: ?Sized> Walker<C> for &'a mut W
    where W: Walker<C>,
{
    type Item = W::Item;
    fn walk_next(&mut self, context: C) -> Option<Self::Item> {
        (**self).walk_next(context)
    }
}

impl<G> Walker<G> for Dfs<G::NodeId, G::Map>
    where G: IntoNeighbors + Visitable
{
    type Item = G::NodeId;
    fn walk_next(&mut self, context: G) -> Option<Self::Item> {
        self.next(context)
    }
}

impl<G> Walker<G> for DfsPostOrder<G::NodeId, G::Map>
    where G: IntoNeighbors + Visitable
{
    type Item = G::NodeId;
    fn walk_next(&mut self, context: G) -> Option<Self::Item> {
        self.next(context)
    }
}

impl<G> Walker<G> for Bfs<G::NodeId, G::Map>
    where G: IntoNeighbors + Visitable
{
    type Item = G::NodeId;
    fn walk_next(&mut self, context: G) -> Option<Self::Item> {
        self.next(context)
    }
}

impl<G> Walker<G> for Topo<G::NodeId, G::Map>
    where G: IntoNeighborsDirected + Visitable,
{
    type Item = G::NodeId;
    fn walk_next(&mut self, context: G) -> Option<Self::Item> {
        self.next(context)
    }
}
<commit_msg>Fix bug in order of iterative dfs<commit_after>
use crate::{Incoming};
use super::{IntoNeighbors, IntoNeighborsDirected, Visitable, VisitMap};
use super::{GraphRef, Reversed, IntoNodeIdentifiers};
use std::collections::VecDeque;

/// Visit nodes of a graph in a depth-first-search (DFS) emitting nodes in
/// preorder (when they are first discovered).
///
/// The traversal starts at a given node and only traverses nodes reachable
/// from it.
///
/// `Dfs` is not recursive.
///
/// `Dfs` does not itself borrow the graph, and because of this you can run
/// a traversal over a graph while still retaining mutable access to it, if you
/// use it like the following example:
///
/// ```
/// use petgraph::Graph;
/// use petgraph::visit::Dfs;
///
/// let mut graph = Graph::<_,()>::new();
/// let a = graph.add_node(0);
///
/// let mut dfs = Dfs::new(&graph, a);
/// while let Some(nx) = dfs.next(&graph) {
///     // we can access `graph` mutably here still
///     graph[nx] += 1;
/// }
///
/// assert_eq!(graph[a], 1);
/// ```
///
/// **Note:** The algorithm may not behave correctly if nodes are removed
/// during iteration. It may not necessarily visit added nodes or edges.
#[derive(Clone, Debug)]
pub struct Dfs<N, VM> {
    /// The stack of nodes to visit
    pub stack: Vec<N>,
    /// The map of discovered nodes
    pub discovered: VM,
}

impl<N, VM> Dfs<N, VM>
    where N: Copy + PartialEq,
          VM: VisitMap<N>,
{
    /// Create a new **Dfs**, using the graph's visitor map, and put **start**
    /// in the stack of nodes to visit.
    pub fn new<G>(graph: G, start: N) -> Self
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        let mut dfs = Dfs::empty(graph);
        dfs.move_to(start);
        dfs
    }

    /// Create a `Dfs` from a vector and a visit map
    pub fn from_parts(stack: Vec<N>, discovered: VM) -> Self {
        Dfs {
            stack: stack,
            discovered: discovered,
        }
    }

    /// Clear the visit state
    pub fn reset<G>(&mut self, graph: G)
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        graph.reset_map(&mut self.discovered);
        self.stack.clear();
    }

    /// Create a new **Dfs** using the graph's visitor map, and no stack.
    pub fn empty<G>(graph: G) -> Self
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        Dfs {
            stack: Vec::new(),
            discovered: graph.visit_map(),
        }
    }

    /// Keep the discovered map, but clear the visit stack and restart
    /// the dfs from a particular node.
    pub fn move_to(&mut self, start: N)
    {
        self.stack.clear();
        self.stack.push(start);
    }

    /// Return the next node in the dfs, or **None** if the traversal is done.
    pub fn next<G>(&mut self, graph: G) -> Option<N>
        where G: IntoNeighbors<NodeId=N>,
    {
        while let Some(node) = self.stack.pop() {
            if self.discovered.visit(node) {
                for succ in graph.neighbors(node) {
                    if !self.discovered.is_visited(&succ) {
                        self.stack.push(succ);
                    }
                }
                return Some(node);
            }
        }
        None
    }
}

/// Visit nodes in a depth-first-search (DFS) emitting nodes in postorder
/// (each node after all its descendants have been emitted).
///
/// `DfsPostOrder` is not recursive.
///
/// The traversal starts at a given node and only traverses nodes reachable
/// from it.
#[derive(Clone, Debug)]
pub struct DfsPostOrder<N, VM> {
    /// The stack of nodes to visit
    pub stack: Vec<N>,
    /// The map of discovered nodes
    pub discovered: VM,
    /// The map of finished nodes
    pub finished: VM,
}

impl<N, VM> DfsPostOrder<N, VM>
    where N: Copy + PartialEq,
          VM: VisitMap<N>,
{
    /// Create a new `DfsPostOrder` using the graph's visitor map, and put
    /// `start` in the stack of nodes to visit.
    pub fn new<G>(graph: G, start: N) -> Self
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        let mut dfs = Self::empty(graph);
        dfs.move_to(start);
        dfs
    }

    /// Create a new `DfsPostOrder` using the graph's visitor map, and no stack.
    pub fn empty<G>(graph: G) -> Self
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        DfsPostOrder {
            stack: Vec::new(),
            discovered: graph.visit_map(),
            finished: graph.visit_map(),
        }
    }

    /// Clear the visit state
    pub fn reset<G>(&mut self, graph: G)
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        graph.reset_map(&mut self.discovered);
        graph.reset_map(&mut self.finished);
        self.stack.clear();
    }

    /// Keep the discovered and finished map, but clear the visit stack and restart
    /// the dfs from a particular node.
    pub fn move_to(&mut self, start: N)
    {
        self.stack.clear();
        self.stack.push(start);
    }

    /// Return the next node in the traversal, or `None` if the traversal is done.
    pub fn next<G>(&mut self, graph: G) -> Option<N>
        where G: IntoNeighbors<NodeId=N>,
    {
        while let Some(&nx) = self.stack.last() {
            if self.discovered.visit(nx) {
                // First time visiting `nx`: Push neighbors, don't pop `nx`
                for succ in graph.neighbors(nx) {
                    if !self.discovered.is_visited(&succ) {
                        self.stack.push(succ);
                    }
                }
            } else {
                self.stack.pop();
                if self.finished.visit(nx) {
                    // Second time: All reachable nodes must have been finished
                    return Some(nx);
                }
            }
        }
        None
    }
}

/// A breadth first search (BFS) of a graph.
///
/// The traversal starts at a given node and only traverses nodes reachable
/// from it.
///
/// `Bfs` is not recursive.
///
/// `Bfs` does not itself borrow the graph, and because of this you can run
/// a traversal over a graph while still retaining mutable access to it, if you
/// use it like the following example:
///
/// ```
/// use petgraph::Graph;
/// use petgraph::visit::Bfs;
///
/// let mut graph = Graph::<_,()>::new();
/// let a = graph.add_node(0);
///
/// let mut bfs = Bfs::new(&graph, a);
/// while let Some(nx) = bfs.next(&graph) {
///     // we can access `graph` mutably here still
///     graph[nx] += 1;
/// }
///
/// assert_eq!(graph[a], 1);
/// ```
///
/// **Note:** The algorithm may not behave correctly if nodes are removed
/// during iteration. It may not necessarily visit added nodes or edges.
#[derive(Clone)]
pub struct Bfs<N, VM> {
    /// The queue of nodes to visit
    pub stack: VecDeque<N>,
    /// The map of discovered nodes
    pub discovered: VM,
}

impl<N, VM> Bfs<N, VM>
    where N: Copy + PartialEq,
          VM: VisitMap<N>,
{
    /// Create a new **Bfs**, using the graph's visitor map, and put **start**
    /// in the stack of nodes to visit.
    pub fn new<G>(graph: G, start: N) -> Self
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        let mut discovered = graph.visit_map();
        discovered.visit(start);
        let mut stack = VecDeque::new();
        stack.push_front(start);
        Bfs {
            stack: stack,
            discovered: discovered,
        }
    }

    /// Return the next node in the bfs, or **None** if the traversal is done.
    pub fn next<G>(&mut self, graph: G) -> Option<N>
        where G: IntoNeighbors<NodeId=N>
    {
        if let Some(node) = self.stack.pop_front() {
            for succ in graph.neighbors(node) {
                if self.discovered.visit(succ) {
                    self.stack.push_back(succ);
                }
            }

            return Some(node);
        }
        None
    }

}

/// A topological order traversal for a graph.
///
/// **Note** that `Topo` only visits nodes that are not part of cycles,
/// i.e. nodes in a true DAG. Use other visitors like `DfsPostOrder` or
/// algorithms like kosaraju_scc to handle graphs with possible cycles.
#[derive(Clone)]
pub struct Topo<N, VM> {
    tovisit: Vec<N>,
    ordered: VM,
}

impl<N, VM> Topo<N, VM>
    where N: Copy + PartialEq,
          VM: VisitMap<N>,
{
    /// Create a new `Topo`, using the graph's visitor map, and put all
    /// initial nodes in the to visit list.
    pub fn new<G>(graph: G) -> Self
        where G: IntoNodeIdentifiers + IntoNeighborsDirected + Visitable<NodeId=N, Map=VM>,
    {
        let mut topo = Self::empty(graph);
        topo.extend_with_initials(graph);
        topo
    }

    fn extend_with_initials<G>(&mut self, g: G)
        where G: IntoNodeIdentifiers + IntoNeighborsDirected<NodeId=N>,
    {
        // find all initial nodes (nodes without incoming edges)
        self.tovisit.extend(g.node_identifiers()
                             .filter(move |&a| g.neighbors_directed(a, Incoming).next().is_none()));
    }

    /* Private until it has a use */
    /// Create a new `Topo`, using the graph's visitor map with *no* starting
    /// index specified.
    fn empty<G>(graph: G) -> Self
        where G: GraphRef + Visitable<NodeId=N, Map=VM>
    {
        Topo {
            ordered: graph.visit_map(),
            tovisit: Vec::new(),
        }
    }

    /// Clear visited state, and put all initial nodes in the to visit list.
    pub fn reset<G>(&mut self, graph: G)
        where G: IntoNodeIdentifiers + IntoNeighborsDirected + Visitable<NodeId=N, Map=VM>,
    {
        graph.reset_map(&mut self.ordered);
        self.tovisit.clear();
        self.extend_with_initials(graph);
    }

    /// Return the next node in the current topological order traversal, or
    /// `None` if the traversal is at the end.
    ///
    /// *Note:* The graph may not have a complete topological order, and the only
    /// way to know is to run the whole traversal and make sure it visits every node.
    pub fn next<G>(&mut self, g: G) -> Option<N>
        where G: IntoNeighborsDirected + Visitable<NodeId=N, Map=VM>,
    {
        // Take an unvisited element and find which of its neighbors are next
        while let Some(nix) = self.tovisit.pop() {
            if self.ordered.is_visited(&nix) {
                continue;
            }
            self.ordered.visit(nix);
            for neigh in g.neighbors(nix) {
                // Look at each neighbor, and those that only have incoming edges
                // from the already ordered list, they are the next to visit.
                if Reversed(g).neighbors(neigh).all(|b| self.ordered.is_visited(&b)) {
                    self.tovisit.push(neigh);
                }
            }
            return Some(nix);
        }
        None
    }
}

/// A walker is a traversal state, but where part of the traversal
/// information is supplied manually to each next call.
///
/// This for example allows graph traversals that don't hold a borrow of the
/// graph they are traversing.
pub trait Walker<Context> {
    type Item;
    /// Advance to the next item
    fn walk_next(&mut self, context: Context) -> Option<Self::Item>;

    /// Create an iterator out of the walker and given `context`.
    fn iter(self, context: Context) -> WalkerIter<Self, Context>
        where Self: Sized,
              Context: Clone,
    {
        WalkerIter {
            walker: self,
            context: context,
        }
    }
}

/// A walker and its context wrapped into an iterator.
#[derive(Clone, Debug)]
pub struct WalkerIter<W, C> {
    walker: W,
    context: C,
}

impl<W, C> WalkerIter<W, C>
    where W: Walker<C>,
          C: Clone,
{
    pub fn context(&self) -> C {
        self.context.clone()
    }

    pub fn inner_ref(&self) -> &W {
        &self.walker
    }

    pub fn inner_mut(&mut self) -> &mut W {
        &mut self.walker
    }
}

impl<W, C> Iterator for WalkerIter<W, C>
    where W: Walker<C>,
          C: Clone,
{
    type Item = W::Item;
    fn next(&mut self) -> Option<Self::Item> {
        self.walker.walk_next(self.context.clone())
    }
}

impl<'a, C, W: ?Sized> Walker<C> for &'a mut W
    where W: Walker<C>,
{
    type Item = W::Item;
    fn walk_next(&mut self, context: C) -> Option<Self::Item> {
        (**self).walk_next(context)
    }
}

impl<G> Walker<G> for Dfs<G::NodeId, G::Map>
    where G: IntoNeighbors + Visitable
{
    type Item = G::NodeId;
    fn walk_next(&mut self, context: G) -> Option<Self::Item> {
        self.next(context)
    }
}

impl<G> Walker<G> for DfsPostOrder<G::NodeId, G::Map>
    where G: IntoNeighbors + Visitable
{
    type Item = G::NodeId;
    fn walk_next(&mut self, context: G) -> Option<Self::Item> {
        self.next(context)
    }
}

impl<G> Walker<G> for Bfs<G::NodeId, G::Map>
    where G: IntoNeighbors + Visitable
{
    type Item = G::NodeId;
    fn walk_next(&mut self, context: G) -> Option<Self::Item> {
        self.next(context)
    }
}

impl<G> Walker<G> for Topo<G::NodeId, G::Map>
    where G: IntoNeighborsDirected + Visitable,
{
    type Item = G::NodeId;
    fn walk_next(&mut self, context: G) -> Option<Self::Item> {
        self.next(context)
    }
}
<|endoftext|>


<commit_before>use super::{PgConnection, PgTypeMetadata};
use prelude::*;

/// Determines the OID of types at runtime
#[allow(missing_debug_implementations)]
pub struct PgMetadataLookup {
    conn: PgConnection,
}

impl PgMetadataLookup {
    #[allow(clippy::new_ret_no_self)]
    pub(crate) fn new(conn: &PgConnection) -> &Self {
        unsafe { &*(conn as *const PgConnection as *const PgMetadataLookup) }
    }

    /// Determine the type metadata for the given `type_name`
    ///
    /// This function should only be used for user defined types, or types which
    /// come from an extension. This function may perform a SQL query to look
    /// up the type. For built-in types, a static OID should be preferred.
    pub fn lookup_type(&self, type_name: &str) -> PgTypeMetadata {
        use self::pg_type::dsl::*;

        pg_type
            .select((oid, typarray))
            .filter(typname.eq(type_name))
            .first(&self.conn)
            .unwrap_or_default()
    }
}

table! {
    pg_type (oid) {
        oid -> Oid,
        typname -> Text,
        typarray -> Oid,
    }
}
<commit_msg>Add `#[repr(transparent)]` to `PgMetadataLookup`<commit_after>use super::{PgConnection, PgTypeMetadata};
use prelude::*;

/// Determines the OID of types at runtime
#[allow(missing_debug_implementations)]
#[repr(transparent)]
pub struct PgMetadataLookup {
    conn: PgConnection,
}

impl PgMetadataLookup {
    #[allow(clippy::new_ret_no_self)]
    pub(crate) fn new(conn: &PgConnection) -> &Self {
        unsafe { &*(conn as *const PgConnection as *const PgMetadataLookup) }
    }

    /// Determine the type metadata for the given `type_name`
    ///
    /// This function should only be used for user defined types, or types which
    /// come from an extension. This function may perform a SQL query to look
    /// up the type. For built-in types, a static OID should be preferred.
    pub fn lookup_type(&self, type_name: &str) -> PgTypeMetadata {
        use self::pg_type::dsl::*;

        pg_type
            .select((oid, typarray))
            .filter(typname.eq(type_name))
            .first(&self.conn)
            .unwrap_or_default()
    }
}

table! {
    pg_type (oid) {
        oid -> Oid,
        typname -> Text,
        typarray -> Oid,
    }
}
<|endoftext|>


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

use gpu_store::{GpuStore, GpuStoreAddress};
use prim_store::{ClipData, GpuBlock32, PrimitiveStore};
use prim_store::{CLIP_DATA_GPU_SIZE, MASK_DATA_GPU_SIZE};
use util::TransformedRect;
use webrender_traits::{AuxiliaryLists, BorderRadius, ClipRegion, ComplexClipRegion, ImageMask};
use webrender_traits::{DeviceIntRect, DeviceIntSize, LayerRect, LayerToWorldTransform};

#[derive(Clone, Debug)]
pub enum ClipSource {
    NoClip,
    Complex(LayerRect, f32),
    Region(ClipRegion),
}

impl ClipSource {
    pub fn to_rect(&self) -> Option<LayerRect> {
        match self {
            &ClipSource::NoClip => None,
            &ClipSource::Complex(rect, _) => Some(rect),
            &ClipSource::Region(ref region) => Some(region.main),
        }
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct ClipAddressRange {
    pub start: GpuStoreAddress,
    pub item_count: u32,
}

#[derive(Clone, Debug)]
pub struct MaskCacheInfo {
    pub clip_range: ClipAddressRange,
    pub image: Option<(ImageMask, GpuStoreAddress)>,
    pub local_rect: Option<LayerRect>,
    pub local_inner: Option<LayerRect>,
    pub inner_rect: DeviceIntRect,
    pub outer_rect: DeviceIntRect,
}

impl MaskCacheInfo {
    /// Create a new mask cache info. It allocates the GPU store data but leaves
    /// it unitialized for the following `update()` call to deal with.
    pub fn new(source: &ClipSource,
               is_transformed: bool,
               clip_store: &mut GpuStore<GpuBlock32>)
               -> Option<MaskCacheInfo> {
        let (image, clip_range) = match source {
            &ClipSource::NoClip => return None,
            &ClipSource::Complex(..) => {
                (None,
                ClipAddressRange {
                    start: clip_store.alloc(CLIP_DATA_GPU_SIZE),
                    item_count: 1,
                })
            },
            &ClipSource::Region(ref region) => {
                let count = region.complex.length + if is_transformed {1} else {0};
                (region.image_mask.map(|info|
                    (info, clip_store.alloc(MASK_DATA_GPU_SIZE))),
                ClipAddressRange {
                    start: if count > 0 {
                        clip_store.alloc(CLIP_DATA_GPU_SIZE * count)
                    } else {
                        GpuStoreAddress(0)
                    },
                    item_count: count as u32,
                })
            },
        };

        Some(MaskCacheInfo {
            clip_range: clip_range,
            image: image,
            local_rect: None,
            local_inner: None,
            inner_rect: DeviceIntRect::zero(),
            outer_rect: DeviceIntRect::zero(),
        })
    }

    pub fn update(&mut self,
                  source: &ClipSource,
                  transform: &LayerToWorldTransform,
                  clip_store: &mut GpuStore<GpuBlock32>,
                  device_pixel_ratio: f32,
                  aux_lists: &AuxiliaryLists) {

        if self.local_rect.is_none() {
            let mut local_rect;
            let mut local_inner: Option<LayerRect>;
            match source {
                &ClipSource::NoClip => unreachable!(),
                &ClipSource::Complex(rect, radius) => {
                    let slice = clip_store.get_slice_mut(self.clip_range.start, CLIP_DATA_GPU_SIZE);
                    let data = ClipData::uniform(rect, radius);
                    PrimitiveStore::populate_clip_data(slice, data);
                    debug_assert_eq!(self.clip_range.item_count, 1);
                    local_rect = Some(rect);
                    local_inner = ComplexClipRegion::new(rect, BorderRadius::uniform(radius))
                                                    .get_inner_rect();
                }
                &ClipSource::Region(ref region) => {
                    local_rect = Some(region.main);
                    local_inner = match region.image_mask {
                        Some(ref mask) if !mask.repeat => {
                            local_rect = local_rect.and_then(|r| r.intersection(&mask.rect));
                            None
                        },
                        Some(_) => None,
                        None => local_rect,
                    };
                    let clips = aux_lists.complex_clip_regions(&region.complex);
                    assert_eq!(self.clip_range.item_count, clips.len() as u32 + 1);
                    let slice = clip_store.get_slice_mut(self.clip_range.start, CLIP_DATA_GPU_SIZE * (clips.len() + 1));
                    for (clip, chunk) in clips.iter().zip(slice.chunks_mut(CLIP_DATA_GPU_SIZE)) {
                        let data = ClipData::from_clip_region(clip);
                        PrimitiveStore::populate_clip_data(chunk, data);
                        local_rect = local_rect.and_then(|r| r.intersection(&clip.rect));
                        local_inner = local_inner.and_then(|r| clip.get_inner_rect()
                                                                   .and_then(|ref inner| r.intersection(&inner)));
                    }
                    if slice.len() > CLIP_DATA_GPU_SIZE * clips.len() {
                        // we have an extra clip rect coming from the transformed layer
                        PrimitiveStore::populate_clip_data(&mut slice[CLIP_DATA_GPU_SIZE * clips.len() ..],
                                                           ClipData::uniform(region.main, 0.0));
                    }
                }
            };
            self.local_rect = Some(local_rect.unwrap_or(LayerRect::zero()));
            self.local_inner = local_inner;
        }

        let transformed = TransformedRect::new(self.local_rect.as_ref().unwrap(),
                                               &transform,
                                               device_pixel_ratio);
        self.outer_rect = transformed.bounding_rect;

        self.inner_rect = if let Some(ref inner_rect) = self.local_inner {
            let transformed = TransformedRect::new(inner_rect,
                                                   &transform,
                                                   device_pixel_ratio);
            transformed.inner_rect
        } else {
            DeviceIntRect::new(self.outer_rect.origin, DeviceIntSize::zero())
        }
    }
}
<commit_msg>More flexible handling of the extra clip instance generated by a transformed layer<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use gpu_store::{GpuStore, GpuStoreAddress};
use prim_store::{ClipData, GpuBlock32, PrimitiveStore};
use prim_store::{CLIP_DATA_GPU_SIZE, MASK_DATA_GPU_SIZE};
use util::TransformedRect;
use webrender_traits::{AuxiliaryLists, BorderRadius, ClipRegion, ComplexClipRegion, ImageMask};
use webrender_traits::{DeviceIntRect, DeviceIntSize, LayerRect, LayerToWorldTransform};

#[derive(Clone, Debug)]
pub enum ClipSource {
    NoClip,
    Complex(LayerRect, f32),
    Region(ClipRegion),
}

impl ClipSource {
    pub fn to_rect(&self) -> Option<LayerRect> {
        match self {
            &ClipSource::NoClip => None,
            &ClipSource::Complex(rect, _) => Some(rect),
            &ClipSource::Region(ref region) => Some(region.main),
        }
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct ClipAddressRange {
    pub start: GpuStoreAddress,
    pub item_count: u32,
}

#[derive(Clone, Debug)]
pub struct MaskCacheInfo {
    pub clip_range: ClipAddressRange,
    pub image: Option<(ImageMask, GpuStoreAddress)>,
    pub local_rect: Option<LayerRect>,
    pub local_inner: Option<LayerRect>,
    pub inner_rect: DeviceIntRect,
    pub outer_rect: DeviceIntRect,
}

impl MaskCacheInfo {
    /// Create a new mask cache info. It allocates the GPU store data but leaves
    /// it unitialized for the following `update()` call to deal with.
    pub fn new(source: &ClipSource,
               is_transformed: bool,
               clip_store: &mut GpuStore<GpuBlock32>)
               -> Option<MaskCacheInfo> {
        let (image, clip_range) = match source {
            &ClipSource::NoClip => return None,
            &ClipSource::Complex(..) => {
                (None,
                ClipAddressRange {
                    start: clip_store.alloc(CLIP_DATA_GPU_SIZE),
                    item_count: 1,
                })
            },
            &ClipSource::Region(ref region) => {
                let count = region.complex.length + if is_transformed {1} else {0};
                (region.image_mask.map(|info|
                    (info, clip_store.alloc(MASK_DATA_GPU_SIZE))),
                ClipAddressRange {
                    start: if count > 0 {
                        clip_store.alloc(CLIP_DATA_GPU_SIZE * count)
                    } else {
                        GpuStoreAddress(0)
                    },
                    item_count: count as u32,
                })
            },
        };

        Some(MaskCacheInfo {
            clip_range: clip_range,
            image: image,
            local_rect: None,
            local_inner: None,
            inner_rect: DeviceIntRect::zero(),
            outer_rect: DeviceIntRect::zero(),
        })
    }

    pub fn update(&mut self,
                  source: &ClipSource,
                  transform: &LayerToWorldTransform,
                  clip_store: &mut GpuStore<GpuBlock32>,
                  device_pixel_ratio: f32,
                  aux_lists: &AuxiliaryLists) {

        if self.local_rect.is_none() {
            let mut local_rect;
            let mut local_inner: Option<LayerRect>;
            match source {
                &ClipSource::NoClip => unreachable!(),
                &ClipSource::Complex(rect, radius) => {
                    let slice = clip_store.get_slice_mut(self.clip_range.start, CLIP_DATA_GPU_SIZE);
                    let data = ClipData::uniform(rect, radius);
                    PrimitiveStore::populate_clip_data(slice, data);
                    debug_assert_eq!(self.clip_range.item_count, 1);
                    local_rect = Some(rect);
                    local_inner = ComplexClipRegion::new(rect, BorderRadius::uniform(radius))
                                                    .get_inner_rect();
                }
                &ClipSource::Region(ref region) => {
                    local_rect = Some(region.main);
                    local_inner = match region.image_mask {
                        Some(ref mask) if !mask.repeat => {
                            local_rect = local_rect.and_then(|r| r.intersection(&mask.rect));
                            None
                        },
                        Some(_) => None,
                        None => local_rect,
                    };

                    let clips = aux_lists.complex_clip_regions(&region.complex);
                    if self.clip_range.item_count > clips.len() as u32 {
                        // we have an extra clip rect coming from the transformed layer
                        assert_eq!(self.clip_range.item_count, clips.len() as u32 + 1);
                        let address = GpuStoreAddress(self.clip_range.start.0 + (CLIP_DATA_GPU_SIZE * clips.len()) as i32);
                        let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE);
                        PrimitiveStore::populate_clip_data(slice, ClipData::uniform(region.main, 0.0));
                    } else {
                        assert_eq!(self.clip_range.item_count, clips.len() as u32);
                    }

                    let slice = clip_store.get_slice_mut(self.clip_range.start, CLIP_DATA_GPU_SIZE * clips.len());
                    for (clip, chunk) in clips.iter().zip(slice.chunks_mut(CLIP_DATA_GPU_SIZE)) {
                        let data = ClipData::from_clip_region(clip);
                        PrimitiveStore::populate_clip_data(chunk, data);
                        local_rect = local_rect.and_then(|r| r.intersection(&clip.rect));
                        local_inner = local_inner.and_then(|r| clip.get_inner_rect()
                                                                   .and_then(|ref inner| r.intersection(&inner)));
                    }
                }
            };
            self.local_rect = Some(local_rect.unwrap_or(LayerRect::zero()));
            self.local_inner = local_inner;
        }

        let transformed = TransformedRect::new(self.local_rect.as_ref().unwrap(),
                                               &transform,
                                               device_pixel_ratio);
        self.outer_rect = transformed.bounding_rect;

        self.inner_rect = if let Some(ref inner_rect) = self.local_inner {
            let transformed = TransformedRect::new(inner_rect,
                                                   &transform,
                                                   device_pixel_ratio);
            transformed.inner_rect
        } else {
            DeviceIntRect::new(self.outer_rect.origin, DeviceIntSize::zero())
        }
    }
}
<|endoftext|>