<commit_before>use std::rc::Rc;

use error::RuntimeError;

use sys::x11;
use sys::xcb;
use sys::egl;
use sys::gl;

use super::window::LinuxWindow;

pub struct LinuxApplication {
   pub x11_display: X11DisplayHandler,
   pub connection: ConnectionHandler,
   pub screen: ScreenHandler,
   pub egl_display: EglDisplayHandler,
}

impl LinuxApplication {
   pub fn new() -> Result<Self, RuntimeError> {
      let x11_display = try!(X11DisplayHandler::new());
      let connection = try!(ConnectionHandler::new(&x11_display));
      let screen = try!(ScreenHandler::new(&x11_display, &connection));
      let egl_display = try!(EglDisplayHandler::new(&x11_display));

      gl::load(egl::Loader::new());

      Ok(LinuxApplication {
         x11_display: x11_display,
         connection: connection,
         screen: screen,
         egl_display: egl_display,
      })
   }

   #[inline]
   pub fn screen_size(&self) -> (u32, u32) {
      self.screen.size()
   }

   pub fn create_os_window(
      &self, title: &str, x: u32, y: u32, width: u32, height: u32
   ) -> Result<LinuxWindow, RuntimeError> {
      let xcb_window = try!(self.screen.create_window(
         &self.connection, x, y, width, height
      ));

      let surface = try!(EglSurfaceHandler::new(&self.egl_display, &xcb_window));

      try!(self.egl_display.make_current(&surface));

      Ok(LinuxWindow::new(xcb_window, surface, title))
   }
}

pub struct X11DisplayHandler {
   pub display: x11::Display,
}

impl X11DisplayHandler {
   #[inline]
   pub fn new() -> Result<Self, RuntimeError> {
      let display = try!(x11::Display::default());

      display.xcb_own_event_queue();

      Ok(X11DisplayHandler {
         display: display
      })
   }

   #[inline]
   pub fn connection(&self) -> Result<xcb::Connection, RuntimeError> {
      self.display.xcb_connection()
   }

   #[inline]
   pub fn screen_id(&self) -> x11::ScreenID {
      self.display.default_screen()
   }
}

pub struct ConnectionHandler {
   pub connection: Rc<xcb::Connection>,
}

impl ConnectionHandler {
   #[inline]
   pub fn new(display: &X11DisplayHandler) -> Result<Self, RuntimeError> {
      Ok(ConnectionHandler {
         connection: Rc::new(try!(display.connection()))
      })
   }

   #[inline]
   pub fn screen_of_display(&self, display: &X11DisplayHandler) -> Result<xcb::Screen, RuntimeError> {
      let screen_id = display.screen_id();

      self.connection.screen_of_display(&screen_id)
   }
}

pub struct ScreenHandler {
   pub screen: xcb::Screen,
}

impl ScreenHandler {
   #[inline]
   pub fn new(display: &X11DisplayHandler, connection: &ConnectionHandler) -> Result<Self, RuntimeError> {
      Ok(ScreenHandler {
         screen: try!(connection.screen_of_display(display))
      })
   }

   #[inline]
   pub fn size(&self) -> (u32, u32) {
      (
         self.screen.width_in_pixels() as u32,
         self.screen.height_in_pixels() as u32
      )
   }

   #[inline]
   pub fn create_window(
      &self, connection: &ConnectionHandler, x: u32, y: u32, width: u32, height: u32
   ) -> Result<xcb::Window, RuntimeError> {

      xcb::Window::create(
         &connection.connection, &self.screen, x, y, width, height,
      )
   }
}

pub struct EglDisplayHandler {
   pub display: egl::Display,
   pub version: egl::Version,
   pub config: egl::Config,
   pub context: egl::Context,
}

impl EglDisplayHandler {
   pub fn new(x11_display: &X11DisplayHandler) -> Result<Self, RuntimeError> {
      try!(egl::bind_api(egl::API::OpenGL));

      let display = try!(egl::Display::from_native(&x11_display.display));
      let version = try!(egl::initialize(&display));
      let config = try!(egl::choose_config(&display));
      let context = try!(egl::create_context(&display, &config));

      try!(egl::query_context(&display, &context));

      Ok(EglDisplayHandler {
         display: display,
         version: version,
         config: config,
         context: context,
      })
   }

   #[inline]
   pub fn create_surface(&self, xcb_window: &xcb::Window) -> Result<egl::Surface, RuntimeError> {
      egl::create_window_surface(
         &self.display,
         &self.config,
         &xcb_window.window_id.id
      )
   }

   #[inline]
   pub fn make_current(&self, surface: &EglSurfaceHandler) -> Result<(), RuntimeError> {
      egl::make_current(
         &self.display,
         &surface.surface,
         &surface.surface,
         &self.context
      )
   }
}

pub struct EglSurfaceHandler {
   pub surface: egl::Surface,
}

impl EglSurfaceHandler {
   #[inline]
   pub fn new(display: &EglDisplayHandler, xcb_window: &xcb::Window) -> Result<Self, RuntimeError> {
      let surface = try!(display.create_surface(xcb_window));

      Ok(EglSurfaceHandler {
         surface: surface,
      })
   }
}
<commit_msg>gl::reset_pixelstore_alignment in LinuxApplication::new<commit_after>use std::rc::Rc;

use error::RuntimeError;

use sys::x11;
use sys::xcb;
use sys::egl;
use sys::gl;

use super::window::LinuxWindow;

pub struct LinuxApplication {
   pub x11_display: X11DisplayHandler,
   pub connection: ConnectionHandler,
   pub screen: ScreenHandler,
   pub egl_display: EglDisplayHandler,
}

impl LinuxApplication {
   pub fn new() -> Result<Self, RuntimeError> {
      let x11_display = try!(X11DisplayHandler::new());
      let connection = try!(ConnectionHandler::new(&x11_display));
      let screen = try!(ScreenHandler::new(&x11_display, &connection));
      let egl_display = try!(EglDisplayHandler::new(&x11_display));

      gl::load(egl::Loader::new());
      gl::reset_pixelstore_alignment();

      Ok(LinuxApplication {
         x11_display: x11_display,
         connection: connection,
         screen: screen,
         egl_display: egl_display,
      })
   }

   #[inline]
   pub fn screen_size(&self) -> (u32, u32) {
      self.screen.size()
   }

   pub fn create_os_window(
      &self, title: &str, x: u32, y: u32, width: u32, height: u32
   ) -> Result<LinuxWindow, RuntimeError> {
      let xcb_window = try!(self.screen.create_window(
         &self.connection, x, y, width, height
      ));

      let surface = try!(EglSurfaceHandler::new(&self.egl_display, &xcb_window));

      try!(self.egl_display.make_current(&surface));

      Ok(LinuxWindow::new(xcb_window, surface, title))
   }
}

pub struct X11DisplayHandler {
   pub display: x11::Display,
}

impl X11DisplayHandler {
   #[inline]
   pub fn new() -> Result<Self, RuntimeError> {
      let display = try!(x11::Display::default());

      display.xcb_own_event_queue();

      Ok(X11DisplayHandler {
         display: display
      })
   }

   #[inline]
   pub fn connection(&self) -> Result<xcb::Connection, RuntimeError> {
      self.display.xcb_connection()
   }

   #[inline]
   pub fn screen_id(&self) -> x11::ScreenID {
      self.display.default_screen()
   }
}

pub struct ConnectionHandler {
   pub connection: Rc<xcb::Connection>,
}

impl ConnectionHandler {
   #[inline]
   pub fn new(display: &X11DisplayHandler) -> Result<Self, RuntimeError> {
      Ok(ConnectionHandler {
         connection: Rc::new(try!(display.connection()))
      })
   }

   #[inline]
   pub fn screen_of_display(&self, display: &X11DisplayHandler) -> Result<xcb::Screen, RuntimeError> {
      let screen_id = display.screen_id();

      self.connection.screen_of_display(&screen_id)
   }
}

pub struct ScreenHandler {
   pub screen: xcb::Screen,
}

impl ScreenHandler {
   #[inline]
   pub fn new(display: &X11DisplayHandler, connection: &ConnectionHandler) -> Result<Self, RuntimeError> {
      Ok(ScreenHandler {
         screen: try!(connection.screen_of_display(display))
      })
   }

   #[inline]
   pub fn size(&self) -> (u32, u32) {
      (
         self.screen.width_in_pixels() as u32,
         self.screen.height_in_pixels() as u32
      )
   }

   #[inline]
   pub fn create_window(
      &self, connection: &ConnectionHandler, x: u32, y: u32, width: u32, height: u32
   ) -> Result<xcb::Window, RuntimeError> {

      xcb::Window::create(
         &connection.connection, &self.screen, x, y, width, height,
      )
   }
}

pub struct EglDisplayHandler {
   pub display: egl::Display,
   pub version: egl::Version,
   pub config: egl::Config,
   pub context: egl::Context,
}

impl EglDisplayHandler {
   pub fn new(x11_display: &X11DisplayHandler) -> Result<Self, RuntimeError> {
      try!(egl::bind_api(egl::API::OpenGL));

      let display = try!(egl::Display::from_native(&x11_display.display));
      let version = try!(egl::initialize(&display));
      let config = try!(egl::choose_config(&display));
      let context = try!(egl::create_context(&display, &config));

      try!(egl::query_context(&display, &context));

      Ok(EglDisplayHandler {
         display: display,
         version: version,
         config: config,
         context: context,
      })
   }

   #[inline]
   pub fn create_surface(&self, xcb_window: &xcb::Window) -> Result<egl::Surface, RuntimeError> {
      egl::create_window_surface(
         &self.display,
         &self.config,
         &xcb_window.window_id.id
      )
   }

   #[inline]
   pub fn make_current(&self, surface: &EglSurfaceHandler) -> Result<(), RuntimeError> {
      egl::make_current(
         &self.display,
         &surface.surface,
         &surface.surface,
         &self.context
      )
   }
}

pub struct EglSurfaceHandler {
   pub surface: egl::Surface,
}

impl EglSurfaceHandler {
   #[inline]
   pub fn new(display: &EglDisplayHandler, xcb_window: &xcb::Window) -> Result<Self, RuntimeError> {
      let surface = try!(display.create_surface(xcb_window));

      Ok(EglSurfaceHandler {
         surface: surface,
      })
   }
}
<|endoftext|>


