<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation of cross-process surfaces for Linux. This uses X pixmaps.

use platform::surface::NativeSurfaceMethods;
use texturegl::Texture;

use geom::size::Size2D;
use opengles::glx::{GLXFBConfig, GLXDrawable, GLX_BIND_TO_TEXTURE_RGBA_EXT};
use opengles::glx::{GLX_DEPTH_SIZE, GLX_DRAWABLE_TYPE, GLX_FRONT_EXT, GLX_PIXMAP_BIT, GLX_RGBA};
use opengles::glx::{GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT};
use opengles::glx::{GLX_TEXTURE_TARGET_EXT, glXChooseVisual, glXCreatePixmap, glXDestroyPixmap};
use opengles::glx::{glXGetProcAddress, glXGetFBConfigAttrib, glXGetFBConfigs};
use opengles::glx::{glXGetVisualFromFBConfig};
use opengles::glx;
use opengles::gl2::NO_ERROR;
use opengles::gl2;
use std::cast;
use std::libc::{c_int, c_uint, c_void};
use std::ptr;
use xlib::xlib::{Display, Pixmap, XCloseDisplay, XCreateGC, XCreateImage, XCreatePixmap};
use xlib::xlib::{XDefaultScreen, XFreePixmap, XGetGeometry, XOpenDisplay, XPutImage, XRootWindow};
use xlib::xlib::{XVisualInfo, ZPixmap};

/// The display and visual info. This is needed in order to upload on the painting side. This holds
/// a *strong* reference to the display and will close it when done.
///
/// FIXME(pcwalton): Mark nonsendable and noncopyable.
pub struct NativePaintingGraphicsContext {
    display: *Display,
    visual_info: *XVisualInfo,
}

impl NativePaintingGraphicsContext {
    #[fixed_stack_segment]
    pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext {
        unsafe {
            let display = XOpenDisplay(metadata.display.to_c_str().with_ref(|c_str| c_str));

            // FIXME(pcwalton): It would be more robust to actually have the compositor pass the
            // visual.
            let compositor_visual_info =
                NativeCompositingGraphicsContext::compositor_visual_info(display);

            NativePaintingGraphicsContext {
                display: display,
                visual_info: compositor_visual_info,
            }
        }
    }
}

impl Drop for NativePaintingGraphicsContext {
    #[fixed_stack_segment]
    fn drop(&mut self) {
        unsafe {
            let _ = XCloseDisplay(self.display);
        }
    }
}

/// The display, visual info, and framebuffer configuration. This is needed in order to bind to a
/// texture on the compositor side. This holds only a *weak* reference to the display and does not
/// close it.
///
/// FIXME(pcwalton): Unchecked weak references are bad and can violate memory safety. This is hard
/// to fix because the Display is given to us by the native windowing system, but we should fix it
/// someday.
///
/// FIXME(pcwalton): Mark nonsendable.
pub struct NativeCompositingGraphicsContext {
    display: *Display,
    visual_info: *XVisualInfo,
    framebuffer_configuration: GLXFBConfig,
}

impl NativeCompositingGraphicsContext {
    /// Chooses the compositor visual info using the same algorithm that the compositor uses.
    ///
    /// FIXME(pcwalton): It would be more robust to actually have the compositor pass the visual.
    #[fixed_stack_segment]
    fn compositor_visual_info(display: *Display) -> *XVisualInfo {
        unsafe {
            let glx_display: *glx::Display = cast::transmute(display);
            let screen = XDefaultScreen(display);
            let attributes = [ GLX_RGBA, GLX_DEPTH_SIZE, 24, 0 ];
            let compositor_visual_info = glXChooseVisual(glx_display, screen, &attributes[0]);
            cast::transmute(compositor_visual_info)
        }
    }

    /// Creates a native graphics context from the given X display connection. This uses GLX. Only
    /// the compositor is allowed to call this.
    #[fixed_stack_segment]
    pub fn from_display(display: *Display) -> NativeCompositingGraphicsContext {
        unsafe {
            // FIXME(pcwalton): It would be more robust to actually have the compositor pass the
            // visual.
            let compositor_visual_info =
                NativeCompositingGraphicsContext::compositor_visual_info(display);
            let compositor_visual_id = (*compositor_visual_info).visualid;

            // Choose an FB config.
            let glx_display = cast::transmute(display);
            let screen = XDefaultScreen(display);
            let mut fbconfig_count = 0;
            let fbconfigs = glXGetFBConfigs(glx_display, screen, &mut fbconfig_count);
            let mut fbconfig_index = None;
            for i in range(0, fbconfig_count) {
                let fbconfig = *ptr::offset(fbconfigs, i as int);
                let visual_info = glXGetVisualFromFBConfig(glx_display, fbconfig);
                let visual_info: *XVisualInfo = cast::transmute(visual_info);
                if visual_info == ptr::null() || (*visual_info).visualid != compositor_visual_id {
                    continue
                }

                let mut value = 0;
                glXGetFBConfigAttrib(glx_display, fbconfig, GLX_DRAWABLE_TYPE, &mut value);
                if (value & GLX_PIXMAP_BIT) == 0 {
                    continue
                }

                glXGetFBConfigAttrib(glx_display,
                                     fbconfig,
                                     GLX_BIND_TO_TEXTURE_RGBA_EXT,
                                     &mut value);
                if value == 0 {
                    continue
                }

                fbconfig_index = Some(i);
                break
            }

            let framebuffer_configuration = match fbconfig_index {
                None => fail!("No appropriate framebuffer config found!"),
                Some(index) => *ptr::offset(fbconfigs, index as int),
            };

            NativeCompositingGraphicsContext {
                display: display,
                visual_info: compositor_visual_info,
                framebuffer_configuration: framebuffer_configuration,
            }
        }
    }
}

/// The X display string.
#[deriving(Clone)]
pub struct NativeGraphicsMetadata {
    display: ~str,
}

impl NativeGraphicsMetadata {
    /// Creates graphics metadata from a metadata descriptor.
    #[fixed_stack_segment]
    pub fn from_descriptor(descriptor: &NativeGraphicsMetadataDescriptor)
                           -> NativeGraphicsMetadata {
        NativeGraphicsMetadata {
            display: descriptor.display.to_str(),
        }
    }
}

/// A sendable form of the X display string.
#[deriving(Clone, Decodable, Encodable)]
pub struct NativeGraphicsMetadataDescriptor {
    display: ~str,
}

impl NativeGraphicsMetadataDescriptor {
    /// Creates a metadata descriptor from metadata.
    #[fixed_stack_segment]
    pub fn from_metadata(metadata: NativeGraphicsMetadata) -> NativeGraphicsMetadataDescriptor {
        NativeGraphicsMetadataDescriptor {
            display: metadata.display.to_str()
        }
    }
}

#[deriving(Eq)]
pub enum NativeSurfaceTransientData {
    NoTransientData,
    RenderTaskTransientData(*Display, *XVisualInfo),
}

#[deriving(Decodable, Encodable)]
pub struct NativeSurface {
    /// The pixmap.
    pixmap: Pixmap,

    /// Whether this pixmap will leak if the destructor runs. This is for debugging purposes.
    will_leak: bool,
}

impl Drop for NativeSurface {
    fn drop(&mut self) {
        if self.will_leak {
            fail!("You should have disposed of the pixmap properly with destroy()! This pixmap \
                   will leak!");
        }
    }
}

impl NativeSurface {
    #[fixed_stack_segment]
    pub fn from_pixmap(pixmap: Pixmap) -> NativeSurface {
        NativeSurface {
            pixmap: pixmap,
            will_leak: true,
        }
    }
}

impl NativeSurfaceMethods for NativeSurface {
    #[fixed_stack_segment]
    fn new(native_context: &NativePaintingGraphicsContext, size: Size2D<i32>, stride: i32)
           -> NativeSurface {
        unsafe {
            // Create the pixmap.
            let screen = XDefaultScreen(native_context.display);
            let window = XRootWindow(native_context.display, screen);

            let pixmap = XCreatePixmap(native_context.display,
                                       window,
                                       size.width as c_uint,
                                       size.height as c_uint,
                                       ((stride / size.width) * 8) as c_uint);

            NativeSurface::from_pixmap(pixmap)
        }
    }

