<commit_before>//! Wayland specific EGL functionality - EGL based `WlBuffer`s.
//!
//! The types of this module can be used to initialize hardware acceleration rendering
//! based on EGL for clients as it may enabled usage of `EGLImage` based `WlBuffer`s.
//!
//! To use it bind any backend implementing the `EGLWaylandExtensions` trait, that shall do the
//! rendering (so pick a fast one), to the `wayland_server::Display` of your compositor.
//! Note only one backend may be bould to any `Display` at any time.
//!
//! You may then use the resulting `EGLDisplay` to recieve `EGLImages` of an egl-based `WlBuffer`
//! for rendering.

use backend::graphics::egl::{ffi, native, EGLContext, EglExtensionNotSupportedError};
use backend::graphics::egl::error::*;
use backend::graphics::egl::ffi::egl::types::EGLImage;
use nix::libc::c_uint;
use std::fmt;
use std::rc::{Rc, Weak};
use wayland_server::{Display, Resource};
use wayland_server::protocol::wl_buffer::{self, WlBuffer};
use wayland_sys::server::wl_display;

/// Error that can occur when accessing an EGL buffer
pub enum BufferAccessError {
    /// The corresponding Context is not alive anymore
    ContextLost,
    /// This buffer is not managed by the EGL buffer
    NotManaged(Resource<WlBuffer>),
    /// Failed to create EGLImages from the buffer
    EGLImageCreationFailed,
    /// The required EGL extension is not supported by the underlying EGL implementation
    EglExtensionNotSupported(EglExtensionNotSupportedError),
}

impl fmt::Debug for BufferAccessError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
        match *self {
            BufferAccessError::ContextLost => write!(formatter, "BufferAccessError::ContextLost"),
            BufferAccessError::NotManaged(_) => write!(formatter, "BufferAccessError::NotManaged"),
            BufferAccessError::EGLImageCreationFailed => {
                write!(formatter, "BufferAccessError::EGLImageCreationFailed")
            }
            BufferAccessError::EglExtensionNotSupported(ref err) => write!(formatter, "{:?}", err),
        }
    }
}

impl fmt::Display for BufferAccessError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
        use std::error::Error;
        match *self {
            BufferAccessError::ContextLost
            | BufferAccessError::NotManaged(_)
            | BufferAccessError::EGLImageCreationFailed => write!(formatter, "{}", self.description()),
            BufferAccessError::EglExtensionNotSupported(ref err) => err.fmt(formatter),
        }
    }
}