<commit_before>//! SHM handling helpers
//!
//! This module provides helpers to handle SHM-based buffers from wayland clients.
//!
//! SHM (Shared Memory) is the most basic way wayland clients can send content to
//! the compositor: by sending a file descriptor to some (likely RAM-backed) storage
//! containing the actual data. This helper handles for you most of the logic for
//! handling these file descriptor and accessing their contents as simple `&[u8]` slices.
//!
//! This module is heavily inspired from
//! [the similar helpers](https://cgit.freedesktop.org/wayland/wayland/tree/src/wayland-shm.c)
//! of the wayland C libraries.
//!
//! To use it, first add a `ShmGlobal` to your display, specifying the formats
//! you want to support (ARGB8888 and XRGB8888 are always considered as supported,
//! as specified by the wayland protocol).
//!
//! ```
//! extern crate wayland_server;
//! extern crate smithay;
//!
//! use smithay::wayland::shm::init_shm_global;
//! use wayland_server::protocol::wl_shm::Format;
//!
//! # let mut display = wayland_server::Display::new();
//! // Insert the ShmGlobal into your event loop
//! // Here, we specify that Yuyv and C8 format are supported
//! // additionally to the standard Argb8888 and Xrgb8888.
//! init_shm_global(
//!     &mut display,
//!     vec![Format::Yuyv, Format::C8],
//!     None // we don't provide a logger here
//! );
//! ```
//!
//! Then, when you have a [`WlBuffer`](wayland_server::protocol::wl_buffer::WlBuffer)
//! and need to retrieve its contents, use the
//! [`with_buffer_contents`] function to do it:
//!
//! ```
//! # extern crate wayland_server;
//! # extern crate smithay;
//! # use smithay::wayland::buffer::Buffer;
//! # fn wrap(buffer: &Buffer) {
//! use smithay::wayland::shm::{with_buffer_contents, BufferData, BufferAccessError};
//!
//! let content = with_buffer_contents(&buffer,
//!     |slice: &[u8], buffer_metadata: BufferData| {
//!         // do something to extract the contents of the buffer
//!     }
//! );
//!
//! match content {
//!     Ok(something) =>  {
//!         /* `something` is the value you returned from the closure */
//!     },
//!     Err(BufferAccessError::NotManaged) => {
//!         /* This buffer is not managed by the SHM global, but by something else */
//!     },
//!     Err(BufferAccessError::BadMap) => {
//!         /* The client supplied invalid content specification for this buffer,
//!            and was killed.
//!          */
//!     }
//! }
//! # }
//! ```
//!
//! **Note**
//!
//! This handler makes itself safe regarding the client providing a wrong size for the memory pool
//! by using a SIGBUS handler.
//!
//! If you are already using an handler for this signal, you probably don't want to use this handler.

use std::sync::Arc;

use wayland_server::{
    backend::GlobalId,
    protocol::{
        wl_buffer,
        wl_shm::{self, WlShm},
        wl_shm_pool::WlShmPool,
    },
    Dispatch, DisplayHandle, GlobalDispatch, Resource,
};

mod handlers;
mod pool;

use crate::utils::UnmanagedResource;

use self::pool::Pool;

use super::buffer::BufferHandler;

/// State of SHM module
#[derive(Debug)]
pub struct ShmState {
    formats: Vec<wl_shm::Format>,
    shm: GlobalId,
    log: ::slog::Logger,
}

impl ShmState {
    /// Create a new SHM global advertizing the given formats.
    ///
    /// This global will always advertize `ARGB8888` and `XRGB8888` since these formats are required by the
    /// protocol. Formats given as an argument are also advertized.
    ///
    /// The global is directly created on the provided [`Display`](wayland_server::Display),
    /// and this function returns the a delegate type. The id provided by [`ShmState::global`] may be used to
    /// remove this global in the future.
    pub fn new<D, L>(display: &DisplayHandle, mut formats: Vec<wl_shm::Format>, logger: L) -> ShmState
    where
        D: GlobalDispatch<WlShm, ()>
            + Dispatch<WlShm, ()>
            + Dispatch<WlShmPool, ShmPoolUserData>
            + BufferHandler
            + AsRef<ShmState>
            + 'static,
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_fallback(logger);

        // Mandatory formats
        formats.push(wl_shm::Format::Argb8888);
        formats.push(wl_shm::Format::Xrgb8888);

        let shm = display.create_global::<D, WlShm, _>(1, ());

        ShmState {
            formats,
            shm,
            log: log.new(slog::o!("smithay_module" => "shm_handler")),
        }
    }

    /// Returns the id of the [`WlShm`] global.
    pub fn global(&self) -> GlobalId {
        self.shm.clone()
    }
}

/// Error that can occur when accessing an SHM buffer
#[derive(Debug, thiserror::Error)]
pub enum BufferAccessError {
    /// This buffer is not managed by the SHM handler
    #[error("non-SHM buffer")]
    NotManaged,

    /// An error occurred while accessing the memory map
    ///
    /// This can happen if the client advertized a wrong size
    /// for the memory map.
    ///
    /// If this error occurs, the client has been killed as a result.
    #[error("invalid client buffer")]
    BadMap,
}

impl From<UnmanagedResource> for BufferAccessError {
    fn from(_: UnmanagedResource) -> Self {
        Self::NotManaged
    }
}

/// Call given closure with the contents of the given buffer
///
/// If the buffer is managed by the provided `ShmGlobal`, its contents are
/// extracted and the closure is extracted with them:
///
/// - The first argument is a data slice of the contents of the pool
/// - The second argument is the specification of this buffer is this pool
///
/// If the buffer is not managed by the provided `ShmGlobal`, the closure is not called
/// and this method will return `Err(BufferAccessError::NotManaged)` (this will be the case for an
/// EGL buffer for example).
pub fn with_buffer_contents<F, T>(buffer: &wl_buffer::WlBuffer, f: F) -> Result<T, BufferAccessError>
where
    F: FnOnce(&[u8], BufferData) -> T,
{
    let data = buffer
        .data::<ShmBufferUserData>()
        .ok_or(BufferAccessError::NotManaged)?;

    match data.pool.with_data_slice(|slice| f(slice, data.data)) {
        Ok(t) => Ok(t),
        Err(()) => {
            // SIGBUS error occurred
            // FIXME: This error should be emitted.
            // buffer.post_error(display_handle, wl_shm::Error::InvalidFd, "Bad pool size.");
            Err(BufferAccessError::BadMap)
        }
    }
}

/// Details of the contents of a buffer relative to its pool
#[derive(Copy, Clone, Debug)]
pub struct BufferData {
    /// Offset of the start of the buffer relative to the beginning of the pool in bytes
    pub offset: i32,
    /// Width of the buffer in bytes
    pub width: i32,
    /// Height of the buffer in bytes
    pub height: i32,
    /// Stride of the buffer in bytes
    pub stride: i32,
    /// Format used by this buffer
    pub format: wl_shm::Format,
}

/// User data of WlShmPool
#[derive(Debug)]
pub struct ShmPoolUserData {
    inner: Arc<Pool>,
}

/// User data of shm WlBuffer
#[derive(Debug)]
pub struct ShmBufferUserData {
    pub(crate) pool: Arc<Pool>,
    pub(crate) data: BufferData,
}

#[allow(missing_docs)] // TODO
#[macro_export]
macro_rules! delegate_shm {
    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
        $crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_server::protocol::wl_shm::WlShm: ()
        ] => $crate::wayland::shm::ShmState);

        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_server::protocol::wl_shm::WlShm: ()
        ] => $crate::wayland::shm::ShmState);
        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_server::protocol::wl_shm_pool::WlShmPool: $crate::wayland::shm::ShmPoolUserData
        ] => $crate::wayland::shm::ShmState);
        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_server::protocol::wl_buffer::WlBuffer: $crate::wayland::shm::ShmBufferUserData
        ] => $crate::wayland::shm::ShmState);
    };
}
<commit_msg>Fix shm TODO<commit_after>//! SHM handling helpers
//!
//! This module provides helpers to handle SHM-based buffers from wayland clients.
//!
//! SHM (Shared Memory) is the most basic way wayland clients can send content to
//! the compositor: by sending a file descriptor to some (likely RAM-backed) storage
//! containing the actual data. This helper handles for you most of the logic for
//! handling these file descriptor and accessing their contents as simple `&[u8]` slices.
//!
//! This module is heavily inspired from
//! [the similar helpers](https://cgit.freedesktop.org/wayland/wayland/tree/src/wayland-shm.c)
//! of the wayland C libraries.
//!
//! To use it, first add a `ShmGlobal` to your display, specifying the formats
//! you want to support (ARGB8888 and XRGB8888 are always considered as supported,
//! as specified by the wayland protocol).
//!
//! ```
//! extern crate wayland_server;
//! extern crate smithay;
//!
//! use smithay::wayland::shm::init_shm_global;
//! use wayland_server::protocol::wl_shm::Format;
//!
//! # let mut display = wayland_server::Display::new();
//! // Insert the ShmGlobal into your event loop
//! // Here, we specify that Yuyv and C8 format are supported
//! // additionally to the standard Argb8888 and Xrgb8888.
//! init_shm_global(
//!     &mut display,
//!     vec![Format::Yuyv, Format::C8],
//!     None // we don't provide a logger here
//! );
//! ```
//!
//! Then, when you have a [`WlBuffer`](wayland_server::protocol::wl_buffer::WlBuffer)
//! and need to retrieve its contents, use the
//! [`with_buffer_contents`] function to do it:
//!
//! ```
//! # extern crate wayland_server;
//! # extern crate smithay;
//! # use smithay::wayland::buffer::Buffer;
//! # fn wrap(buffer: &Buffer) {
//! use smithay::wayland::shm::{with_buffer_contents, BufferData, BufferAccessError};
//!
//! let content = with_buffer_contents(&buffer,
//!     |slice: &[u8], buffer_metadata: BufferData| {
//!         // do something to extract the contents of the buffer
//!     }
//! );
//!
//! match content {
//!     Ok(something) =>  {
//!         /* `something` is the value you returned from the closure */
//!     },
//!     Err(BufferAccessError::NotManaged) => {
//!         /* This buffer is not managed by the SHM global, but by something else */
//!     },
//!     Err(BufferAccessError::BadMap) => {
//!         /* The client supplied invalid content specification for this buffer,
//!            and was killed.
//!          */
//!     }
//! }
//! # }
//! ```
//!
//! **Note**
//!
//! This handler makes itself safe regarding the client providing a wrong size for the memory pool
//! by using a SIGBUS handler.
//!
//! If you are already using an handler for this signal, you probably don't want to use this handler.

use std::sync::Arc;

use wayland_server::{
    backend::GlobalId,
    protocol::{
        wl_buffer,
        wl_shm::{self, WlShm},
        wl_shm_pool::WlShmPool,
    },
    Dispatch, DisplayHandle, GlobalDispatch, Resource,
};

mod handlers;
mod pool;

use crate::utils::UnmanagedResource;

use self::pool::Pool;

use super::buffer::BufferHandler;

/// State of SHM module
#[derive(Debug)]
pub struct ShmState {
    formats: Vec<wl_shm::Format>,
    shm: GlobalId,
    log: ::slog::Logger,
}

