<commit_before>//! EGL context related structs
use std::{
    collections::HashSet,
    os::raw::c_int,
    sync::{atomic::Ordering, Arc},
};

use super::{ffi, wrap_egl_call, Error, MakeCurrentError};
use crate::{
    backend::{
        allocator::Format as DrmFormat,
        egl::{
            display::{EGLDisplay, PixelFormat},
            EGLSurface,
        },
    },
    utils::user_data::UserDataMap,
};

use slog::{info, o, trace};

/// EGL context for rendering
#[derive(Debug)]
pub struct EGLContext {
    context: ffi::egl::types::EGLContext,
    pub(crate) display: EGLDisplay,
    config_id: ffi::egl::types::EGLConfig,
    pixel_format: Option<PixelFormat>,
    user_data: Arc<UserDataMap>,
}
// EGLContexts can be moved between threads safely
unsafe impl Send for EGLContext {}
unsafe impl Sync for EGLContext {}

impl EGLContext {
    /// Creates a new configless `EGLContext` from a given `EGLDisplay`
    pub fn new<L>(display: &EGLDisplay, log: L) -> Result<EGLContext, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        Self::new_internal(display, None, None, log)
    }

    /// Create a new [`EGLContext`] from a given `EGLDisplay` and configuration requirements
    pub fn new_with_config<L>(
        display: &EGLDisplay,
        attributes: GlAttributes,
        reqs: PixelFormatRequirements,
        log: L,
    ) -> Result<EGLContext, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        Self::new_internal(display, None, Some((attributes, reqs)), log)
    }

    /// Create a new configless `EGLContext` from a given `EGLDisplay` sharing resources with another context
    pub fn new_shared<L>(display: &EGLDisplay, share: &EGLContext, log: L) -> Result<EGLContext, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        Self::new_internal(display, Some(share), None, log)
    }

    /// Create a new `EGLContext` from a given `EGLDisplay` and configuration requirements sharing resources with another context
    pub fn new_shared_with_config<L>(
        display: &EGLDisplay,
        share: &EGLContext,
        attributes: GlAttributes,
        reqs: PixelFormatRequirements,
        log: L,
    ) -> Result<EGLContext, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        Self::new_internal(display, Some(share), Some((attributes, reqs)), log)
    }

    fn new_internal<L>(
        display: &EGLDisplay,
        shared: Option<&EGLContext>,
        config: Option<(GlAttributes, PixelFormatRequirements)>,
        log: L,
    ) -> Result<EGLContext, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_fallback(log.into()).new(o!("smithay_module" => "backend_egl"));

        let (pixel_format, config_id) = match config {
            Some((attributes, reqs)) => {
                let (format, config_id) = display.choose_config(attributes, reqs)?;
                (Some(format), config_id)
            }
            None => {
                if !display
                    .extensions
                    .iter()
                    .any(|x| x == "EGL_KHR_no_config_context")
                    && !display
                        .extensions
                        .iter()
                        .any(|x| x == "EGL_MESA_configless_context")
                    && !display
                        .extensions
                        .iter()
                        .any(|x| x == "EGL_KHR_surfaceless_context")
                {
                    return Err(Error::EglExtensionNotSupported(&[
                        "EGL_KHR_no_config_context",
                        "EGL_MESA_configless_context",
                        "EGL_KHR_surfaceless_context",
                    ]));
                }
                (None, ffi::egl::NO_CONFIG_KHR)
            }
        };

        let mut context_attributes = Vec::with_capacity(10);

        if let Some((attributes, _)) = config {
            let version = attributes.version;

            if display.egl_version >= (1, 5)
                || display.extensions.iter().any(|s| s == "EGL_KHR_create_context")
            {
                trace!(log, "Setting CONTEXT_MAJOR_VERSION to {}", version.0);
                context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32);
                context_attributes.push(version.0 as i32);
                trace!(log, "Setting CONTEXT_MINOR_VERSION to {}", version.1);
                context_attributes.push(ffi::egl::CONTEXT_MINOR_VERSION as i32);
                context_attributes.push(version.1 as i32);

                if attributes.debug && display.egl_version >= (1, 5) {
                    trace!(log, "Setting CONTEXT_OPENGL_DEBUG to TRUE");
                    context_attributes.push(ffi::egl::CONTEXT_OPENGL_DEBUG as i32);
                    context_attributes.push(ffi::egl::TRUE as i32);
                }

                context_attributes.push(ffi::egl::CONTEXT_FLAGS_KHR as i32);
                context_attributes.push(0);
            } else if display.egl_version >= (1, 3) {
                trace!(log, "Setting CONTEXT_CLIENT_VERSION to {}", version.0);
                context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32);
                context_attributes.push(version.0 as i32);
            }
        } else {
            trace!(log, "Setting CONTEXT_CLIENT_VERSION to 2");
            context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32);
            context_attributes.push(2);
        }

        context_attributes.push(ffi::egl::NONE as i32);

        trace!(log, "Creating EGL context...");
        let context = wrap_egl_call(|| unsafe {
            ffi::egl::CreateContext(
                **display.display,
                config_id,
                shared
                    .map(|context| context.context)
                    .unwrap_or(ffi::egl::NO_CONTEXT),
                context_attributes.as_ptr(),
            )
        })
        .map_err(Error::CreationFailed)?;

        info!(log, "EGL context created");

        Ok(EGLContext {
            context,
            display: display.clone(),
            config_id,
            pixel_format,
            user_data: if let Some(shared) = shared {
                shared.user_data.clone()
            } else {
                Arc::new(UserDataMap::default())
            },
        })
    }

    /// Makes the OpenGL context the current context in the current thread with a surface to
    /// read/write to.
    ///
    /// # Safety
    ///
    /// This function is marked unsafe, because the context cannot be made current
    /// on multiple threads without being unbound again (see `unbind`).
    pub unsafe fn make_current_with_surface(&self, surface: &EGLSurface) -> Result<(), MakeCurrentError> {
        let surface_ptr = surface.surface.load(Ordering::SeqCst);
        wrap_egl_call(|| {
            ffi::egl::MakeCurrent(**self.display.display, surface_ptr, surface_ptr, self.context)
        })
        .map(|_| ())
        .map_err(Into::into)
    }

    /// Makes the OpenGL context the current context in the current thread with no surface bound.
    ///
    /// # Safety
    ///
    /// This function is marked unsafe, because the context cannot be made current
    /// on multiple threads without being unbound again (see `unbind`).
    pub unsafe fn make_current(&self) -> Result<(), MakeCurrentError> {
        wrap_egl_call(|| {
            ffi::egl::MakeCurrent(
                **self.display.display,
                ffi::egl::NO_SURFACE,
                ffi::egl::NO_SURFACE,
                self.context,
            )
        })
        .map(|_| ())
        .map_err(Into::into)
    }

    /// Returns true if the OpenGL context is the current one in the thread.
    pub fn is_current(&self) -> bool {
        unsafe { ffi::egl::GetCurrentContext() == self.context as *const _ }
    }

    /// Returns the egl config for this context
    pub fn config_id(&self) -> ffi::egl::types::EGLConfig {
        self.config_id
    }

    /// Returns the pixel format of the main framebuffer of the context.
    pub fn pixel_format(&self) -> Option<PixelFormat> {
        self.pixel_format
    }

    /// Unbinds this context from the current thread, if set.
    ///
    /// This does nothing if this context is not the current context.
    pub fn unbind(&self) -> Result<(), MakeCurrentError> {
        if self.is_current() {
            wrap_egl_call(|| unsafe {
                ffi::egl::MakeCurrent(
                    **self.display.display,
                    ffi::egl::NO_SURFACE,
                    ffi::egl::NO_SURFACE,
                    ffi::egl::NO_CONTEXT,
                )
            })?;
        }
        Ok(())
    }

    /// Returns a list of formats for dmabufs that can be rendered to.
    pub fn dmabuf_render_formats(&self) -> &HashSet<DrmFormat> {
        &self.display.dmabuf_render_formats
    }

    /// Returns a list of formats for dmabufs that can be used as textures.
    pub fn dmabuf_texture_formats(&self) -> &HashSet<DrmFormat> {
        &self.display.dmabuf_import_formats
    }

    /// Retrieve user_data associated with this context
    ///
    /// *Note:* UserData is shared between shared context, if constructed with
    /// [`new_shared`](EGLContext::new_shared) or [`new_shared_with_config`](EGLContext::new_shared_with_config).
    pub fn user_data(&self) -> &UserDataMap {
        &*self.user_data
    }

    /// Get a raw handle to the underlying context.
    ///
    /// The pointer will become invalid, when this struct is destroyed.
    pub fn get_context_handle(&self) -> ffi::egl::types::EGLContext {
        self.context
    }
}

impl Drop for EGLContext {
    fn drop(&mut self) {
        unsafe {
            // We need to ensure the context is unbound, otherwise it egl stalls the destroy call
            // ignore failures at this point
            let _ = self.unbind();
            ffi::egl::DestroyContext(**self.display.display, self.context);
        }
    }
}

/// Attributes to use when creating an OpenGL context.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct GlAttributes {
    /// Describes the OpenGL API and version that are being requested when a context is created.
    ///
    /// `(3, 0)` will request a OpenGL ES 3.0 context for example.
    /// `(2, 0)` is the minimum.
    pub version: (u8, u8),
    /// OpenGL profile to use.
    pub profile: Option<GlProfile>,
    /// Whether to enable the debug flag of the context.
    ///
    /// Debug contexts are usually slower but give better error reporting.
    pub debug: bool,
    /// Whether to use vsync. If vsync is enabled, calling `swap_buffers` will block until the screen refreshes.
    /// This is typically used to prevent screen tearing.
    pub vsync: bool,
}

/// Describes the requested OpenGL context profiles.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GlProfile {
    /// Include all the immediate functions and definitions.
    Compatibility,
    /// Include all the future-compatible functions and definitions.
    Core,
}

/// Describes how the backend should choose a pixel format.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PixelFormatRequirements {
    /// If `true`, only hardware-accelerated formats will be considered. If `false`, only software renderers.
    /// `None` means "don't care". Default is `None`.
    pub hardware_accelerated: Option<bool>,
    /// Minimum number of bits for the color buffer, excluding alpha. `None` means "don't care". The default is `None`.
    pub color_bits: Option<u8>,
    /// If `true`, the color buffer must be in a floating point format. Default is `false`.
    ///
    /// Using floating points allows you to write values outside the `[0.0, 1.0]` range.
    pub float_color_buffer: bool,
    /// Minimum number of bits for the alpha in the color buffer. `None` means "don't care". The default is `None`.
    pub alpha_bits: Option<u8>,
    /// Minimum number of bits for the depth buffer. `None` means "don't care". The default value is `None`.
    pub depth_bits: Option<u8>,
    /// Minimum number of bits for the depth buffer. `None` means "don't care". The default value is `None`.
    pub stencil_bits: Option<u8>,
    /// Contains the minimum number of samples per pixel in the color, depth and stencil buffers.
    /// `None` means "don't care". Default is `None`. A value of `Some(0)` indicates that multisampling must not be enabled.
    pub multisampling: Option<u16>,
}