    /// This may only be called on the compositor side.
    #[fixed_stack_segment]
    fn bind_to_texture(&self,
                       native_context: &NativeCompositingGraphicsContext,
                       texture: &Texture,
                       _size: Size2D<int>) {
        unsafe {
            // Create the GLX pixmap.
            //
            // FIXME(pcwalton): RAII for exception safety?
            let pixmap_attributes = [
                GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
                GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
                0
            ];
            let glx_display = cast::transmute(native_context.display);
            let glx_pixmap = glXCreatePixmap(glx_display,
                                             native_context.framebuffer_configuration,
                                             self.pixmap,
                                             &pixmap_attributes[0]);

            let glXBindTexImageEXT: extern "C" fn(*Display, GLXDrawable, c_int, *c_int) =
                cast::transmute(glXGetProcAddress(cast::transmute(&"glXBindTexImageEXT\x00"[0])));
            assert!(glXBindTexImageEXT as *c_void != ptr::null());
            let _bound = texture.bind();
            glXBindTexImageEXT(native_context.display,
                               cast::transmute(glx_pixmap),
                               GLX_FRONT_EXT,
                               ptr::null());
            assert_eq!(gl2::get_error(), NO_ERROR);

            // FIXME(pcwalton): Recycle these for speed?
            glXDestroyPixmap(glx_display, glx_pixmap);
        }
    }

    /// This may only be called on the painting side.
    #[fixed_stack_segment]
    fn upload(&self, graphics_context: &NativePaintingGraphicsContext, data: &[u8]) {
        unsafe {
            // Ensure that we're running on the render task. Take the display.
            let pixmap = self.pixmap;

            // Figure out the width, height, and depth of the pixmap.
            let mut root_window = 0;
            let mut x = 0;
            let mut y = 0;
            let mut width = 0;
            let mut height = 0;
            let mut border_width = 0;
            let mut depth = 0;
            let _ = XGetGeometry(graphics_context.display,
                                 cast::transmute(pixmap),
                                 &mut root_window,
                                 &mut x,
                                 &mut y,
                                 &mut width,
                                 &mut height,
                                 &mut border_width,
                                 &mut depth);

            // Create the image.
            let image = XCreateImage(graphics_context.display,
                                     (*graphics_context.visual_info).visual,
                                     depth,
                                     ZPixmap,
                                     0,
                                     cast::transmute(&data[0]),
                                     width as c_uint,
                                     height as c_uint,
                                     32,
                                     0);

            // Create the X graphics context.
            let gc = XCreateGC(graphics_context.display, pixmap, 0, ptr::null());

            // Draw the image.
            let _ = XPutImage(graphics_context.display,
                              pixmap,
                              gc,
                              image,
                              0,
                              0,
                              0,
                              0,
                              width,
                              height);
        }
    }

    fn get_id(&self) -> int {
        self.pixmap as int
    }

    #[fixed_stack_segment]
    fn destroy(&mut self, graphics_context: &NativePaintingGraphicsContext) {
        unsafe {
            assert!(self.pixmap != 0);
            XFreePixmap(graphics_context.display, self.pixmap);
            self.mark_wont_leak()
        }
    }

    fn mark_will_leak(&mut self) {
        self.will_leak = true
    }

    fn mark_wont_leak(&mut self) {
        self.will_leak = false
    }
}

<commit_msg>Fix unsafe use of CString::with_ref<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation of cross-process surfaces for Linux. This uses X pixmaps.

use platform::surface::NativeSurfaceMethods;
use texturegl::Texture;

use geom::size::Size2D;
use opengles::glx::{GLXFBConfig, GLXDrawable, GLX_BIND_TO_TEXTURE_RGBA_EXT};
use opengles::glx::{GLX_DEPTH_SIZE, GLX_DRAWABLE_TYPE, GLX_FRONT_EXT, GLX_PIXMAP_BIT, GLX_RGBA};
use opengles::glx::{GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT};
use opengles::glx::{GLX_TEXTURE_TARGET_EXT, glXChooseVisual, glXCreatePixmap, glXDestroyPixmap};
use opengles::glx::{glXGetProcAddress, glXGetFBConfigAttrib, glXGetFBConfigs};
use opengles::glx::{glXGetVisualFromFBConfig};
use opengles::glx;
use opengles::gl2::NO_ERROR;
use opengles::gl2;
use std::cast;
use std::libc::{c_int, c_uint, c_void};
use std::ptr;
use xlib::xlib::{Display, Pixmap, XCloseDisplay, XCreateGC, XCreateImage, XCreatePixmap};
use xlib::xlib::{XDefaultScreen, XFreePixmap, XGetGeometry, XOpenDisplay, XPutImage, XRootWindow};
use xlib::xlib::{XVisualInfo, ZPixmap};

/// The display and visual info. This is needed in order to upload on the painting side. This holds
/// a *strong* reference to the display and will close it when done.
///
/// FIXME(pcwalton): Mark nonsendable and noncopyable.
pub struct NativePaintingGraphicsContext {
    display: *Display,
    visual_info: *XVisualInfo,
}

impl NativePaintingGraphicsContext {
    #[fixed_stack_segment]
    pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext {
        unsafe {
            let display = do metadata.display.with_c_str |c_str| {
                XOpenDisplay(c_str)
            };

            // FIXME(pcwalton): It would be more robust to actually have the compositor pass the
            // visual.
            let compositor_visual_info =
                NativeCompositingGraphicsContext::compositor_visual_info(display);

            NativePaintingGraphicsContext {
                display: display,
                visual_info: compositor_visual_info,
            }
        }
    }
}

impl Drop for NativePaintingGraphicsContext {
    #[fixed_stack_segment]
    fn drop(&mut self) {
        unsafe {
            let _ = XCloseDisplay(self.display);
        }
    }
}

/// The display, visual info, and framebuffer configuration. This is needed in order to bind to a
/// texture on the compositor side. This holds only a *weak* reference to the display and does not
/// close it.
///
/// FIXME(pcwalton): Unchecked weak references are bad and can violate memory safety. This is hard
/// to fix because the Display is given to us by the native windowing system, but we should fix it
/// someday.
///
/// FIXME(pcwalton): Mark nonsendable.
pub struct NativeCompositingGraphicsContext {
    display: *Display,
    visual_info: *XVisualInfo,
    framebuffer_configuration: GLXFBConfig,
}

impl NativeCompositingGraphicsContext {
    /// Chooses the compositor visual info using the same algorithm that the compositor uses.
    ///
    /// FIXME(pcwalton): It would be more robust to actually have the compositor pass the visual.
    #[fixed_stack_segment]
    fn compositor_visual_info(display: *Display) -> *XVisualInfo {
        unsafe {
            let glx_display: *glx::Display = cast::transmute(display);
            let screen = XDefaultScreen(display);
            let attributes = [ GLX_RGBA, GLX_DEPTH_SIZE, 24, 0 ];
            let compositor_visual_info = glXChooseVisual(glx_display, screen, &attributes[0]);
            cast::transmute(compositor_visual_info)
        }
    }

    /// Creates a native graphics context from the given X display connection. This uses GLX. Only
    /// the compositor is allowed to call this.
    #[fixed_stack_segment]
    pub fn from_display(display: *Display) -> NativeCompositingGraphicsContext {
        unsafe {
            // FIXME(pcwalton): It would be more robust to actually have the compositor pass the
            // visual.
            let compositor_visual_info =
                NativeCompositingGraphicsContext::compositor_visual_info(display);
            let compositor_visual_id = (*compositor_visual_info).visualid;

            // Choose an FB config.
            let glx_display = cast::transmute(display);
            let screen = XDefaultScreen(display);
            let mut fbconfig_count = 0;
            let fbconfigs = glXGetFBConfigs(glx_display, screen, &mut fbconfig_count);
            let mut fbconfig_index = None;
            for i in range(0, fbconfig_count) {
                let fbconfig = *ptr::offset(fbconfigs, i as int);
                let visual_info = glXGetVisualFromFBConfig(glx_display, fbconfig);
                let visual_info: *XVisualInfo = cast::transmute(visual_info);
                if visual_info == ptr::null() || (*visual_info).visualid != compositor_visual_id {
                    continue
                }

                let mut value = 0;
                glXGetFBConfigAttrib(glx_display, fbconfig, GLX_DRAWABLE_TYPE, &mut value);
                if (value & GLX_PIXMAP_BIT) == 0 {
                    continue
                }

                glXGetFBConfigAttrib(glx_display,
                                     fbconfig,
                                     GLX_BIND_TO_TEXTURE_RGBA_EXT,
                                     &mut value);
                if value == 0 {
                    continue
                }

                fbconfig_index = Some(i);
                break
            }

            let framebuffer_configuration = match fbconfig_index {
                None => fail!("No appropriate framebuffer config found!"),
                Some(index) => *ptr::offset(fbconfigs, index as int),
            };

            NativeCompositingGraphicsContext {
                display: display,
                visual_info: compositor_visual_info,
                framebuffer_configuration: framebuffer_configuration,
            }
        }
    }
}

/// The X display string.
#[deriving(Clone)]
pub struct NativeGraphicsMetadata {
    display: ~str,
}