impl ShmState {
    /// Create a new SHM global advertizing the given formats.
    ///
    /// This global will always advertize `ARGB8888` and `XRGB8888` since these formats are required by the
    /// protocol. Formats given as an argument are also advertized.
    ///
    /// The global is directly created on the provided [`Display`](wayland_server::Display),
    /// and this function returns the a delegate type. The id provided by [`ShmState::global`] may be used to
    /// remove this global in the future.
    pub fn new<D, L>(display: &DisplayHandle, mut formats: Vec<wl_shm::Format>, logger: L) -> ShmState
    where
        D: GlobalDispatch<WlShm, ()>
            + Dispatch<WlShm, ()>
            + Dispatch<WlShmPool, ShmPoolUserData>
            + BufferHandler
            + AsRef<ShmState>
            + 'static,
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_fallback(logger);

        // Mandatory formats
        formats.push(wl_shm::Format::Argb8888);
        formats.push(wl_shm::Format::Xrgb8888);

        let shm = display.create_global::<D, WlShm, _>(1, ());

        ShmState {
            formats,
            shm,
            log: log.new(slog::o!("smithay_module" => "shm_handler")),
        }
    }

    /// Returns the id of the [`WlShm`] global.
    pub fn global(&self) -> GlobalId {
        self.shm.clone()
    }
}

/// Error that can occur when accessing an SHM buffer
#[derive(Debug, thiserror::Error)]
pub enum BufferAccessError {
    /// This buffer is not managed by the SHM handler
    #[error("non-SHM buffer")]
    NotManaged,

    /// An error occurred while accessing the memory map
    ///
    /// This can happen if the client advertized a wrong size
    /// for the memory map.
    ///
    /// If this error occurs, the client has been killed as a result.
    #[error("invalid client buffer")]
    BadMap,
}

impl From<UnmanagedResource> for BufferAccessError {
    fn from(_: UnmanagedResource) -> Self {
        Self::NotManaged
    }
}

/// Call given closure with the contents of the given buffer
///
/// If the buffer is managed by the provided `ShmGlobal`, its contents are
/// extracted and the closure is extracted with them:
///
/// - The first argument is a data slice of the contents of the pool
/// - The second argument is the specification of this buffer is this pool
///
/// If the buffer is not managed by the provided `ShmGlobal`, the closure is not called
/// and this method will return `Err(BufferAccessError::NotManaged)` (this will be the case for an
/// EGL buffer for example).
pub fn with_buffer_contents<F, T>(buffer: &wl_buffer::WlBuffer, f: F) -> Result<T, BufferAccessError>
where
    F: FnOnce(&[u8], BufferData) -> T,
{
    let data = buffer
        .data::<ShmBufferUserData>()
        .ok_or(BufferAccessError::NotManaged)?;

    match data.pool.with_data_slice(|slice| f(slice, data.data)) {
        Ok(t) => Ok(t),
        Err(()) => {
            // SIGBUS error occurred
            buffer.post_error(wl_shm::Error::InvalidFd, "Bad pool size.");
            Err(BufferAccessError::BadMap)
        }
    }
}

/// Details of the contents of a buffer relative to its pool
#[derive(Copy, Clone, Debug)]
pub struct BufferData {
    /// Offset of the start of the buffer relative to the beginning of the pool in bytes
    pub offset: i32,
    /// Width of the buffer in bytes
    pub width: i32,
    /// Height of the buffer in bytes
    pub height: i32,
    /// Stride of the buffer in bytes
    pub stride: i32,
    /// Format used by this buffer
    pub format: wl_shm::Format,
}

/// User data of WlShmPool
#[derive(Debug)]
pub struct ShmPoolUserData {
    inner: Arc<Pool>,
}

/// User data of shm WlBuffer
#[derive(Debug)]
pub struct ShmBufferUserData {
    pub(crate) pool: Arc<Pool>,
    pub(crate) data: BufferData,
}

#[allow(missing_docs)] // TODO
#[macro_export]
macro_rules! delegate_shm {
    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
        $crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_server::protocol::wl_shm::WlShm: ()
        ] => $crate::wayland::shm::ShmState);

        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_server::protocol::wl_shm::WlShm: ()
        ] => $crate::wayland::shm::ShmState);
        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_server::protocol::wl_shm_pool::WlShmPool: $crate::wayland::shm::ShmPoolUserData
        ] => $crate::wayland::shm::ShmState);
        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_server::protocol::wl_buffer::WlBuffer: $crate::wayland::shm::ShmBufferUserData
        ] => $crate::wayland::shm::ShmState);
    };
}
<|endoftext|>


<commit_before>use rustbox::keyboard::Key;
use rustbox::{RustBox, Color};
use rustbox;
use time::Tm;

use tui::messaging::MessagingUI;
use tui::MsgTarget;
use tui::widget::{Widget, WidgetRet};

use utils::opt_to_vec;

// TODO: How to reorder tabs?
// TODO: How to report errors?

pub struct Tabbed {
    tabs       : Vec<Tab>,
    active_idx : Option<usize>,
    width      : i32,
    height     : i32,
}

struct Tab {
    widget : MessagingUI,
    src    : MsgSource,
}

/// TUI source of a message from the user.
#[derive(Debug, Clone)]
pub enum MsgSource {
    /// Message sent to a server tab.
    Serv { serv_name : String },

    /// Message sent to a channel tab.
    Chan { serv_name : String, chan_name : String },

    /// Message sent to a privmsg tab.
    User { serv_name : String, nick : String },
}

impl MsgSource {
    pub fn serv_name<'a>(&'a self) -> &'a str {
        match self {
            &MsgSource::Serv { ref serv_name } => serv_name,
            &MsgSource::Chan { ref serv_name, .. } => serv_name,
            &MsgSource::User { ref serv_name, .. } => serv_name,
        }
    }
}

impl Tab {
    pub fn visible_name<'a>(&'a self) -> &'a str {
        match &self.src {
            &MsgSource::Serv { ref serv_name, .. } => serv_name,
            &MsgSource::Chan { ref chan_name, .. } => chan_name,
            &MsgSource::User { ref nick, .. } => nick,
        }
    }
}

pub enum TabbedRet<'t> {
    KeyHandled,
    KeyIgnored,

    Input {
        msg  : Vec<char>,
        from : &'t MsgSource,
    },
}

impl Tabbed {
    pub fn new(width : i32, height : i32) -> Tabbed {
        Tabbed {
            tabs: Vec::new(),
            active_idx: None,
            width: width,
            height: height,
        }
    }

    /// Returns index of the new tab if a new tab is created.
    pub fn new_server_tab(&mut self, serv_name : &str) -> Option<usize> {
        match self.find_serv_tab_idx(&serv_name) {
            None => {
                self.tabs.push(Tab {
                    widget: MessagingUI::new(self.width, self.height - 1),
                    src: MsgSource::Serv { serv_name: serv_name.to_owned() },
                });
                self.active_idx = Some(self.tabs.len() - 1);
                Some(self.tabs.len() - 1)
            },
            Some(tab_idx) => {
                self.active_idx = Some(tab_idx);
                None
            }
        }
    }

    /// Returns index of the new tab if a new tab is created.
    pub fn new_chan_tab(&mut self, serv_name : &str, chan_name : &str) -> Option<usize> {
        match self.find_chan_tab_idx(&serv_name, &chan_name) {
            None => {
                match self.find_last_serv_tab_idx(&serv_name) {
                    None => {
                        self.new_server_tab(serv_name);
                        self.new_chan_tab(serv_name, chan_name)
                    },
                    Some(tab_idx) => {
                        self.tabs.insert(tab_idx + 1, Tab {
                            widget: MessagingUI::new(self.width, self.height - 1),
                            src: MsgSource::Chan { serv_name: serv_name.to_owned(),
                                                   chan_name: chan_name.to_owned() },
                        });
                        self.active_idx = Some(tab_idx + 1);
                        Some(tab_idx + 1)
                    }
                }
            },
            Some(tab_idx) => {
                self.active_idx = Some(tab_idx);
                None
            }
        }
    }

    /// Returns index of the new tab if a new tab is created.
    pub fn new_user_tab(&mut self, serv_name : &str, nick : &str) -> Option<usize> {
        match self.find_user_tab_idx(serv_name, nick) {
            None => {
                match self.find_last_serv_tab_idx(&serv_name) {
                    None => {
                        self.new_server_tab(serv_name);
                        self.new_user_tab(serv_name, nick)
                    },
                    Some(tab_idx) => {
                        self.tabs.insert(tab_idx + 1, Tab {
                            widget: MessagingUI::new(self.width, self.height - 1),
                            src: MsgSource::User { serv_name: serv_name.to_owned(),
                                                   nick: nick.to_owned() },
                        });
                        self.active_idx = Some(tab_idx + 1);
                        Some(tab_idx + 1)
                    }
                }
            },
            Some(tab_idx) => {
                self.active_idx = Some(tab_idx);
                None
            }
        }
    }

    pub fn draw(&self, rustbox : &RustBox, pos_x : i32, pos_y : i32) {
        match self.active_idx {
            None => {},
            Some(idx) => self.tabs[idx as usize].widget.draw(rustbox, pos_x, pos_y),
        }

        let mut tab_name_col = 0;
        for (tab_idx, tab) in self.tabs.iter().enumerate() {
            if self.active_idx == Some(tab_idx) {
                rustbox.print(tab_name_col, (self.height as usize) - 1,
                              rustbox::RB_BOLD, Color::White, Color::Blue, tab.visible_name());
            } else {
                rustbox.print(tab_name_col, (self.height as usize) - 1,
                              rustbox::RB_BOLD, Color::White, Color::Default, tab.visible_name());
            }
            // len() is OK since sever, chan and nick names are ascii
            tab_name_col += tab.visible_name().len();
        }
    }

    pub fn keypressed(&mut self, key : Key) -> TabbedRet {
        if key == Key::Tab {
            if self.tabs.len() > 0 {
                self.active_idx = Some((self.active_idx.unwrap() + 1) % self.tabs.len());
            }
            return TabbedRet::KeyHandled;
        }

        match self.active_idx {
            None => TabbedRet::KeyIgnored,
            Some(idx) => {
                match self.tabs[idx as usize].widget.keypressed(key) {
                    WidgetRet::KeyHandled => TabbedRet::KeyHandled,
                    WidgetRet::KeyIgnored => TabbedRet::KeyIgnored,
                    WidgetRet::Input(input) => {
                        TabbedRet::Input {
                            msg: input,
                            from: &self.tabs[idx as usize].src
                        }
                    },
                }
            }
        }
    }