impl Default for PixelFormatRequirements {
    fn default() -> Self {
        PixelFormatRequirements {
            hardware_accelerated: Some(true),
            color_bits: Some(24),
            float_color_buffer: false,
            alpha_bits: Some(8),
            depth_bits: Some(24),
            stencil_bits: Some(8),
            multisampling: None,
        }
    }
}

impl PixelFormatRequirements {
    /// Append the requirements to the given attribute list
    pub fn create_attributes(&self, out: &mut Vec<c_int>, logger: &slog::Logger) {
        if let Some(hardware_accelerated) = self.hardware_accelerated {
            out.push(ffi::egl::CONFIG_CAVEAT as c_int);
            out.push(if hardware_accelerated {
                trace!(logger, "Setting CONFIG_CAVEAT to NONE");
                ffi::egl::NONE as c_int
            } else {
                trace!(logger, "Setting CONFIG_CAVEAT to SLOW_CONFIG");
                ffi::egl::SLOW_CONFIG as c_int
            });
        }

        if let Some(color) = self.color_bits {
            trace!(logger, "Setting RED_SIZE to {}", color / 3);
            out.push(ffi::egl::RED_SIZE as c_int);
            out.push((color / 3) as c_int);
            trace!(
                logger,
                "Setting GREEN_SIZE to {}",
                color / 3 + if color % 3 != 0 { 1 } else { 0 }
            );
            out.push(ffi::egl::GREEN_SIZE as c_int);
            out.push((color / 3 + if color % 3 != 0 { 1 } else { 0 }) as c_int);
            trace!(
                logger,
                "Setting BLUE_SIZE to {}",
                color / 3 + if color % 3 == 2 { 1 } else { 0 }
            );
            out.push(ffi::egl::BLUE_SIZE as c_int);
            out.push((color / 3 + if color % 3 == 2 { 1 } else { 0 }) as c_int);
        }

        if let Some(alpha) = self.alpha_bits {
            trace!(logger, "Setting ALPHA_SIZE to {}", alpha);
            out.push(ffi::egl::ALPHA_SIZE as c_int);
            out.push(alpha as c_int);
        }

        if let Some(depth) = self.depth_bits {
            trace!(logger, "Setting DEPTH_SIZE to {}", depth);
            out.push(ffi::egl::DEPTH_SIZE as c_int);
            out.push(depth as c_int);
        }

        if let Some(stencil) = self.stencil_bits {
            trace!(logger, "Setting STENCIL_SIZE to {}", stencil);
            out.push(ffi::egl::STENCIL_SIZE as c_int);
            out.push(stencil as c_int);
        }

        if let Some(multisampling) = self.multisampling {
            trace!(logger, "Setting SAMPLES to {}", multisampling);
            out.push(ffi::egl::SAMPLES as c_int);
            out.push(multisampling as c_int);
        }
    }
}
<commit_msg>EGLContext is not Sync<commit_after>//! EGL context related structs
use std::{
    collections::HashSet,
    os::raw::c_int,
    sync::{atomic::Ordering, Arc},
};

use super::{ffi, wrap_egl_call, Error, MakeCurrentError};
use crate::{
    backend::{
        allocator::Format as DrmFormat,
        egl::{
            display::{EGLDisplay, PixelFormat},
            EGLSurface,
        },
    },
    utils::user_data::UserDataMap,
};

use slog::{info, o, trace};

/// EGL context for rendering
#[derive(Debug)]
pub struct EGLContext {
    context: ffi::egl::types::EGLContext,
    pub(crate) display: EGLDisplay,
    config_id: ffi::egl::types::EGLConfig,
    pixel_format: Option<PixelFormat>,
    user_data: Arc<UserDataMap>,
}

// SAFETY: A context can be sent to another thread when this context is not current.
//
// If the context is made current, the safety requirements for calling `EGLDisplay::make_current` must be
// upheld. This means a context which is made current must be unbound (using `unbind`) in order to send this
// context to another thread.
unsafe impl Send for EGLContext {}

impl EGLContext {
    /// Creates a new configless `EGLContext` from a given `EGLDisplay`
    pub fn new<L>(display: &EGLDisplay, log: L) -> Result<EGLContext, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        Self::new_internal(display, None, None, log)
    }

    /// Create a new [`EGLContext`] from a given `EGLDisplay` and configuration requirements
    pub fn new_with_config<L>(
        display: &EGLDisplay,
        attributes: GlAttributes,
        reqs: PixelFormatRequirements,
        log: L,
    ) -> Result<EGLContext, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        Self::new_internal(display, None, Some((attributes, reqs)), log)
    }

    /// Create a new configless `EGLContext` from a given `EGLDisplay` sharing resources with another context
    pub fn new_shared<L>(display: &EGLDisplay, share: &EGLContext, log: L) -> Result<EGLContext, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        Self::new_internal(display, Some(share), None, log)
    }

    /// Create a new `EGLContext` from a given `EGLDisplay` and configuration requirements sharing resources with another context
    pub fn new_shared_with_config<L>(
        display: &EGLDisplay,
        share: &EGLContext,
        attributes: GlAttributes,
        reqs: PixelFormatRequirements,
        log: L,
    ) -> Result<EGLContext, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        Self::new_internal(display, Some(share), Some((attributes, reqs)), log)
    }

    fn new_internal<L>(
        display: &EGLDisplay,
        shared: Option<&EGLContext>,
        config: Option<(GlAttributes, PixelFormatRequirements)>,
        log: L,
    ) -> Result<EGLContext, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_fallback(log.into()).new(o!("smithay_module" => "backend_egl"));

        let (pixel_format, config_id) = match config {
            Some((attributes, reqs)) => {
                let (format, config_id) = display.choose_config(attributes, reqs)?;
                (Some(format), config_id)
            }
            None => {
                if !display
                    .extensions
                    .iter()
                    .any(|x| x == "EGL_KHR_no_config_context")
                    && !display
                        .extensions
                        .iter()
                        .any(|x| x == "EGL_MESA_configless_context")
                    && !display
                        .extensions
                        .iter()
                        .any(|x| x == "EGL_KHR_surfaceless_context")
                {
                    return Err(Error::EglExtensionNotSupported(&[
                        "EGL_KHR_no_config_context",
                        "EGL_MESA_configless_context",
                        "EGL_KHR_surfaceless_context",
                    ]));
                }
                (None, ffi::egl::NO_CONFIG_KHR)
            }
        };

        let mut context_attributes = Vec::with_capacity(10);

        if let Some((attributes, _)) = config {
            let version = attributes.version;

            if display.egl_version >= (1, 5)
                || display.extensions.iter().any(|s| s == "EGL_KHR_create_context")
            {
                trace!(log, "Setting CONTEXT_MAJOR_VERSION to {}", version.0);
                context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32);
                context_attributes.push(version.0 as i32);
                trace!(log, "Setting CONTEXT_MINOR_VERSION to {}", version.1);
                context_attributes.push(ffi::egl::CONTEXT_MINOR_VERSION as i32);
                context_attributes.push(version.1 as i32);

                if attributes.debug && display.egl_version >= (1, 5) {
                    trace!(log, "Setting CONTEXT_OPENGL_DEBUG to TRUE");
                    context_attributes.push(ffi::egl::CONTEXT_OPENGL_DEBUG as i32);
                    context_attributes.push(ffi::egl::TRUE as i32);
                }

                context_attributes.push(ffi::egl::CONTEXT_FLAGS_KHR as i32);
                context_attributes.push(0);
            } else if display.egl_version >= (1, 3) {
                trace!(log, "Setting CONTEXT_CLIENT_VERSION to {}", version.0);
                context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32);
                context_attributes.push(version.0 as i32);
            }
        } else {
            trace!(log, "Setting CONTEXT_CLIENT_VERSION to 2");
            context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32);
            context_attributes.push(2);
        }

        context_attributes.push(ffi::egl::NONE as i32);

        trace!(log, "Creating EGL context...");
        let context = wrap_egl_call(|| unsafe {
            ffi::egl::CreateContext(
                **display.display,
                config_id,
                shared
                    .map(|context| context.context)
                    .unwrap_or(ffi::egl::NO_CONTEXT),
                context_attributes.as_ptr(),
            )
        })
        .map_err(Error::CreationFailed)?;

        info!(log, "EGL context created");

        Ok(EGLContext {
            context,
            display: display.clone(),
            config_id,
            pixel_format,
            user_data: if let Some(shared) = shared {
                shared.user_data.clone()
            } else {
                Arc::new(UserDataMap::default())
            },
        })
    }

    /// Makes the OpenGL context the current context in the current thread with a surface to
    /// read/write to.
    ///
    /// # Safety
    ///
    /// This function is marked unsafe, because the context cannot be made current on another thread without
    /// being unbound again (see [`EGLContext::unbind`]).
    pub unsafe fn make_current_with_surface(&self, surface: &EGLSurface) -> Result<(), MakeCurrentError> {
        let surface_ptr = surface.surface.load(Ordering::SeqCst);
        wrap_egl_call(|| {
            ffi::egl::MakeCurrent(**self.display.display, surface_ptr, surface_ptr, self.context)
        })
        .map(|_| ())
        .map_err(Into::into)
    }

    /// Makes the OpenGL context the current context in the current thread with no surface bound.
    ///
    /// # Safety
    ///
    /// This function is marked unsafe, because the context cannot be made current on another thread without
    /// being unbound again (see [`EGLContext::unbind`]).
    pub unsafe fn make_current(&self) -> Result<(), MakeCurrentError> {
        wrap_egl_call(|| {
            ffi::egl::MakeCurrent(
                **self.display.display,
                ffi::egl::NO_SURFACE,
                ffi::egl::NO_SURFACE,
                self.context,
            )
        })
        .map(|_| ())
        .map_err(Into::into)
    }

    /// Returns true if the OpenGL context is the current one in the thread.
    pub fn is_current(&self) -> bool {
        unsafe { ffi::egl::GetCurrentContext() == self.context as *const _ }
    }

    /// Returns the egl config for this context
    pub fn config_id(&self) -> ffi::egl::types::EGLConfig {
        self.config_id
    }

    /// Returns the pixel format of the main framebuffer of the context.
    pub fn pixel_format(&self) -> Option<PixelFormat> {
        self.pixel_format
    }

    /// Unbinds this context from the current thread, if set.
    ///
    /// This does nothing if this context is not the current context.
    pub fn unbind(&self) -> Result<(), MakeCurrentError> {
        if self.is_current() {
            wrap_egl_call(|| unsafe {
                ffi::egl::MakeCurrent(
                    **self.display.display,
                    ffi::egl::NO_SURFACE,
                    ffi::egl::NO_SURFACE,
                    ffi::egl::NO_CONTEXT,
                )
            })?;
        }
        Ok(())
    }

    /// Returns a list of formats for dmabufs that can be rendered to.
    pub fn dmabuf_render_formats(&self) -> &HashSet<DrmFormat> {
        &self.display.dmabuf_render_formats
    }

    /// Returns a list of formats for dmabufs that can be used as textures.
    pub fn dmabuf_texture_formats(&self) -> &HashSet<DrmFormat> {
        &self.display.dmabuf_import_formats
    }

    /// Retrieve user_data associated with this context
    ///
    /// *Note:* UserData is shared between shared context, if constructed with
    /// [`new_shared`](EGLContext::new_shared) or [`new_shared_with_config`](EGLContext::new_shared_with_config).
    pub fn user_data(&self) -> &UserDataMap {
        &*self.user_data
    }

    /// Get a raw handle to the underlying context.
    ///
    /// The pointer will become invalid, when this struct is destroyed.
    pub fn get_context_handle(&self) -> ffi::egl::types::EGLContext {
        self.context
    }
}