impl ::std::error::Error for BufferAccessError {
    fn description(&self) -> &str {
        match *self {
            BufferAccessError::ContextLost => "The corresponding context was lost",
            BufferAccessError::NotManaged(_) => "This buffer is not mananged by EGL",
            BufferAccessError::EGLImageCreationFailed => "Failed to create EGLImages from the buffer",
            BufferAccessError::EglExtensionNotSupported(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            BufferAccessError::EglExtensionNotSupported(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<EglExtensionNotSupportedError> for BufferAccessError {
    fn from(error: EglExtensionNotSupportedError) -> Self {
        BufferAccessError::EglExtensionNotSupported(error)
    }
}

/// Error that might happen when binding an `EGLImage` to a gl texture
#[derive(Debug, Clone, PartialEq)]
pub enum TextureCreationError {
    /// The given plane index is out of bounds
    PlaneIndexOutOfBounds,
    /// The OpenGL context has been lost and needs to be recreated.
    ///
    /// All the objects associated to it (textures, buffers, programs, etc.)
    /// need to be recreated from scratch.
    ///
    /// Operations will have no effect. Functions that read textures, buffers, etc.
    /// from OpenGL will return uninitialized data instead.
    ///
    /// A context loss usually happens on mobile devices when the user puts the
    /// application on sleep and wakes it up later. However any OpenGL implementation
    /// can theoretically lose the context at any time.
    ContextLost,
    /// Failed to bind the EGLImage to the given texture
    ///
    /// The given argument is the gl error code
    TextureBindingFailed(u32),
}

impl fmt::Display for TextureCreationError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
        use std::error::Error;
        match *self {
            TextureCreationError::ContextLost => write!(formatter, "{}", self.description()),
            TextureCreationError::PlaneIndexOutOfBounds => write!(formatter, "{}", self.description()),
            TextureCreationError::TextureBindingFailed(code) => write!(
                formatter,
                "{}. Gl error code: {:?}",
                self.description(),
                code
            ),
        }
    }
}

impl ::std::error::Error for TextureCreationError {
    fn description(&self) -> &str {
        match *self {
            TextureCreationError::ContextLost => "The context has been lost, it needs to be recreated",
            TextureCreationError::PlaneIndexOutOfBounds => "This buffer is not mananged by EGL",
            TextureCreationError::TextureBindingFailed(_) => "Failed to create EGLImages from the buffer",
        }
    }

    fn cause(&self) -> Option<&::std::error::Error> {
        None
    }
}

/// Texture format types
#[repr(i32)]
#[allow(non_camel_case_types)]
pub enum Format {
    /// RGB format
    RGB = ffi::egl::TEXTURE_RGB as i32,
    /// RGB + alpha channel format
    RGBA = ffi::egl::TEXTURE_RGBA as i32,
    /// External format
    External = ffi::egl::TEXTURE_EXTERNAL_WL,
    /// 2-plane Y and UV format
    Y_UV = ffi::egl::TEXTURE_Y_UV_WL,
    /// 3-plane Y, U and V format
    Y_U_V = ffi::egl::TEXTURE_Y_U_V_WL,
    /// 2-plane Y and XUXV format
    Y_XUXV = ffi::egl::TEXTURE_Y_XUXV_WL,
}

impl Format {
    /// Amount of planes this format uses
    pub fn num_planes(&self) -> usize {
        match *self {
            Format::RGB | Format::RGBA | Format::External => 1,
            Format::Y_UV | Format::Y_XUXV => 2,
            Format::Y_U_V => 3,
        }
    }
}

/// Images of the egl-based `WlBuffer`.
pub struct EGLImages {
    display: Weak<ffi::egl::types::EGLDisplay>,
    /// Width in pixels
    pub width: u32,
    /// Height in pixels
    pub height: u32,
    /// If the y-axis is inverted or not
    pub y_inverted: bool,
    /// Format of these images
    pub format: Format,
    images: Vec<EGLImage>,
    buffer: Resource<WlBuffer>,
}

impl EGLImages {
    /// Amount of planes of these `EGLImages`
    pub fn num_planes(&self) -> usize {
        self.format.num_planes()
    }

    /// Bind plane to an OpenGL texture id
    ///
    /// This does only temporarily modify the OpenGL state any changes are reverted before returning.
    ///
    /// # Unsafety
    ///
    /// The given `tex_id` needs to be a valid GL texture otherwise undefined behavior might occur.
    pub unsafe fn bind_to_texture(
        &self,
        plane: usize,
        tex_id: c_uint,
    ) -> ::std::result::Result<(), TextureCreationError> {
        if self.display.upgrade().is_some() {
            let mut old_tex_id: i32 = 0;
            ffi::gl::GetIntegerv(ffi::gl::TEXTURE_BINDING_2D, &mut old_tex_id);
            ffi::gl::BindTexture(ffi::gl::TEXTURE_2D, tex_id);
            ffi::gl::EGLImageTargetTexture2DOES(
                ffi::gl::TEXTURE_2D,
                *self.images
                    .get(plane)
                    .ok_or(TextureCreationError::PlaneIndexOutOfBounds)?,
            );
            let res = match ffi::egl::GetError() as u32 {
                ffi::egl::SUCCESS => Ok(()),
                err => Err(TextureCreationError::TextureBindingFailed(err)),
            };
            ffi::gl::BindTexture(ffi::gl::TEXTURE_2D, old_tex_id as u32);
            res
        } else {
            Err(TextureCreationError::ContextLost)
        }
    }
}

impl Drop for EGLImages {
    fn drop(&mut self) {
        if let Some(display) = self.display.upgrade() {
            for image in self.images.drain(..) {
                unsafe {
                    ffi::egl::DestroyImageKHR(*display, image);
                }
            }
        }
        self.buffer.send(wl_buffer::Event::Release);
    }
}

/// Trait any backend type may implement that allows binding a `wayland_server::Display`
/// to create an `EGLDisplay` for egl-based `WlBuffer`s.
pub trait EGLWaylandExtensions {
    /// Binds this EGL context to the given Wayland display.
    ///
    /// This will allow clients to utilize EGL to create hardware-accelerated
    /// surfaces. The server will need to be able to handle egl-wl_buffers.
    /// See the `wayland::drm` module.
    ///
    /// ## Errors
    ///
    /// This might return `WlExtensionNotSupported` if binding is not supported
    /// by the EGL implementation.
    ///
    /// This might return `OtherEGLDisplayAlreadyBound` if called for the same
    /// `Display` multiple times, as only one context may be bound at any given time.
    fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay>;
}

/// Type to recieve `EGLImages` for egl-based `WlBuffer`s.
///
/// Can be created by using `EGLWaylandExtensions::bind_wl_display`.
pub struct EGLDisplay(Weak<ffi::egl::types::EGLDisplay>, *mut wl_display);

impl EGLDisplay {
    fn new<B: native::Backend, N: native::NativeDisplay<B>>(
        context: &EGLContext<B, N>,
        display: *mut wl_display,
    ) -> EGLDisplay {
        EGLDisplay(Rc::downgrade(&context.display), display)
    }

    /// Try to recieve `EGLImages` from a given `WlBuffer`.
    ///
    /// In case the buffer is not managed by egl (but e.g. the wayland::shm module)
    /// a `BufferAccessError::NotManaged(WlBuffer)` is returned with the original buffer
    /// to render it another way.
    pub fn egl_buffer_contents(
        &self,
        buffer: Resource<WlBuffer>,
    ) -> ::std::result::Result<EGLImages, BufferAccessError> {
        if let Some(display) = self.0.upgrade() {
            let mut format: i32 = 0;
            if unsafe {
                ffi::egl::QueryWaylandBufferWL(
                    *display,
                    buffer.c_ptr() as *mut _,
                    ffi::egl::EGL_TEXTURE_FORMAT,
                    &mut format as *mut _,
                ) == 0
            } {
                return Err(BufferAccessError::NotManaged(buffer));
            }
            let format = match format {
                x if x == ffi::egl::TEXTURE_RGB as i32 => Format::RGB,
                x if x == ffi::egl::TEXTURE_RGBA as i32 => Format::RGBA,
                ffi::egl::TEXTURE_EXTERNAL_WL => Format::External,
                ffi::egl::TEXTURE_Y_UV_WL => Format::Y_UV,
                ffi::egl::TEXTURE_Y_U_V_WL => Format::Y_U_V,
                ffi::egl::TEXTURE_Y_XUXV_WL => Format::Y_XUXV,
                _ => panic!("EGL returned invalid texture type"),
            };

            let mut width: i32 = 0;
            if unsafe {
                ffi::egl::QueryWaylandBufferWL(
                    *display,
                    buffer.c_ptr() as *mut _,
                    ffi::egl::WIDTH as i32,
                    &mut width as *mut _,
                ) == 0
            } {
                return Err(BufferAccessError::NotManaged(buffer));
            }

            let mut height: i32 = 0;
            if unsafe {
                ffi::egl::QueryWaylandBufferWL(
                    *display,
                    buffer.c_ptr() as *mut _,
                    ffi::egl::HEIGHT as i32,
                    &mut height as *mut _,
                ) == 0
            } {
                return Err(BufferAccessError::NotManaged(buffer));
            }

            let mut inverted: i32 = 0;
            if unsafe {
                ffi::egl::QueryWaylandBufferWL(
                    *display,
                    buffer.c_ptr() as *mut _,
                    ffi::egl::WAYLAND_Y_INVERTED_WL,
                    &mut inverted as *mut _,
                ) != 0
            } {
                inverted = 1;
            }

            let mut images = Vec::with_capacity(format.num_planes());
            for i in 0..format.num_planes() {
                let mut out = Vec::with_capacity(3);
                out.push(ffi::egl::WAYLAND_PLANE_WL as i32);
                out.push(i as i32);
                out.push(ffi::egl::NONE as i32);

                images.push({
                    let image = unsafe {
                        ffi::egl::CreateImageKHR(
                            *display,
                            ffi::egl::NO_CONTEXT,
                            ffi::egl::WAYLAND_BUFFER_WL,
                            buffer.c_ptr() as *mut _,
                            out.as_ptr(),
                        )
                    };
                    if image == ffi::egl::NO_IMAGE_KHR {
                        return Err(BufferAccessError::EGLImageCreationFailed);
                    } else {
                        image
                    }
                });
            }

            Ok(EGLImages {
                display: Rc::downgrade(&display),
                width: width as u32,
                height: height as u32,
                y_inverted: inverted != 0,
                format,
                images,
                buffer,
            })
        } else {
            Err(BufferAccessError::ContextLost)
        }
    }
}

impl Drop for EGLDisplay {
    fn drop(&mut self) {
        if let Some(display) = self.0.upgrade() {
            if !self.1.is_null() {
                unsafe {
                    ffi::egl::UnbindWaylandDisplayWL(*display, self.1 as *mut _);
                }
            }
        }
    }
}

impl<E: EGLWaylandExtensions> EGLWaylandExtensions for Rc<E> {
    fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay> {
        (**self).bind_wl_display(display)
    }
}

impl<B: native::Backend, N: native::NativeDisplay<B>> EGLWaylandExtensions for EGLContext<B, N> {
    fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay> {
        if !self.wl_drm_support {
            bail!(ErrorKind::EglExtensionNotSupported(&[
                "EGL_WL_bind_wayland_display"
            ]));
        }
        if !self.egl_to_texture_support {
            bail!(ErrorKind::EglExtensionNotSupported(&["GL_OES_EGL_image"]));
        }
        let res = unsafe { ffi::egl::BindWaylandDisplayWL(*self.display, display.c_ptr() as *mut _) };
        if res == 0 {
            bail!(ErrorKind::OtherEGLDisplayAlreadyBound);
        }
        Ok(EGLDisplay::new(self, display.c_ptr()))
    }
}
<commit_msg>wayland.backend.egl: derive Debug for Format<commit_after>//! Wayland specific EGL functionality - EGL based `WlBuffer`s.
//!
//! The types of this module can be used to initialize hardware acceleration rendering
//! based on EGL for clients as it may enabled usage of `EGLImage` based `WlBuffer`s.
//!
//! To use it bind any backend implementing the `EGLWaylandExtensions` trait, that shall do the
//! rendering (so pick a fast one), to the `wayland_server::Display` of your compositor.
//! Note only one backend may be bould to any `Display` at any time.
//!
//! You may then use the resulting `EGLDisplay` to recieve `EGLImages` of an egl-based `WlBuffer`
//! for rendering.

use backend::graphics::egl::{ffi, native, EGLContext, EglExtensionNotSupportedError};
use backend::graphics::egl::error::*;
use backend::graphics::egl::ffi::egl::types::EGLImage;
use nix::libc::c_uint;
use std::fmt;
use std::rc::{Rc, Weak};
use wayland_server::{Display, Resource};
use wayland_server::protocol::wl_buffer::{self, WlBuffer};
use wayland_sys::server::wl_display;

/// Error that can occur when accessing an EGL buffer
pub enum BufferAccessError {
    /// The corresponding Context is not alive anymore
    ContextLost,
    /// This buffer is not managed by the EGL buffer
    NotManaged(Resource<WlBuffer>),
    /// Failed to create EGLImages from the buffer
    EGLImageCreationFailed,
    /// The required EGL extension is not supported by the underlying EGL implementation
    EglExtensionNotSupported(EglExtensionNotSupportedError),
}

impl fmt::Debug for BufferAccessError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
        match *self {
            BufferAccessError::ContextLost => write!(formatter, "BufferAccessError::ContextLost"),
            BufferAccessError::NotManaged(_) => write!(formatter, "BufferAccessError::NotManaged"),
            BufferAccessError::EGLImageCreationFailed => {
                write!(formatter, "BufferAccessError::EGLImageCreationFailed")
            }
            BufferAccessError::EglExtensionNotSupported(ref err) => write!(formatter, "{:?}", err),
        }
    }
}

impl fmt::Display for BufferAccessError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
        use std::error::Error;
        match *self {
            BufferAccessError::ContextLost
            | BufferAccessError::NotManaged(_)
            | BufferAccessError::EGLImageCreationFailed => write!(formatter, "{}", self.description()),
            BufferAccessError::EglExtensionNotSupported(ref err) => err.fmt(formatter),
        }
    }
}