impl NativeGraphicsMetadata {
    /// Creates graphics metadata from a metadata descriptor.
    #[fixed_stack_segment]
    pub fn from_descriptor(descriptor: &NativeGraphicsMetadataDescriptor)
                           -> NativeGraphicsMetadata {
        NativeGraphicsMetadata {
            display: descriptor.display.to_str(),
        }
    }
}

/// A sendable form of the X display string.
#[deriving(Clone, Decodable, Encodable)]
pub struct NativeGraphicsMetadataDescriptor {
    display: ~str,
}

impl NativeGraphicsMetadataDescriptor {
    /// Creates a metadata descriptor from metadata.
    #[fixed_stack_segment]
    pub fn from_metadata(metadata: NativeGraphicsMetadata) -> NativeGraphicsMetadataDescriptor {
        NativeGraphicsMetadataDescriptor {
            display: metadata.display.to_str()
        }
    }
}

#[deriving(Eq)]
pub enum NativeSurfaceTransientData {
    NoTransientData,
    RenderTaskTransientData(*Display, *XVisualInfo),
}

#[deriving(Decodable, Encodable)]
pub struct NativeSurface {
    /// The pixmap.
    pixmap: Pixmap,

    /// Whether this pixmap will leak if the destructor runs. This is for debugging purposes.
    will_leak: bool,
}

impl Drop for NativeSurface {
    fn drop(&mut self) {
        if self.will_leak {
            fail!("You should have disposed of the pixmap properly with destroy()! This pixmap \
                   will leak!");
        }
    }
}

impl NativeSurface {
    #[fixed_stack_segment]
    pub fn from_pixmap(pixmap: Pixmap) -> NativeSurface {
        NativeSurface {
            pixmap: pixmap,
            will_leak: true,
        }
    }
}

impl NativeSurfaceMethods for NativeSurface {
    #[fixed_stack_segment]
    fn new(native_context: &NativePaintingGraphicsContext, size: Size2D<i32>, stride: i32)
           -> NativeSurface {
        unsafe {
            // Create the pixmap.
            let screen = XDefaultScreen(native_context.display);
            let window = XRootWindow(native_context.display, screen);

            let pixmap = XCreatePixmap(native_context.display,
                                       window,
                                       size.width as c_uint,
                                       size.height as c_uint,
                                       ((stride / size.width) * 8) as c_uint);

            NativeSurface::from_pixmap(pixmap)
        }
    }

    /// This may only be called on the compositor side.
    #[fixed_stack_segment]
    fn bind_to_texture(&self,
                       native_context: &NativeCompositingGraphicsContext,
                       texture: &Texture,
                       _size: Size2D<int>) {
        unsafe {
            // Create the GLX pixmap.
            //
            // FIXME(pcwalton): RAII for exception safety?
            let pixmap_attributes = [
                GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
                GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
                0
            ];
            let glx_display = cast::transmute(native_context.display);
            let glx_pixmap = glXCreatePixmap(glx_display,
                                             native_context.framebuffer_configuration,
                                             self.pixmap,
                                             &pixmap_attributes[0]);

            let glXBindTexImageEXT: extern "C" fn(*Display, GLXDrawable, c_int, *c_int) =
                cast::transmute(glXGetProcAddress(cast::transmute(&"glXBindTexImageEXT\x00"[0])));
            assert!(glXBindTexImageEXT as *c_void != ptr::null());
            let _bound = texture.bind();
            glXBindTexImageEXT(native_context.display,
                               cast::transmute(glx_pixmap),
                               GLX_FRONT_EXT,
                               ptr::null());
            assert_eq!(gl2::get_error(), NO_ERROR);

            // FIXME(pcwalton): Recycle these for speed?
            glXDestroyPixmap(glx_display, glx_pixmap);
        }
    }

    /// This may only be called on the painting side.
    #[fixed_stack_segment]
    fn upload(&self, graphics_context: &NativePaintingGraphicsContext, data: &[u8]) {
        unsafe {
            // Ensure that we're running on the render task. Take the display.
            let pixmap = self.pixmap;

            // Figure out the width, height, and depth of the pixmap.
            let mut root_window = 0;
            let mut x = 0;
            let mut y = 0;
            let mut width = 0;
            let mut height = 0;
            let mut border_width = 0;
            let mut depth = 0;
            let _ = XGetGeometry(graphics_context.display,
                                 cast::transmute(pixmap),
                                 &mut root_window,
                                 &mut x,
                                 &mut y,
                                 &mut width,
                                 &mut height,
                                 &mut border_width,
                                 &mut depth);

            // Create the image.
            let image = XCreateImage(graphics_context.display,
                                     (*graphics_context.visual_info).visual,
                                     depth,
                                     ZPixmap,
                                     0,
                                     cast::transmute(&data[0]),
                                     width as c_uint,
                                     height as c_uint,
                                     32,
                                     0);

            // Create the X graphics context.
            let gc = XCreateGC(graphics_context.display, pixmap, 0, ptr::null());

            // Draw the image.
            let _ = XPutImage(graphics_context.display,
                              pixmap,
                              gc,
                              image,
                              0,
                              0,
                              0,
                              0,
                              width,
                              height);
        }
    }

    fn get_id(&self) -> int {
        self.pixmap as int
    }

    #[fixed_stack_segment]
    fn destroy(&mut self, graphics_context: &NativePaintingGraphicsContext) {
        unsafe {
            assert!(self.pixmap != 0);
            XFreePixmap(graphics_context.display, self.pixmap);
            self.mark_wont_leak()
        }
    }

    fn mark_will_leak(&mut self) {
        self.will_leak = true
    }

    fn mark_wont_leak(&mut self) {
        self.will_leak = false
    }
}

<|endoftext|>


<commit_before>use cocoa::base::id;

pub trait MTLRenderPassDepthAttachmentDescriptor {
    /// The depth to use when the depth attachment is cleared.
    ///
    /// # Discussion
    ///
    /// The default value is 1.0.
    ///
    /// If the `loadAction` property of the attachment is set to
    /// `MTLLoadActionClear`, then at the start of a rendering pass,
    /// the contents of the texture are filled with the value stored
    /// in the `clearDepth` property. Otherwise, `clearDepth` is ignored.
    unsafe fn clearDepth(self) -> f64;
    unsafe fn setClearDepth(self, clearDepth: f64);

    /// The filter used for an MSAA depth resolve operation.
    ///
    /// # Discussion
    ///
    /// The default value is `MTLMultisampleDepthResolveFilterSample0`.
    unsafe fn depthResolveFilter(self) -> MTLMultisampleDepthResolveFilter;
    unsafe fn setDepthResolveFilter(self, resolveFilter: MTLMultisampleDepthResolveFilter);

    unsafe fn copy(self) -> self;
}

impl MTLRenderPassDepthAttachmentDescriptor for id {
    unsafe fn clearDepth(self) -> f64 {
        msg_send![self, clearDepth]
    }

    unsafe fn setClearDepth(self, clearDepth: f64) {
        msg_send![self, setClearDepth:clearDepth]
    }

    unsafe fn depthResolveFilter(self) -> MTLMultisampleDepthResolveFilter {
        msg_send![self, depthResolveFilter]
    }

    unsafe fn setDepthResolveFilter(self, resolveFilter: MTLMultisampleDepthResolveFilter) {
        msg_send![self, setDepthResolveFilter:resolveFilter]
    }

    unsafe fn copy(self) -> self {
        msg_send![self, copy]
    }
}

#[repr(usize)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum MTLMultisampleDepthResolveFilter {
    MTLMultisampleDepthResolveFilterSample0 = 0,
    MTLMultisampleDepthResolveFilterMin = 1,
    MTLMultisampleDepthResolveFilterMax = 2,
}
<commit_msg>Fix MTLRenderPassDepthAttachmentDescriptor::copy<commit_after>use cocoa::base::id;

pub trait MTLRenderPassDepthAttachmentDescriptor {
    /// The depth to use when the depth attachment is cleared.
    ///
    /// # Discussion
    ///
    /// The default value is 1.0.
    ///
    /// If the `loadAction` property of the attachment is set to
    /// `MTLLoadActionClear`, then at the start of a rendering pass,
    /// the contents of the texture are filled with the value stored
    /// in the `clearDepth` property. Otherwise, `clearDepth` is ignored.
    unsafe fn clearDepth(self) -> f64;
    unsafe fn setClearDepth(self, clearDepth: f64);

    /// The filter used for an MSAA depth resolve operation.
    ///
    /// # Discussion
    ///
    /// The default value is `MTLMultisampleDepthResolveFilterSample0`.
    unsafe fn depthResolveFilter(self) -> MTLMultisampleDepthResolveFilter;
    unsafe fn setDepthResolveFilter(self, resolveFilter: MTLMultisampleDepthResolveFilter);

    unsafe fn copy(self) -> Self;
}

impl MTLRenderPassDepthAttachmentDescriptor for id {
    unsafe fn clearDepth(self) -> f64 {
        msg_send![self, clearDepth]
    }