impl Drop for EGLContext {
    fn drop(&mut self) {
        unsafe {
            // We need to ensure the context is unbound, otherwise it egl stalls the destroy call
            // ignore failures at this point
            let _ = self.unbind();
            ffi::egl::DestroyContext(**self.display.display, self.context);
        }
    }
}

/// Attributes to use when creating an OpenGL context.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct GlAttributes {
    /// Describes the OpenGL API and version that are being requested when a context is created.
    ///
    /// `(3, 0)` will request a OpenGL ES 3.0 context for example.
    /// `(2, 0)` is the minimum.
    pub version: (u8, u8),
    /// OpenGL profile to use.
    pub profile: Option<GlProfile>,
    /// Whether to enable the debug flag of the context.
    ///
    /// Debug contexts are usually slower but give better error reporting.
    pub debug: bool,
    /// Whether to use vsync. If vsync is enabled, calling `swap_buffers` will block until the screen refreshes.
    /// This is typically used to prevent screen tearing.
    pub vsync: bool,
}

/// Describes the requested OpenGL context profiles.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GlProfile {
    /// Include all the immediate functions and definitions.
    Compatibility,
    /// Include all the future-compatible functions and definitions.
    Core,
}

/// Describes how the backend should choose a pixel format.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PixelFormatRequirements {
    /// If `true`, only hardware-accelerated formats will be considered. If `false`, only software renderers.
    /// `None` means "don't care". Default is `None`.
    pub hardware_accelerated: Option<bool>,
    /// Minimum number of bits for the color buffer, excluding alpha. `None` means "don't care". The default is `None`.
    pub color_bits: Option<u8>,
    /// If `true`, the color buffer must be in a floating point format. Default is `false`.
    ///
    /// Using floating points allows you to write values outside the `[0.0, 1.0]` range.
    pub float_color_buffer: bool,
    /// Minimum number of bits for the alpha in the color buffer. `None` means "don't care". The default is `None`.
    pub alpha_bits: Option<u8>,
    /// Minimum number of bits for the depth buffer. `None` means "don't care". The default value is `None`.
    pub depth_bits: Option<u8>,
    /// Minimum number of bits for the depth buffer. `None` means "don't care". The default value is `None`.
    pub stencil_bits: Option<u8>,
    /// Contains the minimum number of samples per pixel in the color, depth and stencil buffers.
    /// `None` means "don't care". Default is `None`. A value of `Some(0)` indicates that multisampling must not be enabled.
    pub multisampling: Option<u16>,
}

impl Default for PixelFormatRequirements {
    fn default() -> Self {
        PixelFormatRequirements {
            hardware_accelerated: Some(true),
            color_bits: Some(24),
            float_color_buffer: false,
            alpha_bits: Some(8),
            depth_bits: Some(24),
            stencil_bits: Some(8),
            multisampling: None,
        }
    }
}

impl PixelFormatRequirements {
    /// Append the requirements to the given attribute list
    pub fn create_attributes(&self, out: &mut Vec<c_int>, logger: &slog::Logger) {
        if let Some(hardware_accelerated) = self.hardware_accelerated {
            out.push(ffi::egl::CONFIG_CAVEAT as c_int);
            out.push(if hardware_accelerated {
                trace!(logger, "Setting CONFIG_CAVEAT to NONE");
                ffi::egl::NONE as c_int
            } else {
                trace!(logger, "Setting CONFIG_CAVEAT to SLOW_CONFIG");
                ffi::egl::SLOW_CONFIG as c_int
            });
        }

        if let Some(color) = self.color_bits {
            trace!(logger, "Setting RED_SIZE to {}", color / 3);
            out.push(ffi::egl::RED_SIZE as c_int);
            out.push((color / 3) as c_int);
            trace!(
                logger,
                "Setting GREEN_SIZE to {}",
                color / 3 + if color % 3 != 0 { 1 } else { 0 }
            );
            out.push(ffi::egl::GREEN_SIZE as c_int);
            out.push((color / 3 + if color % 3 != 0 { 1 } else { 0 }) as c_int);
            trace!(
                logger,
                "Setting BLUE_SIZE to {}",
                color / 3 + if color % 3 == 2 { 1 } else { 0 }
            );
            out.push(ffi::egl::BLUE_SIZE as c_int);
            out.push((color / 3 + if color % 3 == 2 { 1 } else { 0 }) as c_int);
        }

        if let Some(alpha) = self.alpha_bits {
            trace!(logger, "Setting ALPHA_SIZE to {}", alpha);
            out.push(ffi::egl::ALPHA_SIZE as c_int);
            out.push(alpha as c_int);
        }

        if let Some(depth) = self.depth_bits {
            trace!(logger, "Setting DEPTH_SIZE to {}", depth);
            out.push(ffi::egl::DEPTH_SIZE as c_int);
            out.push(depth as c_int);
        }

        if let Some(stencil) = self.stencil_bits {
            trace!(logger, "Setting STENCIL_SIZE to {}", stencil);
            out.push(ffi::egl::STENCIL_SIZE as c_int);
            out.push(stencil as c_int);
        }

        if let Some(multisampling) = self.multisampling {
            trace!(logger, "Setting SAMPLES to {}", multisampling);
            out.push(ffi::egl::SAMPLES as c_int);
            out.push(multisampling as c_int);
        }
    }
}
<|endoftext|>


<commit_before>// aux-build:cci_capture_clause.rs
// xfail-fast
// xfail-win32

// This test makes sure we can do cross-crate inlining on functions
// that use capture clauses.

use cci_capture_clause;

import comm::recv;
import comm::methods;

fn main() {
    cci_capture_clause::foo(()).recv()
}
<commit_msg>Revert "test: xfail-win32 run-pass/cci_capture_clause.rs"<commit_after>// aux-build:cci_capture_clause.rs
// xfail-fast

// This test makes sure we can do cross-crate inlining on functions
// that use capture clauses.

use cci_capture_clause;

import comm::recv;
import comm::methods;

fn main() {
    cci_capture_clause::foo(()).recv()
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate rustc_driver;
extern crate rustc_span;

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::env;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;

use rustc_span::edition::DEFAULT_EDITION;

use rustdoc::html::markdown::{ErrorCodes, IdMap, Markdown, Playground};

pub struct ErrorMetadata {
    pub description: Option<String>,
}

/// Mapping from error codes to metadata that can be (de)serialized.
pub type ErrorMetadataMap = BTreeMap<String, ErrorMetadata>;

enum OutputFormat {
    HTML(HTMLFormatter),
    Markdown(MarkdownFormatter),
    Unknown(String),
}

impl OutputFormat {
    fn from(format: &str, resource_suffix: &str) -> OutputFormat {
        match &*format.to_lowercase() {
            "html" => OutputFormat::HTML(HTMLFormatter(
                RefCell::new(IdMap::new()),
                resource_suffix.to_owned(),
            )),
            "markdown" => OutputFormat::Markdown(MarkdownFormatter),
            s => OutputFormat::Unknown(s.to_owned()),
        }
    }
}

trait Formatter {
    fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
    fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
    fn error_code_block(
        &self,
        output: &mut dyn Write,
        info: &ErrorMetadata,
        err_code: &str,
    ) -> Result<(), Box<dyn Error>>;
    fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
}

struct HTMLFormatter(RefCell<IdMap>, String);
struct MarkdownFormatter;

impl Formatter for HTMLFormatter {
    fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
        write!(
            output,
            r##"<!DOCTYPE html>

<title>Rust Compiler Error Index</title>
<meta charset="utf-8">

<link rel="stylesheet" type="text/css" href="rustdoc{suffix}.css"/>
<link rel="stylesheet" type="text/css" href="light{suffix}.css"/>
<link rel="stylesheet" type="text/css" href="rust.css"/>

"##,
            suffix = self.1
        )?;
        Ok(())
    }

    fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
        write!(output, "
Rust Compiler Error Index
\n")?;
        Ok(())
    }

    fn error_code_block(
        &self,
        output: &mut dyn Write,
        info: &ErrorMetadata,
        err_code: &str,
    ) -> Result<(), Box<dyn Error>> {
        // Enclose each error in a div so they can be shown/hidden en masse.
        let desc_desc = match info.description {
            Some(_) => "error-described",
            None => "error-undescribed",
        };
        write!(output, "
", desc_desc)?;

        // Error title (with self-link).
        write!(
            output,
            "
{0}
\n",
            err_code
        )?;

        // Description rendered as markdown.
        match info.description {
            Some(ref desc) => {
                let mut id_map = self.0.borrow_mut();
                let playground = Playground {
                    crate_name: None,
                    url: String::from("https://play.rust-lang.org/"),
                };
                write!(
                    output,
                    "{}",
                    Markdown(
                        desc,
                        &[],
                        &mut id_map,
                        ErrorCodes::Yes,
                        DEFAULT_EDITION,
                        &Some(playground)
                    )
                    .into_string()
                )?
            }
            None => write!(output, "
No description.
\n")?,
        }

        write!(output, "
\n")?;
        Ok(())
    }

    fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
        write!(
            output,
            r##"

"##
        )?;
        Ok(())
    }
}

impl Formatter for MarkdownFormatter {
    #[allow(unused_variables)]
    fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
        Ok(())
    }

    fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
        write!(output, "# Rust Compiler Error Index\n")?;
        Ok(())
    }

    fn error_code_block(
        &self,
        output: &mut dyn Write,
        info: &ErrorMetadata,
        err_code: &str,
    ) -> Result<(), Box<dyn Error>> {
        Ok(match info.description {
            Some(ref desc) => write!(output, "## {}\n{}\n", err_code, desc)?,
            None => (),
        })
    }

    #[allow(unused_variables)]
    fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
        Ok(())
    }
}