impl ::std::error::Error for BufferAccessError {
    fn description(&self) -> &str {
        match *self {
            BufferAccessError::ContextLost => "The corresponding context was lost",
            BufferAccessError::NotManaged(_) => "This buffer is not mananged by EGL",
            BufferAccessError::EGLImageCreationFailed => "Failed to create EGLImages from the buffer",
            BufferAccessError::EglExtensionNotSupported(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            BufferAccessError::EglExtensionNotSupported(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<EglExtensionNotSupportedError> for BufferAccessError {
    fn from(error: EglExtensionNotSupportedError) -> Self {
        BufferAccessError::EglExtensionNotSupported(error)
    }
}

/// Error that might happen when binding an `EGLImage` to a gl texture
#[derive(Debug, Clone, PartialEq)]
pub enum TextureCreationError {
    /// The given plane index is out of bounds
    PlaneIndexOutOfBounds,
    /// The OpenGL context has been lost and needs to be recreated.
    ///
    /// All the objects associated to it (textures, buffers, programs, etc.)
    /// need to be recreated from scratch.
    ///
    /// Operations will have no effect. Functions that read textures, buffers, etc.
    /// from OpenGL will return uninitialized data instead.
    ///
    /// A context loss usually happens on mobile devices when the user puts the
    /// application on sleep and wakes it up later. However any OpenGL implementation
    /// can theoretically lose the context at any time.
    ContextLost,
    /// Failed to bind the EGLImage to the given texture
    ///
    /// The given argument is the gl error code
    TextureBindingFailed(u32),
}

impl fmt::Display for TextureCreationError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
        use std::error::Error;
        match *self {
            TextureCreationError::ContextLost => write!(formatter, "{}", self.description()),
            TextureCreationError::PlaneIndexOutOfBounds => write!(formatter, "{}", self.description()),
            TextureCreationError::TextureBindingFailed(code) => write!(
                formatter,
                "{}. Gl error code: {:?}",
                self.description(),
                code
            ),
        }
    }
}

impl ::std::error::Error for TextureCreationError {
    fn description(&self) -> &str {
        match *self {
            TextureCreationError::ContextLost => "The context has been lost, it needs to be recreated",
            TextureCreationError::PlaneIndexOutOfBounds => "This buffer is not mananged by EGL",
            TextureCreationError::TextureBindingFailed(_) => "Failed to create EGLImages from the buffer",
        }
    }

    fn cause(&self) -> Option<&::std::error::Error> {
        None
    }
}

/// Texture format types
#[repr(i32)]
#[allow(non_camel_case_types)]
#[derive(Debug)]
pub enum Format {
    /// RGB format
    RGB = ffi::egl::TEXTURE_RGB as i32,
    /// RGB + alpha channel format
    RGBA = ffi::egl::TEXTURE_RGBA as i32,
    /// External format
    External = ffi::egl::TEXTURE_EXTERNAL_WL,
    /// 2-plane Y and UV format
    Y_UV = ffi::egl::TEXTURE_Y_UV_WL,
    /// 3-plane Y, U and V format
    Y_U_V = ffi::egl::TEXTURE_Y_U_V_WL,
    /// 2-plane Y and XUXV format
    Y_XUXV = ffi::egl::TEXTURE_Y_XUXV_WL,
}

impl Format {
    /// Amount of planes this format uses
    pub fn num_planes(&self) -> usize {
        match *self {
            Format::RGB | Format::RGBA | Format::External => 1,
            Format::Y_UV | Format::Y_XUXV => 2,
            Format::Y_U_V => 3,
        }
    }
}

/// Images of the egl-based `WlBuffer`.
pub struct EGLImages {
    display: Weak<ffi::egl::types::EGLDisplay>,
    /// Width in pixels
    pub width: u32,
    /// Height in pixels
    pub height: u32,
    /// If the y-axis is inverted or not
    pub y_inverted: bool,
    /// Format of these images
    pub format: Format,
    images: Vec<EGLImage>,
    buffer: Resource<WlBuffer>,
}

impl EGLImages {
    /// Amount of planes of these `EGLImages`
    pub fn num_planes(&self) -> usize {
        self.format.num_planes()
    }

    /// Bind plane to an OpenGL texture id
    ///
    /// This does only temporarily modify the OpenGL state any changes are reverted before returning.
    ///
    /// # Unsafety
    ///
    /// The given `tex_id` needs to be a valid GL texture otherwise undefined behavior might occur.
    pub unsafe fn bind_to_texture(
        &self,
        plane: usize,
        tex_id: c_uint,
    ) -> ::std::result::Result<(), TextureCreationError> {
        if self.display.upgrade().is_some() {
            let mut old_tex_id: i32 = 0;
            ffi::gl::GetIntegerv(ffi::gl::TEXTURE_BINDING_2D, &mut old_tex_id);
            ffi::gl::BindTexture(ffi::gl::TEXTURE_2D, tex_id);
            ffi::gl::EGLImageTargetTexture2DOES(
                ffi::gl::TEXTURE_2D,
                *self.images
                    .get(plane)
                    .ok_or(TextureCreationError::PlaneIndexOutOfBounds)?,
            );
            let res = match ffi::egl::GetError() as u32 {
                ffi::egl::SUCCESS => Ok(()),
                err => Err(TextureCreationError::TextureBindingFailed(err)),
            };
            ffi::gl::BindTexture(ffi::gl::TEXTURE_2D, old_tex_id as u32);
            res
        } else {
            Err(TextureCreationError::ContextLost)
        }
    }
}

impl Drop for EGLImages {
    fn drop(&mut self) {
        if let Some(display) = self.display.upgrade() {
            for image in self.images.drain(..) {
                unsafe {
                    ffi::egl::DestroyImageKHR(*display, image);
                }
            }
        }
        self.buffer.send(wl_buffer::Event::Release);
    }
}

/// Trait any backend type may implement that allows binding a `wayland_server::Display`
/// to create an `EGLDisplay` for egl-based `WlBuffer`s.
pub trait EGLWaylandExtensions {
    /// Binds this EGL context to the given Wayland display.
    ///
    /// This will allow clients to utilize EGL to create hardware-accelerated
    /// surfaces. The server will need to be able to handle egl-wl_buffers.
    /// See the `wayland::drm` module.
    ///
    /// ## Errors
    ///
    /// This might return `WlExtensionNotSupported` if binding is not supported
    /// by the EGL implementation.
    ///
    /// This might return `OtherEGLDisplayAlreadyBound` if called for the same
    /// `Display` multiple times, as only one context may be bound at any given time.
    fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay>;
}

/// Type to recieve `EGLImages` for egl-based `WlBuffer`s.
///
/// Can be created by using `EGLWaylandExtensions::bind_wl_display`.
pub struct EGLDisplay(Weak<ffi::egl::types::EGLDisplay>, *mut wl_display);

impl EGLDisplay {
    fn new<B: native::Backend, N: native::NativeDisplay<B>>(
        context: &EGLContext<B, N>,
        display: *mut wl_display,
    ) -> EGLDisplay {
        EGLDisplay(Rc::downgrade(&context.display), display)
    }

    /// Try to recieve `EGLImages` from a given `WlBuffer`.
    ///
    /// In case the buffer is not managed by egl (but e.g. the wayland::shm module)
    /// a `BufferAccessError::NotManaged(WlBuffer)` is returned with the original buffer
    /// to render it another way.
    pub fn egl_buffer_contents(
        &self,
        buffer: Resource<WlBuffer>,
    ) -> ::std::result::Result<EGLImages, BufferAccessError> {
        if let Some(display) = self.0.upgrade() {
            let mut format: i32 = 0;
            if unsafe {
                ffi::egl::QueryWaylandBufferWL(
                    *display,
                    buffer.c_ptr() as *mut _,
                    ffi::egl::EGL_TEXTURE_FORMAT,
                    &mut format as *mut _,
                ) == 0
            } {
                return Err(BufferAccessError::NotManaged(buffer));
            }
            let format = match format {
                x if x == ffi::egl::TEXTURE_RGB as i32 => Format::RGB,
                x if x == ffi::egl::TEXTURE_RGBA as i32 => Format::RGBA,
                ffi::egl::TEXTURE_EXTERNAL_WL => Format::External,
                ffi::egl::TEXTURE_Y_UV_WL => Format::Y_UV,
                ffi::egl::TEXTURE_Y_U_V_WL => Format::Y_U_V,
                ffi::egl::TEXTURE_Y_XUXV_WL => Format::Y_XUXV,
                _ => panic!("EGL returned invalid texture type"),
            };

            let mut width: i32 = 0;
            if unsafe {
                ffi::egl::QueryWaylandBufferWL(
                    *display,
                    buffer.c_ptr() as *mut _,
                    ffi::egl::WIDTH as i32,
                    &mut width as *mut _,
                ) == 0
            } {
                return Err(BufferAccessError::NotManaged(buffer));
            }

            let mut height: i32 = 0;
            if unsafe {
                ffi::egl::QueryWaylandBufferWL(
                    *display,
                    buffer.c_ptr() as *mut _,
                    ffi::egl::HEIGHT as i32,
                    &mut height as *mut _,
                ) == 0
            } {
                return Err(BufferAccessError::NotManaged(buffer));
            }

            let mut inverted: i32 = 0;
            if unsafe {
                ffi::egl::QueryWaylandBufferWL(
                    *display,
                    buffer.c_ptr() as *mut _,
                    ffi::egl::WAYLAND_Y_INVERTED_WL,
                    &mut inverted as *mut _,
                ) != 0
            } {
                inverted = 1;
            }

            let mut images = Vec::with_capacity(format.num_planes());
            for i in 0..format.num_planes() {
                let mut out = Vec::with_capacity(3);
                out.push(ffi::egl::WAYLAND_PLANE_WL as i32);
                out.push(i as i32);
                out.push(ffi::egl::NONE as i32);

                images.push({
                    let image = unsafe {
                        ffi::egl::CreateImageKHR(
                            *display,
                            ffi::egl::NO_CONTEXT,
                            ffi::egl::WAYLAND_BUFFER_WL,
                            buffer.c_ptr() as *mut _,
                            out.as_ptr(),
                        )
                    };
                    if image == ffi::egl::NO_IMAGE_KHR {
                        return Err(BufferAccessError::EGLImageCreationFailed);
                    } else {
                        image
                    }
                });
            }

            Ok(EGLImages {
                display: Rc::downgrade(&display),
                width: width as u32,
                height: height as u32,
                y_inverted: inverted != 0,
                format,
                images,
                buffer,
            })
        } else {
            Err(BufferAccessError::ContextLost)
        }
    }
}

impl Drop for EGLDisplay {
    fn drop(&mut self) {
        if let Some(display) = self.0.upgrade() {
            if !self.1.is_null() {
                unsafe {
                    ffi::egl::UnbindWaylandDisplayWL(*display, self.1 as *mut _);
                }
            }
        }
    }
}

impl<E: EGLWaylandExtensions> EGLWaylandExtensions for Rc<E> {
    fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay> {
        (**self).bind_wl_display(display)
    }
}

impl<B: native::Backend, N: native::NativeDisplay<B>> EGLWaylandExtensions for EGLContext<B, N> {
    fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay> {
        if !self.wl_drm_support {
            bail!(ErrorKind::EglExtensionNotSupported(&[
                "EGL_WL_bind_wayland_display"
            ]));
        }
        if !self.egl_to_texture_support {
            bail!(ErrorKind::EglExtensionNotSupported(&["GL_OES_EGL_image"]));
        }
        let res = unsafe { ffi::egl::BindWaylandDisplayWL(*self.display, display.c_ptr() as *mut _) };
        if res == 0 {
            bail!(ErrorKind::OtherEGLDisplayAlreadyBound);
        }
        Ok(EGLDisplay::new(self, display.c_ptr()))
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use super::{
    actor::{self, SharedState},
    Idle, Result, State, StateChangeImpl, StateMachine, TransitionError,
};

use slog_scope::{error, info};

#[derive(Debug)]
pub(super) struct Error {
    error: TransitionError,
}

impl PartialEq for Error {
    fn eq(&self, _other: &Self) -> bool {
        // error field intentionally ignored
        true
    }
}

#[async_trait::async_trait]
impl StateChangeImpl for State<Error> {
    fn name(&self) -> &'static str {
        "error"
    }

    async fn handle(self, _: &mut SharedState) -> Result<(StateMachine, actor::StepTransition)> {
        error!("Error state reached: {:?}", self.0.error);

        info!("Returning to idle state");
        Ok((StateMachine::Idle(State(Idle {})), actor::StepTransition::Immediate))
    }
}

impl From<TransitionError> for StateMachine {
    fn from(error: TransitionError) -> StateMachine {
        StateMachine::Error(State(Error { error }))
    }
}
<commit_msg>updatehub: Use display instead of debug for error log on Error state<commit_after>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use super::{
    actor::{self, SharedState},
    Idle, Result, State, StateChangeImpl, StateMachine, TransitionError,
};

use slog_scope::{error, info};

#[derive(Debug)]
pub(super) struct Error {
    error: TransitionError,
}

impl PartialEq for Error {
    fn eq(&self, _other: &Self) -> bool {
        // error field intentionally ignored
        true
    }
}

#[async_trait::async_trait]
impl StateChangeImpl for State<Error> {
    fn name(&self) -> &'static str {
        "error"
    }

    async fn handle(self, _: &mut SharedState) -> Result<(StateMachine, actor::StepTransition)> {
        error!("Error state reached: {}", self.0.error);

        info!("Returning to idle state");
        Ok((StateMachine::Idle(State(Idle {})), actor::StepTransition::Immediate))
    }
}

impl From<TransitionError> for StateMachine {
    fn from(error: TransitionError) -> StateMachine {
        StateMachine::Error(State(Error { error }))
    }
}
<|endoftext|>


<commit_before>//! This mod specifies and implements the Distributed Lock Manager Redlock object, as well
//! as the necessary functions lock() and unlock(). It also declares the struct Lock which
//! is used to hold necessary information about each lock a client acquires.

use redis::{Client, Connection, RedisResult, cmd, Value};
use types::{RedlockResult, Error};
use time::precise_time_s;
use std::time::Duration;
use std::thread::sleep;
use rand::{thread_rng, Rng};

/// Distributed Lock Manager class object
pub struct Redlock {
    /// list of connections with Master Nodes
    servers: Vec<Connection>,
    /// no. of retries to secure locks
    retry_count: i32,
    /// time delay between each retry
    retry_delay: f32,
    /// number of locks needed
    quorum: i32,
    /// clock drift factor
    clock_drift_factor: f32,
}

/// Represents the Lock a client holds
pub struct Lock {
    /// an integer representing the number of milliseconds the lock will be valid
    validity: i32,
    /// the name of the locked resource as specified by the user.
    resource: String,
    /// a random value which is used to safely reclaim the lock.
    key: String,
    /// start time in seconds returned by Rust's `precise_time_s()` from which `validity` runs from
    start_time: f64,
}

impl Redlock {
    /// instantialize a lock manager with a vector of URLs (format: redis://host:port/db)
    /// for each Redis master node, and optionally specify a retry count and delay between
    /// each retry. If None is given, the default will be 3 and 0.2s respectively
    pub fn dlm(urls : Vec<String>, retry_count: Option<i32>, retry_delay: Option<f32>)
        -> RedlockResult<Redlock> {
        let mut servers = Vec::new();
        let quorum = urls.len() as i32;
        for u in urls {
            let client_res = Client::open(&*u);
            if client_res.is_ok() {
                let con_res = client_res.unwrap().get_connection();
                if con_res.is_ok() {
                    servers.push(con_res.unwrap());
                    println!("added server");
                }
            }
        }
        if (servers.len() as i32) < quorum {
            return Err(Error::NotEnoughMasters);
        }
        let rc = match retry_count {
            Some(x) => x,
            None => 3,
        };
        let rd = match retry_delay {
            Some(x) => x,
            None => 0.2,

        };
        let cdf = 0.01;
        Ok(Redlock {
            servers: servers,
            retry_count: rc,
            retry_delay: rd,
            quorum: quorum,
            clock_drift_factor: cdf,
        })
    }

    /// generates unique id for lock key
    fn get_unique_id(&self) -> String {
        let id_len = 22;
        thread_rng().gen_ascii_chars().take(id_len).collect()
    }

   /// locks resource specified by res_name for ttl in miliseconds
    pub fn lock(&mut self, res_name: String, ttl: i32) -> RedlockResult<Lock> {
        let mut retry = 0;
        let val = self.get_unique_id();
        let drift : i32 = (((ttl as f32) * self.clock_drift_factor) as i32) + 2;
        while retry < self.retry_count {
            let mut n = 0;
            let start_time : i32 = (precise_time_s() * 1000.0) as i32;
            for server in &mut self.servers {
                let res = lock_instance(server, &res_name, &val, ttl);
                if res.is_ok() {
                    n = n + 1;
                }
            }
            let elapsed_time : i32 = ((precise_time_s() * 1000.0) as i32) - start_time;
            let validity = ttl - elapsed_time - drift;
            let start_time = precise_time_s();
            if validity > 0 && n >= self.quorum {
                // lock successful!
                return Ok(Lock::new(validity, res_name, val, start_time));
            }  else {
                for server in &mut self.servers {
                    let res = unlock_instance(server, &res_name, &val);
                    if res.is_err() {
                        return Err(Error::RedlockConn);
                    }
                }
                retry = retry + 1;
                // sleep for retry_delay
                sleep(Duration::from_millis((self.retry_delay as u64) * 1000));
            }
        }
        Err(Error::CannotObtainLock)
    }
    /// unlocks resource held by Lock
    pub fn unlock(&mut self, lock: Lock) -> RedlockResult<()> {
        for server in &mut self.servers {
            let res = unlock_instance(server, &lock.resource, &lock.key);
            if res.is_err() {
                return Err(Error::RedlockConn);
            }
        }
        Ok(())
    }
}

impl Lock {
    /// instantialize a Lock with validity, resource name, and key
    pub fn new(validity: i32, res: String, key: String, start_time: f64) -> Self {
        Lock { validity: validity, resource: res, key: key, start_time: start_time, }
    }

    /// checks if lock is still valid
    pub fn still_valid(&self) -> bool {
        (((precise_time_s() - self.start_time) * 1000.0) as i32) < self.validity
    }
}

/// release lock from one server
fn unlock_instance(server : &Connection, res_name : &str,
                   val : &str) -> RedlockResult<()> {
    let unlock_script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
    let res : RedisResult<i32> = cmd("EVAL").arg(unlock_script).arg(1).arg(res_name).arg(val)
                                    .query(server);
    match res {
        Ok(1) => Ok(()),
        Ok(0) => Err(Error::UnlockFailed),
        _ => Err(Error::RedlockConn),
    }
}

/// acquire lock from one server
fn lock_instance(server : &Connection, res_name : &str, val : &str,
                 ttl: i32) -> RedlockResult<()> {
    let res : RedisResult<Value> = cmd("SET").arg(res_name).arg(val).arg("NX").arg("PX")
                                    .arg(ttl).query(server);
    match res {
        Ok(Value::Okay) => Ok(()),
        Ok(Value::Nil) => Err(Error::CannotObtainLock),
        _ => Err(Error::RedlockConn),
    }
}

#[test]
pub fn test_lock_instance() {
    let client = Client::open("redis://127.0.0.1/").unwrap();
    let con = client.get_connection().unwrap();
    assert!(lock_instance(&con, "lock_test_res", "uni_val", 1000).is_ok());
    assert!(lock_instance(&con, "lock_test_res", "uni_val", 1000).is_err());
    sleep(Duration::from_secs(1));
    assert!(lock_instance(&con, "lock_test_res", "uni_val", 10).is_ok());
}

#[test]
pub fn test_unlock_instance() {
    let client = Client::open("redis://127.0.0.1/").unwrap();
    let con = client.get_connection().unwrap();
    assert!(lock_instance(&con, "unlock_test_res", "uni_val", 30000).is_ok());
    let res = unlock_instance(&con, "unlock_test_res", "uni_val");
    assert!(res.is_ok());
    assert_eq!(res, Ok(()));
    let res = unlock_instance(&con, "unlock_test_res", "uni_val");
    assert!(res.is_err());
}

#[cfg(test)]
mod test{
    use super::Redlock;
    use redis;
    use redis::{RedisResult, Value};

    #[test]
    pub fn redis_check() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let res : RedisResult<Value> = redis::cmd("SET").arg("res").arg("key").arg("NX").arg("PX").arg(3000).query(&con);
        assert_eq!(res, Ok(Value::Okay));
        assert_eq!(redis::cmd("GET").arg("res").query(&con), Ok("key".to_string()));
        let res : RedisResult<Value> = redis::cmd("SET").arg("res").arg("key").arg("NX").arg("PX").arg(3000).query(&con);
        assert_eq!(res, Ok(Value::Nil));
    }

    #[test]
    pub fn single_server_lock() {
        let mut dlm = Redlock::dlm(vec!["redis://127.0.0.1".to_string()], None, None).unwrap();
        let my_lock = dlm.lock("my_resource_name".to_string(), 5000);
        assert!(my_lock.is_ok());
    }

    /*
    #[test]
    pub fn missing_server() {
        assert!(Redlock::dlm(vec!["redis://123.123.123.123".to_string()], None, None).is_err());
    }*/

}
<commit_msg>added multi server test<commit_after>//! This mod specifies and implements the Distributed Lock Manager Redlock object, as well
//! as the necessary functions lock() and unlock(). It also declares the struct Lock which
//! is used to hold necessary information about each lock a client acquires.

use redis::{Client, Connection, RedisResult, cmd, Value};
use types::{RedlockResult, Error};
use time::precise_time_s;
use std::time::Duration;
use std::thread::sleep;
use rand::{thread_rng, Rng};

/// Distributed Lock Manager class object
pub struct Redlock {
    /// list of connections with Master Nodes
    servers: Vec<Connection>,
    /// no. of retries to secure locks
    retry_count: i32,
    /// time delay between each retry
    retry_delay: f32,
    /// number of locks needed
    quorum: i32,
    /// clock drift factor
    clock_drift_factor: f32,
}

/// Represents the Lock a client holds
pub struct Lock {
    /// an integer representing the number of milliseconds the lock will be valid
    validity: i32,
    /// the name of the locked resource as specified by the user.
    resource: String,
    /// a random value which is used to safely reclaim the lock.
    key: String,
    /// start time in seconds returned by Rust's `precise_time_s()` from which `validity` runs from
    start_time: f64,
}

impl Redlock {
    /// instantialize a lock manager with a vector of URLs (format: redis://host:port/db)
    /// for each Redis master node, and optionally specify a retry count and delay between
    /// each retry. If None is given, the default will be 3 and 0.2s respectively
    pub fn dlm(urls : Vec<String>, retry_count: Option<i32>, retry_delay: Option<f32>)
        -> RedlockResult<Redlock> {
        let mut servers = Vec::new();
        let quorum = urls.len() as i32;
        for u in urls {
            let client_res = Client::open(&*u);
            if client_res.is_ok() {
                let con_res = client_res.unwrap().get_connection();
                if con_res.is_ok() {
                    servers.push(con_res.unwrap());
                    println!("added server");
                }
            }
        }
        if (servers.len() as i32) < quorum {
            return Err(Error::NotEnoughMasters);
        }
        let rc = match retry_count {
            Some(x) => x,
            None => 3,
        };
        let rd = match retry_delay {
            Some(x) => x,
            None => 0.2,

        };
        let cdf = 0.01;
        Ok(Redlock {
            servers: servers,
            retry_count: rc,
            retry_delay: rd,
            quorum: quorum,
            clock_drift_factor: cdf,
        })
    }

    /// generates unique id for lock key
    fn get_unique_id(&self) -> String {
        let id_len = 22;
        thread_rng().gen_ascii_chars().take(id_len).collect()
    }

   /// locks resource specified by res_name for ttl in miliseconds
    pub fn lock(&mut self, res_name: String, ttl: i32) -> RedlockResult<Lock> {
        let mut retry = 0;
        let val = self.get_unique_id();
        let drift : i32 = (((ttl as f32) * self.clock_drift_factor) as i32) + 2;
        while retry < self.retry_count {
            let mut n = 0;
            let start_time : i32 = (precise_time_s() * 1000.0) as i32;
            for server in &mut self.servers {
                let res = lock_instance(server, &res_name, &val, ttl);
                if res.is_ok() {
                    n = n + 1;
                }
            }
            let elapsed_time : i32 = ((precise_time_s() * 1000.0) as i32) - start_time;
            let validity = ttl - elapsed_time - drift;
            let start_time = precise_time_s();
            if validity > 0 && n >= self.quorum {
                // lock successful!
                return Ok(Lock::new(validity, res_name, val, start_time));
            }  else {
                for server in &mut self.servers {
                    let res = unlock_instance(server, &res_name, &val);
                    if res.is_err() {
                        return Err(Error::RedlockConn);
                    }
                }
                retry = retry + 1;
                // sleep for retry_delay
                sleep(Duration::from_millis((self.retry_delay as u64) * 1000));
            }
        }
        Err(Error::CannotObtainLock)
    }
    /// unlocks resource held by Lock
    pub fn unlock(&mut self, lock: Lock) -> RedlockResult<()> {
        for server in &mut self.servers {
            let res = unlock_instance(server, &lock.resource, &lock.key);
            if res.is_err() {
                return Err(Error::RedlockConn);
            }
        }
        Ok(())
    }
}

impl Lock {
    /// instantialize a Lock with validity, resource name, and key
    pub fn new(validity: i32, res: String, key: String, start_time: f64) -> Self {
        Lock { validity: validity, resource: res, key: key, start_time: start_time, }
    }

    /// checks if lock is still valid
    pub fn still_valid(&self) -> bool {
        (((precise_time_s() - self.start_time) * 1000.0) as i32) < self.validity
    }
}

/// release lock from one server
fn unlock_instance(server : &Connection, res_name : &str,
                   val : &str) -> RedlockResult<()> {
    let unlock_script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
    let res : RedisResult<i32> = cmd("EVAL").arg(unlock_script).arg(1).arg(res_name).arg(val)
                                    .query(server);
    match res {
        Ok(1) => Ok(()),
        Ok(0) => Err(Error::UnlockFailed),
        _ => Err(Error::RedlockConn),
    }
}

/// acquire lock from one server
fn lock_instance(server : &Connection, res_name : &str, val : &str,
                 ttl: i32) -> RedlockResult<()> {
    let res : RedisResult<Value> = cmd("SET").arg(res_name).arg(val).arg("NX").arg("PX")
                                    .arg(ttl).query(server);
    match res {
        Ok(Value::Okay) => Ok(()),
        Ok(Value::Nil) => Err(Error::CannotObtainLock),
        _ => Err(Error::RedlockConn),
    }
}

#[test]
pub fn test_lock_instance() {
    let client = Client::open("redis://127.0.0.1/").unwrap();
    let con = client.get_connection().unwrap();
    assert!(lock_instance(&con, "lock_test_res", "uni_val", 1000).is_ok());
    assert!(lock_instance(&con, "lock_test_res", "uni_val", 1000).is_err());
    sleep(Duration::from_secs(1));
    assert!(lock_instance(&con, "lock_test_res", "uni_val", 10).is_ok());
}

#[test]
pub fn test_unlock_instance() {
    let client = Client::open("redis://127.0.0.1/").unwrap();
    let con = client.get_connection().unwrap();
    assert!(lock_instance(&con, "unlock_test_res", "uni_val", 30000).is_ok());
    let res = unlock_instance(&con, "unlock_test_res", "uni_val");
    assert!(res.is_ok());
    assert_eq!(res, Ok(()));
    let res = unlock_instance(&con, "unlock_test_res", "uni_val");
    assert!(res.is_err());
}

#[cfg(test)]
mod test{
    use super::Redlock;
    use redis;
    use redis::{RedisResult, Value};

    #[test]
    pub fn redis_check() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let res : RedisResult<Value> = redis::cmd("SET").arg("res").arg("key").arg("NX").arg("PX").arg(3000).query(&con);
        assert_eq!(res, Ok(Value::Okay));
        assert_eq!(redis::cmd("GET").arg("res").query(&con), Ok("key".to_string()));
        let res : RedisResult<Value> = redis::cmd("SET").arg("res").arg("key").arg("NX").arg("PX").arg(3000).query(&con);
        assert_eq!(res, Ok(Value::Nil));
    }

    #[test]
    pub fn single_server_lock() {
        let mut dlm = Redlock::dlm(vec!["redis://127.0.0.1".to_string()], None, None).unwrap();
        let my_lock = dlm.lock("my_resource_name".to_string(), 5000);
        assert!(my_lock.is_ok());
    }

    #[test]
    pub fn multi_server_speclab_test() {
        let urls = vec!["redis://127.0.0.1"to_string(),
                        "redis://spec02.seas.upenn.edu".to_string(),
                        "redis://spec10.seas.upenn.edu".to_string()];
        let mut dlm = Redlock::dlm(urls, None, None).unwrap();
        let my_lock = dlm.lock("multi_server_res".to_string(), 5000);
        assert!(my_lock.is_ok());
    }

    /*
    #[test]
    pub fn missing_server() {
        assert!(Redlock::dlm(vec!["redis://123.123.123.123".to_string()], None, None).is_err());
    }*/

}
<|endoftext|>


<commit_before>// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
// file at the top-level directory of this distribution.

use std::env;
use std::path::Path;
use std::io::Write;

extern crate minidump;

use minidump::*;

const USAGE : &'static str = "Usage: minidump_dump <minidump>";

fn print_minidump_dump(path : &Path) {
    match Minidump::read_path(path) {
        Ok(mut dump) => {
            let stdout = &mut std::io::stdout();
            dump.print(stdout).unwrap();
            if let Ok(thread_list) = dump.get_stream::<MinidumpThreadList>() {
                thread_list.print(stdout).unwrap();
            }
            if let Ok(module_list) = dump.get_stream::<MinidumpModuleList>() {
                module_list.print(stdout).unwrap();
            }
            // TODO: MemoryList
            if let Ok(exception) = dump.get_stream::<MinidumpException>() {
                exception.print(stdout).unwrap();
            }
            // TODO: Assertion
            if let Ok(system_info) = dump.get_stream::<MinidumpSystemInfo>() {
                system_info.print(stdout).unwrap();
            }
            if let Ok(misc_info) = dump.get_stream::<MinidumpMiscInfo>() {
                misc_info.print(stdout).unwrap();
            }
            if let Ok(breakpad_info) = dump.get_stream::<MinidumpBreakpadInfo>() {
                breakpad_info.print(stdout).unwrap();
            }
            // TODO: MemoryInfoList
            // TODO: raw Linux streams
        },
        Err(err) => {
            let mut stderr = std::io::stderr();
            writeln!(&mut stderr, "Error reading dump: {:?}", err).unwrap();
        }
    }
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    if let Some(dump_arg) = env::args().nth(1) {
        let path = Path::new(&dump_arg);
        print_minidump_dump(&path);
    } else {
        let mut stderr = std::io::stderr();
        writeln!(&mut stderr, "{}", USAGE).unwrap();
    }
}
<commit_msg>Dump Linux streams in minidump_dump<commit_after>// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
// file at the top-level directory of this distribution.

use std::env;
use std::path::Path;
use std::io::{self,Write};
use std::str;

extern crate minidump;

use minidump::*;

const USAGE : &'static str = "Usage: minidump_dump <minidump>";

macro_rules! streams {
    ( $( $x:ident ),* ) => {
        &[$( ( minidump_format::$x, stringify!($x) ) ),*]
    };
}

fn print_raw_stream<T: Write>(name: &str, contents: Vec<u8>, out: &mut T) -> io::Result<()> {
    try!(writeln!(out, "Stream {}:", name));
    let s = &contents.split(|&v| v == 0)
        .map(|s| String::from_utf8_lossy(s))
        .collect::<Vec<_>>()
        .join("\\0\n");
    write!(out, "{}\n\n", s)
}

fn print_minidump_dump(path : &Path) {
    match Minidump::read_path(path) {
        Ok(mut dump) => {
            let stdout = &mut std::io::stdout();
            dump.print(stdout).unwrap();
            if let Ok(thread_list) = dump.get_stream::<MinidumpThreadList>() {
                thread_list.print(stdout).unwrap();
            }
            if let Ok(module_list) = dump.get_stream::<MinidumpModuleList>() {
                module_list.print(stdout).unwrap();
            }
            // TODO: MemoryList
            if let Ok(exception) = dump.get_stream::<MinidumpException>() {
                exception.print(stdout).unwrap();
            }
            // TODO: Assertion
            if let Ok(system_info) = dump.get_stream::<MinidumpSystemInfo>() {
                system_info.print(stdout).unwrap();
            }
            if let Ok(misc_info) = dump.get_stream::<MinidumpMiscInfo>() {
                misc_info.print(stdout).unwrap();
            }
            if let Ok(breakpad_info) = dump.get_stream::<MinidumpBreakpadInfo>() {
                breakpad_info.print(stdout).unwrap();
            }
            // TODO: MemoryInfoList
            for &(stream, name) in streams!(
                MD_LINUX_CMD_LINE,
                MD_LINUX_ENVIRON,
                MD_LINUX_LSB_RELEASE,
                MD_LINUX_PROC_STATUS,
                MD_LINUX_CPU_INFO,
                MD_LINUX_MAPS
                    ) {
                if let Ok(contents) = dump.get_raw_stream(stream) {
                    print_raw_stream(name, contents, stdout).unwrap();
                }
            }
        },
        Err(err) => {
            let mut stderr = std::io::stderr();
            writeln!(&mut stderr, "Error reading dump: {:?}", err).unwrap();
        }
    }
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    if let Some(dump_arg) = env::args().nth(1) {
        let path = Path::new(&dump_arg);
        print_minidump_dump(&path);
    } else {
        let mut stderr = std::io::stderr();
        writeln!(&mut stderr, "{}", USAGE).unwrap();
    }
}
<|endoftext|>


<commit_before>use bitstream::byteread::*;

pub trait BitRead {
    fn count(&self) -> usize;
    fn can_refill(&self) -> bool;
    fn refill64(&mut self) -> ();
    fn get_val(&mut self, n:usize) -> u64;
    fn get_bit(&mut self) -> bool;
/*
    fn peek_bit1(size : u8) -> bool;

    fn get_bits32(size : u8) -> u32;

    fn get_bits64(size : u8) -> u64;

    fn peek_bits32(size : u8) -> u32;

    fn peek_bits64(size : u8) -> u64;

    fn skip_bits(size : u8) -> ();
*/
}

pub struct BitReadLE <'a> {
    buffer : &'a[u8], /// read buffer, 8-bytes padded
    index : usize,
    cache : u64,
    left : usize,
}