    unsafe fn setClearDepth(self, clearDepth: f64) {
        msg_send![self, setClearDepth:clearDepth]
    }

    unsafe fn depthResolveFilter(self) -> MTLMultisampleDepthResolveFilter {
        msg_send![self, depthResolveFilter]
    }

    unsafe fn setDepthResolveFilter(self, resolveFilter: MTLMultisampleDepthResolveFilter) {
        msg_send![self, setDepthResolveFilter:resolveFilter]
    }

    unsafe fn copy(self) -> Self {
        msg_send![self, copy]
    }
}

#[repr(usize)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum MTLMultisampleDepthResolveFilter {
    MTLMultisampleDepthResolveFilterSample0 = 0,
    MTLMultisampleDepthResolveFilterMin = 1,
    MTLMultisampleDepthResolveFilterMax = 2,
}
<|endoftext|>


<commit_before>use std::cell::Cell;
use std::env;
use std::fs;
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};

use log::debug;

fn global_test_root() -> PathBuf {
    let mut path = env::current_exe().unwrap();
    path.pop(); // chop off exe name
    path.pop(); // chop off 'debug'

    // If `cargo test` is run manually then our path looks like
    // `target/debug/foo`, in which case our `path` is already pointing at
    // `target`. If, however, `cargo test --target $target` is used then the
    // output is `target/$target/debug/foo`, so our path is pointing at
    // `target/$target`. Here we conditionally pop the `$target` name.
    if path.file_name().and_then(|s| s.to_str()) != Some("target") {
        path.pop();
    }

    path.join("int-test")
}

fn test_root() -> PathBuf {
    let root = global_test_root();

    static NEXT_TEST_NUM: AtomicUsize = ATOMIC_USIZE_INIT;
    thread_local!(static TEST_NUM: usize = NEXT_TEST_NUM.fetch_add(1, Ordering::SeqCst));
    let root = root.join(&TEST_NUM.with(|my_id| format!("t{}", my_id)));

    thread_local!(static TEST_ROOT_INIT: Cell<bool> = Cell::new(false));
    TEST_ROOT_INIT.with(|i| {
        if i.get() {
            return;
        }
        i.set(true);
        if root.exists() {
            fs::remove_dir_all(&root).expect("removing root");
            debug!("deleted root {}", root.display());
        }
    });

    root
}

pub fn test_home() -> PathBuf {
    test_root().join("home")
}
<commit_msg>Fix deprecation warning in test<commit_after>use std::cell::Cell;
use std::env;
use std::fs;
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};

use log::debug;

fn global_test_root() -> PathBuf {
    let mut path = env::current_exe().unwrap();
    path.pop(); // chop off exe name
    path.pop(); // chop off 'debug'

    // If `cargo test` is run manually then our path looks like
    // `target/debug/foo`, in which case our `path` is already pointing at
    // `target`. If, however, `cargo test --target $target` is used then the
    // output is `target/$target/debug/foo`, so our path is pointing at
    // `target/$target`. Here we conditionally pop the `$target` name.
    if path.file_name().and_then(|s| s.to_str()) != Some("target") {
        path.pop();
    }

    path.join("int-test")
}

fn test_root() -> PathBuf {
    let root = global_test_root();

    static NEXT_TEST_NUM: AtomicUsize = AtomicUsize::new(0);
    thread_local!(static TEST_NUM: usize = NEXT_TEST_NUM.fetch_add(1, Ordering::SeqCst));
    let root = root.join(&TEST_NUM.with(|my_id| format!("t{}", my_id)));

    thread_local!(static TEST_ROOT_INIT: Cell<bool> = Cell::new(false));
    TEST_ROOT_INIT.with(|i| {
        if i.get() {
            return;
        }
        i.set(true);
        if root.exists() {
            fs::remove_dir_all(&root).expect("removing root");
            debug!("deleted root {}", root.display());
        }
    });

    root
}

pub fn test_home() -> PathBuf {
    test_root().join("home")
}
<|endoftext|>


<commit_before>// Copyright © 2018 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details.

extern crate cmake;
extern crate pkg_config;

use std::env;
use std::fs;
use std::path::Path;
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

fn main() {
    let gecko_in_tree = env::var("CARGO_FEATURE_GECKO_IN_TREE").is_ok();
    if gecko_in_tree {
        return;
    }

    if env::var("LIBCUBEB_SYS_USE_PKG_CONFIG").is_ok() {
        if pkg_config::find_library("libcubeb").is_ok() {
            return;
        }
    }

    if !Path::new("libcubeb/.git").exists() {
        let _ = Command::new("git")
            .args(&["submodule", "update", "--init", "--recursive"])
            .status();
    }

    let target = env::var("TARGET").unwrap();
    //    let host = env::var("HOST").unwrap();
    let windows = target.contains("windows");
    let darwin = target.contains("darwin");
    let mut cfg = cmake::Config::new("libcubeb");

    let _ = fs::remove_dir_all(env::var("OUT_DIR").unwrap());
    t!(fs::create_dir_all(env::var("OUT_DIR").unwrap()));

    env::remove_var("DESTDIR");
    let dst = cfg.define("BUILD_SHARED_LIBS", "OFF")
        .define("BUILD_TESTS", "OFF")
        .build();

    if windows {
        println!("cargo:rustc-link-lib=static=cubeb");
        println!("cargo:rustc-link-lib=dylib=avrt");
        println!("cargo:rustc-link-lib=dylib=ole32");
        println!("cargo:rustc-link-lib=dylib=user32");
        println!("cargo:rustc-link-lib=dylib=winmm");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
    } else if darwin {
        println!("cargo:rustc-link-lib=static=cubeb");
        println!("cargo:rustc-link-lib=framework=AudioUnit");
        println!("cargo:rustc-link-lib=framework=CoreAudio");
        println!("cargo:rustc-link-lib=framework=CoreServices");
        println!("cargo:rustc-link-lib=dylib=c++");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
    } else {
        println!("cargo:rustc-link-lib=static=cubeb");
        println!("cargo:rustc-link-lib=dylib=stdc++");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());

        // Ignore the result of find_library. We don't care if the
        // libraries are missing.
        let _ = pkg_config::find_library("alsa");
        let _ = pkg_config::find_library("libpulse");
        let _ = pkg_config::find_library("jack");
    }
}
<commit_msg>cubeb-sys: Search both lib and lib64 in build.rs.<commit_after>// Copyright © 2018 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details.

extern crate cmake;
extern crate pkg_config;

use std::env;
use std::fs;
use std::path::Path;
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

fn main() {
    let gecko_in_tree = env::var("CARGO_FEATURE_GECKO_IN_TREE").is_ok();
    if gecko_in_tree {
        return;
    }

    if env::var("LIBCUBEB_SYS_USE_PKG_CONFIG").is_ok() {
        if pkg_config::find_library("libcubeb").is_ok() {
            return;
        }
    }

    if !Path::new("libcubeb/.git").exists() {
        let _ = Command::new("git")
            .args(&["submodule", "update", "--init", "--recursive"])
            .status();
    }

    let target = env::var("TARGET").unwrap();
    //    let host = env::var("HOST").unwrap();
    let windows = target.contains("windows");
    let darwin = target.contains("darwin");
    let mut cfg = cmake::Config::new("libcubeb");

    let _ = fs::remove_dir_all(env::var("OUT_DIR").unwrap());
    t!(fs::create_dir_all(env::var("OUT_DIR").unwrap()));

    env::remove_var("DESTDIR");
    let dst = cfg.define("BUILD_SHARED_LIBS", "OFF")
        .define("BUILD_TESTS", "OFF")
        .build();

    if windows {
        println!("cargo:rustc-link-lib=static=cubeb");
        println!("cargo:rustc-link-lib=dylib=avrt");
        println!("cargo:rustc-link-lib=dylib=ole32");
        println!("cargo:rustc-link-lib=dylib=user32");
        println!("cargo:rustc-link-lib=dylib=winmm");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
    } else if darwin {
        println!("cargo:rustc-link-lib=static=cubeb");
        println!("cargo:rustc-link-lib=framework=AudioUnit");
        println!("cargo:rustc-link-lib=framework=CoreAudio");
        println!("cargo:rustc-link-lib=framework=CoreServices");
        println!("cargo:rustc-link-lib=dylib=c++");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
    } else {
        println!("cargo:rustc-link-lib=static=cubeb");
        println!("cargo:rustc-link-lib=dylib=stdc++");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
        println!("cargo:rustc-link-search=native={}/lib64", dst.display());

        // Ignore the result of find_library. We don't care if the
        // libraries are missing.
        let _ = pkg_config::find_library("alsa");
        let _ = pkg_config::find_library("libpulse");
        let _ = pkg_config::find_library("jack");
    }
}
<|endoftext|>


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