    pub fn resize(&mut self, width : i32, height : i32) {
        for tab in self.tabs.iter_mut() {
            tab.widget.resize(width, height - 1);
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    // Interfacing with tabs

    fn apply_to_target<F>(&mut self, target : &MsgTarget, f : &F)
            where F : Fn(&mut Tab) -> () {

        // Creating a vector just to make borrow checker happy. Borrow checker
        // sucks once more. Here it sucks 2x, I can't even create a Vec<&mut Tab>,
        // I need a Vec<usize>.
        //
        // (I could use an array on stack but whatever)
        let mut target_idxs : Vec<usize> = Vec::with_capacity(self.tabs.len());

        match target {
            &MsgTarget::Server { serv_name } => {
                for (tab_idx, tab) in self.tabs.iter().enumerate() {
                    match &tab.src {
                        &MsgSource::Serv { serv_name: ref serv_name_ } => {
                            if serv_name == serv_name_ {
                                target_idxs.push(tab_idx);
                                break;
                            }
                        },
                        _ => {}
                    }
                }
            },

            &MsgTarget::Chan { serv_name, chan_name } => {
                for (tab_idx, tab) in self.tabs.iter().enumerate() {
                    match &tab.src {
                        &MsgSource::Chan { serv_name: ref serv_name_, chan_name: ref chan_name_ } => {
                            if serv_name == serv_name_ && chan_name == chan_name_ {
                                target_idxs.push(tab_idx);
                                break;
                            }
                        },
                        _ => {}
                    }
                }
            },

            &MsgTarget::User { serv_name, nick } => {
                for (tab_idx, tab) in self.tabs.iter().enumerate() {
                    match &tab.src {
                        &MsgSource::User { serv_name: ref serv_name_, nick: ref nick_ } => {
                            if serv_name == serv_name_ && nick == nick_ {
                                target_idxs.push(tab_idx);
                                break;
                            }
                        },
                        _ => {}
                    }
                }
            },

            &MsgTarget::AllServTabs { serv_name } => {
                for (tab_idx, tab) in self.tabs.iter().enumerate() {
                    if tab.src.serv_name() == serv_name {
                        target_idxs.push(tab_idx);
                    }
                }
            },

            &MsgTarget::AllTabs => {
                for tab_idx in 0 .. self.tabs.len() {
                    target_idxs.push(tab_idx);
                }
            },

            &MsgTarget::CurrentTab => {
                target_idxs.push(self.active_idx.unwrap());
            },

            &MsgTarget::MultipleTabs(ref targets) => {
                for target in targets.iter() {
                    self.apply_to_target(target, f);
                }
            }
        }

        // Create server/chan/user tab when necessary
        if target_idxs.len() == 0 {
            for idx in self.maybe_create_tab(target) {
                target_idxs.push(idx);
            }
        }

        for tab_idx in target_idxs {
            f(unsafe { self.tabs.get_unchecked_mut(tab_idx) });
        }
    }

    fn maybe_create_tab(&mut self, target : &MsgTarget) -> Vec<usize> {
        match target {
            &MsgTarget::Server { serv_name } => {
                opt_to_vec(self.new_server_tab(serv_name))
            },

            &MsgTarget::Chan { serv_name, chan_name } => {
                opt_to_vec(self.new_chan_tab(serv_name, chan_name))
            },

            &MsgTarget::User { serv_name, nick } => {
                opt_to_vec(self.new_user_tab(serv_name, nick))
            },

            &MsgTarget::MultipleTabs(ref targets) => {
                targets.iter().flat_map(|t : &Box<MsgTarget>| self.maybe_create_tab(&*t)).collect()
            }

            _ => vec![]
        }
    }

    #[inline]
    pub fn add_client_err_msg(&mut self, msg : &str, target : &MsgTarget) {
        self.apply_to_target(target, &|tab : &mut Tab| {
            tab.widget.add_client_err_msg(msg);
        });
    }

    #[inline]
    pub fn add_client_msg(&mut self, msg : &str, target : &MsgTarget) {
        self.apply_to_target(target, &|tab : &mut Tab| {
            tab.widget.add_client_msg(msg);
        });
    }

    #[inline]
    pub fn add_privmsg(&mut self, sender : &str, msg : &str, tm : &Tm, target : &MsgTarget) {
        self.apply_to_target(target, &|tab : &mut Tab| {
            tab.widget.add_privmsg(sender, msg, tm);
        });
    }

    #[inline]
    pub fn add_msg(&mut self, msg : &str, tm : &Tm, target : &MsgTarget) {
        self.apply_to_target(target, &|tab : &mut Tab| {
            tab.widget.add_msg(msg, tm);
        });
    }

    #[inline]
    pub fn add_err_msg(&mut self, msg : &str, tm : &Tm, target : &MsgTarget) {
        self.apply_to_target(target, &|tab : &mut Tab| {
            tab.widget.add_err_msg(msg, tm);
        });
    }

    #[inline]
    pub fn set_topic(&mut self, title : &str, target : &MsgTarget) {
        self.apply_to_target(target, &|tab : &mut Tab| {
            tab.widget.set_topic(title.to_owned());
        });
    }

    ////////////////////////////////////////////////////////////////////////////
    // Helpers

    fn find_serv_tab_idx(&self, serv_name_ : &str) -> Option<usize> {
        for (tab_idx, tab) in self.tabs.iter().enumerate() {
            match &tab.src {
                &MsgSource::Serv { ref serv_name } => {
                    if serv_name_ == serv_name {
                        return Some(tab_idx);
                    }
                },
                _ => {},
            }
        }
        None
    }

    fn find_chan_tab_idx(&self, serv_name_ : &str, chan_name_ : &str) -> Option<usize> {
        for (tab_idx, tab) in self.tabs.iter().enumerate() {
            match &tab.src {
                &MsgSource::Chan { ref serv_name, ref chan_name } => {
                    if serv_name_ == serv_name && chan_name_ == chan_name {
                        return Some(tab_idx);
                    }
                },
                _ => {},
            }
        }
        None
    }

    fn find_user_tab_idx(&self, serv_name_ : &str, nick_ : &str) -> Option<usize> {
        for (tab_idx, tab) in self.tabs.iter().enumerate() {
            match &tab.src {
                &MsgSource::User { ref serv_name, ref nick } => {
                    if serv_name_ == serv_name && nick_ == nick {
                        return Some(tab_idx);
                    }
                },
                _ => {},
            }
        }
        None
    }

    /// Index of the last tab with the given server name.
    fn find_last_serv_tab_idx(&self, serv_name : &str) -> Option<usize> {
        for (tab_idx, tab) in self.tabs.iter().enumerate().rev() {
            if tab.src.serv_name() == serv_name {
                return Some(tab_idx);
            }
        }
        None
    }
}
<commit_msg>add_msg: I think one tab is the norm<commit_after>use rustbox::keyboard::Key;
use rustbox::{RustBox, Color};
use rustbox;
use time::Tm;

use tui::messaging::MessagingUI;
use tui::MsgTarget;
use tui::widget::{Widget, WidgetRet};

use utils::opt_to_vec;

// TODO: How to reorder tabs?
// TODO: How to report errors?

pub struct Tabbed {
    tabs       : Vec<Tab>,
    active_idx : Option<usize>,
    width      : i32,
    height     : i32,
}

struct Tab {
    widget : MessagingUI,
    src    : MsgSource,
}

/// TUI source of a message from the user.
#[derive(Debug, Clone)]
pub enum MsgSource {
    /// Message sent to a server tab.
    Serv { serv_name : String },

    /// Message sent to a channel tab.
    Chan { serv_name : String, chan_name : String },

    /// Message sent to a privmsg tab.
    User { serv_name : String, nick : String },
}

impl MsgSource {
    pub fn serv_name<'a>(&'a self) -> &'a str {
        match self {
            &MsgSource::Serv { ref serv_name } => serv_name,
            &MsgSource::Chan { ref serv_name, .. } => serv_name,
            &MsgSource::User { ref serv_name, .. } => serv_name,
        }
    }
}

impl Tab {
    pub fn visible_name<'a>(&'a self) -> &'a str {
        match &self.src {
            &MsgSource::Serv { ref serv_name, .. } => serv_name,
            &MsgSource::Chan { ref chan_name, .. } => chan_name,
            &MsgSource::User { ref nick, .. } => nick,
        }
    }
}

pub enum TabbedRet<'t> {
    KeyHandled,
    KeyIgnored,

    Input {
        msg  : Vec<char>,
        from : &'t MsgSource,
    },
}

impl Tabbed {
    pub fn new(width : i32, height : i32) -> Tabbed {
        Tabbed {
            tabs: Vec::new(),
            active_idx: None,
            width: width,
            height: height,
        }
    }

    /// Returns index of the new tab if a new tab is created.
    pub fn new_server_tab(&mut self, serv_name : &str) -> Option<usize> {
        match self.find_serv_tab_idx(&serv_name) {
            None => {
                self.tabs.push(Tab {
                    widget: MessagingUI::new(self.width, self.height - 1),
                    src: MsgSource::Serv { serv_name: serv_name.to_owned() },
                });
                self.active_idx = Some(self.tabs.len() - 1);
                Some(self.tabs.len() - 1)
            },
            Some(tab_idx) => {
                self.active_idx = Some(tab_idx);
                None
            }
        }
    }

    /// Returns index of the new tab if a new tab is created.
    pub fn new_chan_tab(&mut self, serv_name : &str, chan_name : &str) -> Option<usize> {
        match self.find_chan_tab_idx(&serv_name, &chan_name) {
            None => {
                match self.find_last_serv_tab_idx(&serv_name) {
                    None => {
                        self.new_server_tab(serv_name);
                        self.new_chan_tab(serv_name, chan_name)
                    },
                    Some(tab_idx) => {
                        self.tabs.insert(tab_idx + 1, Tab {
                            widget: MessagingUI::new(self.width, self.height - 1),
                            src: MsgSource::Chan { serv_name: serv_name.to_owned(),
                                                   chan_name: chan_name.to_owned() },
                        });
                        self.active_idx = Some(tab_idx + 1);
                        Some(tab_idx + 1)
                    }
                }
            },
            Some(tab_idx) => {
                self.active_idx = Some(tab_idx);
                None
            }
        }
    }

    /// Returns index of the new tab if a new tab is created.
    pub fn new_user_tab(&mut self, serv_name : &str, nick : &str) -> Option<usize> {
        match self.find_user_tab_idx(serv_name, nick) {
            None => {
                match self.find_last_serv_tab_idx(&serv_name) {
                    None => {
                        self.new_server_tab(serv_name);
                        self.new_user_tab(serv_name, nick)
                    },
                    Some(tab_idx) => {
                        self.tabs.insert(tab_idx + 1, Tab {
                            widget: MessagingUI::new(self.width, self.height - 1),
                            src: MsgSource::User { serv_name: serv_name.to_owned(),
                                                   nick: nick.to_owned() },
                        });
                        self.active_idx = Some(tab_idx + 1);
                        Some(tab_idx + 1)
                    }
                }
            },
            Some(tab_idx) => {
                self.active_idx = Some(tab_idx);
                None
            }
        }
    }