impl <'a> BitRead for BitReadLE<'a> {
    #[inline]
    fn count(&self) -> usize {
        self.index * 8 - self.left
    }

    #[inline]
    fn can_refill(&self) -> bool {
        self.index < self.buffer.len() - 8
    }

    #[inline]
    fn refill64(&mut self) -> () {
        if !self.can_refill() {
            return;
        }

        self.cache  = get_u64l(&self.buffer[self.index..]);
        self.index += 8;
        self.left   = 64;
    }

    #[inline]
    fn get_val(&mut self, n:usize) -> u64 {
        let ret = self.cache & ((1u64 << n) - 1);

        self.cache = self.cache >> n;
        self.left -= n;

        return ret;
    }

    fn get_bit(&mut self) -> bool {
        if self.left <= 0 {
            self.refill64();
        }

        self.get_val(1) != 0
    }
}

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

#[test]
    fn get_bit() {
        let buf = &[2, 0, 0, 0,
                    0, 0, 0, 0,
                    1, 0, 0, 0,
                    0, 0, 0, 0];

        let mut reader = BitReadLE {
            buffer : buf,
            index : 0,
            cache: 0,
            left: 0
        };

        assert!(!reader.get_bit());
        assert!(reader.get_bit());
    }
}
<commit_msg>rename BitRead::count to BitRead::consume<commit_after>use bitstream::byteread::*;