use move_deps::{
    move_binary_format::errors::PartialVMResult,
    move_core_types::account_address::AccountAddress,
    move_vm_runtime::native_functions::NativeContext,
    move_vm_types::{
        gas_schedule::NativeCostIndex,
        loaded_data::runtime_types::Type,
        natives::function::{native_gas, NativeResult},
        pop_arg,
        values::Value,
    },
};
use smallvec::smallvec;
use std::collections::VecDeque;

pub fn native_create_signer(
    context: &mut NativeContext,
    ty_args: Vec<Type>,
    mut arguments: VecDeque<Value>,
) -> PartialVMResult<NativeResult> {
    debug_assert!(ty_args.is_empty());
    debug_assert!(arguments.len() == 1);

    let address = pop_arg!(arguments, AccountAddress);
    let cost = native_gas(context.cost_table(), NativeCostIndex::CREATE_SIGNER, 0);
    Ok(NativeResult::ok(cost, smallvec![Value::signer(address)]))
}

/// NOTE: this function will be deprecated after the Aptos v3 release, but must
/// remain for replaying old transactions
pub fn native_destroy_signer(
    context: &mut NativeContext,
    ty_args: Vec<Type>,
    arguments: VecDeque<Value>,
) -> PartialVMResult<NativeResult> {
    debug_assert!(ty_args.is_empty());
    debug_assert!(arguments.len() == 1);

    let cost = native_gas(context.cost_table(), NativeCostIndex::DESTROY_SIGNER, 0);
    Ok(NativeResult::ok(cost, smallvec![]))
}
<commit_msg>[framework] remove unused native destroy signer<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use move_deps::{
    move_binary_format::errors::PartialVMResult,
    move_core_types::account_address::AccountAddress,
    move_vm_runtime::native_functions::NativeContext,
    move_vm_types::{
        gas_schedule::NativeCostIndex,
        loaded_data::runtime_types::Type,
        natives::function::{native_gas, NativeResult},
        pop_arg,
        values::Value,
    },
};
use smallvec::smallvec;
use std::collections::VecDeque;

pub fn native_create_signer(
    context: &mut NativeContext,
    ty_args: Vec<Type>,
    mut arguments: VecDeque<Value>,
) -> PartialVMResult<NativeResult> {
    debug_assert!(ty_args.is_empty());
    debug_assert!(arguments.len() == 1);

    let address = pop_arg!(arguments, AccountAddress);
    let cost = native_gas(context.cost_table(), NativeCostIndex::CREATE_SIGNER, 0);
    Ok(NativeResult::ok(cost, smallvec![Value::signer(address)]))
}
<|endoftext|>


<commit_before>// Copyright 2014 The HTML5 for Rust Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use util::foreach_html5lib_test;

use std::io;
use std::mem::replace;
use std::default::Default;
use std::path::Path;
use std::collections::hashmap::HashMap;
use test::{TestDesc, TestDescAndFn, DynTestName, DynTestFn};

use html5::sink::rcdom::{RcDom, Handle, Document, Doctype, Text, Comment, Element};
use html5::{parse, one_input};

fn parse_tests<It: Iterator<String>>(mut lines: It) -> Vec<HashMap<String, String>> {
    let mut tests = vec!();
    let mut test = HashMap::new();
    let mut key = None;
    let mut val = String::new();

    macro_rules! finish_val ( () => (
        match key.take() {
            None => (),
            Some(key) => assert!(test.insert(key, replace(&mut val, String::new()))),
        }
    ))

    macro_rules! finish_test ( () => (
        if !test.is_empty() {
            tests.push(replace(&mut test, HashMap::new()));
        }
    ))

    loop {
        match lines.next() {
            None => break,
            Some(line) => {
                if line.as_slice().starts_with("#") {
                    finish_val!();
                    if line.as_slice() == "#data\n" {
                        finish_test!();
                    }
                    key = Some(line.as_slice().slice_from(1)
                        .trim_right_chars('\n').to_string());
                } else {
                    val.push_str(line.as_slice());
                }
            }
        }
    }

    finish_val!();
    finish_test!();
    tests
}

fn serialize(buf: &mut String, indent: uint, handle: Handle) {
    buf.push_str("|");
    buf.grow(indent, ' ');

    let node = handle.borrow();
    match node.node {
        Document => fail!("should not reach Document"),

        Doctype(ref name, ref public, ref system) => {
            buf.push_str("<!DOCTYPE ");
            buf.push_str(name.as_slice());
            if !public.is_empty() || !system.is_empty() {
                buf.push_str(format!(" \"{}\" \"{}\"", public, system).as_slice());
            }
            buf.push_str(">\n");
        }

        Text(ref text) => {
            buf.push_str("\"");
            buf.push_str(text.as_slice());
            buf.push_str("\"\n");
        }

        Comment(ref text) => {
            buf.push_str("<!-- ");
            buf.push_str(text.as_slice());
            buf.push_str(" -->\n");
        }

        Element(ref name, ref attrs) => {
            buf.push_str("<");
            buf.push_str(name.as_slice());
            buf.push_str(">\n");

            let mut attrs = attrs.clone();
            attrs.sort_by(|x, y| x.name.name.cmp(&y.name.name));
            // FIXME: sort by UTF-16 code unit

            for attr in attrs.move_iter() {
                buf.push_str("|");
                buf.grow(indent+2, ' ');
                buf.push_str(format!("{}=\"{}\"\n",
                    attr.name.name.as_slice(), attr.value).as_slice());
            }
        }
    }

    for child in node.children.iter() {
        serialize(buf, indent+2, child.clone());
    }
}

fn make_test(
        tests: &mut Vec<TestDescAndFn>,
        path_str: &str,
        idx: uint,
        fields: HashMap<String, String>) {

    let get_field = |key| {
        let field = fields.find_equiv(&key).expect("missing field");
        field.as_slice().trim_right_chars('\n').to_string()
    };

    if fields.find_equiv(&"document-fragment").is_some() {
        // FIXME
        return;
    }

    let data = get_field("data");
    let expected = get_field("document");
    tests.push(TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(format!("tb: {}-{}", path_str, idx)),
            ignore: false,
            should_fail: false,
        },
        testfn: DynTestFn(proc() {
            let dom: RcDom = parse(one_input(data.clone()), Default::default());

            let mut result = String::new();
            for child in dom.document.borrow().children.iter() {
                serialize(&mut result, 1, child.clone());
            }
            let len = result.len();
            result.truncate(len - 1);  // drop the trailing newline

            if result != expected {
                fail!("\ninput: {}\ngot:\n{}\nexpected:\n{}\n",
                    data, result, expected);
            }
        }),
    });
}

pub fn tests(src_dir: Path) -> Vec<TestDescAndFn> {
    let mut tests = vec!();

    foreach_html5lib_test(src_dir, "tree-construction", ".dat", |path_str, file| {
        let mut buf = io::BufferedReader::new(file);
        let lines = buf.lines()
            .map(|res| res.ok().expect("couldn't read"));
        let data = parse_tests(lines);

        for (i, test) in data.move_iter().enumerate() {
            make_test(&mut tests, path_str, i, test);
        }
    });

    tests
}
<commit_msg>Ignore tree builder tests for MathML, SVG, and <template><commit_after>// Copyright 2014 The HTML5 for Rust Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use util::foreach_html5lib_test;

use std::io;
use std::mem::replace;
use std::default::Default;
use std::path::Path;
use std::collections::hashmap::HashMap;
use test::{TestDesc, TestDescAndFn, DynTestName, DynTestFn};

use html5::sink::rcdom::{RcDom, Handle, Document, Doctype, Text, Comment, Element};
use html5::{parse, one_input};

fn parse_tests<It: Iterator<String>>(mut lines: It) -> Vec<HashMap<String, String>> {
    let mut tests = vec!();
    let mut test = HashMap::new();
    let mut key = None;
    let mut val = String::new();

    macro_rules! finish_val ( () => (
        match key.take() {
            None => (),
            Some(key) => assert!(test.insert(key, replace(&mut val, String::new()))),
        }
    ))

    macro_rules! finish_test ( () => (
        if !test.is_empty() {
            tests.push(replace(&mut test, HashMap::new()));
        }
    ))

    loop {
        match lines.next() {
            None => break,
            Some(line) => {
                if line.as_slice().starts_with("#") {
                    finish_val!();
                    if line.as_slice() == "#data\n" {
                        finish_test!();
                    }
                    key = Some(line.as_slice().slice_from(1)
                        .trim_right_chars('\n').to_string());
                } else {
                    val.push_str(line.as_slice());
                }
            }
        }
    }

    finish_val!();
    finish_test!();
    tests
}