    pub fn draw(&self, rustbox : &RustBox, pos_x : i32, pos_y : i32) {
        match self.active_idx {
            None => {},
            Some(idx) => self.tabs[idx as usize].widget.draw(rustbox, pos_x, pos_y),
        }

        let mut tab_name_col = 0;
        for (tab_idx, tab) in self.tabs.iter().enumerate() {
            if self.active_idx == Some(tab_idx) {
                rustbox.print(tab_name_col, (self.height as usize) - 1,
                              rustbox::RB_BOLD, Color::White, Color::Blue, tab.visible_name());
            } else {
                rustbox.print(tab_name_col, (self.height as usize) - 1,
                              rustbox::RB_BOLD, Color::White, Color::Default, tab.visible_name());
            }
            // len() is OK since sever, chan and nick names are ascii
            tab_name_col += tab.visible_name().len();
        }
    }

    pub fn keypressed(&mut self, key : Key) -> TabbedRet {
        if key == Key::Tab {
            if self.tabs.len() > 0 {
                self.active_idx = Some((self.active_idx.unwrap() + 1) % self.tabs.len());
            }
            return TabbedRet::KeyHandled;
        }

        match self.active_idx {
            None => TabbedRet::KeyIgnored,
            Some(idx) => {
                match self.tabs[idx as usize].widget.keypressed(key) {
                    WidgetRet::KeyHandled => TabbedRet::KeyHandled,
                    WidgetRet::KeyIgnored => TabbedRet::KeyIgnored,
                    WidgetRet::Input(input) => {
                        TabbedRet::Input {
                            msg: input,
                            from: &self.tabs[idx as usize].src
                        }
                    },
                }
            }
        }
    }