pub trait BitRead {
    fn consumed(&self) -> usize;
    fn can_refill(&self) -> bool;
    fn refill64(&mut self) -> ();
    fn get_val(&mut self, n:usize) -> u64;
    fn get_bit(&mut self) -> bool;
/*
    fn peek_bit1(size : u8) -> bool;

    fn get_bits32(size : u8) -> u32;

    fn get_bits64(size : u8) -> u64;

    fn peek_bits32(size : u8) -> u32;

    fn peek_bits64(size : u8) -> u64;

    fn skip_bits(size : u8) -> ();
*/
}

pub struct BitReadLE <'a> {
    buffer : &'a[u8], /// read buffer, 8-bytes padded
    index : usize,
    cache : u64,
    left : usize,
}

impl <'a> BitRead for BitReadLE<'a> {
    #[inline]
    fn consumed(&self) -> usize {
        self.index * 8 - self.left
    }

    #[inline]
    fn can_refill(&self) -> bool {
        self.index < self.buffer.len() - 8
    }

    #[inline]
    fn refill64(&mut self) -> () {
        if !self.can_refill() {
            return;
        }

        self.cache  = get_u64l(&self.buffer[self.index..]);
        self.index += 8;
        self.left   = 64;
    }

    #[inline]
    fn get_val(&mut self, n:usize) -> u64 {
        let ret = self.cache & ((1u64 << n) - 1);

        self.cache = self.cache >> n;
        self.left -= n;

        return ret;
    }