fn serialize(buf: &mut String, indent: uint, handle: Handle) {
    buf.push_str("|");
    buf.grow(indent, ' ');

    let node = handle.borrow();
    match node.node {
        Document => fail!("should not reach Document"),

        Doctype(ref name, ref public, ref system) => {
            buf.push_str("<!DOCTYPE ");
            buf.push_str(name.as_slice());
            if !public.is_empty() || !system.is_empty() {
                buf.push_str(format!(" \"{}\" \"{}\"", public, system).as_slice());
            }
            buf.push_str(">\n");
        }

        Text(ref text) => {
            buf.push_str("\"");
            buf.push_str(text.as_slice());
            buf.push_str("\"\n");
        }

        Comment(ref text) => {
            buf.push_str("<!-- ");
            buf.push_str(text.as_slice());
            buf.push_str(" -->\n");
        }

        Element(ref name, ref attrs) => {
            buf.push_str("<");
            buf.push_str(name.as_slice());
            buf.push_str(">\n");

            let mut attrs = attrs.clone();
            attrs.sort_by(|x, y| x.name.name.cmp(&y.name.name));
            // FIXME: sort by UTF-16 code unit

            for attr in attrs.move_iter() {
                buf.push_str("|");
                buf.grow(indent+2, ' ');
                buf.push_str(format!("{}=\"{}\"\n",
                    attr.name.name.as_slice(), attr.value).as_slice());
            }
        }
    }

    for child in node.children.iter() {
        serialize(buf, indent+2, child.clone());
    }
}

// Ignore tests containing these strings; we don't support these features yet.
static ignore_substrs: &'static [&'static str]
    = &["<math", "<svg", "<template"];

fn make_test(
        tests: &mut Vec<TestDescAndFn>,
        path_str: &str,
        idx: uint,
        fields: HashMap<String, String>) {

    let get_field = |key| {
        let field = fields.find_equiv(&key).expect("missing field");
        field.as_slice().trim_right_chars('\n').to_string()
    };

    if fields.find_equiv(&"document-fragment").is_some() {
        // FIXME
        return;
    }

    let data = get_field("data");
    let expected = get_field("document");
    tests.push(TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(format!("tb: {}-{}", path_str, idx)),
            ignore: ignore_substrs.iter().any(|&ig| data.as_slice().contains(ig)),
            should_fail: false,
        },
        testfn: DynTestFn(proc() {
            let dom: RcDom = parse(one_input(data.clone()), Default::default());

            let mut result = String::new();
            for child in dom.document.borrow().children.iter() {
                serialize(&mut result, 1, child.clone());
            }
            let len = result.len();
            result.truncate(len - 1);  // drop the trailing newline

            if result != expected {
                fail!("\ninput: {}\ngot:\n{}\nexpected:\n{}\n",
                    data, result, expected);
            }
        }),
    });
}

pub fn tests(src_dir: Path) -> Vec<TestDescAndFn> {
    let mut tests = vec!();

    foreach_html5lib_test(src_dir, "tree-construction", ".dat", |path_str, file| {
        let mut buf = io::BufferedReader::new(file);
        let lines = buf.lines()
            .map(|res| res.ok().expect("couldn't read"));
        let data = parse_tests(lines);

        for (i, test) in data.move_iter().enumerate() {
            make_test(&mut tests, path_str, i, test);
        }
    });

    tests
}
<|endoftext|>


<commit_before> #[feature(struct_variant)];
extern mod extra;
use extra::getopts;
use std::rand;
use std::fmt;

fn randrange(min : uint, max : uint) -> uint {
    min + rand::random::<uint>() % (max - min)
}

#[deriving(Eq)]
struct ServerID(uint);

#[deriving(Eq, Ord)]
struct Term(uint);

#[deriving(Ord)]
struct Index(uint);

#[deriving(Ord)]
struct Time(uint);

struct Environment {
    clock: Time,
    network: ~[~Message],
}

impl Environment {
    fn new() -> Environment {
        Environment {
            clock: Time(0),
            network: ~[],
        }
    }
    fn make_time(&self, min: uint, max: uint) -> Time {
        Time(*self.clock + randrange(min, max))
    }
    fn make_network_latency(&self, from: ServerID, to: ServerID) -> Time {
        Time(*self.clock + randrange(2, 5))
    }
    fn multicast(&mut self, from: ServerID, to: &[ServerID], body: &MessageBody) {
        for peer in to.iter() {
            let m = ~Message {
                from: from,
                to: *peer,
                deliver: self.make_network_latency(from, *peer),
                body: *body,
            };
            self.network.push(m);
        }
    }
    fn reply(&mut self, request: &Message, response_body: &MessageBody) {
        let m = ~Message {
            from: request.to,
            to: request.from,
            deliver: self.make_network_latency(request.to, request.from),
            body: *response_body,
        };
        self.network.push(m);
    }
    fn pop_ready_messages(&mut self) -> ~[~Message] {
        let mut all = ~[];
        std::util::swap(&mut all, &mut self.network);
        let (ready, notready) = all.partition(|msg| msg.deliver <= self.clock);
        self.network = notready;
        return ready;
    }
}

struct Message {
    from: ServerID,
    to: ServerID,
    deliver: Time,
    body: MessageBody,
}

enum MessageBody {
    RequestVoteRequest {
        term: Term,
        lastLogTerm: Term,
        lastLogIndex: Index,
    },
    RequestVoteResponse {
        term: Term,
        granted: bool,
    },
    AppendEntriesRequest {
        term: Term,
        seqno: uint,
    },
    AppendEntriesResponse {
        term: Term,
        seqno: uint,
    },
}

impl fmt::Default for Message {
    fn fmt(msg: &Message, f: &mut fmt::Formatter) {
        write!(f.buf, "{} to {}: {}",
               *msg.from,
               *msg.to,
               msg.body);
    }
}

impl fmt::Default for MessageBody {
    fn fmt(b: &MessageBody, f: &mut fmt::Formatter) {
        match *b {
            RequestVoteRequest{term, lastLogTerm, lastLogIndex} =>
                write!(f.buf, "RequestVoteRequest({}, {}, {})",
                       term, lastLogTerm, lastLogIndex),
            RequestVoteResponse{term, granted} =>
                write!(f.buf, "RequestVoteResponse({}, {})",
                       term, granted),
            AppendEntriesRequest{term, seqno} =>
                write!(f.buf, "AppendEntriesRequest({}, {})",
                       term, seqno),
            AppendEntriesResponse{term, seqno} =>
                write!(f.buf, "AppendEntriesResponse({}, {})",
                       term, seqno),
        }
    }
}

enum ServerState {
    Follower  { timer: Time },
    Candidate { timer: Time, votes: uint },
    Leader    { timer: Time, heartbeat_seqno: uint,  acks: uint},
}

impl fmt::Default for Time {
    fn fmt(time: &Time, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", **time)
    }
}

impl fmt::Default for Term {
    fn fmt(term: &Term, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", **term)
    }
}

impl fmt::Default for Index {
    fn fmt(index: &Index, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", **index)
    }
}

impl fmt::Default for ServerState {
    fn fmt(state: &ServerState, f: &mut fmt::Formatter) {
        match *state {
            Follower{timer} => write!(f.buf, "Follower({})", timer),
            Candidate{timer, votes} => write!(f.buf, "Candidate({}, {})", timer, votes),
            Leader{timer, heartbeat_seqno, acks} => write!(f.buf, "Leader({}, {}, {})", timer, heartbeat_seqno, acks),
        }
    }
}

struct LogEntry {
    term: Term,
    // command: ~str,
}

struct Log(~[LogEntry]);

impl Log {
    fn new() -> Log {
        Log(~[])
    }
}

struct Server {
    id: ServerID,
    peers: ~[ServerID],
    term: Term,
    state: ServerState,
    vote: Option<ServerID>,
    log: Log,
}

impl Server {
    fn new(id : ServerID, peers: ~[ServerID], env: &Environment) -> Server {
        Server {
            id: id,
            peers: peers,
            term: Term(0),
            state: Follower { timer: env.make_time(150, 300) },
            log: Log::new(),
            vote: None,
        }
    }
    /*
    fn reset_timer(&mut self) {
        self.set_timer(Time(*self.env.clock + randrange(150, 300)));
    }
    fn set_timer(&mut self, time: Time) {
        match self.state {
            Follower  {timer : ref mut timer, _} |
            Candidate {timer : ref mut timer, _} =>
                { *timer = time },
            Leader => {},
        }
    }
    */
    fn tick(&mut self, env: &mut Environment) {
        let mut need_step_down = false;
        match self.state {
            Follower  {timer, _} |
            Candidate {timer, _} => {
                if timer <= env.clock {
                    self.term = Term(*self.term + 1);
                    self.vote = None;
                    self.state = Candidate {
                        timer: env.make_time(150, 300),
                        votes: 1,
                    };
                    env.multicast(self.id, self.peers, &RequestVoteRequest {
                        term: self.term,
                        lastLogTerm: Term(0),
                        lastLogIndex: Index(0),
                    });
                }
                self.try_become_leader(env);
            },
            Leader {timer, heartbeat_seqno: ref mut heartbeat_seqno, acks: ref mut acks} => {
                if timer <= env.clock {
                    if (*acks > (self.peers.len() + 1) / 2) {
                        *heartbeat_seqno += 1;
                        *acks = 0;
                        env.multicast(self.id, self.peers, &AppendEntriesRequest {
                            term: self.term,
                            seqno: *heartbeat_seqno,
                        });
                    } else {
                        need_step_down = true;
                    }
                }
            },
        }
        if need_step_down {
            self.step_down(env, self.term)
        }
    }
    fn step_down(&mut self, env: &Environment, term: Term) {
        self.term = term;
        self.vote = None;
        self.state = Follower {
            timer: env.make_time(150, 300),
        };
    }