    pub fn resize(&mut self, width : i32, height : i32) {
        for tab in self.tabs.iter_mut() {
            tab.widget.resize(width, height - 1);
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    // Interfacing with tabs

    fn apply_to_target<F>(&mut self, target : &MsgTarget, f : &F)
            where F : Fn(&mut Tab) -> () {

        // Creating a vector just to make borrow checker happy. Borrow checker
        // sucks once more. Here it sucks 2x, I can't even create a Vec<&mut Tab>,
        // I need a Vec<usize>.
        //
        // (I could use an array on stack but whatever)
        let mut target_idxs : Vec<usize> = Vec::with_capacity(1);

        match target {
            &MsgTarget::Server { serv_name } => {
                for (tab_idx, tab) in self.tabs.iter().enumerate() {
                    match &tab.src {
                        &MsgSource::Serv { serv_name: ref serv_name_ } => {
                            if serv_name == serv_name_ {
                                target_idxs.push(tab_idx);
                                break;
                            }
                        },
                        _ => {}
                    }
                }
            },

            &MsgTarget::Chan { serv_name, chan_name } => {
                for (tab_idx, tab) in self.tabs.iter().enumerate() {
                    match &tab.src {
                        &MsgSource::Chan { serv_name: ref serv_name_, chan_name: ref chan_name_ } => {
                            if serv_name == serv_name_ && chan_name == chan_name_ {
                                target_idxs.push(tab_idx);
                                break;
                            }
                        },
                        _ => {}
                    }
                }
            },

            &MsgTarget::User { serv_name, nick } => {
                for (tab_idx, tab) in self.tabs.iter().enumerate() {
                    match &tab.src {
                        &MsgSource::User { serv_name: ref serv_name_, nick: ref nick_ } => {
                            if serv_name == serv_name_ && nick == nick_ {
                                target_idxs.push(tab_idx);
                                break;
                            }
                        },
                        _ => {}
                    }
                }
            },

            &MsgTarget::AllServTabs { serv_name } => {
                for (tab_idx, tab) in self.tabs.iter().enumerate() {
                    if tab.src.serv_name() == serv_name {
                        target_idxs.push(tab_idx);
                    }
                }
            },

            &MsgTarget::AllTabs => {
                for tab_idx in 0 .. self.tabs.len() {
                    target_idxs.push(tab_idx);
                }
            },

            &MsgTarget::CurrentTab => {
                target_idxs.push(self.active_idx.unwrap());
            },

            &MsgTarget::MultipleTabs(ref targets) => {
                for target in targets.iter() {
                    self.apply_to_target(target, f);
                }
            }
        }

        // Create server/chan/user tab when necessary
        if target_idxs.len() == 0 {
            for idx in self.maybe_create_tab(target) {
                target_idxs.push(idx);
            }
        }

        for tab_idx in target_idxs {
            f(unsafe { self.tabs.get_unchecked_mut(tab_idx) });
        }
    }

    fn maybe_create_tab(&mut self, target : &MsgTarget) -> Vec<usize> {
        match target {
            &MsgTarget::Server { serv_name } => {
                opt_to_vec(self.new_server_tab(serv_name))
            },

            &MsgTarget::Chan { serv_name, chan_name } => {
                opt_to_vec(self.new_chan_tab(serv_name, chan_name))
            },

            &MsgTarget::User { serv_name, nick } => {
                opt_to_vec(self.new_user_tab(serv_name, nick))
            },

            &MsgTarget::MultipleTabs(ref targets) => {
                targets.iter().flat_map(|t : &Box<MsgTarget>| self.maybe_create_tab(&*t)).collect()
            }

            _ => vec![]
        }
    }

    #[inline]
    pub fn add_client_err_msg(&mut self, msg : &str, target : &MsgTarget) {
        self.apply_to_target(target, &|tab : &mut Tab| {
            tab.widget.add_client_err_msg(msg);
        });
    }

    #[inline]
    pub fn add_client_msg(&mut self, msg : &str, target : &MsgTarget) {
        self.apply_to_target(target, &|tab : &mut Tab| {
            tab.widget.add_client_msg(msg);
        });
    }

    #[inline]
    pub fn add_privmsg(&mut self, sender : &str, msg : &str, tm : &Tm, target : &MsgTarget) {
        self.apply_to_target(target, &|tab : &mut Tab| {
            tab.widget.add_privmsg(sender, msg, tm);
        });
    }

    #[inline]
    pub fn add_msg(&mut self, msg : &str, tm : &Tm, target : &MsgTarget) {
        self.apply_to_target(target, &|tab : &mut Tab| {
            tab.widget.add_msg(msg, tm);
        });
    }

    #[inline]
    pub fn add_err_msg(&mut self, msg : &str, tm : &Tm, target : &MsgTarget) {
        self.apply_to_target(target, &|tab : &mut Tab| {
            tab.widget.add_err_msg(msg, tm);
        });
    }

    #[inline]
    pub fn set_topic(&mut self, title : &str, target : &MsgTarget) {
        self.apply_to_target(target, &|tab : &mut Tab| {
            tab.widget.set_topic(title.to_owned());
        });
    }

    ////////////////////////////////////////////////////////////////////////////
    // Helpers

    fn find_serv_tab_idx(&self, serv_name_ : &str) -> Option<usize> {
        for (tab_idx, tab) in self.tabs.iter().enumerate() {
            match &tab.src {
                &MsgSource::Serv { ref serv_name } => {
                    if serv_name_ == serv_name {
                        return Some(tab_idx);
                    }
                },
                _ => {},
            }
        }
        None
    }

    fn find_chan_tab_idx(&self, serv_name_ : &str, chan_name_ : &str) -> Option<usize> {
        for (tab_idx, tab) in self.tabs.iter().enumerate() {
            match &tab.src {
                &MsgSource::Chan { ref serv_name, ref chan_name } => {
                    if serv_name_ == serv_name && chan_name_ == chan_name {
                        return Some(tab_idx);
                    }
                },
                _ => {},
            }
        }
        None
    }

    fn find_user_tab_idx(&self, serv_name_ : &str, nick_ : &str) -> Option<usize> {
        for (tab_idx, tab) in self.tabs.iter().enumerate() {
            match &tab.src {
                &MsgSource::User { ref serv_name, ref nick } => {
                    if serv_name_ == serv_name && nick_ == nick {
                        return Some(tab_idx);
                    }
                },
                _ => {},
            }
        }
        None
    }

    /// Index of the last tab with the given server name.
    fn find_last_serv_tab_idx(&self, serv_name : &str) -> Option<usize> {
        for (tab_idx, tab) in self.tabs.iter().enumerate().rev() {
            if tab.src.serv_name() == serv_name {
                return Some(tab_idx);
            }
        }
        None
    }
}
<|endoftext|>


<commit_before>//! Wrapper for the `wlr_box` type.
//! Note that we renamed it to `Area` to avoid conflicts with Rust's Box.

use libc::{c_double, c_int};

use wlroots_sys::{wl_output_transform, wlr_box, wlr_box_closest_point, wlr_box_contains_point,
                  wlr_box_empty, wlr_box_intersection, wlr_box_transform};

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// Result of applying an intersection of two `Area`s.
pub enum IntersectionResult {
    /// This area is the intersection between the two points.
    Intersection(Area),
    /// There was not an intersection
    NoIntersection
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Origin {
    pub x: c_int,
    pub y: c_int
}

impl Default for Origin {
    fn default() -> Self {
        Origin { x: 0, y: 0 }
    }
}

impl Into<Area> for Origin {
    fn into(self) -> Area {
        Area::new(self, Size::default())
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Size {
    pub width: c_int,
    pub height: c_int
}

impl Default for Size {
    fn default() -> Self {
        Size { width: 0,
               height: 0 }
    }
}

impl Into<Area> for Size {
    fn into(self) -> Area {
        Area::new(Origin::default(), self)
    }
}

#[derive(Debug, Clone, Copy)]
/// Generic geometry-like struct. Container an origin (x, y) point and bounds
/// (width, height).
pub struct Area(pub wlr_box);

impl Default for Area {
    fn default() -> Area {
        Area(wlr_box { x: 0,
                       y: 0,
                       width: 0,
                       height: 0 })
    }
}

impl Area {
    pub fn new(origin: Origin, size: Size) -> Self {
        Area(wlr_box { x: origin.x,
                       y: origin.y,
                       width: size.width,
                       height: size.height })
    }

    /// Finds the closest point within the box to the given point.
    /// If the (x, y) point lies outside of the box, then it finds the closest
    /// corner and returns that.
    ///
    /// Returned value is in form of (x, y).
    pub fn closest_point(&mut self, x: c_double, y: c_double) -> (c_double, c_double) {
        unsafe {
            let (mut dest_x, mut dest_y) = (0.0, 0.0);
            wlr_box_closest_point(&mut self.0, x, y, &mut dest_x, &mut dest_y);
            (dest_x, dest_y)
        }
    }

    /// Gets the intersection of the two areas.
    pub fn intersection(&self, other_box: &Area) -> IntersectionResult {
        unsafe {
            let mut res = Area::default();
            let is_empty = wlr_box_intersection(&self.0, &other_box.0, &mut res.0);
            if is_empty {
                IntersectionResult::NoIntersection
            } else {
                IntersectionResult::Intersection(res)
            }
        }
    }

    /// Determines if the box contains the given point.
    pub fn contains_point(&mut self, x: c_double, y: c_double) -> bool {
        unsafe { wlr_box_contains_point(&mut self.0, x, y) }
    }

    /// Determines if the box is empty (e.g if the bounds give it an area of 0).
    pub fn is_empty(&mut self) -> bool {
        unsafe { wlr_box_empty(&mut self.0) }
    }

    /// Transforms the box coordinates and bounds according to the
    /// output transformation.
    ///
    /// e.g: If it's `WL_OUTPUT_TRANSFORM_90` then it will flip the Area 90° clockwise.
    pub fn transform(&mut self, transform: wl_output_transform) -> Area {
        unsafe {
            let mut res = Area::default();
            wlr_box_transform(&mut self.0, transform, &mut res.0);
            res
        }
    }
}

impl PartialEq for Area {
    fn eq(&self, other: &Area) -> bool {
        self.0.x == other.0.x && self.0.y == other.0.y && self.0.height == other.0.height
        && self.0.width == other.0.width
    }
}

impl Eq for Area {}
<commit_msg>Revert "Removed dumb deref and derefmut for Area"<commit_after>//! Wrapper for the `wlr_box` type.
//! Note that we renamed it to `Area` to avoid conflicts with Rust's Box.

use std::ops::{Deref, DerefMut};

use libc::{c_double, c_int};

use wlroots_sys::{wl_output_transform, wlr_box, wlr_box_closest_point, wlr_box_contains_point,
                  wlr_box_empty, wlr_box_intersection, wlr_box_transform};

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// Result of applying an intersection of two `Area`s.
pub enum IntersectionResult {
    /// This area is the intersection between the two points.
    Intersection(Area),
    /// There was not an intersection
    NoIntersection
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Origin {
    pub x: c_int,
    pub y: c_int
}

impl Default for Origin {
    fn default() -> Self {
        Origin { x: 0, y: 0 }
    }
}

impl Into<Area> for Origin {
    fn into(self) -> Area {
        Area::new(self, Size::default())
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Size {
    pub width: c_int,
    pub height: c_int
}

impl Default for Size {
    fn default() -> Self {
        Size { width: 0,
               height: 0 }
    }
}

impl Into<Area> for Size {
    fn into(self) -> Area {
        Area::new(Origin::default(), self)
    }
}

#[derive(Debug, Clone, Copy)]
/// Generic geometry-like struct. Container an origin (x, y) point and bounds
/// (width, height).
pub struct Area(pub wlr_box);

impl Default for Area {
    fn default() -> Area {
        Area(wlr_box { x: 0,
                       y: 0,
                       width: 0,
                       height: 0 })
    }
}

impl Area {
    pub fn new(origin: Origin, size: Size) -> Self {
        Area(wlr_box { x: origin.x,
                       y: origin.y,
                       width: size.width,
                       height: size.height })
    }

    /// Finds the closest point within the box to the given point.
    /// If the (x, y) point lies outside of the box, then it finds the closest
    /// corner and returns that.
    ///
    /// Returned value is in form of (x, y).
    pub fn closest_point(&mut self, x: c_double, y: c_double) -> (c_double, c_double) {
        unsafe {
            let (mut dest_x, mut dest_y) = (0.0, 0.0);
            wlr_box_closest_point(&mut self.0, x, y, &mut dest_x, &mut dest_y);
            (dest_x, dest_y)
        }
    }

    /// Gets the intersection of the two areas.
    pub fn intersection(&self, other_box: &Area) -> IntersectionResult {
        unsafe {
            let mut res = Area::default();
            let is_empty = wlr_box_intersection(&self.0, &other_box.0, &mut res.0);
            if is_empty {
                IntersectionResult::NoIntersection
            } else {
                IntersectionResult::Intersection(res)
            }
        }
    }

    /// Determines if the box contains the given point.
    pub fn contains_point(&mut self, x: c_double, y: c_double) -> bool {
        unsafe { wlr_box_contains_point(&mut self.0, x, y) }
    }

    /// Determines if the box is empty (e.g if the bounds give it an area of 0).
    pub fn is_empty(&mut self) -> bool {
        unsafe { wlr_box_empty(&mut self.0) }
    }

    /// Transforms the box coordinates and bounds according to the
    /// output transformation.
    ///
    /// e.g: If it's `WL_OUTPUT_TRANSFORM_90` then it will flip the Area 90° clockwise.
    pub fn transform(&mut self, transform: wl_output_transform) -> Area {
        unsafe {
            let mut res = Area::default();
            wlr_box_transform(&mut self.0, transform, &mut res.0);
            res
        }
    }
}

impl Deref for Area {
    type Target = wlr_box;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Area {
    fn deref_mut(&mut self) -> &mut wlr_box {
        &mut self.0
    }
}

impl PartialEq for Area {
    fn eq(&self, other: &Area) -> bool {
        self.x == other.x && self.y == other.y && self.height == other.height
        && self.width == other.width
    }
}

impl Eq for Area {}
<|endoftext|>


<commit_before>#![no_main]
use cfb::CompoundFile;
use libfuzzer_sys::fuzz_target;
use std::io::{Cursor, Read};

fuzz_target!(|data: &[u8]| {
    let cursor = Cursor::new(data);
    let mut cfb = match CompoundFile::open(cursor) {
        Ok(cfb) => cfb,
        Err(_) => return,
    };
    let stream_paths = cfb
        .walk()
        .filter(|e| e.is_stream())
        .map(|e| e.path().to_path_buf())
        .collect::<Vec<_>>();

    let paths = stream_paths
        .into_iter()
        .map(|s| {
            let mut data = Vec::new();
            cfb.open_stream(&s)?.read_to_end(&mut data)?;
            Ok((s, data))
        })
        .collect::<Result<std::collections::HashMap<_, _>, std::io::Error>>()
        .unwrap();
});
<commit_msg>fixed harness to not crash incorrectly<commit_after>#![no_main]
use cfb::CompoundFile;
use libfuzzer_sys::fuzz_target;
use std::io::{Cursor, Read};

fuzz_target!(|data: &[u8]| {
    let cursor = Cursor::new(data);
    let mut cfb = match CompoundFile::open(cursor) {
        Ok(cfb) => cfb,
        Err(_) => return,
    };
    let stream_paths = cfb
        .walk()
        .filter(|e| e.is_stream())
        .map(|e| e.path().to_path_buf())
        .collect::<Vec<_>>();

    let paths = stream_paths
        .into_iter()
        .map(|s| {
            let mut data = Vec::new();
            cfb.open_stream(&s)?.read_to_end(&mut data)?;
            Ok((s, data))
        })
        .collect::<Result<std::collections::HashMap<_, _>, std::io::Error>>();
});
<|endoftext|>


<commit_before>// Edge Operation Genome

use evo::prob::{Probability, ProbabilityValue};
use evo::crossover::linear_2point_crossover_random;
use evo::nsga2::Mate;
use rand::Rng;
use rand::distributions::{IndependentSample, Weighted};
use graph_edge_evolution::{EdgeOperation, GraphBuilder, NthEdgeF};
use owned_weighted_choice::OwnedWeightedChoice;
use std::str::FromStr;
use std::string::ToString;
use triadic_census::OptDenseDigraph;
use std::collections::BTreeMap;
use serde_json::Value;
use sexp::{Atom, Sexp};

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Op {
    Dup,
    Split,
    Loop,
    Merge,
    Next,
    Parent,
    Reverse,
    Save,
    Restore,
}

impl ToString for Op {
    fn to_string(&self) -> String {
        match *self {
            Op::Dup => "Dup".to_string(),
            Op::Split => "Split".to_string(),
            Op::Loop => "Loop".to_string(),
            Op::Merge => "Merge".to_string(),
            Op::Next => "Next".to_string(),
            Op::Parent => "Parent".to_string(),
            Op::Reverse => "Reverse".to_string(),
            Op::Save => "Save".to_string(),
            Op::Restore => "Restore".to_string(),
        }
    }
}

impl FromStr for Op {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "Dup" => Ok(Op::Dup),
            "Split" => Ok(Op::Split),
            "Loop" => Ok(Op::Loop),
            "Merge" => Ok(Op::Merge),
            "Next" => Ok(Op::Next),
            "Parent" => Ok(Op::Parent),
            "Reverse" => Ok(Op::Reverse),
            "Save" => Ok(Op::Save),
            "Restore" => Ok(Op::Restore),
            _ => Err(format!("Invalid opcode: {}", s)),
        }
    }
}

/// Element-wise Mutation operation.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum MutOp {
    /// No mutation (copy element)
    Copy,
    /// Insert new operation
    Insert,
    /// Remove an operation
    Remove,
    /// Modify the operation
    ModifyOp,
    /// Modify a parameter value
    ModifyParam,
    /// Modify both operation and parameter
    Replace,
}

impl FromStr for MutOp {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "Copy" => Ok(MutOp::Copy),
            "Insert" => Ok(MutOp::Insert),
            "Remove" => Ok(MutOp::Remove),
            "ModifyOp" => Ok(MutOp::ModifyOp),
            "ModifyParam" => Ok(MutOp::ModifyParam),
            "Replace" => Ok(MutOp::Replace),
            _ => Err(format!("Invalid opcode: {}", s)),
        }
    }
}

/// Variation operators
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum VarOp {
    /// No variation. Reproduce exactly
    Copy,

    /// Mutate
    Mutate,

    /// 2-point Linear crossover
    LinearCrossover2,

    /// Uniform crossover
    UniformCrossover,
}

impl FromStr for VarOp {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "Copy" => Ok(VarOp::Copy),
            "Mutate" => Ok(VarOp::Mutate),
            "LinearCrossover2" => Ok(VarOp::LinearCrossover2),
            "UniformCrossover" => Ok(VarOp::UniformCrossover),
            _ => Err(format!("Invalid opcode: {}", s)),
        }
    }
}

#[derive(Clone, Debug)]
pub struct EdgeOpsGenome {
    edge_ops: Vec<(Op, f32)>,
}

pub struct Toolbox {
    weighted_op: OwnedWeightedChoice<Op>,
    weighted_var_op: OwnedWeightedChoice<VarOp>,
    weighted_mut_op: OwnedWeightedChoice<MutOp>,
    prob_mutate_elem: Probability,
}

impl Mate<EdgeOpsGenome> for Toolbox {
    // p1 is potentially "better" than p2
    fn mate<R: Rng>(&mut self,
                    rng: &mut R,
                    p1: &EdgeOpsGenome,
                    p2: &EdgeOpsGenome)
                    -> EdgeOpsGenome {

        match self.weighted_var_op.ind_sample(rng) {
            VarOp::Copy => {
                p1.clone()
            }
            VarOp::Mutate => {
                self.mutate(rng, p1)
            }
            VarOp::LinearCrossover2 => {
                EdgeOpsGenome {
                    edge_ops: linear_2point_crossover_random(rng,
                                                             &p1.edge_ops[..],
                                                             &p2.edge_ops[..]),
                }
            }
            VarOp::UniformCrossover => {
                panic!("TODO");
            }
        }
    }
}

pub fn parse_weighted_op_list<T>(s: &str) -> Result<Vec<(T, u32)>, String>
    where T: FromStr<Err = String>
{
    let mut v = Vec::new();
    for opstr in s.split(",") {
        if opstr.is_empty() {
            continue;
        }
        let mut i = opstr.splitn(2, ":");
        if let Some(ops) = i.next() {
            match T::from_str(ops) {
                Ok(op) => {
                    let ws = i.next().unwrap_or("1");
                    if let Ok(weight) = u32::from_str(ws) {
                        v.push((op, weight));
                    } else {
                        return Err(format!("Invalid weight: {}", ws));
                    }
                }
                Err(s) => {
                    return Err(s);
                }
            }
        } else {
            return Err("missing op".to_string());
        }
    }
    return Ok(v);
}

impl EdgeOpsGenome {
    pub fn len(&self) -> usize {
        self.edge_ops.len()
    }

    pub fn to_json(&self) -> Value {
        let edge_ops: Vec<Value> = self.edge_ops
                                       .iter()
                                       .map(|&(ref op, param)| {
                                           let mut gene = BTreeMap::new();
                                           gene.insert("op".to_string(),
                                                       Value::String(op.to_string()));
                                           gene.insert("param".to_string(),
                                                       Value::F64(param as f64));
                                           Value::Object(gene)
                                           // Value::Array(vec![Value::String(op.to_string()),
                                           // Value::F64(param as f64)])
                                       })
                                       .collect();
        let mut map = BTreeMap::new();
        map.insert("edge_ops".to_string(), Value::Array(edge_ops));
        Value::Object(map)
    }

    pub fn to_sexp(&self) -> Sexp {
        let edge_ops: Vec<Sexp> = self.edge_ops
                                      .iter()
                                      .map(|&(ref op, param)| {
                                          Sexp::List(vec![Sexp::Atom(Atom::S(op.to_string())),
                                                          Sexp::Atom(Atom::F(param as f64))])
                                      })
                                      .collect();

        Sexp::List(vec![Sexp::Atom(Atom::S("EdgeOpsGenome".to_string())), Sexp::List(edge_ops)])
    }

    pub fn from_json(val: &Value) -> EdgeOpsGenome {
        let edge_ops = val.find("edge_ops").unwrap();
        let edge_ops = edge_ops.as_array().unwrap();
        let edge_ops = edge_ops.iter()
                               .map(|gene| {
                                   let op = Op::from_str(gene.find("op")
                                                             .unwrap()
                                                             .as_string()
                                                             .unwrap())
                                                .unwrap();
                                   let param = gene.find("param").unwrap().as_f64().unwrap();
                                   (op, param as f32)
                               })
                               .collect();
        EdgeOpsGenome { edge_ops: edge_ops }
    }

    pub fn to_graph(&self) -> OptDenseDigraph<(), ()> {
        let mut builder: GraphBuilder<f32, ()> = GraphBuilder::new();
        for &(op, f) in &self.edge_ops[..] {
            let graph_op = match op {
                Op::Dup => {
                    EdgeOperation::Duplicate { weight: f }
                }
                Op::Split => {
                    EdgeOperation::Split { weight: f }
                }
                Op::Loop => {
                    EdgeOperation::Loop { weight: f }
                }
                Op::Merge => {
                    EdgeOperation::Merge { n: NthEdgeF(f) }
                }
                Op::Next => {
                    EdgeOperation::Next { n: NthEdgeF(f) }
                }
                Op::Parent => {
                    EdgeOperation::Parent { n: NthEdgeF(f) }
                }
                Op::Reverse => {
                    EdgeOperation::Reverse
                }
                Op::Save => {
                    EdgeOperation::Save
                }
                Op::Restore => {
                    EdgeOperation::Restore
                }
            };
            builder.apply_operation(graph_op);
        }

        let mut g: OptDenseDigraph<(), ()> = OptDenseDigraph::new(builder.total_number_of_nodes()); // XXX: rename to real_number

        // maps node_idx to index used within the graph.
        let mut node_map: BTreeMap<usize, usize> = BTreeMap::new(); // XXX: with_capacity

        builder.visit_nodes(|node_idx, _| {
            let graph_idx = g.add_node();
            node_map.insert(node_idx, graph_idx);
        });

        builder.visit_edges(|(a, b), _| {
            g.add_edge(node_map[&a], node_map[&b]);
        });

        return g;
    }
}

impl Toolbox {
    pub fn mutate<R: Rng>(&self, rng: &mut R, ind: &EdgeOpsGenome) -> EdgeOpsGenome {
        let mut mut_ind = Vec::with_capacity(ind.len() + 1);

        for edge_op in ind.edge_ops.iter() {
            let new_op = if rng.gen::<ProbabilityValue>().is_probable_with(self.prob_mutate_elem) {
                match self.weighted_mut_op.ind_sample(rng) {
                    MutOp::Copy => {
                        edge_op.clone()
                    }
                    MutOp::Insert => {
                        // Insert a new op before the current operation
                        mut_ind.push(self.generate_random_edge_operation(rng));
                        edge_op.clone()
                    }
                    MutOp::Remove => {
                        // remove current operation
                        continue;
                    }
                    MutOp::ModifyOp => {
                        (self.weighted_op.ind_sample(rng), edge_op.1)
                    }
                    MutOp::ModifyParam => {
                        (edge_op.0, rng.gen::<f32>())
                    }
                    MutOp::Replace => {
                        self.generate_random_edge_operation(rng)
                    }
                }
            } else {
                edge_op.clone()
            };
            mut_ind.push(new_op);
        }

        EdgeOpsGenome { edge_ops: mut_ind }
    }

    pub fn new(weighted_op: &[(Op, u32)],
               weighted_var_op: &[(VarOp, u32)],
               prob_mutate_elem: Probability,
               weighed_mut_op: &[(MutOp, u32)])
               -> Toolbox {
        let mut w_ops = Vec::new();
        for &(op, weight) in weighted_op {
            if weight > 0 {
                // an operation with weight=0 cannot be selected
                w_ops.push(Weighted {
                    weight: weight,
                    item: op,
                });
            }
        }

        let mut w_var_ops = Vec::new();
        for &(op, weight) in weighted_var_op {
            if weight > 0 {
                // an operation with weight=0 cannot be selected
                w_var_ops.push(Weighted {
                    weight: weight,
                    item: op,
                });
            }
        }

        let mut w_mut_ops = Vec::new();
        for &(op, weight) in weighed_mut_op {
            if weight > 0 {
                // an operation with weight=0 cannot be selected
                w_mut_ops.push(Weighted {
                    weight: weight,
                    item: op,
                });
            }
        }

        assert!(w_ops.len() > 0);
        assert!(w_var_ops.len() > 0);
        assert!(w_mut_ops.len() > 0);

        Toolbox {
            prob_mutate_elem: prob_mutate_elem,
            weighted_op: OwnedWeightedChoice::new(w_ops),
            weighted_var_op: OwnedWeightedChoice::new(w_var_ops),
            weighted_mut_op: OwnedWeightedChoice::new(w_mut_ops),
        }
    }

    fn generate_random_edge_operation<R: Rng>(&self, rng: &mut R) -> (Op, f32) /*EdgeOperation<f32, ()>*/ {
        (self.weighted_op.ind_sample(rng), rng.gen::<f32>())
    }

    pub fn random_genome<R: Rng>(&self, rng: &mut R, len: usize) -> EdgeOpsGenome {
        EdgeOpsGenome {
            edge_ops: (0..len)
                          .map(|_| self.generate_random_edge_operation(rng))
                          .collect(),
        }
    }
}

#[test]
fn test_parse_weighted_op_choice_list() {
    fn parse_weighted_op_choice_list(s: &str) -> Result<Vec<(Op, u32)>, String> {
        parse_weighted_op_list(s)
    }
    assert_eq!(Ok(vec![]), parse_weighted_op_choice_list(""));
    assert_eq!(Ok(vec![(Op::Dup, 1)]), parse_weighted_op_choice_list("Dup"));
    assert_eq!(Ok(vec![(Op::Dup, 1)]),
               parse_weighted_op_choice_list("Dup:1"));
    assert_eq!(Ok(vec![(Op::Dup, 2)]),
               parse_weighted_op_choice_list("Dup:2"));
    assert_eq!(Ok(vec![(Op::Dup, 2), (Op::Split, 1)]),
               parse_weighted_op_choice_list("Dup:2,Split"));
    assert_eq!(Err("Invalid weight: ".to_string()),
               parse_weighted_op_choice_list("Dup:2,Split:"));
    assert_eq!(Err("Invalid weight: a".to_string()),
               parse_weighted_op_choice_list("Dup:2,Split:a"));
    assert_eq!(Err("Invalid opcode: dup".to_string()),
               parse_weighted_op_choice_list("dup:2,Split:a"));
}
<commit_msg>Refactor<commit_after>// Edge Operation Genome

use evo::prob::{Probability, ProbabilityValue};
use evo::crossover::linear_2point_crossover_random;
use evo::nsga2::Mate;
use rand::Rng;
use rand::distributions::{IndependentSample, Weighted};
use graph_edge_evolution::{EdgeOperation, GraphBuilder, NthEdgeF};
use owned_weighted_choice::OwnedWeightedChoice;
use std::str::FromStr;
use std::string::ToString;
use triadic_census::OptDenseDigraph;
use std::collections::BTreeMap;
use serde_json::Value;
use sexp::{Atom, Sexp};

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Op {
    Dup,
    Split,
    Loop,
    Merge,
    Next,
    Parent,
    Reverse,
    Save,
    Restore,
}

impl ToString for Op {
    fn to_string(&self) -> String {
        match *self {
            Op::Dup => "Dup".to_string(),
            Op::Split => "Split".to_string(),
            Op::Loop => "Loop".to_string(),
            Op::Merge => "Merge".to_string(),
            Op::Next => "Next".to_string(),
            Op::Parent => "Parent".to_string(),
            Op::Reverse => "Reverse".to_string(),
            Op::Save => "Save".to_string(),
            Op::Restore => "Restore".to_string(),
        }
    }
}

impl FromStr for Op {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "Dup" => Ok(Op::Dup),
            "Split" => Ok(Op::Split),
            "Loop" => Ok(Op::Loop),
            "Merge" => Ok(Op::Merge),
            "Next" => Ok(Op::Next),
            "Parent" => Ok(Op::Parent),
            "Reverse" => Ok(Op::Reverse),
            "Save" => Ok(Op::Save),
            "Restore" => Ok(Op::Restore),
            _ => Err(format!("Invalid opcode: {}", s)),
        }
    }
}