/// Output an HTML page for the errors in `err_map` to `output_path`.
fn render_error_page<T: Formatter>(
    err_map: &ErrorMetadataMap,
    output_path: &Path,
    formatter: T,
) -> Result<(), Box<dyn Error>> {
    let mut output_file = File::create(output_path)?;

    formatter.header(&mut output_file)?;
    formatter.title(&mut output_file)?;

    for (err_code, info) in err_map {
        formatter.error_code_block(&mut output_file, info, err_code)?;
    }

    formatter.footer(&mut output_file)
}

fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<dyn Error>> {
    let long_codes = register_all();
    let mut err_map = BTreeMap::new();
    for (code, desc) in long_codes {
        err_map.insert(code.to_string(), ErrorMetadata { description: desc.map(String::from) });
    }
    match format {
        OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
        OutputFormat::HTML(h) => render_error_page(&err_map, dst, h)?,
        OutputFormat::Markdown(m) => render_error_page(&err_map, dst, m)?,
    }
    Ok(())
}

fn parse_args() -> (OutputFormat, PathBuf) {
    let mut args = env::args().skip(1);
    let format = args.next();
    let dst = args.next();
    let resource_suffix = args.next().unwrap_or_else(String::new);
    let format = format
        .map(|a| OutputFormat::from(&a, &resource_suffix))
        .unwrap_or(OutputFormat::from("html", &resource_suffix));
    let dst = dst.map(PathBuf::from).unwrap_or_else(|| match format {
        OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"),
        OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"),
        OutputFormat::Unknown(..) => PathBuf::from("<nul>"),
    });
    (format, dst)
}

fn main() {
    rustc_driver::init_env_logger("RUST_LOG");
    let (format, dst) = parse_args();
    let result =
        rustc_span::create_default_session_globals_then(move || main_with_result(format, &dst));
    if let Err(e) = result {
        panic!("{}", e.to_string());
    }
}

include!(concat!(env!("OUT_DIR"), "/error_codes.rs"));
<commit_msg>Rollup merge of #89535 - notriddle:notriddle/error-index-generator-js, r=Mark-Simulacrum<commit_after>#![feature(rustc_private)]

extern crate rustc_driver;
extern crate rustc_span;

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::env;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;

use rustc_span::edition::DEFAULT_EDITION;

use rustdoc::html::markdown::{ErrorCodes, IdMap, Markdown, Playground};

pub struct ErrorMetadata {
    pub description: Option<String>,
}

/// Mapping from error codes to metadata that can be (de)serialized.
pub type ErrorMetadataMap = BTreeMap<String, ErrorMetadata>;

enum OutputFormat {
    HTML(HTMLFormatter),
    Markdown(MarkdownFormatter),
    Unknown(String),
}

impl OutputFormat {
    fn from(format: &str, resource_suffix: &str) -> OutputFormat {
        match &*format.to_lowercase() {
            "html" => OutputFormat::HTML(HTMLFormatter(
                RefCell::new(IdMap::new()),
                resource_suffix.to_owned(),
            )),
            "markdown" => OutputFormat::Markdown(MarkdownFormatter),
            s => OutputFormat::Unknown(s.to_owned()),
        }
    }
}

trait Formatter {
    fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
    fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
    fn error_code_block(
        &self,
        output: &mut dyn Write,
        info: &ErrorMetadata,
        err_code: &str,
    ) -> Result<(), Box<dyn Error>>;
    fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
}

struct HTMLFormatter(RefCell<IdMap>, String);
struct MarkdownFormatter;

impl Formatter for HTMLFormatter {
    fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
        write!(
            output,
            r##"<!DOCTYPE html>

<title>Rust Compiler Error Index</title>
<meta charset="utf-8">

<link rel="stylesheet" type="text/css" href="rustdoc{suffix}.css"/>
<link rel="stylesheet" type="text/css" href="light{suffix}.css"/>
<link rel="stylesheet" type="text/css" href="rust.css"/>

"##,
            suffix = self.1
        )?;
        Ok(())
    }

    fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
        write!(output, "
Rust Compiler Error Index
\n")?;
        Ok(())
    }

    fn error_code_block(
        &self,
        output: &mut dyn Write,
        info: &ErrorMetadata,
        err_code: &str,
    ) -> Result<(), Box<dyn Error>> {
        // Enclose each error in a div so they can be shown/hidden en masse.
        let desc_desc = match info.description {
            Some(_) => "error-described",
            None => "error-undescribed",
        };
        write!(output, "
", desc_desc)?;

        // Error title (with self-link).
        write!(
            output,
            "
{0}
\n",
            err_code
        )?;

        // Description rendered as markdown.
        match info.description {
            Some(ref desc) => {
                let mut id_map = self.0.borrow_mut();
                let playground = Playground {
                    crate_name: None,
                    url: String::from("https://play.rust-lang.org/"),
                };
                write!(
                    output,
                    "{}",
                    Markdown(
                        desc,
                        &[],
                        &mut id_map,
                        ErrorCodes::Yes,
                        DEFAULT_EDITION,
                        &Some(playground)
                    )
                    .into_string()
                )?
            }
            None => write!(output, "
No description.
\n")?,
        }

        write!(output, "
\n")?;
        Ok(())
    }

    fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
        write!(
            output,
            r##"

"##
        )?;
        Ok(())
    }
}

impl Formatter for MarkdownFormatter {
    #[allow(unused_variables)]
    fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
        Ok(())
    }

    fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
        write!(output, "# Rust Compiler Error Index\n")?;
        Ok(())
    }

    fn error_code_block(
        &self,
        output: &mut dyn Write,
        info: &ErrorMetadata,
        err_code: &str,
    ) -> Result<(), Box<dyn Error>> {
        Ok(match info.description {
            Some(ref desc) => write!(output, "## {}\n{}\n", err_code, desc)?,
            None => (),
        })
    }

    #[allow(unused_variables)]
    fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
        Ok(())
    }
}

/// Output an HTML page for the errors in `err_map` to `output_path`.
fn render_error_page<T: Formatter>(
    err_map: &ErrorMetadataMap,
    output_path: &Path,
    formatter: T,
) -> Result<(), Box<dyn Error>> {
    let mut output_file = File::create(output_path)?;

    formatter.header(&mut output_file)?;
    formatter.title(&mut output_file)?;

    for (err_code, info) in err_map {
        formatter.error_code_block(&mut output_file, info, err_code)?;
    }

    formatter.footer(&mut output_file)
}

fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<dyn Error>> {
    let long_codes = register_all();
    let mut err_map = BTreeMap::new();
    for (code, desc) in long_codes {
        err_map.insert(code.to_string(), ErrorMetadata { description: desc.map(String::from) });
    }
    match format {
        OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
        OutputFormat::HTML(h) => render_error_page(&err_map, dst, h)?,
        OutputFormat::Markdown(m) => render_error_page(&err_map, dst, m)?,
    }
    Ok(())
}

fn parse_args() -> (OutputFormat, PathBuf) {
    let mut args = env::args().skip(1);
    let format = args.next();
    let dst = args.next();
    let resource_suffix = args.next().unwrap_or_else(String::new);
    let format = format
        .map(|a| OutputFormat::from(&a, &resource_suffix))
        .unwrap_or(OutputFormat::from("html", &resource_suffix));
    let dst = dst.map(PathBuf::from).unwrap_or_else(|| match format {
        OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"),
        OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"),
        OutputFormat::Unknown(..) => PathBuf::from("<nul>"),
    });
    (format, dst)
}

fn main() {
    rustc_driver::init_env_logger("RUST_LOG");
    let (format, dst) = parse_args();
    let result =
        rustc_span::create_default_session_globals_then(move || main_with_result(format, &dst));
    if let Err(e) = result {
        panic!("{}", e.to_string());
    }
}

include!(concat!(env!("OUT_DIR"), "/error_codes.rs"));
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

mod aptos_debug_natives;

use crate::{
    common::{
        types::{
            load_account_arg, AccountAddressWrapper, CliError, CliTypedResult, MovePackageDir,
            PromptOptions, TransactionOptions, TransactionSummary,
        },
        utils::check_if_file_exists,
    },
    CliCommand, CliResult,
};
use aptos_module_verifier::module_init::verify_module_init_function;
use aptos_rest_client::aptos_api_types::MoveType;
use aptos_types::transaction::{ModuleBundle, ScriptFunction, TransactionPayload};
use async_trait::async_trait;
use clap::{Parser, Subcommand};
use move_deps::{
    move_cli,
    move_cli::package::cli::UnitTestResult,
    move_command_line_common::env::get_bytecode_version_from_env,
    move_core_types::{
        account_address::AccountAddress,
        identifier::Identifier,
        language_storage::{ModuleId, TypeTag},
    },
    move_package::{
        compilation::compiled_package::CompiledPackage,
        source_package::layout::SourcePackageLayout, BuildConfig,
    },
    move_unit_test::UnitTestingConfig,
};
use std::{
    collections::BTreeMap,
    convert::TryFrom,
    fs::create_dir_all,
    io::Write,
    path::{Path, PathBuf},
    str::FromStr,
};

/// CLI tool for performing Move tasks
///
#[derive(Subcommand)]
pub enum MoveTool {
    Compile(CompilePackage),
    Init(InitPackage),
    Publish(PublishPackage),
    Run(RunFunction),
    Test(TestPackage),
}

impl MoveTool {
    pub async fn execute(self) -> CliResult {
        match self {
            MoveTool::Compile(tool) => tool.execute_serialized().await,
            MoveTool::Init(tool) => tool.execute_serialized_success().await,
            MoveTool::Publish(tool) => tool.execute_serialized().await,
            MoveTool::Run(tool) => tool.execute_serialized().await,
            MoveTool::Test(tool) => tool.execute_serialized().await,
        }
    }
}

/// Creates a new Move package at the given location
#[derive(Parser)]
pub struct InitPackage {
    /// Name of the new move package
    #[clap(long)]
    name: String,
    /// Path to create the new move package
    #[clap(long, parse(from_os_str), default_value_os_t = crate::common::utils::current_dir())]
    package_dir: PathBuf,
    /// Named addresses for the move binary
    ///
    /// Example: alice=0x1234, bob=0x5678
    ///
    /// Note: This will fail if there are duplicates in the Move.toml file remove those first.
    #[clap(long, parse(try_from_str = crate::common::utils::parse_map), default_value = "")]
    named_addresses: BTreeMap<String, AccountAddressWrapper>,
    #[clap(flatten)]
    prompt_options: PromptOptions,
}