    fn try_become_leader(&mut self, env: &mut Environment) {
        match self.state {
            Follower {_} => {},
            Candidate {votes, _} => {
                if votes > (self.peers.len() + 1) / 2 {
                    self.state = Leader {
                        timer: env.make_time(75, 76),
                        heartbeat_seqno: 0,
                        acks: 1,
                    };
                    env.multicast(self.id, self.peers, &AppendEntriesRequest {
                        term: self.term,
                        seqno: 0,
                    });
                }
            },
            Leader {_} => {},
        }
    }
    fn handle(&mut self, env: &mut Environment, msg: &Message) {
        match msg.body {
            RequestVoteRequest {term, _} => {
                let reply = |granted| {
                    env.reply(msg, &RequestVoteResponse {
                        term: self.term,
                        granted: granted,
                    });
                };
                if term < self.term {
                    reply(false);
                } else {
                    if term > self.term {
                        self.step_down(env, term);
                    }
                    match self.vote {
                        None => {
                            self.vote = Some(msg.from);
                            reply(true);
                        },
                        Some(c) => {
                            reply(c == msg.from);
                        },
                    }
                }
            },
            RequestVoteResponse {term, granted, _} => {
                if term == self.term && granted {
                    match self.state {
                        Follower {_} => {},
                        Candidate {votes: ref mut votes, _} => {
                            *votes += 1;
                        },
                        Leader {_} => {},
                    }
                    self.try_become_leader(env)
                } else if term > self.term {
                    self.step_down(env, term);
                }
            },
            AppendEntriesRequest {term, seqno} => {
                if term == self.term {
                    self.state = Follower {
                        timer: env.make_time(150, 300),
                    };
                } else if term > self.term {
                    self.step_down(env, term);
                }
                env.reply(msg, &AppendEntriesResponse {
                    term: self.term,
                    seqno: seqno,
                });
            },
            AppendEntriesResponse {term, seqno} => {
                if term == self.term {
                    match self.state {
                        Follower {_} | Candidate {_} => {},
                        Leader { heartbeat_seqno, acks: ref mut acks, _ } => {
                            if seqno == heartbeat_seqno {
                                *acks += 1;
                            }
                        },
                    }
                }
            },
        }
    }

    /*
    fn next_event_time(&self) -> Time {
        match self.state {
            Follower  {timer, _} |
            Candidate {timer, _} =>
                timer,
            Leader => Time(!0)
        }
    }
    */
}

impl ToStr for Server {
    fn to_str(&self) -> ~str {
        format!("Server {}: {}", *self.id, self.state)
    }
}

struct Cluster(~[Server]);

impl Cluster {
    fn new(env: &Environment, num_servers: uint) -> Cluster {
        let mut servers = ~[];
        for i in range(0, num_servers) {
            let mut peers = ~[];
            for j in range(0, num_servers) {
                if i != j {
                    peers.push(ServerID(j + 1));
                }
            }
            let s = Server::new(ServerID(i + 1), peers, env);
            servers.push(s);
        }
        return Cluster(servers);
    }

    fn deliver(&mut self, env: &mut Environment, msg: &Message) {
        self[*msg.to - 1].handle(env, msg);
    }
}

fn main() {
    let args = std::os::args();
    let opts = [
        getopts::optflag("h"),
        getopts::optflag("help"),
        getopts::optopt("servers"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m },
        Err(f) => { fail!(f.to_err_msg()) },
    };
    let usage = || {
        println!("Usage: {} [options]", args[0]);
        println("-h, --help   Print this help message");
        println("--servers=N  Simulate cluster with N servers");
    };
    if matches.opt_present("h") || matches.opt_present("help") {
        usage();
        return;
    }
    if !matches.free.is_empty() {
        usage();
        fail!(format!("Extra arguments: {}", matches.free.len()));
    }
    let num_servers : uint = match matches.opt_str("servers") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of servers from '{}'", s));
            },
        }},
        None => { 5 },
    };
    let env = &mut Environment::new();
    let mut cluster = Cluster::new(env, num_servers);
    loop {
        env.clock = Time(*env.clock + 1);
        for server in cluster.mut_iter() {
            server.tick(env);
        }
        for msg in env.pop_ready_messages().move_iter() {
            cluster.deliver(env, msg);
        }
        //for server in cluster.iter() {
        //    println(server.to_str());
        //}
        for message in env.network.iter() {
            println!("{}", **message);
        }
    }
}

<commit_msg>Simulate many times<commit_after> #[feature(struct_variant)];
extern mod extra;
use extra::getopts;
use std::rand;
use std::fmt;

fn randrange(min : uint, max : uint) -> uint {
    min + rand::random::<uint>() % (max - min)
}

#[deriving(Eq)]
struct ServerID(uint);

#[deriving(Eq, Ord)]
struct Term(uint);

impl fmt::Default for Term {
    fn fmt(term: &Term, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", **term)
    }
}

#[deriving(Ord)]
struct Index(uint);

impl fmt::Default for Index {
    fn fmt(index: &Index, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", **index)
    }
}

#[deriving(Ord, Clone)]
struct Time(uint);

impl fmt::Default for Time {
    fn fmt(time: &Time, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", **time)
    }
}

struct Environment {
    clock: Time,
    network: ~[~Message],
}

impl Environment {
    fn new() -> Environment {
        Environment {
            clock: Time(0),
            network: ~[],
        }
    }
    fn make_time(&self, min: uint, max: uint) -> Time {
        Time(*self.clock + randrange(min, max))
    }
    fn make_network_latency(&self, from: ServerID, to: ServerID) -> Time {
        Time(*self.clock + randrange(2, 5))
    }
    fn multicast(&mut self, from: ServerID, to: &[ServerID], body: &MessageBody) {
        for peer in to.iter() {
            let m = ~Message {
                from: from,
                to: *peer,
                deliver: self.make_network_latency(from, *peer),
                body: *body,
            };
            self.network.push(m);
        }
    }
    fn reply(&mut self, request: &Message, response_body: &MessageBody) {
        let m = ~Message {
            from: request.to,
            to: request.from,
            deliver: self.make_network_latency(request.to, request.from),
            body: *response_body,
        };
        self.network.push(m);
    }
    fn pop_ready_messages(&mut self) -> ~[~Message] {
        let mut all = ~[];
        std::util::swap(&mut all, &mut self.network);
        let (ready, notready) = all.partition(|msg| msg.deliver <= self.clock);
        self.network = notready;
        return ready;
    }
}

struct Message {
    from: ServerID,
    to: ServerID,
    deliver: Time,
    body: MessageBody,
}

enum MessageBody {
    RequestVoteRequest {
        term: Term,
        lastLogTerm: Term,
        lastLogIndex: Index,
    },
    RequestVoteResponse {
        term: Term,
        granted: bool,
    },
    AppendEntriesRequest {
        term: Term,
        seqno: uint,
    },
    AppendEntriesResponse {
        term: Term,
        seqno: uint,
    },
}

impl fmt::Default for Message {
    fn fmt(msg: &Message, f: &mut fmt::Formatter) {
        write!(f.buf, "{} to {}: {}",
               *msg.from,
               *msg.to,
               msg.body);
    }
}

impl fmt::Default for MessageBody {
    fn fmt(b: &MessageBody, f: &mut fmt::Formatter) {
        match *b {
            RequestVoteRequest{term, lastLogTerm, lastLogIndex} =>
                write!(f.buf, "RequestVoteRequest(term: {}, lastLogTerm: {}, lastLogIndex: {})",
                       term, lastLogTerm, lastLogIndex),
            RequestVoteResponse{term, granted} =>
                write!(f.buf, "RequestVoteResponse(term: {}, granted: {})",
                       term, granted),
            AppendEntriesRequest{term, seqno} =>
                write!(f.buf, "AppendEntriesRequest(term: {}, seqno: {})",
                       term, seqno),
            AppendEntriesResponse{term, seqno} =>
                write!(f.buf, "AppendEntriesResponse(term: {}, seqno: {})",
                       term, seqno),
        }
    }
}