    fn get_bit(&mut self) -> bool {
        if self.left <= 0 {
            self.refill64();
        }

        self.get_val(1) != 0
    }
}

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

#[test]
    fn get_bit() {
        let buf = &[2, 0, 0, 0,
                    0, 0, 0, 0,
                    1, 0, 0, 0,
                    0, 0, 0, 0];

        let mut reader = BitReadLE {
            buffer : buf,
            index : 0,
            cache: 0,
            left: 0
        };

        assert!(!reader.get_bit());
        assert!(reader.get_bit());
    }
}
<|endoftext|>


<commit_before>//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.

use std::env;
use std::fs;
use std::path::{Component, Path, PathBuf};
use std::process::Command;

use build_helper::t;

use crate::dist::{self, pkgname, sanitize_sh, tmpdir};
use crate::Compiler;

use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::config::Config;

pub fn install_docs(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "docs", "rust-docs", stage, Some(host));
}

pub fn install_std(builder: &Builder<'_>, stage: u32, target: Interned<String>) {
    install_sh(builder, "std", "rust-std", stage, Some(target));
}

pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "cargo", "cargo", stage, Some(host));
}

pub fn install_rls(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rls", "rls", stage, Some(host));
}
pub fn install_rust_analyzer(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rust-analyzer", "rust-analyzer", stage, Some(host));
}
pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "clippy", "clippy", stage, Some(host));
}
pub fn install_miri(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "miri", "miri", stage, Some(host));
}

pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustfmt", "rustfmt", stage, Some(host));
}

pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
}

pub fn install_src(builder: &Builder<'_>, stage: u32) {
    install_sh(builder, "src", "rust-src", stage, None);
}
pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustc", "rustc", stage, Some(host));
}

fn install_sh(
    builder: &Builder<'_>,
    package: &str,
    name: &str,
    stage: u32,
    host: Option<Interned<String>>,
) {
    builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));

    let prefix_default = PathBuf::from("/usr/local");
    let sysconfdir_default = PathBuf::from("/etc");
    let datadir_default = PathBuf::from("share");
    let docdir_default = datadir_default.join("doc/rust");
    let libdir_default = PathBuf::from("lib");
    let mandir_default = datadir_default.join("man");
    let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
        fs::create_dir_all(p)
            .unwrap_or_else(|err| panic!("could not create {}: {}", p.display(), err));
        fs::canonicalize(p)
            .unwrap_or_else(|err| panic!("could not canonicalize {}: {}", p.display(), err))
    });
    let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
    let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
    let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default);
    let bindir = &builder.config.bindir;
    let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default);
    let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default);

    let sysconfdir = prefix.join(sysconfdir);
    let datadir = prefix.join(datadir);
    let docdir = prefix.join(docdir);
    let bindir = prefix.join(bindir);
    let libdir = prefix.join(libdir);
    let mandir = prefix.join(mandir);

    let destdir = env::var_os("DESTDIR").map(PathBuf::from);

    let prefix = add_destdir(&prefix, &destdir);
    let sysconfdir = add_destdir(&sysconfdir, &destdir);
    let datadir = add_destdir(&datadir, &destdir);
    let docdir = add_destdir(&docdir, &destdir);
    let bindir = add_destdir(&bindir, &destdir);
    let libdir = add_destdir(&libdir, &destdir);
    let mandir = add_destdir(&mandir, &destdir);

    let empty_dir = builder.out.join("tmp/empty_dir");

    t!(fs::create_dir_all(&empty_dir));
    let package_name = if let Some(host) = host {
        format!("{}-{}", pkgname(builder, name), host)
    } else {
        pkgname(builder, name)
    };

    let mut cmd = Command::new("sh");
    cmd.current_dir(&empty_dir)
        .arg(sanitize_sh(&tmpdir(builder).join(&package_name).join("install.sh")))
        .arg(format!("--prefix={}", sanitize_sh(&prefix)))
        .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
        .arg(format!("--datadir={}", sanitize_sh(&datadir)))
        .arg(format!("--docdir={}", sanitize_sh(&docdir)))
        .arg(format!("--bindir={}", sanitize_sh(&bindir)))
        .arg(format!("--libdir={}", sanitize_sh(&libdir)))
        .arg(format!("--mandir={}", sanitize_sh(&mandir)))
        .arg("--disable-ldconfig");
    builder.run(&mut cmd);
    t!(fs::remove_dir_all(&empty_dir));
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
    let mut ret = match *destdir {
        Some(ref dest) => dest.clone(),
        None => return path.to_path_buf(),
    };
    for part in path.components() {
        if let Component::Normal(s) = part {
            ret.push(s)
        }
    }
    ret
}

macro_rules! install {
    (($sel:ident, $builder:ident, $_config:ident),
       $($name:ident,
       $path:expr,
       $default_cond:expr,
       only_hosts: $only_hosts:expr,
       $run_item:block $(, $c:ident)*;)+) => {
        $(
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
            pub compiler: Compiler,
            pub target: Interned<String>,
        }

        impl $name {
            #[allow(dead_code)]
            fn should_build(config: &Config) -> bool {
                config.extended && config.tools.as_ref()
                    .map_or(true, |t| t.contains($path))
            }

            #[allow(dead_code)]
            fn should_install(builder: &Builder<'_>) -> bool {
                builder.config.tools.as_ref().map_or(false, |t| t.contains($path))
            }
        }

        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = true;
            const ONLY_HOSTS: bool = $only_hosts;
            $(const $c: bool = true;)*

            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                let $_config = &run.builder.config;
                run.path($path).default_condition($default_cond)
            }

            fn make_run(run: RunConfig<'_>) {
                run.builder.ensure($name {
                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
                    target: run.target,
                });
            }

            fn run($sel, $builder: &Builder<'_>) {
                $run_item
            }
        })+
    }
}