#[async_trait]
impl CliCommand<()> for InitPackage {
    fn command_name(&self) -> &'static str {
        "InitPackage"
    }

    async fn execute(self) -> CliTypedResult<()> {
        let move_toml = self.package_dir.join(SourcePackageLayout::Manifest.path());
        check_if_file_exists(move_toml.as_path(), self.prompt_options)?;
        create_dir_all(self.package_dir.join(SourcePackageLayout::Sources.path())).map_err(
            |err| {
                CliError::IO(
                    format!(
                        "Failed to create {} move package directories",
                        self.package_dir.display()
                    ),
                    err,
                )
            },
        )?;
        let mut w = std::fs::File::create(move_toml.as_path()).map_err(|err| {
            CliError::UnexpectedError(format!(
                "Failed to create {}: {}",
                self.package_dir.join(Path::new("Move.toml")).display(),
                err
            ))
        })?;

        let addresses: BTreeMap<String, String> = self
            .named_addresses
            .clone()
            .into_iter()
            .map(|(key, value)| (key, value.account_address.to_hex_literal()))
            .collect();

        // TODO: Support Git as default when Github credentials are properly handled from GH CLI
        writeln!(
            &mut w,
            "[package]
name = \"{}\"
version = \"0.0.0\"

[dependencies]
AptosFramework = {{ git = \"https://github.com/aptos-labs/aptos-core.git\", subdir = \"aptos-move/framework/aptos-framework/\", rev = \"main\" }}

[addresses]
{}
",
            self.name,
            toml::to_string(&addresses).unwrap()
        )
        .map_err(|err| {
            CliError::UnexpectedError(format!(
                "Failed to write {:?}: {}",
                self.package_dir.join(Path::new("Move.toml")),
                err
            ))
        })
    }
}

/// Compiles a package and returns the [`ModuleId`]s
#[derive(Parser)]
pub struct CompilePackage {
    #[clap(flatten)]
    move_options: MovePackageDir,
}

#[async_trait]
impl CliCommand<Vec<String>> for CompilePackage {
    fn command_name(&self) -> &'static str {
        "CompilePackage"
    }

    async fn execute(self) -> CliTypedResult<Vec<String>> {
        let build_config = BuildConfig {
            additional_named_addresses: self.move_options.named_addresses(),
            generate_abis: true,
            generate_docs: true,
            install_dir: self.move_options.output_dir.clone(),
            ..Default::default()
        };
        let compiled_package = compile_move(build_config, self.move_options.package_dir.as_path())?;
        let mut ids = Vec::new();
        for &module in compiled_package.root_modules_map().iter_modules().iter() {
            verify_module_init_function(module)
                .map_err(|e| CliError::MoveCompilationError(e.to_string()))?;
            ids.push(module.self_id().to_string());
        }
        Ok(ids)
    }
}

/// Run Move unit tests against a package path
#[derive(Parser)]
pub struct TestPackage {
    #[clap(flatten)]
    move_options: MovePackageDir,

    /// A filter string to determine which unit tests to run
    #[clap(long)]
    pub filter: Option<String>,
}

#[async_trait]
impl CliCommand<&'static str> for TestPackage {
    fn command_name(&self) -> &'static str {
        "TestPackage"
    }

    async fn execute(self) -> CliTypedResult<&'static str> {
        let config = BuildConfig {
            additional_named_addresses: self.move_options.named_addresses(),
            test_mode: true,
            install_dir: self.move_options.output_dir.clone(),
            ..Default::default()
        };
        let result = move_cli::package::cli::run_move_unit_tests(
            self.move_options.package_dir.as_path(),
            config,
            UnitTestingConfig {
                filter: self.filter,
                ..UnitTestingConfig::default_with_bound(Some(100_000))
            },
            aptos_debug_natives::aptos_debug_natives(),
            false,
        )
        .map_err(|err| CliError::UnexpectedError(err.to_string()))?;

        // TODO: commit back up to the move repo
        match result {
            UnitTestResult::Success => Ok("Success"),
            UnitTestResult::Failure => Err(CliError::MoveTestError),
        }
    }
}

/// Compiles a Move package dir, and returns the compiled modules.
fn compile_move(build_config: BuildConfig, package_dir: &Path) -> CliTypedResult<CompiledPackage> {
    // TODO: Add caching
    build_config
        .compile_package(package_dir, &mut Vec::new())
        .map_err(|err| CliError::MoveCompilationError(err.to_string()))
}

/// Publishes the modules in a Move package
#[derive(Parser)]
pub struct PublishPackage {
    #[clap(flatten)]
    move_options: MovePackageDir,
    #[clap(flatten)]
    txn_options: TransactionOptions,
}

#[async_trait]
impl CliCommand<TransactionSummary> for PublishPackage {
    fn command_name(&self) -> &'static str {
        "PublishPackage"
    }

    async fn execute(self) -> CliTypedResult<TransactionSummary> {
        let build_config = BuildConfig {
            additional_named_addresses: self.move_options.named_addresses(),
            generate_abis: false,
            generate_docs: true,
            install_dir: self.move_options.output_dir.clone(),
            ..Default::default()
        };
        let package = compile_move(build_config, self.move_options.package_dir.as_path())?;
        let compiled_units: Vec<Vec<u8>> = package
            .root_compiled_units
            .iter()
            .map(|unit_with_source| {
                unit_with_source
                    .unit
                    .serialize(get_bytecode_version_from_env())
            })
            .collect();

        // Send the compiled module
        self.txn_options
            .submit_transaction(TransactionPayload::ModuleBundle(ModuleBundle::new(
                compiled_units,
            )))
            .await
            .map(TransactionSummary::from)
    }
}

/// Run a Move function
#[derive(Parser)]
pub struct RunFunction {
    #[clap(flatten)]
    txn_options: TransactionOptions,
    /// Function name as `<ADDRESS>::<MODULE_ID>::<FUNCTION_NAME>`
    ///
    /// Example: `0x842ed41fad9640a2ad08fdd7d3e4f7f505319aac7d67e1c0dd6a7cce8732c7e3::message::set_message`
    #[clap(long, parse(try_from_str = parse_function_name))]
    function_id: FunctionId,
    /// Hex encoded arguments separated by spaces.
    ///
    /// Example: `0x01 0x02 0x03`
    #[clap(long, multiple_values = true)]
    args: Vec<ArgWithType>,
    /// TypeTag arguments separated by spaces.
    ///
    /// Example: `u8 u64 u128 bool address vector true false signer`
    #[clap(long, multiple_values = true)]
    type_args: Vec<MoveType>,
}

#[async_trait]
impl CliCommand<TransactionSummary> for RunFunction {
    fn command_name(&self) -> &'static str {
        "RunFunction"
    }

    async fn execute(self) -> CliTypedResult<TransactionSummary> {
        let args: Vec<Vec<u8>> = self
            .args
            .iter()
            .map(|arg_with_type| arg_with_type.arg.clone())
            .collect();
        let mut type_args: Vec<TypeTag> = Vec::new();

        // These TypeArgs are used for generics
        for type_arg in self.type_args.iter().cloned() {
            let type_tag = TypeTag::try_from(type_arg)
                .map_err(|err| CliError::UnableToParse("--type-args", err.to_string()))?;
            type_args.push(type_tag)
        }

        self.txn_options
            .submit_transaction(TransactionPayload::ScriptFunction(ScriptFunction::new(
                self.function_id.module_id.clone(),
                self.function_id.function_id.clone(),
                type_args,
                args,
            )))
            .await
            .map(TransactionSummary::from)
    }
}

#[derive(Clone, Debug)]
enum FunctionArgType {
    Address,
    Bool,
    Hex,
    String,
    U8,
    U64,
    U128,
}

impl FunctionArgType {
    fn parse_arg(&self, arg: &str) -> CliTypedResult<Vec<u8>> {
        match self {
            FunctionArgType::Address => bcs::to_bytes(
                &AccountAddress::from_str(arg)
                    .map_err(|err| CliError::UnableToParse("address", err.to_string()))?,
            ),
            FunctionArgType::Bool => bcs::to_bytes(
                &bool::from_str(arg)
                    .map_err(|err| CliError::UnableToParse("bool", err.to_string()))?,
            ),
            FunctionArgType::Hex => bcs::to_bytes(
                &hex::decode(arg).map_err(|err| CliError::UnableToParse("hex", err.to_string()))?,
            ),
            FunctionArgType::String => bcs::to_bytes(arg),
            FunctionArgType::U8 => bcs::to_bytes(
                &u8::from_str(arg).map_err(|err| CliError::UnableToParse("u8", err.to_string()))?,
            ),
            FunctionArgType::U64 => bcs::to_bytes(
                &u64::from_str(arg)
                    .map_err(|err| CliError::UnableToParse("u64", err.to_string()))?,
            ),
            FunctionArgType::U128 => bcs::to_bytes(
                &u128::from_str(arg)
                    .map_err(|err| CliError::UnableToParse("u128", err.to_string()))?,
            ),
        }
        .map_err(|err| CliError::BCS("arg", err))
    }
}

impl FromStr for FunctionArgType {
    type Err = CliError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "address" => Ok(FunctionArgType::Address),
            "bool" => Ok(FunctionArgType::Bool),
            "hex" => Ok(FunctionArgType::Hex),
            "string" => Ok(FunctionArgType::String),
            "u8" => Ok(FunctionArgType::U8),
            "u64" => Ok(FunctionArgType::U64),
            "u128" => Ok(FunctionArgType::U128),
            str => Err(CliError::CommandArgumentError(format!("Invalid arg type '{}'.  Must be one of: ['address','bool','hex','string','u8','u64','u128']", str))),
        }
    }
}

/// A parseable arg with a type separated by a colon
pub struct ArgWithType {
    _ty: FunctionArgType,
    arg: Vec<u8>,
}

impl FromStr for ArgWithType {
    type Err = CliError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<_> = s.split(':').collect();
        if parts.len() != 2 {
            return Err(CliError::CommandArgumentError(
                "Arguments must be pairs of <type>:<arg> e.g. bool:true".to_string(),
            ));
        }

        let ty = FunctionArgType::from_str(parts.first().unwrap())?;
        let arg = parts.last().unwrap();
        let arg = ty.parse_arg(arg)?;

        Ok(ArgWithType { _ty: ty, arg })
    }
}

pub struct FunctionId {
    pub module_id: ModuleId,
    pub function_id: Identifier,
}