/// Element-wise Mutation operation.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum MutOp {
    /// No mutation (copy element)
    Copy,
    /// Insert new operation
    Insert,
    /// Remove an operation
    Remove,
    /// Modify the operation
    ModifyOp,
    /// Modify a parameter value
    ModifyParam,
    /// Modify both operation and parameter
    Replace,
}

impl FromStr for MutOp {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "Copy" => Ok(MutOp::Copy),
            "Insert" => Ok(MutOp::Insert),
            "Remove" => Ok(MutOp::Remove),
            "ModifyOp" => Ok(MutOp::ModifyOp),
            "ModifyParam" => Ok(MutOp::ModifyParam),
            "Replace" => Ok(MutOp::Replace),
            _ => Err(format!("Invalid opcode: {}", s)),
        }
    }
}

/// Variation operators
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum VarOp {
    /// No variation. Reproduce exactly
    Copy,

    /// Mutate
    Mutate,

    /// 2-point Linear crossover
    LinearCrossover2,

    /// Uniform crossover
    UniformCrossover,
}

impl FromStr for VarOp {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "Copy" => Ok(VarOp::Copy),
            "Mutate" => Ok(VarOp::Mutate),
            "LinearCrossover2" => Ok(VarOp::LinearCrossover2),
            "UniformCrossover" => Ok(VarOp::UniformCrossover),
            _ => Err(format!("Invalid opcode: {}", s)),
        }
    }
}