enum ServerState {
    Follower  { timer: Time },
    Candidate { timer: Time, votes: uint },
    Leader    { timer: Time, heartbeat_seqno: uint, acks: uint, start_time: Time},
}

impl fmt::Default for ServerState {
    fn fmt(state: &ServerState, f: &mut fmt::Formatter) {
        match *state {
            Follower{timer} => {
                write!(f.buf, "Follower(timer: {})",
                       timer)
            },
            Candidate{timer, votes} => {
                write!(f.buf, "Candidate(timer: {}, votes: {})",
                       timer, votes)
            },
            Leader{timer, heartbeat_seqno, acks, start_time} => {
                write!(f.buf, "Leader(timer: {}, seqno: {}, acks: {}, start_time: {})",
                       timer, heartbeat_seqno, acks, start_time)
            },
        }
    }
}

struct LogEntry {
    term: Term,
    // command: ~str,
}

struct Log(~[LogEntry]);

impl Log {
    fn new() -> Log {
        Log(~[])
    }
}

struct Server {
    id: ServerID,
    peers: ~[ServerID],
    term: Term,
    state: ServerState,
    vote: Option<ServerID>,
    log: Log,
}

impl Server {
    fn new(id : ServerID, peers: ~[ServerID], env: &Environment) -> Server {
        Server {
            id: id,
            peers: peers,
            term: Term(0),
            state: Follower { timer: env.make_time(150, 300) },
            log: Log::new(),
            vote: None,
        }
    }
    /*
    fn reset_timer(&mut self) {
        self.set_timer(Time(*self.env.clock + randrange(150, 300)));
    }
    fn set_timer(&mut self, time: Time) {
        match self.state {
            Follower  {timer : ref mut timer, _} |
            Candidate {timer : ref mut timer, _} =>
                { *timer = time },
            Leader => {},
        }
    }
    */
    fn tick(&mut self, env: &mut Environment) {
        let mut need_step_down = false;
        match self.state {
            Follower  {timer, _} |
            Candidate {timer, _} => {
                if timer <= env.clock {
                    self.term = Term(*self.term + 1);
                    self.vote = None;
                    self.state = Candidate {
                        timer: env.make_time(150, 300),
                        votes: 1,
                    };
                    env.multicast(self.id, self.peers, &RequestVoteRequest {
                        term: self.term,
                        lastLogTerm: Term(0),
                        lastLogIndex: Index(0),
                    });
                }
                self.try_become_leader(env);
            },
            Leader {timer: ref mut timer, heartbeat_seqno: ref mut heartbeat_seqno, acks: ref mut acks, _} => {
                if *timer <= env.clock {
                    if (*acks > (self.peers.len() + 1) / 2) {
                        *heartbeat_seqno += 1;
                        *acks = 0;
                        *timer = env.make_time(75, 76);
                        env.multicast(self.id, self.peers, &AppendEntriesRequest {
                            term: self.term,
                            seqno: *heartbeat_seqno,
                        });
                    } else {
                        need_step_down = true;
                    }
                }
            },
        }
        if need_step_down {
            println!("Failed to maintain leadership: {}", *self);
            self.step_down(env, self.term)
        }
    }
    fn step_down(&mut self, env: &Environment, term: Term) {
        self.term = term;
        self.vote = None;
        self.state = Follower {
            timer: env.make_time(150, 300),
        };
    }

    fn try_become_leader(&mut self, env: &mut Environment) {
        match self.state {
            Follower {_} => {},
            Candidate {votes, _} => {
                if votes > (self.peers.len() + 1) / 2 {
                    self.state = Leader {
                        timer: env.make_time(75, 76),
                        heartbeat_seqno: 0,
                        acks: 1,
                        start_time: env.clock,
                    };
                    env.multicast(self.id, self.peers, &AppendEntriesRequest {
                        term: self.term,
                        seqno: 0,
                    });
                }
            },
            Leader {_} => {},
        }
    }

    fn stable_leader_start_time(&self) -> Option<Time> {
        match self.state {
            Leader {heartbeat_seqno, start_time, _} if heartbeat_seqno > 4 => Some(start_time),
            _ => None,
        }
    }

    fn handle(&mut self, env: &mut Environment, msg: &Message) {
        match msg.body {
            RequestVoteRequest {term, _} => {
                let reply = |granted| {
                    env.reply(msg, &RequestVoteResponse {
                        term: self.term,
                        granted: granted,
                    });
                };
                if term < self.term {
                    reply(false);
                } else {
                    if term > self.term {
                        self.step_down(env, term);
                    }
                    match self.vote {
                        None => {
                            self.vote = Some(msg.from);
                            reply(true);
                        },
                        Some(c) => {
                            reply(c == msg.from);
                        },
                    }
                }
            },
            RequestVoteResponse {term, granted, _} => {
                if term == self.term && granted {
                    match self.state {
                        Follower {_} => {},
                        Candidate {votes: ref mut votes, _} => {
                            *votes += 1;
                        },
                        Leader {_} => {},
                    }
                    self.try_become_leader(env)
                } else if term > self.term {
                    self.step_down(env, term);
                }
            },
            AppendEntriesRequest {term, seqno} => {
                if term == self.term {
                    self.state = Follower {
                        timer: env.make_time(150, 300),
                    };
                } else if term > self.term {
                    self.step_down(env, term);
                }
                env.reply(msg, &AppendEntriesResponse {
                    term: self.term,
                    seqno: seqno,
                });
            },
            AppendEntriesResponse {term, seqno} => {
                if term == self.term {
                    match self.state {
                        Follower {_} | Candidate {_} => {},
                        Leader { heartbeat_seqno, acks: ref mut acks, _ } => {
                            if seqno == heartbeat_seqno {
                                *acks += 1;
                            }
                        },
                    }
                }
            },
        }
    }

    /*
    fn next_event_time(&self) -> Time {
        match self.state {
            Follower  {timer, _} |
            Candidate {timer, _} =>
                timer,
            Leader => Time(!0)
        }
    }
    */
}

impl fmt::Default for Server {
    fn fmt(server: &Server, f: &mut fmt::Formatter) {
        write!(f.buf, "Server {}: {}", *server.id, server.state)
    }
}

struct Cluster(~[Server]);

impl Cluster {
    fn new(env: &Environment, num_servers: uint) -> Cluster {
        let mut servers = ~[];
        for i in range(0, num_servers) {
            let mut peers = ~[];
            for j in range(0, num_servers) {
                if i != j {
                    peers.push(ServerID(j + 1));
                }
            }
            let s = Server::new(ServerID(i + 1), peers, env);
            servers.push(s);
        }
        return Cluster(servers);
    }

    fn deliver(&mut self, env: &mut Environment, msg: &Message) {
        self[*msg.to - 1].handle(env, msg);
    }
}

fn main() {
    let args = std::os::args();
    let opts = [
        getopts::optflag("h"),
        getopts::optflag("help"),
        getopts::optopt("servers"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m },
        Err(f) => { fail!(f.to_err_msg()) },
    };
    let usage = || {
        println!("Usage: {} [options]", args[0]);
        println("-h, --help   Print this help message");
        println("--servers=N  Simulate cluster with N servers");
    };
    if matches.opt_present("h") || matches.opt_present("help") {
        usage();
        return;
    }
    if !matches.free.is_empty() {
        usage();
        fail!(format!("Extra arguments: {}", matches.free.len()));
    }
    let num_servers : uint = match matches.opt_str("servers") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of servers from '{}'", s));
            },
        }},
        None => { 5 },
    };
    let mut samples = ~[];
    for i in range(0, 10000) {
        samples.push(simulate(num_servers))
    }
    extra::sort::tim_sort(samples);
    println!("{}", samples[0]);
    println!("{}", samples[samples.len()/2]);
    println!("{}", samples[samples.len()-1]);
}

fn simulate(num_servers: uint) -> Time {
    let env = &mut Environment::new();
    let mut cluster = Cluster::new(env, num_servers);
    let mut end = None;
    while end.is_none() {
        env.clock = Time(*env.clock + 1);
        for server in cluster.mut_iter() {
            server.tick(env);
        }
        for msg in env.pop_ready_messages().move_iter() {
            cluster.deliver(env, msg);
        }
        for server in cluster.iter() {
            end = server.stable_leader_start_time();
            if end.is_some() {
                break;
            }
        }
        /*
        println!("Tick: {}", env.clock);
        for server in cluster.iter() {
            println!("{}", *server);
        }
        for message in env.network.iter() {
            println!("{}", **message);
        }
        println!("");
        */
    }
    return end.unwrap();
}

<|endoftext|>