fn parse_function_name(function_id: &str) -> CliTypedResult<FunctionId> {
    let ids: Vec<&str> = function_id.split_terminator("::").collect();
    if ids.len() != 3 {
        return Err(CliError::CommandArgumentError(
            "FunctionId is not well formed.  Must be of the form <address>::<module>::<function>"
                .to_string(),
        ));
    }
    let address = load_account_arg(ids.get(0).unwrap())?;
    let module = Identifier::from_str(ids.get(1).unwrap())
        .map_err(|err| CliError::UnableToParse("Module Name", err.to_string()))?;
    let function_id = Identifier::from_str(ids.get(2).unwrap())
        .map_err(|err| CliError::UnableToParse("Function Name", err.to_string()))?;
    let module_id = ModuleId::new(address, module);
    Ok(FunctionId {
        module_id,
        function_id,
    })
}
<commit_msg>[aptos-cli] Fix profiles as inputs to function inputs<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

mod aptos_debug_natives;

use crate::{
    common::{
        types::{
            load_account_arg, AccountAddressWrapper, CliError, CliTypedResult, MovePackageDir,
            PromptOptions, TransactionOptions, TransactionSummary,
        },
        utils::check_if_file_exists,
    },
    CliCommand, CliResult,
};
use aptos_module_verifier::module_init::verify_module_init_function;
use aptos_rest_client::aptos_api_types::MoveType;
use aptos_types::transaction::{ModuleBundle, ScriptFunction, TransactionPayload};
use async_trait::async_trait;
use clap::{Parser, Subcommand};
use move_deps::{
    move_cli,
    move_cli::package::cli::UnitTestResult,
    move_command_line_common::env::get_bytecode_version_from_env,
    move_core_types::{
        identifier::Identifier,
        language_storage::{ModuleId, TypeTag},
    },
    move_package::{
        compilation::compiled_package::CompiledPackage,
        source_package::layout::SourcePackageLayout, BuildConfig,
    },
    move_unit_test::UnitTestingConfig,
};
use std::{
    collections::BTreeMap,
    convert::TryFrom,
    fs::create_dir_all,
    io::Write,
    path::{Path, PathBuf},
    str::FromStr,
};

/// CLI tool for performing Move tasks
///
#[derive(Subcommand)]
pub enum MoveTool {
    Compile(CompilePackage),
    Init(InitPackage),
    Publish(PublishPackage),
    Run(RunFunction),
    Test(TestPackage),
}

impl MoveTool {
    pub async fn execute(self) -> CliResult {
        match self {
            MoveTool::Compile(tool) => tool.execute_serialized().await,
            MoveTool::Init(tool) => tool.execute_serialized_success().await,
            MoveTool::Publish(tool) => tool.execute_serialized().await,
            MoveTool::Run(tool) => tool.execute_serialized().await,
            MoveTool::Test(tool) => tool.execute_serialized().await,
        }
    }
}

/// Creates a new Move package at the given location
#[derive(Parser)]
pub struct InitPackage {
    /// Name of the new move package
    #[clap(long)]
    name: String,
    /// Path to create the new move package
    #[clap(long, parse(from_os_str), default_value_os_t = crate::common::utils::current_dir())]
    package_dir: PathBuf,
    /// Named addresses for the move binary
    ///
    /// Example: alice=0x1234, bob=0x5678
    ///
    /// Note: This will fail if there are duplicates in the Move.toml file remove those first.
    #[clap(long, parse(try_from_str = crate::common::utils::parse_map), default_value = "")]
    named_addresses: BTreeMap<String, AccountAddressWrapper>,
    #[clap(flatten)]
    prompt_options: PromptOptions,
}

#[async_trait]
impl CliCommand<()> for InitPackage {
    fn command_name(&self) -> &'static str {
        "InitPackage"
    }

    async fn execute(self) -> CliTypedResult<()> {
        let move_toml = self.package_dir.join(SourcePackageLayout::Manifest.path());
        check_if_file_exists(move_toml.as_path(), self.prompt_options)?;
        create_dir_all(self.package_dir.join(SourcePackageLayout::Sources.path())).map_err(
            |err| {
                CliError::IO(
                    format!(
                        "Failed to create {} move package directories",
                        self.package_dir.display()
                    ),
                    err,
                )
            },
        )?;
        let mut w = std::fs::File::create(move_toml.as_path()).map_err(|err| {
            CliError::UnexpectedError(format!(
                "Failed to create {}: {}",
                self.package_dir.join(Path::new("Move.toml")).display(),
                err
            ))
        })?;

        let addresses: BTreeMap<String, String> = self
            .named_addresses
            .clone()
            .into_iter()
            .map(|(key, value)| (key, value.account_address.to_hex_literal()))
            .collect();

        // TODO: Support Git as default when Github credentials are properly handled from GH CLI
        writeln!(
            &mut w,
            "[package]
name = \"{}\"
version = \"0.0.0\"

[dependencies]
AptosFramework = {{ git = \"https://github.com/aptos-labs/aptos-core.git\", subdir = \"aptos-move/framework/aptos-framework/\", rev = \"main\" }}

[addresses]
{}
",
            self.name,
            toml::to_string(&addresses).unwrap()
        )
        .map_err(|err| {
            CliError::UnexpectedError(format!(
                "Failed to write {:?}: {}",
                self.package_dir.join(Path::new("Move.toml")),
                err
            ))
        })
    }
}

/// Compiles a package and returns the [`ModuleId`]s
#[derive(Parser)]
pub struct CompilePackage {
    #[clap(flatten)]
    move_options: MovePackageDir,
}

#[async_trait]
impl CliCommand<Vec<String>> for CompilePackage {
    fn command_name(&self) -> &'static str {
        "CompilePackage"
    }

    async fn execute(self) -> CliTypedResult<Vec<String>> {
        let build_config = BuildConfig {
            additional_named_addresses: self.move_options.named_addresses(),
            generate_abis: true,
            generate_docs: true,
            install_dir: self.move_options.output_dir.clone(),
            ..Default::default()
        };
        let compiled_package = compile_move(build_config, self.move_options.package_dir.as_path())?;
        let mut ids = Vec::new();
        for &module in compiled_package.root_modules_map().iter_modules().iter() {
            verify_module_init_function(module)
                .map_err(|e| CliError::MoveCompilationError(e.to_string()))?;
            ids.push(module.self_id().to_string());
        }
        Ok(ids)
    }
}

/// Run Move unit tests against a package path
#[derive(Parser)]
pub struct TestPackage {
    #[clap(flatten)]
    move_options: MovePackageDir,

    /// A filter string to determine which unit tests to run
    #[clap(long)]
    pub filter: Option<String>,
}

#[async_trait]
impl CliCommand<&'static str> for TestPackage {
    fn command_name(&self) -> &'static str {
        "TestPackage"
    }

    async fn execute(self) -> CliTypedResult<&'static str> {
        let config = BuildConfig {
            additional_named_addresses: self.move_options.named_addresses(),
            test_mode: true,
            install_dir: self.move_options.output_dir.clone(),
            ..Default::default()
        };
        let result = move_cli::package::cli::run_move_unit_tests(
            self.move_options.package_dir.as_path(),
            config,
            UnitTestingConfig {
                filter: self.filter,
                ..UnitTestingConfig::default_with_bound(Some(100_000))
            },
            aptos_debug_natives::aptos_debug_natives(),
            false,
        )
        .map_err(|err| CliError::UnexpectedError(err.to_string()))?;

        // TODO: commit back up to the move repo
        match result {
            UnitTestResult::Success => Ok("Success"),
            UnitTestResult::Failure => Err(CliError::MoveTestError),
        }
    }
}

/// Compiles a Move package dir, and returns the compiled modules.
fn compile_move(build_config: BuildConfig, package_dir: &Path) -> CliTypedResult<CompiledPackage> {
    // TODO: Add caching
    build_config
        .compile_package(package_dir, &mut Vec::new())
        .map_err(|err| CliError::MoveCompilationError(err.to_string()))
}

/// Publishes the modules in a Move package
#[derive(Parser)]
pub struct PublishPackage {
    #[clap(flatten)]
    move_options: MovePackageDir,
    #[clap(flatten)]
    txn_options: TransactionOptions,
}

#[async_trait]
impl CliCommand<TransactionSummary> for PublishPackage {
    fn command_name(&self) -> &'static str {
        "PublishPackage"
    }

    async fn execute(self) -> CliTypedResult<TransactionSummary> {
        let build_config = BuildConfig {
            additional_named_addresses: self.move_options.named_addresses(),
            generate_abis: false,
            generate_docs: true,
            install_dir: self.move_options.output_dir.clone(),
            ..Default::default()
        };
        let package = compile_move(build_config, self.move_options.package_dir.as_path())?;
        let compiled_units: Vec<Vec<u8>> = package
            .root_compiled_units
            .iter()
            .map(|unit_with_source| {
                unit_with_source
                    .unit
                    .serialize(get_bytecode_version_from_env())
            })
            .collect();

        // Send the compiled module
        self.txn_options
            .submit_transaction(TransactionPayload::ModuleBundle(ModuleBundle::new(
                compiled_units,
            )))
            .await
            .map(TransactionSummary::from)
    }
}

/// Run a Move function
#[derive(Parser)]
pub struct RunFunction {
    #[clap(flatten)]
    txn_options: TransactionOptions,
    /// Function name as `<ADDRESS>::<MODULE_ID>::<FUNCTION_NAME>`
    ///
    /// Example: `0x842ed41fad9640a2ad08fdd7d3e4f7f505319aac7d67e1c0dd6a7cce8732c7e3::message::set_message`
    #[clap(long, parse(try_from_str = parse_function_name))]
    function_id: FunctionId,
    /// Hex encoded arguments separated by spaces.
    ///
    /// Example: `0x01 0x02 0x03`
    #[clap(long, multiple_values = true)]
    args: Vec<ArgWithType>,
    /// TypeTag arguments separated by spaces.
    ///
    /// Example: `u8 u64 u128 bool address vector true false signer`
    #[clap(long, multiple_values = true)]
    type_args: Vec<MoveType>,
}

#[async_trait]
impl CliCommand<TransactionSummary> for RunFunction {
    fn command_name(&self) -> &'static str {
        "RunFunction"
    }

    async fn execute(self) -> CliTypedResult<TransactionSummary> {
        let args: Vec<Vec<u8>> = self
            .args
            .iter()
            .map(|arg_with_type| arg_with_type.arg.clone())
            .collect();
        let mut type_args: Vec<TypeTag> = Vec::new();

        // These TypeArgs are used for generics
        for type_arg in self.type_args.iter().cloned() {
            let type_tag = TypeTag::try_from(type_arg)
                .map_err(|err| CliError::UnableToParse("--type-args", err.to_string()))?;
            type_args.push(type_tag)
        }

        self.txn_options
            .submit_transaction(TransactionPayload::ScriptFunction(ScriptFunction::new(
                self.function_id.module_id.clone(),
                self.function_id.function_id.clone(),
                type_args,
                args,
            )))
            .await
            .map(TransactionSummary::from)
    }
}