install!((self, builder, _config),
    Docs, "src/doc", _config.docs, only_hosts: false, {
        builder.ensure(dist::Docs { host: self.target });
        install_docs(builder, self.compiler.stage, self.target);
    };
    Std, "src/libstd", true, only_hosts: true, {
        for target in &builder.targets {
            builder.ensure(dist::Std {
                compiler: self.compiler,
                target: *target
            });
            install_std(builder, self.compiler.stage, *target);
        }
    };
    Cargo, "cargo", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::Cargo { compiler: self.compiler, target: self.target });
        install_cargo(builder, self.compiler.stage, self.target);
    };
    Rls, "rls", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() ||
            Self::should_install(builder) {
            install_rls(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install RLS stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    RustAnalyzer, "rust-analyzer", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target });
        if Self::should_install(builder) {
            install_rust_analyzer(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install rust-analyzer stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::Clippy { compiler: self.compiler, target: self.target });
        if Self::should_install(builder) {
            install_clippy(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install clippy stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Miri, "miri", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() ||
            Self::should_install(builder) {
            install_miri(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rustfmt {
            compiler: self.compiler,
            target: self.target
        }).is_some() || Self::should_install(builder) {
            install_rustfmt(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
        builder.ensure(dist::Analysis {
            // Find the actual compiler (handling the full bootstrap option) which
            // produced the save-analysis data because that data isn't copied
            // through the sysroot uplifting.
            compiler: builder.compiler_for(builder.top_stage, builder.config.build, self.target),
            target: self.target
        });
        install_analysis(builder, self.compiler.stage, self.target);
    };
    Rustc, "src/librustc", true, only_hosts: true, {
        builder.ensure(dist::Rustc {
            compiler: builder.compiler(builder.top_stage, self.target),
        });
        install_rustc(builder, self.compiler.stage, self.target);
    };
);

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Src {
    pub stage: u32,
}

impl Step for Src {
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        let config = &run.builder.config;
        let cond = config.extended && config.tools.as_ref().map_or(true, |t| t.contains("src"));
        run.path("src").default_condition(cond)
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Src { stage: run.builder.top_stage });
    }

    fn run(self, builder: &Builder<'_>) {
        builder.ensure(dist::Src);
        install_src(builder, self.stage);
    }
}
<commit_msg>rustbuild: drop tool::should_install<commit_after>//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.

use std::env;
use std::fs;
use std::path::{Component, Path, PathBuf};
use std::process::Command;

use build_helper::t;

use crate::dist::{self, pkgname, sanitize_sh, tmpdir};
use crate::Compiler;

use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::config::Config;

pub fn install_docs(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "docs", "rust-docs", stage, Some(host));
}

pub fn install_std(builder: &Builder<'_>, stage: u32, target: Interned<String>) {
    install_sh(builder, "std", "rust-std", stage, Some(target));
}

pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "cargo", "cargo", stage, Some(host));
}

pub fn install_rls(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rls", "rls", stage, Some(host));
}
pub fn install_rust_analyzer(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rust-analyzer", "rust-analyzer", stage, Some(host));
}
pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "clippy", "clippy", stage, Some(host));
}
pub fn install_miri(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "miri", "miri", stage, Some(host));
}

pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustfmt", "rustfmt", stage, Some(host));
}

pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
}

pub fn install_src(builder: &Builder<'_>, stage: u32) {
    install_sh(builder, "src", "rust-src", stage, None);
}
pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
    install_sh(builder, "rustc", "rustc", stage, Some(host));
}

fn install_sh(
    builder: &Builder<'_>,
    package: &str,
    name: &str,
    stage: u32,
    host: Option<Interned<String>>,
) {
    builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));

    let prefix_default = PathBuf::from("/usr/local");
    let sysconfdir_default = PathBuf::from("/etc");
    let datadir_default = PathBuf::from("share");
    let docdir_default = datadir_default.join("doc/rust");
    let libdir_default = PathBuf::from("lib");
    let mandir_default = datadir_default.join("man");
    let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
        fs::create_dir_all(p)
            .unwrap_or_else(|err| panic!("could not create {}: {}", p.display(), err));
        fs::canonicalize(p)
            .unwrap_or_else(|err| panic!("could not canonicalize {}: {}", p.display(), err))
    });
    let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
    let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
    let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default);
    let bindir = &builder.config.bindir;
    let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default);
    let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default);

    let sysconfdir = prefix.join(sysconfdir);
    let datadir = prefix.join(datadir);
    let docdir = prefix.join(docdir);
    let bindir = prefix.join(bindir);
    let libdir = prefix.join(libdir);
    let mandir = prefix.join(mandir);

    let destdir = env::var_os("DESTDIR").map(PathBuf::from);

    let prefix = add_destdir(&prefix, &destdir);
    let sysconfdir = add_destdir(&sysconfdir, &destdir);
    let datadir = add_destdir(&datadir, &destdir);
    let docdir = add_destdir(&docdir, &destdir);
    let bindir = add_destdir(&bindir, &destdir);
    let libdir = add_destdir(&libdir, &destdir);
    let mandir = add_destdir(&mandir, &destdir);

    let empty_dir = builder.out.join("tmp/empty_dir");

    t!(fs::create_dir_all(&empty_dir));
    let package_name = if let Some(host) = host {
        format!("{}-{}", pkgname(builder, name), host)
    } else {
        pkgname(builder, name)
    };

    let mut cmd = Command::new("sh");
    cmd.current_dir(&empty_dir)
        .arg(sanitize_sh(&tmpdir(builder).join(&package_name).join("install.sh")))
        .arg(format!("--prefix={}", sanitize_sh(&prefix)))
        .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
        .arg(format!("--datadir={}", sanitize_sh(&datadir)))
        .arg(format!("--docdir={}", sanitize_sh(&docdir)))
        .arg(format!("--bindir={}", sanitize_sh(&bindir)))
        .arg(format!("--libdir={}", sanitize_sh(&libdir)))
        .arg(format!("--mandir={}", sanitize_sh(&mandir)))
        .arg("--disable-ldconfig");
    builder.run(&mut cmd);
    t!(fs::remove_dir_all(&empty_dir));
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
    let mut ret = match *destdir {
        Some(ref dest) => dest.clone(),
        None => return path.to_path_buf(),
    };
    for part in path.components() {
        if let Component::Normal(s) = part {
            ret.push(s)
        }
    }
    ret
}

macro_rules! install {
    (($sel:ident, $builder:ident, $_config:ident),
       $($name:ident,
       $path:expr,
       $default_cond:expr,
       only_hosts: $only_hosts:expr,
       $run_item:block $(, $c:ident)*;)+) => {
        $(
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
            pub compiler: Compiler,
            pub target: Interned<String>,
        }

        impl $name {
            #[allow(dead_code)]
            fn should_build(config: &Config) -> bool {
                config.extended && config.tools.as_ref()
                    .map_or(true, |t| t.contains($path))
            }
        }

        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = true;
            const ONLY_HOSTS: bool = $only_hosts;
            $(const $c: bool = true;)*

            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                let $_config = &run.builder.config;
                run.path($path).default_condition($default_cond)
            }

            fn make_run(run: RunConfig<'_>) {
                run.builder.ensure($name {
                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
                    target: run.target,
                });
            }

            fn run($sel, $builder: &Builder<'_>) {
                $run_item
            }
        })+
    }
}

install!((self, builder, _config),
    Docs, "src/doc", _config.docs, only_hosts: false, {
        builder.ensure(dist::Docs { host: self.target });
        install_docs(builder, self.compiler.stage, self.target);
    };
    Std, "src/libstd", true, only_hosts: true, {
        for target in &builder.targets {
            builder.ensure(dist::Std {
                compiler: self.compiler,
                target: *target
            });
            install_std(builder, self.compiler.stage, *target);
        }
    };
    Cargo, "cargo", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::Cargo { compiler: self.compiler, target: self.target });
        install_cargo(builder, self.compiler.stage, self.target);
    };
    Rls, "rls", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() {
            install_rls(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install RLS stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    RustAnalyzer, "rust-analyzer", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target });
        install_rust_analyzer(builder, self.compiler.stage, self.target);
    };
    Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::Clippy { compiler: self.compiler, target: self.target });
        install_clippy(builder, self.compiler.stage, self.target);
    };
    Miri, "miri", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() {
            install_miri(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rustfmt {
            compiler: self.compiler,
            target: self.target
        }).is_some() {
            install_rustfmt(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
        builder.ensure(dist::Analysis {
            // Find the actual compiler (handling the full bootstrap option) which
            // produced the save-analysis data because that data isn't copied
            // through the sysroot uplifting.
            compiler: builder.compiler_for(builder.top_stage, builder.config.build, self.target),
            target: self.target
        });
        install_analysis(builder, self.compiler.stage, self.target);
    };
    Rustc, "src/librustc", true, only_hosts: true, {
        builder.ensure(dist::Rustc {
            compiler: builder.compiler(builder.top_stage, self.target),
        });
        install_rustc(builder, self.compiler.stage, self.target);
    };
);

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Src {
    pub stage: u32,
}

impl Step for Src {
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        let config = &run.builder.config;
        let cond = config.extended && config.tools.as_ref().map_or(true, |t| t.contains("src"));
        run.path("src").default_condition(cond)
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Src { stage: run.builder.top_stage });
    }

    fn run(self, builder: &Builder<'_>) {
        builder.ensure(dist::Src);
        install_src(builder, self.stage);
    }
}
<|endoftext|>