#[derive(Clone, Debug)]
pub struct EdgeOpsGenome {
    edge_ops: Vec<(Op, f32)>,
}

pub struct Toolbox {
    weighted_op: OwnedWeightedChoice<Op>,
    weighted_var_op: OwnedWeightedChoice<VarOp>,
    weighted_mut_op: OwnedWeightedChoice<MutOp>,
    prob_mutate_elem: Probability,
}

impl Mate<EdgeOpsGenome> for Toolbox {
    // p1 is potentially "better" than p2
    fn mate<R: Rng>(&mut self,
                    rng: &mut R,
                    p1: &EdgeOpsGenome,
                    p2: &EdgeOpsGenome)
                    -> EdgeOpsGenome {

        match self.weighted_var_op.ind_sample(rng) {
            VarOp::Copy => {
                p1.clone()
            }
            VarOp::Mutate => {
                self.mutate(rng, p1)
            }
            VarOp::LinearCrossover2 => {
                EdgeOpsGenome {
                    edge_ops: linear_2point_crossover_random(rng,
                                                             &p1.edge_ops[..],
                                                             &p2.edge_ops[..]),
                }
            }
            VarOp::UniformCrossover => {
                panic!("TODO");
            }
        }
    }
}

pub fn parse_weighted_op_list<T>(s: &str) -> Result<Vec<(T, u32)>, String>
    where T: FromStr<Err = String>
{
    let mut v = Vec::new();
    for opstr in s.split(",") {
        if opstr.is_empty() {
            continue;
        }
        let mut i = opstr.splitn(2, ":");
        if let Some(ops) = i.next() {
            match T::from_str(ops) {
                Ok(op) => {
                    let ws = i.next().unwrap_or("1");
                    if let Ok(weight) = u32::from_str(ws) {
                        v.push((op, weight));
                    } else {
                        return Err(format!("Invalid weight: {}", ws));
                    }
                }
                Err(s) => {
                    return Err(s);
                }
            }
        } else {
            return Err("missing op".to_string());
        }
    }
    return Ok(v);
}

pub fn to_weighted_vec<T:Clone>(ops: &[(T,u32)]) -> Vec<Weighted<T>> {
    let mut w = Vec::with_capacity(ops.len());
    for &(ref op, weight) in ops {
        if weight > 0 {
            // an operation with weight=0 cannot be selected
            w.push(Weighted {
                weight: weight,
                item: op.clone(),
            });
        }
    }
    w
}

impl EdgeOpsGenome {
    pub fn len(&self) -> usize {
        self.edge_ops.len()
    }

    pub fn to_json(&self) -> Value {
        let edge_ops: Vec<Value> = self.edge_ops
                                       .iter()
                                       .map(|&(ref op, param)| {
                                           let mut gene = BTreeMap::new();
                                           gene.insert("op".to_string(),
                                                       Value::String(op.to_string()));
                                           gene.insert("param".to_string(),
                                                       Value::F64(param as f64));
                                           Value::Object(gene)
                                           // Value::Array(vec![Value::String(op.to_string()),
                                           // Value::F64(param as f64)])
                                       })
                                       .collect();
        let mut map = BTreeMap::new();
        map.insert("edge_ops".to_string(), Value::Array(edge_ops));
        Value::Object(map)
    }

    pub fn to_sexp(&self) -> Sexp {
        let edge_ops: Vec<Sexp> = self.edge_ops
                                      .iter()
                                      .map(|&(ref op, param)| {
                                          Sexp::List(vec![Sexp::Atom(Atom::S(op.to_string())),
                                                          Sexp::Atom(Atom::F(param as f64))])
                                      })
                                      .collect();

        Sexp::List(vec![Sexp::Atom(Atom::S("EdgeOpsGenome".to_string())), Sexp::List(edge_ops)])
    }

    pub fn from_json(val: &Value) -> EdgeOpsGenome {
        let edge_ops = val.find("edge_ops").unwrap();
        let edge_ops = edge_ops.as_array().unwrap();
        let edge_ops = edge_ops.iter()
                               .map(|gene| {
                                   let op = Op::from_str(gene.find("op")
                                                             .unwrap()
                                                             .as_string()
                                                             .unwrap())
                                                .unwrap();
                                   let param = gene.find("param").unwrap().as_f64().unwrap();
                                   (op, param as f32)
                               })
                               .collect();
        EdgeOpsGenome { edge_ops: edge_ops }
    }

    pub fn to_graph(&self) -> OptDenseDigraph<(), ()> {
        let mut builder: GraphBuilder<f32, ()> = GraphBuilder::new();
        for &(op, f) in &self.edge_ops[..] {
            let graph_op = match op {
                Op::Dup => {
                    EdgeOperation::Duplicate { weight: f }
                }
                Op::Split => {
                    EdgeOperation::Split { weight: f }
                }
                Op::Loop => {
                    EdgeOperation::Loop { weight: f }
                }
                Op::Merge => {
                    EdgeOperation::Merge { n: NthEdgeF(f) }
                }
                Op::Next => {
                    EdgeOperation::Next { n: NthEdgeF(f) }
                }
                Op::Parent => {
                    EdgeOperation::Parent { n: NthEdgeF(f) }
                }
                Op::Reverse => {
                    EdgeOperation::Reverse
                }
                Op::Save => {
                    EdgeOperation::Save
                }
                Op::Restore => {
                    EdgeOperation::Restore
                }
            };
            builder.apply_operation(graph_op);
        }

        let mut g: OptDenseDigraph<(), ()> = OptDenseDigraph::new(builder.total_number_of_nodes()); // XXX: rename to real_number

        // maps node_idx to index used within the graph.
        let mut node_map: BTreeMap<usize, usize> = BTreeMap::new(); // XXX: with_capacity

        builder.visit_nodes(|node_idx, _| {
            let graph_idx = g.add_node();
            node_map.insert(node_idx, graph_idx);
        });

        builder.visit_edges(|(a, b), _| {
            g.add_edge(node_map[&a], node_map[&b]);
        });

        return g;
    }
}

impl Toolbox {
    pub fn mutate<R: Rng>(&self, rng: &mut R, ind: &EdgeOpsGenome) -> EdgeOpsGenome {
        let mut mut_ind = Vec::with_capacity(ind.len() + 1);

        for edge_op in ind.edge_ops.iter() {
            let new_op = if rng.gen::<ProbabilityValue>().is_probable_with(self.prob_mutate_elem) {
                match self.weighted_mut_op.ind_sample(rng) {
                    MutOp::Copy => {
                        edge_op.clone()
                    }
                    MutOp::Insert => {
                        // Insert a new op before the current operation
                        mut_ind.push(self.generate_random_edge_operation(rng));
                        edge_op.clone()
                    }
                    MutOp::Remove => {
                        // remove current operation
                        continue;
                    }
                    MutOp::ModifyOp => {
                        (self.weighted_op.ind_sample(rng), edge_op.1)
                    }
                    MutOp::ModifyParam => {
                        (edge_op.0, rng.gen::<f32>())
                    }
                    MutOp::Replace => {
                        self.generate_random_edge_operation(rng)
                    }
                }
            } else {
                edge_op.clone()
            };
            mut_ind.push(new_op);
        }

        EdgeOpsGenome { edge_ops: mut_ind }
    }

    pub fn new(weighted_op: &[(Op, u32)],
               weighted_var_op: &[(VarOp, u32)],
               prob_mutate_elem: Probability,
               weighted_mut_op: &[(MutOp, u32)])
               -> Toolbox {

        let w_ops = to_weighted_vec(weighted_op);
        let w_var_ops = to_weighted_vec(weighted_var_op);
        let w_mut_ops = to_weighted_vec(weighted_mut_op);

        assert!(w_ops.len() > 0);
        assert!(w_var_ops.len() > 0);
        assert!(w_mut_ops.len() > 0);

        Toolbox {
            prob_mutate_elem: prob_mutate_elem,
            weighted_op: OwnedWeightedChoice::new(w_ops),
            weighted_var_op: OwnedWeightedChoice::new(w_var_ops),
            weighted_mut_op: OwnedWeightedChoice::new(w_mut_ops),
        }
    }

    fn generate_random_edge_operation<R: Rng>(&self, rng: &mut R) -> (Op, f32) /*EdgeOperation<f32, ()>*/ {
        (self.weighted_op.ind_sample(rng), rng.gen::<f32>())
    }

    pub fn random_genome<R: Rng>(&self, rng: &mut R, len: usize) -> EdgeOpsGenome {
        EdgeOpsGenome {
            edge_ops: (0..len)
                          .map(|_| self.generate_random_edge_operation(rng))
                          .collect(),
        }
    }
}

#[test]
fn test_parse_weighted_op_choice_list() {
    fn parse_weighted_op_choice_list(s: &str) -> Result<Vec<(Op, u32)>, String> {
        parse_weighted_op_list(s)
    }
    assert_eq!(Ok(vec![]), parse_weighted_op_choice_list(""));
    assert_eq!(Ok(vec![(Op::Dup, 1)]), parse_weighted_op_choice_list("Dup"));
    assert_eq!(Ok(vec![(Op::Dup, 1)]),
               parse_weighted_op_choice_list("Dup:1"));
    assert_eq!(Ok(vec![(Op::Dup, 2)]),
               parse_weighted_op_choice_list("Dup:2"));
    assert_eq!(Ok(vec![(Op::Dup, 2), (Op::Split, 1)]),
               parse_weighted_op_choice_list("Dup:2,Split"));
    assert_eq!(Err("Invalid weight: ".to_string()),
               parse_weighted_op_choice_list("Dup:2,Split:"));
    assert_eq!(Err("Invalid weight: a".to_string()),
               parse_weighted_op_choice_list("Dup:2,Split:a"));
    assert_eq!(Err("Invalid opcode: dup".to_string()),
               parse_weighted_op_choice_list("dup:2,Split:a"));
}
<|endoftext|>