#[derive(Clone, Debug)]
enum FunctionArgType {
    Address,
    Bool,
    Hex,
    String,
    U8,
    U64,
    U128,
}

impl FunctionArgType {
    fn parse_arg(&self, arg: &str) -> CliTypedResult<Vec<u8>> {
        match self {
            FunctionArgType::Address => bcs::to_bytes(
                &load_account_arg(arg)
                    .map_err(|err| CliError::UnableToParse("address", err.to_string()))?,
            ),
            FunctionArgType::Bool => bcs::to_bytes(
                &bool::from_str(arg)
                    .map_err(|err| CliError::UnableToParse("bool", err.to_string()))?,
            ),
            FunctionArgType::Hex => bcs::to_bytes(
                &hex::decode(arg).map_err(|err| CliError::UnableToParse("hex", err.to_string()))?,
            ),
            FunctionArgType::String => bcs::to_bytes(arg),
            FunctionArgType::U8 => bcs::to_bytes(
                &u8::from_str(arg).map_err(|err| CliError::UnableToParse("u8", err.to_string()))?,
            ),
            FunctionArgType::U64 => bcs::to_bytes(
                &u64::from_str(arg)
                    .map_err(|err| CliError::UnableToParse("u64", err.to_string()))?,
            ),
            FunctionArgType::U128 => bcs::to_bytes(
                &u128::from_str(arg)
                    .map_err(|err| CliError::UnableToParse("u128", err.to_string()))?,
            ),
        }
        .map_err(|err| CliError::BCS("arg", err))
    }
}

impl FromStr for FunctionArgType {
    type Err = CliError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "address" => Ok(FunctionArgType::Address),
            "bool" => Ok(FunctionArgType::Bool),
            "hex" => Ok(FunctionArgType::Hex),
            "string" => Ok(FunctionArgType::String),
            "u8" => Ok(FunctionArgType::U8),
            "u64" => Ok(FunctionArgType::U64),
            "u128" => Ok(FunctionArgType::U128),
            str => Err(CliError::CommandArgumentError(format!("Invalid arg type '{}'.  Must be one of: ['address','bool','hex','string','u8','u64','u128']", str))),
        }
    }
}

/// A parseable arg with a type separated by a colon
pub struct ArgWithType {
    _ty: FunctionArgType,
    arg: Vec<u8>,
}

impl FromStr for ArgWithType {
    type Err = CliError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<_> = s.split(':').collect();
        if parts.len() != 2 {
            return Err(CliError::CommandArgumentError(
                "Arguments must be pairs of <type>:<arg> e.g. bool:true".to_string(),
            ));
        }

        let ty = FunctionArgType::from_str(parts.first().unwrap())?;
        let arg = parts.last().unwrap();
        let arg = ty.parse_arg(arg)?;

        Ok(ArgWithType { _ty: ty, arg })
    }
}

pub struct FunctionId {
    pub module_id: ModuleId,
    pub function_id: Identifier,
}

fn parse_function_name(function_id: &str) -> CliTypedResult<FunctionId> {
    let ids: Vec<&str> = function_id.split_terminator("::").collect();
    if ids.len() != 3 {
        return Err(CliError::CommandArgumentError(
            "FunctionId is not well formed.  Must be of the form <address>::<module>::<function>"
                .to_string(),
        ));
    }
    let address = load_account_arg(ids.get(0).unwrap())?;
    let module = Identifier::from_str(ids.get(1).unwrap())
        .map_err(|err| CliError::UnableToParse("Module Name", err.to_string()))?;
    let function_id = Identifier::from_str(ids.get(2).unwrap())
        .map_err(|err| CliError::UnableToParse("Function Name", err.to_string()))?;
    let module_id = ModuleId::new(address, module);
    Ok(FunctionId {
        module_id,
        function_id,
    })
}
<|endoftext|>


<commit_before>#![cfg(feature = "encoding")]

#[macro_use]
extern crate lambda_calculus as lambda;

use lambda::*;
use lambda::church::numerals::*;
use lambda::combinators::C;

#[test]
fn church_succ() {
    assert_eq!(beta(app!(succ(), 0.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(succ(), 1.into_church()), HAP, 0), 2.into_church());
    assert_eq!(beta(app!(succ(), 2.into_church()), HAP, 0), 3.into_church());
}

#[test]
fn church_pred() {
    assert_eq!(beta(app!(pred(), 0.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(pred(), 1.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(pred(), 5.into_church()), HAP, 0), 4.into_church());
}

#[test]
fn church_add_sub() {
    assert_eq!(beta(app!(     add(), 1.into_church()), HAP, 0), succ());
    assert_eq!(beta(app!(C(), sub(), 1.into_church()), HAP, 0), pred());
}

#[test]
fn church_mult() {
    assert_eq!(beta(app!(mult(), 3.into_church(), 4.into_church()), HAP, 0), 12.into_church());
    assert_eq!(beta(app!(mult(), 1.into_church(), 3.into_church()), HAP, 0),  3.into_church());
    assert_eq!(beta(app!(mult(), 3.into_church(), 1.into_church()), HAP, 0),  3.into_church());
    assert_eq!(beta(app!(mult(), 5.into_church(), 0.into_church()), HAP, 0),  0.into_church());
    assert_eq!(beta(app!(mult(), 0.into_church(), 5.into_church()), HAP, 0),  0.into_church());
}

#[test]
fn church_pow() {
    assert_eq!(beta(app!(pow(), 2.into_church(), 4.into_church()), HAP, 0), 16.into_church());
    assert_eq!(beta(app!(pow(), 1.into_church(), 3.into_church()), HAP, 0),  1.into_church());
    assert_eq!(beta(app!(pow(), 3.into_church(), 1.into_church()), HAP, 0),  3.into_church());
    assert_eq!(beta(app!(pow(), 5.into_church(), 0.into_church()), HAP, 0),  1.into_church());
    assert_eq!(beta(app!(pow(), 0.into_church(), 5.into_church()), HAP, 0),  0.into_church());
}

#[test]
fn church_div() {
    assert_eq!(beta(app!(div(), 2.into_church(), 2.into_church()), HAP, 0), (1.into_church(), 0.into_church()).into_church());
    assert_eq!(beta(app!(div(), 3.into_church(), 2.into_church()), HAP, 0), (1.into_church(), 1.into_church()).into_church());
    assert_eq!(beta(app!(div(), 5.into_church(), 2.into_church()), HAP, 0), (2.into_church(), 1.into_church()).into_church());
    assert_eq!(beta(app!(div(), 2.into_church(), 1.into_church()), HAP, 0), (2.into_church(), 0.into_church()).into_church());
    assert_eq!(beta(app!(div(), 0.into_church(), 3.into_church()), HAP, 0), (0.into_church(), 0.into_church()).into_church());
}

#[test]
fn church_quot() {
    assert_eq!(beta(app!(quot(), 2.into_church(), 2.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(quot(), 3.into_church(), 2.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(quot(), 5.into_church(), 2.into_church()), HAP, 0), 2.into_church());
    assert_eq!(beta(app!(quot(), 2.into_church(), 1.into_church()), HAP, 0), 2.into_church());
    assert_eq!(beta(app!(quot(), 0.into_church(), 3.into_church()), HAP, 0), 0.into_church());
}

#[test]
fn church_rem() {
    assert_eq!(beta(app!(rem(), 2.into_church(), 2.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(rem(), 3.into_church(), 2.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(rem(), 2.into_church(), 5.into_church()), HAP, 0), 2.into_church());
    assert_eq!(beta(app!(rem(), 2.into_church(), 1.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(rem(), 0.into_church(), 3.into_church()), HAP, 0), 0.into_church());
}

#[test]
fn church_fac() {
    assert_eq!(beta(app!(fac(), 0.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(fac(), 1.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(fac(), 2.into_church()), HAP, 0), 2.into_church());
    assert_eq!(beta(app!(fac(), 3.into_church()), HAP, 0), 6.into_church());
}

#[test]
fn church_min() {
    assert_eq!(beta(app!(min(), 0.into_church(), 0.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(min(), 4.into_church(), 4.into_church()), HAP, 0), 4.into_church());
    assert_eq!(beta(app!(min(), 2.into_church(), 3.into_church()), HAP, 0), 2.into_church());
    assert_eq!(beta(app!(min(), 5.into_church(), 3.into_church()), HAP, 0), 3.into_church());
    assert_eq!(beta(app!(min(), 0.into_church(), 1.into_church()), HAP, 0), 0.into_church());
}

#[test]
fn church_max() {
    assert_eq!(beta(app!(max(), 0.into_church(), 0.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(max(), 4.into_church(), 4.into_church()), HAP, 0), 4.into_church());
    assert_eq!(beta(app!(max(), 2.into_church(), 3.into_church()), HAP, 0), 3.into_church());
    assert_eq!(beta(app!(max(), 5.into_church(), 3.into_church()), HAP, 0), 5.into_church());
    assert_eq!(beta(app!(max(), 0.into_church(), 1.into_church()), HAP, 0), 1.into_church());
}

#[test]
fn church_lshift() {
     assert_eq!(beta(app!(lshift(), 0.into_church(), 2.into_church()), HAP, 0), 0.into_church());
     assert_eq!(beta(app!(lshift(), 1.into_church(), 0.into_church()), HAP, 0), 1.into_church());
     assert_eq!(beta(app!(lshift(), 2.into_church(), 0.into_church()), HAP, 0), 2.into_church());
     assert_eq!(beta(app!(lshift(), 2.into_church(), 2.into_church()), HAP, 0), 8.into_church());
     assert_eq!(beta(app!(lshift(), 3.into_church(), 2.into_church()), HAP, 0), 12.into_church());
     assert_eq!(beta(app!(lshift(), 2.into_church(), 3.into_church()), HAP, 0), 16.into_church());
     assert_eq!(beta(app!(lshift(), 5.into_church(), 1.into_church()), HAP, 0), 10.into_church());
}

#[test]
fn church_rshift() {
     assert_eq!(beta(app!(rshift(), 1.into_church(), 0.into_church()), HAP, 0), 1.into_church());
     assert_eq!(beta(app!(rshift(), 2.into_church(), 0.into_church()), HAP, 0), 2.into_church());
     assert_eq!(beta(app!(rshift(), 0.into_church(), 2.into_church()), HAP, 0), 0.into_church());
     assert_eq!(beta(app!(rshift(), 2.into_church(), 1.into_church()), HAP, 0), 1.into_church());
     assert_eq!(beta(app!(rshift(), 2.into_church(), 2.into_church()), HAP, 0), 0.into_church());
     assert_eq!(beta(app!(rshift(), 5.into_church(), 1.into_church()), HAP, 0), 2.into_church());
     assert_eq!(beta(app!(rshift(), 9.into_church(), 1.into_church()), HAP, 0), 4.into_church());
     assert_eq!(beta(app!(rshift(), 9.into_church(), 2.into_church()), HAP, 0), 2.into_church());
     assert_eq!(beta(app!(rshift(), 7.into_church(), 1.into_church()), HAP, 0), 3.into_church());
}

#[test]
fn church_is_even() {
     assert_eq!(beta(app!(is_even(), 0.into_church()), HAP, 0), true.into_church());
     assert_eq!(beta(app!(is_even(), 1.into_church()), HAP, 0), false.into_church());
     assert_eq!(beta(app!(is_even(), 2.into_church()), HAP, 0), true.into_church());
     assert_eq!(beta(app!(is_even(), 8.into_church()), HAP, 0), true.into_church());
     assert_eq!(beta(app!(is_even(), 9.into_church()), HAP, 0), false.into_church());
}

#[test]
fn church_is_odd() {
     assert_eq!(beta(app!(is_odd(), 0.into_church()), HAP, 0), false.into_church());
     assert_eq!(beta(app!(is_odd(), 1.into_church()), HAP, 0), true.into_church());
     assert_eq!(beta(app!(is_odd(), 2.into_church()), HAP, 0), false.into_church());
     assert_eq!(beta(app!(is_odd(), 8.into_church()), HAP, 0), false.into_church());
     assert_eq!(beta(app!(is_odd(), 9.into_church()), HAP, 0), true.into_church());
}
<commit_msg>split church add and sub integration tests<commit_after>#![cfg(feature = "encoding")]

#[macro_use]
extern crate lambda_calculus as lambda;

use lambda::*;
use lambda::church::numerals::*;

#[test]
fn church_succ() {
    assert_eq!(beta(app!(succ(), 0.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(succ(), 1.into_church()), HAP, 0), 2.into_church());
    assert_eq!(beta(app!(succ(), 2.into_church()), HAP, 0), 3.into_church());
}

#[test]
fn church_pred() {
    assert_eq!(beta(app!(pred(), 0.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(pred(), 1.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(pred(), 5.into_church()), HAP, 0), 4.into_church());
}

#[test]
fn church_add() {
    assert_eq!(beta(app!(add(), 0.into_church(), 0.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(add(), 0.into_church(), 1.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(add(), 1.into_church(), 0.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(add(), 2.into_church(), 3.into_church()), HAP, 0), 5.into_church());
}

#[test]
fn church_sub() {
    assert_eq!(beta(app!(sub(), 0.into_church(), 0.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(sub(), 0.into_church(), 1.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(sub(), 1.into_church(), 0.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(sub(), 3.into_church(), 2.into_church()), HAP, 0), 1.into_church());
}

#[test]
fn church_mult() {
    assert_eq!(beta(app!(mult(), 3.into_church(), 4.into_church()), HAP, 0), 12.into_church());
    assert_eq!(beta(app!(mult(), 1.into_church(), 3.into_church()), HAP, 0),  3.into_church());
    assert_eq!(beta(app!(mult(), 3.into_church(), 1.into_church()), HAP, 0),  3.into_church());
    assert_eq!(beta(app!(mult(), 5.into_church(), 0.into_church()), HAP, 0),  0.into_church());
    assert_eq!(beta(app!(mult(), 0.into_church(), 5.into_church()), HAP, 0),  0.into_church());
}

#[test]
fn church_pow() {
    assert_eq!(beta(app!(pow(), 2.into_church(), 4.into_church()), HAP, 0), 16.into_church());
    assert_eq!(beta(app!(pow(), 1.into_church(), 3.into_church()), HAP, 0),  1.into_church());
    assert_eq!(beta(app!(pow(), 3.into_church(), 1.into_church()), HAP, 0),  3.into_church());
    assert_eq!(beta(app!(pow(), 5.into_church(), 0.into_church()), HAP, 0),  1.into_church());
    assert_eq!(beta(app!(pow(), 0.into_church(), 5.into_church()), HAP, 0),  0.into_church());
}

#[test]
fn church_div() {
    assert_eq!(beta(app!(div(), 2.into_church(), 2.into_church()), HAP, 0), (1.into_church(), 0.into_church()).into_church());
    assert_eq!(beta(app!(div(), 3.into_church(), 2.into_church()), HAP, 0), (1.into_church(), 1.into_church()).into_church());
    assert_eq!(beta(app!(div(), 5.into_church(), 2.into_church()), HAP, 0), (2.into_church(), 1.into_church()).into_church());
    assert_eq!(beta(app!(div(), 2.into_church(), 1.into_church()), HAP, 0), (2.into_church(), 0.into_church()).into_church());
    assert_eq!(beta(app!(div(), 0.into_church(), 3.into_church()), HAP, 0), (0.into_church(), 0.into_church()).into_church());
}

#[test]
fn church_quot() {
    assert_eq!(beta(app!(quot(), 2.into_church(), 2.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(quot(), 3.into_church(), 2.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(quot(), 5.into_church(), 2.into_church()), HAP, 0), 2.into_church());
    assert_eq!(beta(app!(quot(), 2.into_church(), 1.into_church()), HAP, 0), 2.into_church());
    assert_eq!(beta(app!(quot(), 0.into_church(), 3.into_church()), HAP, 0), 0.into_church());
}

#[test]
fn church_rem() {
    assert_eq!(beta(app!(rem(), 2.into_church(), 2.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(rem(), 3.into_church(), 2.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(rem(), 2.into_church(), 5.into_church()), HAP, 0), 2.into_church());
    assert_eq!(beta(app!(rem(), 2.into_church(), 1.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(rem(), 0.into_church(), 3.into_church()), HAP, 0), 0.into_church());
}

#[test]
fn church_fac() {
    assert_eq!(beta(app!(fac(), 0.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(fac(), 1.into_church()), HAP, 0), 1.into_church());
    assert_eq!(beta(app!(fac(), 2.into_church()), HAP, 0), 2.into_church());
    assert_eq!(beta(app!(fac(), 3.into_church()), HAP, 0), 6.into_church());
}

#[test]
fn church_min() {
    assert_eq!(beta(app!(min(), 0.into_church(), 0.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(min(), 4.into_church(), 4.into_church()), HAP, 0), 4.into_church());
    assert_eq!(beta(app!(min(), 2.into_church(), 3.into_church()), HAP, 0), 2.into_church());
    assert_eq!(beta(app!(min(), 5.into_church(), 3.into_church()), HAP, 0), 3.into_church());
    assert_eq!(beta(app!(min(), 0.into_church(), 1.into_church()), HAP, 0), 0.into_church());
}

#[test]
fn church_max() {
    assert_eq!(beta(app!(max(), 0.into_church(), 0.into_church()), HAP, 0), 0.into_church());
    assert_eq!(beta(app!(max(), 4.into_church(), 4.into_church()), HAP, 0), 4.into_church());
    assert_eq!(beta(app!(max(), 2.into_church(), 3.into_church()), HAP, 0), 3.into_church());
    assert_eq!(beta(app!(max(), 5.into_church(), 3.into_church()), HAP, 0), 5.into_church());
    assert_eq!(beta(app!(max(), 0.into_church(), 1.into_church()), HAP, 0), 1.into_church());
}

#[test]
fn church_lshift() {
     assert_eq!(beta(app!(lshift(), 0.into_church(), 2.into_church()), HAP, 0), 0.into_church());
     assert_eq!(beta(app!(lshift(), 1.into_church(), 0.into_church()), HAP, 0), 1.into_church());
     assert_eq!(beta(app!(lshift(), 2.into_church(), 0.into_church()), HAP, 0), 2.into_church());
     assert_eq!(beta(app!(lshift(), 2.into_church(), 2.into_church()), HAP, 0), 8.into_church());
     assert_eq!(beta(app!(lshift(), 3.into_church(), 2.into_church()), HAP, 0), 12.into_church());
     assert_eq!(beta(app!(lshift(), 2.into_church(), 3.into_church()), HAP, 0), 16.into_church());
     assert_eq!(beta(app!(lshift(), 5.into_church(), 1.into_church()), HAP, 0), 10.into_church());
}

#[test]
fn church_rshift() {
     assert_eq!(beta(app!(rshift(), 1.into_church(), 0.into_church()), HAP, 0), 1.into_church());
     assert_eq!(beta(app!(rshift(), 2.into_church(), 0.into_church()), HAP, 0), 2.into_church());
     assert_eq!(beta(app!(rshift(), 0.into_church(), 2.into_church()), HAP, 0), 0.into_church());
     assert_eq!(beta(app!(rshift(), 2.into_church(), 1.into_church()), HAP, 0), 1.into_church());
     assert_eq!(beta(app!(rshift(), 2.into_church(), 2.into_church()), HAP, 0), 0.into_church());
     assert_eq!(beta(app!(rshift(), 5.into_church(), 1.into_church()), HAP, 0), 2.into_church());
     assert_eq!(beta(app!(rshift(), 9.into_church(), 1.into_church()), HAP, 0), 4.into_church());
     assert_eq!(beta(app!(rshift(), 9.into_church(), 2.into_church()), HAP, 0), 2.into_church());
     assert_eq!(beta(app!(rshift(), 7.into_church(), 1.into_church()), HAP, 0), 3.into_church());
}

#[test]
fn church_is_even() {
     assert_eq!(beta(app!(is_even(), 0.into_church()), HAP, 0), true.into_church());
     assert_eq!(beta(app!(is_even(), 1.into_church()), HAP, 0), false.into_church());
     assert_eq!(beta(app!(is_even(), 2.into_church()), HAP, 0), true.into_church());
     assert_eq!(beta(app!(is_even(), 8.into_church()), HAP, 0), true.into_church());
     assert_eq!(beta(app!(is_even(), 9.into_church()), HAP, 0), false.into_church());
}

#[test]
fn church_is_odd() {
     assert_eq!(beta(app!(is_odd(), 0.into_church()), HAP, 0), false.into_church());
     assert_eq!(beta(app!(is_odd(), 1.into_church()), HAP, 0), true.into_church());
     assert_eq!(beta(app!(is_odd(), 2.into_church()), HAP, 0), false.into_church());
     assert_eq!(beta(app!(is_odd(), 8.into_church()), HAP, 0), false.into_church());
     assert_eq!(beta(app!(is_odd(), 9.into_church()), HAP, 0), true.into_church());
}
<|endoftext|>