<commit_before>#![allow(unused_variables)]

use block::Block;
use cocoa::base::{BOOL, id};
use cocoa::foundation::NSUInteger;
use libc::c_void;
use {MTLFeatureSet, MTLPipelineOption, MTLSize};

pub type MTLNewLibraryCompletionHandler = Block<(id,), id>;
pub type MTLNewRenderPipleineStateCompletionHandler = Block<(id, id), ()>;
pub type MTLNewRenderPipelineStateWithReflectionCompletionHandler = Block<(id, id, id), ()>;
pub type MTLNewComputePipelineStateCompletionHandler = Block<(id, id), ()>;
pub type MTLNewComputePipelineStateWithReflectionCompletionHandler = Block<(id, id, id), ()>;

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub trait MTLDevice {
    unsafe fn depth24Stencil8PixelFormatSupported(self) -> BOOL;
    unsafe fn headless(self) -> BOOL;
    unsafe fn lowPower(self) -> BOOL;
    unsafe fn maxThreadsPerGroup(self) -> MTLSize;
    unsafe fn name(self) -> id;
    unsafe fn supportsFeatureSet(self, featureSet: MTLFeatureSet) -> BOOL;
    unsafe fn supportsTextureSampleCount(self, textureSampleCount: NSUInteger) -> BOOL;

    unsafe fn newDefaultLibrary(self) -> id;
    unsafe fn newLibraryWithFile_error(self, filePath: id, error: id) -> id;
    unsafe fn newLibraryWithSource_options_completionHandler(self,
                                                             source: id,
                                                             options: id,
                                                             completionHandler: MTLNewLibraryCompletionHandler);
    unsafe fn newLibraryWithSource_options_error(self, source: id, options: id, error: id);
    unsafe fn newLibraryWithData_error(self, data: id, error: id);

    unsafe fn newCommandQueue(self) -> id;
    unsafe fn newCommandQueueWithMaxCommandBufferCount(self, maxCommandBufferCount: NSUInteger) -> id;

    unsafe fn newBufferWithLength_Options(self, length: NSUInteger, options: id) -> id;
    unsafe fn newBufferWithBytes_Length_Options(self, pointer: *mut c_void, length: NSUInteger, options: id) -> id;
    unsafe fn newBufferWithBytesNoCopy_length_options_deallocator(self,
                                                                  pointer: *mut c_void,
                                                                  length: NSUInteger,
                                                                  deallocator: Block<(*mut c_void, NSUInteger), ()>);

    unsafe fn newTextureWithDescriptor(self, descriptor: id) -> id;
    unsafe fn newSamplerStateWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newStencilDepthStateWithDescriptor(self, descriptor: id) -> id;
    unsafe fn newRenderPipleineStateWithDescriptor_completionHandler(
                                                    self,
                                                    descriptor: id,
                                                    completionHandler: MTLNewRenderPipleineStateCompletionHandler);
    unsafe fn newRenderPipelineStateWithDescriptor_options_completionHandler(
                                        self,
                                        descriptor: id,
                                        options: MTLPipelineOption,
                                        completionHandler: MTLNewRenderPipelineStateWithReflectionCompletionHandler);
    unsafe fn newRenderPipelineStateWithDescriptor_error(self, descriptor: id, error: id);
    unsafe fn newRenderPipelineStateWithDescriptor_options_reflection(self,
                                                                      descriptor: id,
                                                                      options: MTLPipelineOption,
                                                                      reflection: id,
                                                                      error: id);

    unsafe fn newComputePipelineStateWithFunction_completionHandler(
                                                        self,
                                                        function: id,
                                                        completionHandler: MTLNewComputePipelineStateCompletionHandler);
    unsafe fn newComputePipelineStateWithFunction_options_completionHandler(
                                        self,
                                        function: id,
                                        options: MTLPipelineOption,
                                        completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler);
    unsafe fn newComputePipelineStateWithFunction_error(self, function: id, error: id);
    unsafe fn newComputePipelineStateWithFunction_options_reflection_error(self,
                                                                           function: id,
                                                                           options: MTLPipelineOption,
                                                                           reflection: id,
                                                                           error: id);

    unsafe fn newComputePipelineStateWithDescriptor_options_completionHandler(self,
                                        descriptor: id,
                                        options: MTLPipelineOption,
                                        completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler);
    unsafe fn newComputePipelineStateWithDescriptor_options_reflection_error(self,
                                                                             descriptor: id,
                                                                             options: MTLPipelineOption,
                                                                             reflection: id,
                                                                             error: id);
}

impl MTLDevice for id {
    unsafe fn depth24Stencil8PixelFormatSupported(self) -> BOOL {
        msg_send![self, isDepth24Stencil8PixelFormatSupported]
    }

    unsafe fn headless(self) -> BOOL {
        msg_send![self, isHeadless]
    }

    unsafe fn lowPower(self) -> BOOL {
        msg_send![self, isLowPower]
    }

    unsafe fn maxThreadsPerGroup(self) -> MTLSize {
        msg_send![self, maxThreadsPerThreadgroup]
    }

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

    unsafe fn supportsFeatureSet(self, featureSet: MTLFeatureSet) -> BOOL {
        msg_send![self, supportsFeatureSet:featureSet]
    }

    unsafe fn supportsTextureSampleCount(self, textureSampleCount: NSUInteger) -> BOOL {
        msg_send![self, supportsTextureSampleCount:textureSampleCount]
    }

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

    unsafe fn newLibraryWithFile_error(self, filePath: id, error: id) -> id {
        msg_send![self, newLibraryWithFile:filePath error:error]
    }

    unsafe fn newLibraryWithSource_options_completionHandler(self,
                                                             source: id,
                                                             options: id,
                                                             completionHandler: MTLNewLibraryCompletionHandler) {
        msg_send![self, newLibraryWithSource:source options:options completionHandler:completionHandler]
    }

    unsafe fn newLibraryWithSource_options_error(self, source: id, options: id, error: id) {
        msg_send![self, newLibraryWithSource:source options:options error:error]
    }

    unsafe fn newLibraryWithData_error(self, data: id, error: id) {
        msg_send![self, newLibraryWithData:data error:error]
    }

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

    unsafe fn newCommandQueueWithMaxCommandBufferCount(self, maxCommandBufferCount: NSUInteger) -> id {
        msg_send![self, newCommandQueueWithMaxCommandBufferCount:maxCommandBufferCount]
    }

    unsafe fn newBufferWithLength_Options(self, length: NSUInteger, options: id) -> id {
        msg_send![self, newBufferWithLength:length options:options]
    }

    unsafe fn newBufferWithBytes_Length_Options(self, pointer: *mut c_void, length: NSUInteger, options: id) -> id {
        msg_send![self, newBufferWithBytes:pointer length:length options:options]
    }

    unsafe fn newBufferWithBytesNoCopy_length_options_deallocator(self,
                                                                  pointer: *mut c_void,
                                                                  length: NSUInteger,
                                                                  deallocator: Block<(*mut c_void, NSUInteger), ()>) {
        msg_send![self, newBufferWithBytesNoCopy:pointer length:length deallocator:deallocator]
    }

    unsafe fn newTextureWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newTextureWithDescriptor:descriptor]
    }

    unsafe fn newSamplerStateWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newSamplerStateWithDescriptor:descriptor]
    }

    unsafe fn newStencilDepthStateWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newStencilDepthStateWithDescriptor:descriptor]
    }

    unsafe fn newRenderPipleineStateWithDescriptor_completionHandler(
                                                    self,
                                                    descriptor: id,
                                                    completionHandler: MTLNewRenderPipleineStateCompletionHandler) {
        msg_send![self, newRenderPipleineStateWithDescriptor:descriptor completionHandler:completionHandler]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_options_completionHandler(
                                        self,
                                        descriptor: id,
                                        options: MTLPipelineOption,
                                        completionHandler: MTLNewRenderPipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                     options:options
                                           completionHandler:completionHandler]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_error(self, descriptor: id, error: id) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor error:error]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_options_reflection(self,
                                                                      descriptor: id,
                                                                      options: MTLPipelineOption,
                                                                      reflection: id,
                                                                      error: id) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                     options:options
                                                  reflection:reflection
                                                       error:error]
    }

    unsafe fn newComputePipelineStateWithFunction_completionHandler(
                  self,
                  function: id,
                  completionHandler: MTLNewComputePipelineStateCompletionHandler) {
        msg_send![self, newComputePipelineStateWithFunction:function completionHandler:completionHandler]
    }

    unsafe fn newComputePipelineStateWithFunction_options_completionHandler(
                   self,
                   function: id,
                   options: MTLPipelineOption,
                   completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                                    options:options
                                          completionHandler:completionHandler]
    }

    unsafe fn newComputePipelineStateWithFunction_error(self, function: id, error: id) {
        msg_send![self, newComputePipelineStateWithFunction:function error:error]
    }

    unsafe fn newComputePipelineStateWithFunction_options_reflection_error(self,
                                                                           function: id,
                                                                           options: MTLPipelineOption,
                                                                           reflection: id,
                                                                           error: id) {
        msg_send![self, newComputePipelineStateWithFunction:function options:options reflection:reflection error:error]
    }

    unsafe fn newComputePipelineStateWithDescriptor_options_completionHandler(
                   self,
                   descriptor: id,
                   options: MTLPipelineOption,
                   completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                      options:options
                                            completionHandler:completionHandler]
    }
    unsafe fn newComputePipelineStateWithDescriptor_options_reflection_error(self,
                                                                             descriptor: id,
                                                                             options: MTLPipelineOption,
                                                                             reflection: id,
                                                                             error: id) {
        msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                      options:options
                                                   reflection:reflection
                                                        error:error]
    }
}
<commit_msg>Doc spree<commit_after>#![allow(unused_variables)]

use block::Block;
use cocoa::base::{BOOL, id};
use cocoa::foundation::NSUInteger;
use libc::c_void;
use {MTLFeatureSet, MTLPipelineOption, MTLSize};

/// The MTLDevice protocol defines the interface to a single graphics processor (GPU). You use
/// an object that conforms to this protocol to query the capabilities of the processor and to
/// allocate objects used to access those capabilities.
///
/// Your app does not define classes that implement this protocol; it is used by Metal to provide
/// a device object to your app. To obtain a system device, call the MTLCreateSystemDefaultDevice
/// function or select a result from the MTLCopyAllDevices function.
///
/// Most objects in Metal that perform graphics rendering and computational work are associated
/// directly with a specific device. For example, texture objects are created by a device object
/// and can be used only with that device. Most methods on a MTLDevice object create non-transient
/// objects, including command queues, resources (such as buffers and textures), and pipeline states.
/// These objects can be expensive to create and you are encouraged to create them soon after your
/// app launches and reuse them throughout the lifetime of your app. Avoid creating these objects
/// in performance sensitive code.
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub trait MTLDevice {
    /// A Boolean value that indicates whether a device supports a packed depth/stencil buffer. (read-only)
    ///
    /// # Discussion
    ///
    /// If the value is YES, the device supports the MTLPixelFormatDepth24Unorm_Stencil8 pixel format.
    unsafe fn depth24Stencil8PixelFormatSupported(self) -> BOOL;

    /// A Boolean value that indicates whether a device is configured as headless. (read-only)
    ///
    /// # Discussion
    ///
    /// If the value is YES, the device can not and does not have any displays attached.
    unsafe fn headless(self) -> BOOL;

    /// Boolean value that indicates whether a device is low-power. (read-only)
    ///
    /// # Discussion
    ///
    /// On multi-GPU systems that support automatic graphics switching, this property will return YES
    /// for the lower-power GPU.
    unsafe fn lowPower(self) -> BOOL;

    /// The maximum number of threads along each dimension of a threadgroup. (read-only)
    ///
    /// # Discussion
    ///
    /// This is the maximum compute grid size (width, height, depth) supported by the device.
    ///
    /// For more information on the specific capabilities of each feature set, see [Metal Programming Guide](
    /// https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn maxThreadsPerGroup(self) -> MTLSize;

    /// A string that identifies the device. (read-only)
    ///
    /// # Discussion
    ///
    /// When this object is viewed in the Xcode debugger, its name is used to label the device.
    /// The name should only be used for informational purposes.
    unsafe fn name(self) -> id;

    /// Determines whether a device implements a particular feature set.
    ///
    /// # Parameters
    ///
    /// `featureSet` - A value that indicates the feature set you are interested in.
    ///
    /// # Return Value
    ///
    /// YES if the feature set is supported by the device; otherwise NO
    ///
    /// # Discussion
    ///
    /// For more information on the specific capabilities of each feature set, see [Metal Programming Guide](
    /// https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn supportsFeatureSet(self, featureSet: MTLFeatureSet) -> BOOL;

    /// Determines whether a device supports a given texture sample count.
    ///
    /// # Parameters
    ///
    /// `textureSampleCount` - The sample count you are interested in.
    ///
    /// # Return Value
    ///
    /// YES if the sample count is supported by the device; otherwise NO.
    ///
    /// # Discussion
    ///
    /// For more information on the specific capabilities of each feature set, see [Metal Programming Guide](
    /// https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn supportsTextureSampleCount(self, textureSampleCount: NSUInteger) -> BOOL;

    unsafe fn newDefaultLibrary(self) -> id;
    unsafe fn newLibraryWithFile_error(self, filePath: id, error: id) -> id;
    unsafe fn newLibraryWithSource_options_completionHandler(self,
                                                             source: id,
                                                             options: id,
                                                             completionHandler: MTLNewLibraryCompletionHandler);
    unsafe fn newLibraryWithSource_options_error(self, source: id, options: id, error: id);
    unsafe fn newLibraryWithData_error(self, data: id, error: id);

    unsafe fn newCommandQueue(self) -> id;
    unsafe fn newCommandQueueWithMaxCommandBufferCount(self, maxCommandBufferCount: NSUInteger) -> id;

    unsafe fn newBufferWithLength_Options(self, length: NSUInteger, options: id) -> id;
    unsafe fn newBufferWithBytes_Length_Options(self, pointer: *mut c_void, length: NSUInteger, options: id) -> id;
    unsafe fn newBufferWithBytesNoCopy_length_options_deallocator(self,
                                                                  pointer: *mut c_void,
                                                                  length: NSUInteger,
                                                                  deallocator: Block<(*mut c_void, NSUInteger), ()>);

    unsafe fn newTextureWithDescriptor(self, descriptor: id) -> id;
    unsafe fn newSamplerStateWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newStencilDepthStateWithDescriptor(self, descriptor: id) -> id;
    unsafe fn newRenderPipleineStateWithDescriptor_completionHandler(
                                                    self,
                                                    descriptor: id,
                                                    completionHandler: MTLNewRenderPipleineStateCompletionHandler);
    unsafe fn newRenderPipelineStateWithDescriptor_options_completionHandler(
                                        self,
                                        descriptor: id,
                                        options: MTLPipelineOption,
                                        completionHandler: MTLNewRenderPipelineStateWithReflectionCompletionHandler);
    unsafe fn newRenderPipelineStateWithDescriptor_error(self, descriptor: id, error: id);
    unsafe fn newRenderPipelineStateWithDescriptor_options_reflection(self,
                                                                      descriptor: id,
                                                                      options: MTLPipelineOption,
                                                                      reflection: id,
                                                                      error: id);

    unsafe fn newComputePipelineStateWithFunction_completionHandler(
                                                        self,
                                                        function: id,
                                                        completionHandler: MTLNewComputePipelineStateCompletionHandler);
    unsafe fn newComputePipelineStateWithFunction_options_completionHandler(
                                        self,
                                        function: id,
                                        options: MTLPipelineOption,
                                        completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler);
    unsafe fn newComputePipelineStateWithFunction_error(self, function: id, error: id);
    unsafe fn newComputePipelineStateWithFunction_options_reflection_error(self,
                                                                           function: id,
                                                                           options: MTLPipelineOption,
                                                                           reflection: id,
                                                                           error: id);

    unsafe fn newComputePipelineStateWithDescriptor_options_completionHandler(self,
                                        descriptor: id,
                                        options: MTLPipelineOption,
                                        completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler);
    unsafe fn newComputePipelineStateWithDescriptor_options_reflection_error(self,
                                                                             descriptor: id,
                                                                             options: MTLPipelineOption,
                                                                             reflection: id,
                                                                             error: id);
}

impl MTLDevice for id {
    unsafe fn depth24Stencil8PixelFormatSupported(self) -> BOOL {
        msg_send![self, isDepth24Stencil8PixelFormatSupported]
    }

    unsafe fn headless(self) -> BOOL {
        msg_send![self, isHeadless]
    }

    unsafe fn lowPower(self) -> BOOL {
        msg_send![self, isLowPower]
    }

    unsafe fn maxThreadsPerGroup(self) -> MTLSize {
        msg_send![self, maxThreadsPerThreadgroup]
    }

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

    unsafe fn supportsFeatureSet(self, featureSet: MTLFeatureSet) -> BOOL {
        msg_send![self, supportsFeatureSet:featureSet]
    }

    unsafe fn supportsTextureSampleCount(self, textureSampleCount: NSUInteger) -> BOOL {
        msg_send![self, supportsTextureSampleCount:textureSampleCount]
    }

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

    unsafe fn newLibraryWithFile_error(self, filePath: id, error: id) -> id {
        msg_send![self, newLibraryWithFile:filePath error:error]
    }

    unsafe fn newLibraryWithSource_options_completionHandler(self,
                                                             source: id,
                                                             options: id,
                                                             completionHandler: MTLNewLibraryCompletionHandler) {
        msg_send![self, newLibraryWithSource:source options:options completionHandler:completionHandler]
    }

    unsafe fn newLibraryWithSource_options_error(self, source: id, options: id, error: id) {
        msg_send![self, newLibraryWithSource:source options:options error:error]
    }

    unsafe fn newLibraryWithData_error(self, data: id, error: id) {
        msg_send![self, newLibraryWithData:data error:error]
    }

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

    unsafe fn newCommandQueueWithMaxCommandBufferCount(self, maxCommandBufferCount: NSUInteger) -> id {
        msg_send![self, newCommandQueueWithMaxCommandBufferCount:maxCommandBufferCount]
    }

    unsafe fn newBufferWithLength_Options(self, length: NSUInteger, options: id) -> id {
        msg_send![self, newBufferWithLength:length options:options]
    }

    unsafe fn newBufferWithBytes_Length_Options(self, pointer: *mut c_void, length: NSUInteger, options: id) -> id {
        msg_send![self, newBufferWithBytes:pointer length:length options:options]
    }

    unsafe fn newBufferWithBytesNoCopy_length_options_deallocator(self,
                                                                  pointer: *mut c_void,
                                                                  length: NSUInteger,
                                                                  deallocator: Block<(*mut c_void, NSUInteger), ()>) {
        msg_send![self, newBufferWithBytesNoCopy:pointer length:length deallocator:deallocator]
    }

    unsafe fn newTextureWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newTextureWithDescriptor:descriptor]
    }

    unsafe fn newSamplerStateWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newSamplerStateWithDescriptor:descriptor]
    }

    unsafe fn newStencilDepthStateWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newStencilDepthStateWithDescriptor:descriptor]
    }

    unsafe fn newRenderPipleineStateWithDescriptor_completionHandler(
                                                    self,
                                                    descriptor: id,
                                                    completionHandler: MTLNewRenderPipleineStateCompletionHandler) {
        msg_send![self, newRenderPipleineStateWithDescriptor:descriptor completionHandler:completionHandler]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_options_completionHandler(
                                        self,
                                        descriptor: id,
                                        options: MTLPipelineOption,
                                        completionHandler: MTLNewRenderPipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                     options:options
                                           completionHandler:completionHandler]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_error(self, descriptor: id, error: id) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor error:error]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_options_reflection(self,
                                                                      descriptor: id,
                                                                      options: MTLPipelineOption,
                                                                      reflection: id,
                                                                      error: id) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                     options:options
                                                  reflection:reflection
                                                       error:error]
    }

    unsafe fn newComputePipelineStateWithFunction_completionHandler(
                  self,
                  function: id,
                  completionHandler: MTLNewComputePipelineStateCompletionHandler) {
        msg_send![self, newComputePipelineStateWithFunction:function completionHandler:completionHandler]
    }

    unsafe fn newComputePipelineStateWithFunction_options_completionHandler(
                   self,
                   function: id,
                   options: MTLPipelineOption,
                   completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                                    options:options
                                          completionHandler:completionHandler]
    }

    unsafe fn newComputePipelineStateWithFunction_error(self, function: id, error: id) {
        msg_send![self, newComputePipelineStateWithFunction:function error:error]
    }

    unsafe fn newComputePipelineStateWithFunction_options_reflection_error(self,
                                                                           function: id,
                                                                           options: MTLPipelineOption,
                                                                           reflection: id,
                                                                           error: id) {
        msg_send![self, newComputePipelineStateWithFunction:function options:options reflection:reflection error:error]
    }

    unsafe fn newComputePipelineStateWithDescriptor_options_completionHandler(
                   self,
                   descriptor: id,
                   options: MTLPipelineOption,
                   completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                      options:options
                                            completionHandler:completionHandler]
    }
    unsafe fn newComputePipelineStateWithDescriptor_options_reflection_error(self,
                                                                             descriptor: id,
                                                                             options: MTLPipelineOption,
                                                                             reflection: id,
                                                                             error: id) {
        msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                      options:options
                                                   reflection:reflection
                                                        error:error]
    }
}

pub type MTLNewLibraryCompletionHandler = Block<(id,), id>;
pub type MTLNewRenderPipleineStateCompletionHandler = Block<(id, id), ()>;
pub type MTLNewRenderPipelineStateWithReflectionCompletionHandler = Block<(id, id, id), ()>;
pub type MTLNewComputePipelineStateCompletionHandler = Block<(id, id), ()>;
pub type MTLNewComputePipelineStateWithReflectionCompletionHandler = Block<(id, id, id), ()>;
<|endoftext|>


<commit_before><commit_msg>write jtm tests<commit_after>use ::{JTM, JTMBuilder};
use std::ffi::CString;

fn assert_jtm(t1: JTM, t2: JTM) {
  assert_eq!(t1.tm_sec, t2.tm_sec);
  assert_eq!(t1.tm_min, t2.tm_min);
  assert_eq!(t1.tm_hour, t2.tm_hour);
  assert_eq!(t1.tm_mday, t2.tm_mday);
  assert_eq!(t1.tm_mon, t2.tm_mon);
  assert_eq!(t1.tm_year, t2.tm_year);
  assert_eq!(t1.tm_wday, t2.tm_wday);
  assert_eq!(t1.tm_yday, t2.tm_yday);
  assert_eq!(t1.tm_isdst, t2.tm_isdst);
  assert_eq!(t1.tm_gmtoff, t2.tm_gmtoff);
  assert_eq!(t1.get_timezone().shrink_to_fit(),
             t2.get_timezone().shrink_to_fit());
}

#[test]
fn it_has_a_valid_timezone_getter() {
  let tm = JTM {
    tm_sec: 11,
    tm_min: 22,
    tm_hour: 33,
    tm_mday: 44,
    tm_mon: 55,
    tm_year: 66,
    tm_wday: 77,
    tm_yday: 88,
    tm_isdst: 1,
    tm_gmtoff: 99,
    tm_zone: CString::new("IRST").unwrap().into_raw(),
  };
  assert_eq!("IRST".to_string(), tm.get_timezone());
}

#[test]
fn it_has_a_valid_builder() {
  let t1 = JTMBuilder::new().set_sec(11).
                             set_min(22).
                             set_hour(33).
                             set_mday(44).
                             set_mon(55).
                             set_year(66).
                             set_wday(77).
                             set_yday(88).
                             set_isdst(1).
                             set_gmtoff(99).
                             set_zone("IRST".to_string()).
                             build();
  let t2 = JTM {
    tm_sec: 11,
    tm_min: 22,
    tm_hour: 33,
    tm_mday: 44,
    tm_mon: 55,
    tm_year: 66,
    tm_wday: 77,
    tm_yday: 88,
    tm_isdst: 1,
    tm_gmtoff: 99,
    tm_zone: CString::new("IRST").unwrap().into_raw(),
  };

  assert_jtm(t1, t2);
}

#[test]
fn it_has_a_valid_from_secs_initializer() {
  let t1 = JTMBuilder::new().set_sec(0).
                             set_min(0).
                             set_hour(20).
                             set_mday(26).
                             set_mon(6).
                             set_year(1371).
                             set_wday(1).
                             set_yday(211).
                             set_isdst(0).
                             set_gmtoff(12600).
                             set_zone("IRST".to_string()).
                             build();
  let t2 = JTM::from_secs(719425800);
  assert_jtm(t1, t2);
}

fn it_has_a_valid_from_days_initializer() {
  let t1 = JTMBuilder::new().set_sec(0).
                             set_min(0).
                             set_hour(20).
                             set_mday(26).
                             set_mon(6).
                             set_year(1371).
                             set_wday(1).
                             set_yday(211).
                             set_isdst(0).
                             set_gmtoff(12600).
                             set_zone("IRST".to_string()).
                             build();
  let t2 = JTM::from_days(8326);
  assert_eq!(t1.tm_year, t2.tm_year);
  assert_eq!(t1.tm_mon, t2.tm_mon);
  assert_eq!(t1.tm_mday, t2.tm_mday);
}

#[test]
fn it_has_a_valid_from_secs_to_utc_initializer() {
  let t1 = JTMBuilder::new().set_sec(0).
                             set_min(30).
                             set_hour(16).
                             set_mday(26).
                             set_mon(6).
                             set_year(1371).
                             set_wday(1).
                             set_yday(211).
                             set_isdst(0).
                             set_gmtoff(0).
                             set_zone("UTC".to_string()).
                             build();
  let t2 = JTM::from_secs_to_utc(719425800);
  assert_jtm(t1, t2);
}

#[test]
fn it_has_a_valid_from_formatted_string_initializer() {
  let tmp1 = "26/07/1371 19:59:59".to_string();
  let tmp2 = "%d/%m/%Y %H:%M:%S".to_string();
  let t1 = JTMBuilder::new().set_sec(59).
                             set_min(59).
                             set_hour(19).
                             set_mday(26).
                             set_mon(6).
                             set_year(1371).
                             set_wday(1).
                             set_yday(211).
                             set_isdst(0).
                             set_gmtoff(12600).
                             set_zone("IRST".to_string()).
                             build();
  let t2 = JTM::from_formatted_string(&tmp1, &tmp2).unwrap();
  assert_jtm(t1, t2);
}

#[test]
fn it_can_create_month_and_day_from_yearday() {
  let t1 = JTMBuilder::new().set_mday(26).set_mon(6).set_yday(211).build();
  let mut t2 = JTMBuilder::new().set_yday(211).build();
  t2.create_date_from_days();
  assert_jtm(t1, t2);
}

#[test]
fn it_can_create_yearday_from_month_and_day() {
  let t1 = JTMBuilder::new().set_mday(26).set_mon(6).set_yday(211).build();
  let mut t2 = JTMBuilder::new().set_mday(26).set_mon(6).build();
  t2.create_days_from_date();
  assert_jtm(t1, t2);
}

#[test]
fn it_has_a_valid_days_since_epoch_calculator() {
  let tmp = JTM::from_secs_to_utc(719425800);
  assert_eq!(tmp.get_days_since_epoch(), 8326);
}

#[test]
fn it_has_a_valid_update_method() {
  let t1 = JTMBuilder::new().set_sec(59).
                             set_min(59).
                             set_hour(19).
                             set_mday(26).
                             set_mon(6).
                             set_year(1371).
                             set_wday(1).
                             set_yday(211).
                             set_isdst(0).
                             set_gmtoff(12600).
                             set_zone("IRST".to_string()).
                             build();
  let mut t2 = JTMBuilder::new().set_sec(59).
                             set_min(59).
                             set_hour(19).
                             set_mday(26).
                             set_mon(6).
                             set_year(1371).
                             set_isdst(0).
                             set_gmtoff(12600).
                             set_zone("IRST".to_string()).
                             build();
  t2.update();
  assert_jtm(t1, t2);
}

#[test]
fn it_has_a_valid_to_string_method() {
  let t = JTMBuilder::new().set_sec(59).
                            set_min(59).
                            set_hour(19).
                            set_mday(26).
                            set_mon(6).
                            set_year(1371).
                            set_wday(1).
                            set_yday(211).
                            set_isdst(0).
                            set_gmtoff(12600).
                            set_zone("IRST".to_string()).
                            build();

  assert_eq!(t.to_string(), "Yek Meh 26 19:59:59 1371\n".to_string());
}

#[test]
fn it_has_a_valid_to_secs_method() {
  let mut tmp = JTMBuilder::new().set_sec(0).
                                  set_min(0).
                                  set_hour(20).
                                  set_mday(26).
                                  set_mon(6).
                                  set_year(1371).
                                  set_wday(1).
                                  set_yday(211).
                                  set_isdst(0).
                                  set_gmtoff(12600).
                                  set_zone("IRST".to_string()).
                                  build();
  assert_eq!(tmp.to_secs(), 719425800);
}

#[test]
fn it_has_a_valid_make_formatted_string_method() {
  let tmp = JTMBuilder::new().set_sec(0).
                              set_min(0).
                              set_hour(20).
                              set_mday(26).
                              set_mon(6).
                              set_year(1371).
                              set_wday(1).
                              set_yday(211).
                              set_isdst(0).
                              set_gmtoff(12600).
                              set_zone("IRST".to_string()).
                              build();
  let f1 = "%H:%M".to_string();
  let f2 = "%Z".to_string();
  let mut buffer1 = String::with_capacity(5);
  let mut buffer2 = String::with_capacity(5);

  tmp.make_formated_string(&f1, &mut buffer1);
  tmp.make_formated_string(&f2, &mut buffer2);

  assert_eq!(buffer1, "20:0".to_string());
  assert_eq!(buffer2, "IRST".to_string());
}
<|endoftext|>


<commit_before>use std;

use std::borrow::Borrow;
use std::ops::Deref;
use std::ptr;
use std::str;

use crlf;
use smallvec::{Array, SmallVec};
use str_utils::{char_to_byte_idx, count_chars};
use tree::MAX_BYTES;

// TODO: handle corner-case when fixing CRLF seams, and then uncomment
// all of the `MAX_BYTES` asserts to make sure that no allocations are
// happening.  Finally, remove SmallVec in favor of a simple byte array
// + len.

/// A custom small string, with an internal buffer of `tree::MAX_BYTES`
/// length.  Has a bunch of methods on it that are useful for the rope
/// tree.
#[derive(Clone, Default)]
pub(crate) struct NodeText {
    buffer: SmallVec<BackingArray>,
}

impl NodeText {
    /// Creates a new empty `NodeText`
    #[inline(always)]
    pub fn new() -> Self {
        NodeText {
            buffer: SmallVec::new(),
        }
    }

    /// Creates a new empty `NodeText` with at least `capacity` bytes
    /// of capacity.
    #[inline(always)]
    pub fn with_capacity(capacity: usize) -> Self {
        NodeText {
            buffer: SmallVec::with_capacity(capacity),
        }
    }

    /// Creates a new `NodeText` with the same contents as the given `&str`.
    pub fn from_str(string: &str) -> Self {
        debug_assert!(string.len() <= MAX_BYTES);
        let mut nodetext = NodeText::with_capacity(string.len());
        unsafe { nodetext.insert_bytes(0, string.as_bytes()) };
        nodetext
    }

    /// Inserts a `&str` at byte offset `idx`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn insert_str(&mut self, byte_idx: usize, string: &str) {
        debug_assert!(self.is_char_boundary(byte_idx));
        debug_assert!(byte_idx <= self.len());
        // debug_assert!((self.len() + string.len()) <= MAX_BYTES);

        unsafe {
            self.insert_bytes(byte_idx, string.as_bytes());
        }
    }

    /// Inserts the given text into the given string at the given char index.
    pub fn insert_str_at_char(&mut self, text: &str, char_idx: usize) {
        // debug_assert!((self.len() + text.len()) <= MAX_BYTES);
        let byte_idx = char_to_byte_idx(self, char_idx);
        self.insert_str(byte_idx, text);
    }

    /// Inserts a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// so if the whole string is a single code point or CRLF pair, the split
    /// will fail and the returned string will be empty.
    pub fn insert_str_split(&mut self, idx: usize, string: &str) -> Self {
        debug_assert!(self.is_char_boundary(idx));
        // debug_assert!((self.len() + string.len()) <= (MAX_BYTES * 2 - 4));

        let tot_len = self.len() + string.len();
        let mid_idx = tot_len / 2;
        let a = idx;
        let b = idx + string.len();

        // Figure out the split index, accounting for code point
        // boundaries and CRLF pairs.
        // We first copy the bytes in the area of the proposed split point into
        // a small 8-byte buffer.  We then use that buffer to look for the
        // real split point.
        let split_idx = {
            let mut buf = [0u8; 8];
            let start = mid_idx - 4.min(mid_idx);
            let end = (mid_idx + 4).min(tot_len);
            for i in start..end {
                buf[i - start] = if i < a {
                    self.as_bytes()[i]
                } else if i < b {
                    string.as_bytes()[i - a]
                } else {
                    self.as_bytes()[i - string.len()]
                };
            }

            crlf::nearest_internal_break(mid_idx - start, &buf[..(end - start)]) + start
        };

        // debug_assert!(split_idx <= MAX_BYTES);

        let mut right = NodeText::new();
        if split_idx <= a {
            right.push_str(&self[split_idx..a]);
            right.push_str(string);
            right.push_str(&self[a..]);
            self.truncate(split_idx);
        } else if split_idx <= b {
            right.push_str(&string[(split_idx - a)..]);
            right.push_str(&self[a..]);
            self.truncate(a);
            self.push_str(&string[..(split_idx - a)]);
        } else {
            right.push_str(&self[(split_idx - string.len())..]);
            self.truncate(split_idx - string.len());
            self.insert_str(a, string);
        }

        right
    }

    /// Appends a `&str` to end the of the `NodeText`.
    pub fn push_str(&mut self, string: &str) {
        // debug_assert!((self.len() + string.len()) <= MAX_BYTES);
        let len = self.len();
        unsafe {
            self.insert_bytes(len, string.as_bytes());
        }
    }

    /// Appends a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// grapheme boundaries, so if the whole string is a single code point or
    /// CRLF pair, the split will fail and the returned string will be empty.
    ///
    /// TODO: make this work without allocations when possible.
    pub fn push_str_split(&mut self, string: &str) -> Self {
        let len = self.len();
        self.insert_str_split(len, string)
    }

    /// Drops the text after byte index `idx`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn truncate(&mut self, idx: usize) {
        assert!(self.is_char_boundary(idx));
        debug_assert!(idx <= self.len());
        self.buffer.truncate(idx);
        self.inline_if_possible();
    }

    /// Drops the text before byte index `idx`, shifting the
    /// rest of the text to fill in the space.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn truncate_front(&mut self, idx: usize) {
        assert!(self.is_char_boundary(idx));
        debug_assert!(idx <= self.len());
        unsafe {
            self.remove_bytes(0, idx);
        }
    }

    /// Removes the text in the byte index interval `[start, end)`.
    ///
    /// Panics if either `start` or `end` are not char boundaries, as that
    /// would result in an invalid utf8 string.
    pub fn remove_range(&mut self, start: usize, end: usize) {
        assert!(self.is_char_boundary(start));
        assert!(self.is_char_boundary(end));
        debug_assert!(end <= self.len());
        debug_assert!(start <= end);
        unsafe {
            self.remove_bytes(start, end);
        }
        self.inline_if_possible();
    }

    pub fn remove_char_range(&mut self, start: usize, end: usize) {
        debug_assert!(start <= end);
        debug_assert!(end <= count_chars(self));

        let byte_start = char_to_byte_idx(self, start);
        let byte_end = char_to_byte_idx(&self[start..], end - start);

        unsafe { self.remove_bytes(byte_start, byte_end) }
        self.inline_if_possible();
    }

    /// Splits the `NodeText` at `idx`.
    ///
    /// The left part remains in the original, and the right part is
    /// returned in a new `NodeText`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn split_off(&mut self, idx: usize) -> Self {
        assert!(self.is_char_boundary(idx));
        assert!(idx <= self.len());
        let len = self.len();
        let mut other = NodeText::with_capacity(len - idx);
        unsafe {
            ptr::copy_nonoverlapping(
                self.buffer.as_ptr().offset(idx as isize),
                other.buffer.as_mut_ptr().offset(0),
                len - idx,
            );
            self.buffer.set_len(idx);
            other.buffer.set_len(len - idx);
        }
        self.inline_if_possible();
        other
    }

    /// Splits a string into two strings at the char index given.
    /// The first section of the split is stored in the original string,
    /// while the second section of the split is returned as a new string.
    pub fn split_off_at_char(&mut self, char_idx: usize) -> Self {
        debug_assert!(char_idx <= count_chars(self));
        let byte_idx = char_to_byte_idx(self, char_idx);
        self.split_off(byte_idx)
    }

    #[inline(always)]
    pub fn shrink_to_fit(&mut self) {
        self.buffer.shrink_to_fit();
    }

    /// Returns whether the string has spilled out into a heap-allocated
    /// memory area.
    pub fn spilled(&self) -> bool {
        self.buffer.spilled()
    }

    #[inline(always)]
    pub unsafe fn as_mut_smallvec(&mut self) -> &mut SmallVec<BackingArray> {
        &mut self.buffer
    }

    #[inline(always)]
    unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
        assert!(idx <= self.len());
        // debug_assert!((self.len() + bytes.len()) <= MAX_BYTES);

        let len = self.len();
        let amt = bytes.len();
        self.buffer.reserve(amt);

        ptr::copy(
            self.buffer.as_ptr().offset(idx as isize),
            self.buffer.as_mut_ptr().offset((idx + amt) as isize),
            len - idx,
        );
        ptr::copy(
            bytes.as_ptr(),
            self.buffer.as_mut_ptr().offset(idx as isize),
            amt,
        );
        self.buffer.set_len(len + amt);
    }

    #[inline(always)]
    unsafe fn remove_bytes(&mut self, start: usize, end: usize) {
        assert!(start <= end);
        assert!(end <= self.len());
        let len = self.len();
        let amt = end - start;
        ptr::copy(
            self.buffer.as_ptr().offset(end as isize),
            self.buffer.as_mut_ptr().offset(start as isize),
            len - end,
        );
        self.buffer.set_len(len - amt);

        self.inline_if_possible();
    }

    /// Re-inlines the data if it's been heap allocated but can
    /// fit inline.
    #[inline(always)]
    fn inline_if_possible(&mut self) {
        if self.buffer.spilled() && (self.buffer.len() <= self.buffer.inline_size()) {
            self.buffer.shrink_to_fit();
        }
    }
}

impl std::cmp::PartialEq for NodeText {
    fn eq(&self, other: &Self) -> bool {
        let (s1, s2): (&str, &str) = (self, other);
        s1 == s2
    }
}

impl<'a> PartialEq<NodeText> for &'a str {
    fn eq(&self, other: &NodeText) -> bool {
        *self == (other as &str)
    }
}

impl<'a> PartialEq<&'a str> for NodeText {
    fn eq(&self, other: &&'a str) -> bool {
        (self as &str) == *other
    }
}

impl std::fmt::Display for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        NodeText::deref(self).fmt(fm)
    }
}

impl std::fmt::Debug for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> std::fmt::Result {
        NodeText::deref(self).fmt(fm)
    }
}

impl<'a> From<&'a str> for NodeText {
    fn from(s: &str) -> Self {
        Self::from_str(s)
    }
}

impl Deref for NodeText {
    type Target = str;

    fn deref(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

impl AsRef<str> for NodeText {
    fn as_ref(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

impl Borrow<str> for NodeText {
    fn borrow(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

//=======================================================================

/// Takes two `NodeText`s and mends the segment break between them, if any.
///
/// Note: this will leave one of the strings empty if the entire composite string
/// is one big grapheme.
pub(crate) fn fix_segment_seam(l: &mut NodeText, r: &mut NodeText) {
    // Early out, if there's nothing to do.
    if crlf::seam_is_break(l.as_bytes(), r.as_bytes()) {
        return;
    }

    let tot_len = l.len() + r.len();

    // Find the new split position, if any.
    let new_split_pos = {
        let l_split = crlf::prev_break(l.len(), l.as_bytes());
        let r_split = l.len() + crlf::next_break(0, r.as_bytes());
        if l_split != 0 && (r_split == tot_len || l.len() > r.len()) {
            l_split
        } else {
            r_split
        }
    };

    // debug_assert!(new_split_pos <= MAX_BYTES);
    // debug_assert!((tot_len - new_split_pos) <= MAX_BYTES);

    // Move the bytes to create the new split
    if new_split_pos < l.len() {
        r.insert_str(0, &l[new_split_pos..]);
        l.truncate(new_split_pos);
    } else {
        let pos = new_split_pos - l.len();
        l.push_str(&r[..pos]);
        r.truncate_front(pos);
    }
}

//=======================================================================

/// The backing internal buffer for `NodeText`.
#[derive(Copy, Clone)]
pub(crate) struct BackingArray([u8; MAX_BYTES]);
unsafe impl Array for BackingArray {
    type Item = u8;
    fn size() -> usize {
        MAX_BYTES
    }
    fn ptr(&self) -> *const u8 {
        &self.0[0]
    }
    fn ptr_mut(&mut self) -> *mut u8 {
        &mut self.0[0]
    }
}

//=======================================================================

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

    #[test]
    fn remove_bytes_01() {
        let mut s = NodeText::new();
        s.push_str("Hello!");
        unsafe {
            s.remove_bytes(2, 4);
        }
        assert_eq!("Heo!", s);
    }
}
<commit_msg>Moved all of NodeText's unsafe code into a smaller safe interface.<commit_after>use std;

use std::borrow::Borrow;
use std::ops::Deref;
use std::ptr;
use std::str;

use crlf;
use smallvec::{Array, SmallVec};
use str_utils::{char_to_byte_idx, count_chars};
use tree::MAX_BYTES;

/// A custom small string, with an internal buffer of `tree::MAX_BYTES`
/// length.  Has a bunch of methods on it that are useful for the rope
/// tree.
#[derive(Clone, Default)]
pub(crate) struct NodeText(NodeSmallString);

impl NodeText {
    /// Creates a new empty `NodeText`
    #[inline(always)]
    pub fn new() -> Self {
        NodeText(NodeSmallString::new())
    }

    /// Creates a new empty `NodeText` with at least `capacity` bytes
    /// of capacity.
    #[inline(always)]
    pub fn with_capacity(capacity: usize) -> Self {
        NodeText(NodeSmallString::with_capacity(capacity))
    }

    /// Creates a new `NodeText` with the same contents as the given `&str`.
    pub fn from_str(string: &str) -> Self {
        NodeText(NodeSmallString::from_str(string))
    }

    /// Inserts a `&str` at byte offset `byte_idx`.
    pub fn insert_str(&mut self, byte_idx: usize, string: &str) {
        self.0.insert_str(byte_idx, string);
    }

    /// Inserts the given text into the given string at the given char index.
    pub fn insert_str_at_char(&mut self, text: &str, char_idx: usize) {
        let byte_idx = char_to_byte_idx(self, char_idx);
        self.insert_str(byte_idx, text);
    }

    /// Inserts `string` at `byte_idx` and splits the resulting string in half,
    /// returning the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// so if the whole string is a single code point or CRLF pair, the split
    /// will fail and the returned string will be empty.
    pub fn insert_str_split(&mut self, byte_idx: usize, string: &str) -> Self {
        debug_assert!(self.is_char_boundary(byte_idx));

        let tot_len = self.len() + string.len();
        let mid_idx = tot_len / 2;
        let a = byte_idx;
        let b = byte_idx + string.len();

        // Figure out the split index, accounting for code point
        // boundaries and CRLF pairs.
        // We first copy the bytes in the area of the proposed split point into
        // a small 8-byte buffer.  We then use that buffer to look for the
        // real split point.
        let split_idx = {
            let mut buf = [0u8; 8];
            let start = mid_idx - 4.min(mid_idx);
            let end = (mid_idx + 4).min(tot_len);
            for i in start..end {
                buf[i - start] = if i < a {
                    self.as_bytes()[i]
                } else if i < b {
                    string.as_bytes()[i - a]
                } else {
                    self.as_bytes()[i - string.len()]
                };
            }

            crlf::nearest_internal_break(mid_idx - start, &buf[..(end - start)]) + start
        };

        let mut right = NodeText::new();
        if split_idx <= a {
            right.push_str(&self[split_idx..a]);
            right.push_str(string);
            right.push_str(&self[a..]);
            self.truncate(split_idx);
        } else if split_idx <= b {
            right.push_str(&string[(split_idx - a)..]);
            right.push_str(&self[a..]);
            self.truncate(a);
            self.push_str(&string[..(split_idx - a)]);
        } else {
            right.push_str(&self[(split_idx - string.len())..]);
            self.truncate(split_idx - string.len());
            self.insert_str(a, string);
        }

        self.0.inline_if_possible();
        right
    }

    /// Appends a `&str` to end the of the `NodeText`.
    pub fn push_str(&mut self, string: &str) {
        let len = self.len();
        self.0.insert_str(len, string);
    }

    /// Appends a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// grapheme boundaries, so if the whole string is a single code point or
    /// CRLF pair, the split will fail and the returned string will be empty.
    pub fn push_str_split(&mut self, string: &str) -> Self {
        let len = self.len();
        self.insert_str_split(len, string)
    }

    /// Drops the text after byte index `byte_idx`.
    pub fn truncate(&mut self, byte_idx: usize) {
        self.0.truncate(byte_idx);
        self.0.inline_if_possible();
    }

    /// Drops the text before byte index `byte_idx`, shifting the
    /// rest of the text to fill in the space.
    pub fn truncate_front(&mut self, byte_idx: usize) {
        self.0.remove_range(0, byte_idx);
        self.0.inline_if_possible();
    }

    /// Removes the text in the byte index interval `[byte_start, byte_end)`.
    pub fn remove_range(&mut self, byte_start: usize, byte_end: usize) {
        self.0.remove_range(byte_start, byte_end);
        self.0.inline_if_possible();
    }

    pub fn remove_char_range(&mut self, char_start: usize, char_end: usize) {
        debug_assert!(char_start <= char_end);
        debug_assert!(char_end <= count_chars(self));

        let byte_start = char_to_byte_idx(self, char_start);
        let byte_end = char_to_byte_idx(&self[char_start..], char_end - char_start);

        self.0.remove_range(byte_start, byte_end);
        self.0.inline_if_possible();
    }

    /// Splits the `NodeText` at `byte_idx`.
    ///
    /// The left part remains in the original, and the right part is
    /// returned in a new `NodeText`.
    pub fn split_off(&mut self, byte_idx: usize) -> Self {
        let other = NodeText(self.0.split_off(byte_idx));
        self.0.inline_if_possible();
        other
    }

    /// Splits a string into two strings at the char index given.
    /// The first section of the split is stored in the original string,
    /// while the second section of the split is returned as a new string.
    pub fn split_off_at_char(&mut self, char_idx: usize) -> Self {
        debug_assert!(char_idx <= count_chars(self));
        let byte_idx = char_to_byte_idx(self, char_idx);
        self.split_off(byte_idx)
    }
}

impl std::cmp::PartialEq for NodeText {
    fn eq(&self, other: &Self) -> bool {
        let (s1, s2): (&str, &str) = (self, other);
        s1 == s2
    }
}

impl<'a> PartialEq<NodeText> for &'a str {
    fn eq(&self, other: &NodeText) -> bool {
        *self == (other as &str)
    }
}

impl<'a> PartialEq<&'a str> for NodeText {
    fn eq(&self, other: &&'a str) -> bool {
        (self as &str) == *other
    }
}

impl std::fmt::Display for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        NodeText::deref(self).fmt(fm)
    }
}

impl std::fmt::Debug for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> std::fmt::Result {
        NodeText::deref(self).fmt(fm)
    }
}

impl<'a> From<&'a str> for NodeText {
    fn from(s: &str) -> Self {
        Self::from_str(s)
    }
}

impl Deref for NodeText {
    type Target = str;

    fn deref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for NodeText {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl Borrow<str> for NodeText {
    fn borrow(&self) -> &str {
        self.0.as_str()
    }
}

//=======================================================================

/// Takes two `NodeText`s and mends the segment break between them, if any.
///
/// Note: this will leave one of the strings empty if the entire composite string
/// is one big grapheme.
pub(crate) fn fix_segment_seam(l: &mut NodeText, r: &mut NodeText) {
    // Early out, if there's nothing to do.
    if crlf::seam_is_break(l.as_bytes(), r.as_bytes()) {
        return;
    }

    let tot_len = l.len() + r.len();

    // Find the new split position, if any.
    let new_split_pos = {
        let l_split = crlf::prev_break(l.len(), l.as_bytes());
        let r_split = l.len() + crlf::next_break(0, r.as_bytes());
        if l_split != 0 && (r_split == tot_len || l.len() > r.len()) {
            l_split
        } else {
            r_split
        }
    };

    // Move the bytes to create the new split
    if new_split_pos < l.len() {
        r.insert_str(0, &l[new_split_pos..]);
        l.truncate(new_split_pos);
    } else {
        let pos = new_split_pos - l.len();
        l.push_str(&r[..pos]);
        r.truncate_front(pos);
    }
}

//=======================================================================

/// The backing internal buffer type for `NodeText`.
#[derive(Copy, Clone)]
pub(crate) struct BackingArray([u8; MAX_BYTES]);
unsafe impl Array for BackingArray {
    type Item = u8;
    fn size() -> usize {
        MAX_BYTES
    }
    fn ptr(&self) -> *const u8 {
        &self.0[0]
    }
    fn ptr_mut(&mut self) -> *mut u8 {
        &mut self.0[0]
    }
}

/// Internal small string for `NodeText`, to compartmentalize the unsafe
/// code.  This exposes a minimal safe interface that guarantees memory
/// safety and makes it impossible to accidentally create invalid utf8
/// data. `NodeText` implements the more sophisticated API on top of this.
#[derive(Clone, Default)]
struct NodeSmallString {
    buffer: SmallVec<BackingArray>,
}

impl NodeSmallString {
    #[inline(always)]
    fn new() -> Self {
        NodeSmallString {
            buffer: SmallVec::new(),
        }
    }

    #[inline(always)]
    fn with_capacity(capacity: usize) -> Self {
        NodeSmallString {
            buffer: SmallVec::with_capacity(capacity),
        }
    }

    #[inline(always)]
    fn from_str(string: &str) -> Self {
        let mut nodetext = NodeSmallString::with_capacity(string.len());
        nodetext.insert_str(0, string);
        nodetext
    }

    #[inline(always)]
    fn len(&self) -> usize {
        self.buffer.len()
    }

    #[inline(always)]
    fn as_str(&self) -> &str {
        // NodeSmallString's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }

    /// Inserts `string` at `byte_idx`.
    ///
    /// Panics on out-of-bounds or of `byte_idx` isn't a char boundary.
    #[inline(always)]
    fn insert_str(&mut self, byte_idx: usize, string: &str) {
        assert!(byte_idx <= self.len());
        assert!(self.as_str().is_char_boundary(byte_idx));

        let len = self.len();
        let amt = string.len();
        self.buffer.reserve(amt);

        unsafe {
            ptr::copy(
                self.buffer.as_ptr().offset(byte_idx as isize),
                self.buffer.as_mut_ptr().offset((byte_idx + amt) as isize),
                len - byte_idx,
            );
            ptr::copy(
                string.as_ptr(),
                self.buffer.as_mut_ptr().offset(byte_idx as isize),
                amt,
            );
            self.buffer.set_len(len + amt);
        }
    }

    /// Removes text in range `[start_byte_idx, end_byte_idx)`
    ///
    /// Panics on out-of-bounds or non-char-boundary indices.
    #[inline(always)]
    fn remove_range(&mut self, start_byte_idx: usize, end_byte_idx: usize) {
        assert!(start_byte_idx <= end_byte_idx);
        assert!(end_byte_idx <= self.len());
        assert!(self.as_str().is_char_boundary(start_byte_idx));
        assert!(self.as_str().is_char_boundary(end_byte_idx));
        let len = self.len();
        let amt = end_byte_idx - start_byte_idx;

        unsafe {
            ptr::copy(
                self.buffer.as_ptr().offset(end_byte_idx as isize),
                self.buffer.as_mut_ptr().offset(start_byte_idx as isize),
                len - end_byte_idx,
            );
            self.buffer.set_len(len - amt);
        }
    }

    /// Removes text after `byte_idx`.
    #[inline(always)]
    pub fn truncate(&mut self, byte_idx: usize) {
        assert!(byte_idx <= self.len());
        assert!(self.as_str().is_char_boundary(byte_idx));
        self.buffer.truncate(byte_idx);
    }

    /// Splits at `byte_idx`, returning the right part and leaving the
    /// left part in the original.
    ///
    /// Panics on out-of-bounds or of `byte_idx` isn't a char boundary.
    #[inline(always)]
    fn split_off(&mut self, byte_idx: usize) -> Self {
        assert!(byte_idx <= self.len());
        assert!(self.as_str().is_char_boundary(byte_idx));
        let len = self.len();
        let mut other = NodeSmallString::with_capacity(len - byte_idx);
        unsafe {
            ptr::copy_nonoverlapping(
                self.buffer.as_ptr().offset(byte_idx as isize),
                other.buffer.as_mut_ptr().offset(0),
                len - byte_idx,
            );
            self.buffer.set_len(byte_idx);
            other.buffer.set_len(len - byte_idx);
        }
        other
    }

    /// Re-inlines the data if it's been heap allocated but can
    /// fit inline.
    #[inline(always)]
    fn inline_if_possible(&mut self) {
        if self.buffer.spilled() && (self.buffer.len() <= self.buffer.inline_size()) {
            self.buffer.shrink_to_fit();
        }
    }
}

//=======================================================================

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

    #[test]
    fn remove_bytes_01() {
        let mut s = NodeSmallString::from_str("Hello!");
        s.remove_range(2, 4);
        assert_eq!("Heo!", s.as_str());
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ops;
use std::sync::{Condvar, Mutex, MutexGuard, PoisonError};

pub struct SyncPool<V> {
    vals: Mutex<Vec<V>>,
    cond: Condvar,
}

pub struct SyncPoolGuard<'mutex, V: 'mutex> {
    m: &'mutex SyncPool<V>,
    v: Option<V>,
}

impl<'mutex, V> ops::Deref for SyncPoolGuard<'mutex, V> {
    type Target = V;
    fn deref(&self) -> &V {
        self.v.as_ref().unwrap()
    }
}

impl<'mutex, V> ops::DerefMut for SyncPoolGuard<'mutex, V> {
    fn deref_mut(&mut self) -> &mut V {
        self.v.as_mut().unwrap()
    }
}

impl<'mutex, V> ops::Drop for SyncPoolGuard<'mutex, V> {
    fn drop(&mut self) {
        let mut vals = self.m.vals.lock().unwrap();
        let v = mem::replace(&mut self.v, None);
        vals.push(v.unwrap());
        self.m.cond.notify_one();
    }
}

impl<V> SyncPool<V> {
    pub fn new(vals: Vec<V>) -> SyncPool<V> {
        SyncPool {
            vals: Mutex::new(vals),
            cond: Condvar::new(),
        }
    }

    pub fn lock(&self) -> Result<SyncPoolGuard<V>, PoisonError<MutexGuard<Vec<V>>>> {
        let v = {
            let mut vs = try!(self.vals.lock());
            while vs.len() == 0 {
                vs = try!(self.cond.wait(vs));
            }
            vs.pop().unwrap()
        };
        Ok(SyncPoolGuard {
            m: &self,
            v: Some(v),
        })
    }
}
<commit_msg>Add header.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::mem;
use std::ops;
use std::sync::{Condvar, Mutex, MutexGuard, PoisonError};

pub struct SyncPool<V> {
    vals: Mutex<Vec<V>>,
    cond: Condvar,
}

pub struct SyncPoolGuard<'mutex, V: 'mutex> {
    m: &'mutex SyncPool<V>,
    v: Option<V>,
}

impl<'mutex, V> ops::Deref for SyncPoolGuard<'mutex, V> {
    type Target = V;
    fn deref(&self) -> &V {
        self.v.as_ref().unwrap()
    }
}

impl<'mutex, V> ops::DerefMut for SyncPoolGuard<'mutex, V> {
    fn deref_mut(&mut self) -> &mut V {
        self.v.as_mut().unwrap()
    }
}

impl<'mutex, V> ops::Drop for SyncPoolGuard<'mutex, V> {
    fn drop(&mut self) {
        let mut vals = self.m.vals.lock().unwrap();
        let v = mem::replace(&mut self.v, None);
        vals.push(v.unwrap());
        self.m.cond.notify_one();
    }
}

impl<V> SyncPool<V> {
    pub fn new(vals: Vec<V>) -> SyncPool<V> {
        SyncPool {
            vals: Mutex::new(vals),
            cond: Condvar::new(),
        }
    }

    pub fn lock(&self) -> Result<SyncPoolGuard<V>, PoisonError<MutexGuard<Vec<V>>>> {
        let v = {
            let mut vs = try!(self.vals.lock());
            while vs.len() == 0 {
                vs = try!(self.cond.wait(vs));
            }
            vs.pop().unwrap()
        };
        Ok(SyncPoolGuard {
            m: &self,
            v: Some(v),
        })
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::sync::mpsc_queue::Queue;

/// Manages a collection of threads.
///
/// A new thread is created every time all the existing threads are full.
/// Any idle thread will automatically die after 5 seconds.
pub struct TaskPool {
    free_tasks: Arc<Queue<Sender<proc():Send>>>,
}

/// Number of milliseconds after which an idle thread dies.
static THREAD_IDLE_DIEAFTER: u64 = 5000;

impl TaskPool {
    pub fn new() -> TaskPool {
        TaskPool {
            free_tasks: Arc::new(Queue::new()),
        }
    }

    /// Executes a function in a thread.
    /// If no thread is available, spawns a new one.
    pub fn spawn(&self, mut code: proc():Send) {
        use std::task;
        use std::sync::mpsc_queue::{Data, Empty, Inconsistent};

        loop {
            match self.free_tasks.pop() {
                Data(sender) => {
                    match sender.send_opt(code) {
                        Ok(_) => return,
                        Err(org) => code = org
                    }
                },
                Inconsistent =>
                    task::deschedule(),
                Empty => {
                    self.add_thread(Some(code));
                    return
                }
            }
        }
    }

    fn add_thread(&self, initial_fn: Option<proc():Send>) {
        use std::io::timer::Timer;

        let queue = self.free_tasks.clone();

        spawn(proc() {
            let mut timer = Timer::new().unwrap();

            if initial_fn.is_some() {
                let f = initial_fn.unwrap();
                f();
            }

            loop {
                let (tx, rx) = channel();
                queue.push(tx);

                let timeout = timer.oneshot(THREAD_IDLE_DIEAFTER);
                select! {
                    next_fn = rx.recv() => next_fn(),
                    _ = timeout.recv() => break
                }
            }
        })
    }
}
<commit_msg>There is a now a minimum number of active threads in the pool<commit_after>use std::sync::Arc;
use std::sync::atomics::AtomicUint;
use std::sync::mpsc_queue::Queue;

/// Manages a collection of threads.
///
/// A new thread is created every time all the existing threads are full.
/// Any idle thread will automatically die after 5 seconds.
pub struct TaskPool {
    free_tasks: Arc<Queue<Sender<proc():Send>>>,
    active_tasks: Arc<AtomicUint>,
}

/// Number of milliseconds after which an idle thread dies.
static THREAD_IDLE_DIEAFTER: u64 = 5000;

/// Minimum number of active threads.
static MIN_THREADS: uint = 4;

struct Registration {
    nb: Arc<AtomicUint>
}

impl Registration {
    fn new(nb: Arc<AtomicUint>) -> Registration {
        use std::sync::atomics::Relaxed;
        nb.fetch_add(1, Relaxed);
        Registration { nb: nb }
    }
}

impl Drop for Registration {
    fn drop(&mut self) {
        use std::sync::atomics::Relaxed;
        self.nb.fetch_sub(1, Relaxed);
    }
}

impl TaskPool {
    pub fn new() -> TaskPool {
        let pool = TaskPool {
            free_tasks: Arc::new(Queue::new()),
            active_tasks: Arc::new(AtomicUint::new(0)),
        };

        for _ in range(0, MIN_THREADS) {
            pool.add_thread(None)
        }

        pool
    }

    /// Executes a function in a thread.
    /// If no thread is available, spawns a new one.
    pub fn spawn(&self, mut code: proc():Send) {
        use std::task;
        use std::sync::mpsc_queue::{Data, Empty, Inconsistent};

        loop {
            match self.free_tasks.pop() {
                Data(sender) => {
                    match sender.send_opt(code) {
                        Ok(_) => return,
                        Err(org) => code = org
                    }
                },
                Inconsistent =>
                    task::deschedule(),
                Empty => {
                    self.add_thread(Some(code));
                    return
                }
            }
        }
    }

    fn add_thread(&self, initial_fn: Option<proc():Send>) {
        use std::io::timer::Timer;

        let queue = self.free_tasks.clone();
        let active_tasks = self.active_tasks.clone();

        spawn(proc() {
            let active_tasks = active_tasks;
            let _ = Registration::new(active_tasks.clone());
            let mut timer = Timer::new().unwrap();

            if initial_fn.is_some() {
                let f = initial_fn.unwrap();
                f();
            }

            loop {
                let (tx, rx) = channel();
                queue.push(tx);

                let timeout = timer.oneshot(THREAD_IDLE_DIEAFTER);
                select! {
                    next_fn = rx.recv() => next_fn(),
                    _ = timeout.recv() => {
                        use std::sync::atomics::Relaxed;
                        if active_tasks.load(Relaxed) >= MIN_THREADS {
                            break
                        }
                    }
                }
            }
        })
    }
}

impl Drop for TaskPool {
    fn drop(&mut self) {
        use std::sync::atomics::Relaxed;
        self.active_tasks.store(999999999, Relaxed);
    }
}
<|endoftext|>


<commit_before>#![allow(unused, missing_docs)]

use std::fmt;
use std::iter::repeat;
use elements::{BlockType, External, FunctionType, GlobalEntry, GlobalType, Internal, MemoryType,
               Module, Opcode, ResizableLimits, TableType, Type, ValueType, InitExpr};
use common::stack;
use self::context::ModuleContext;
use self::func::Validator;

pub use self::module::ValidatedModule;

mod context;
mod module;
mod func;

#[cfg(test)]
mod tests;

pub struct Error(String);

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{}", self.0)
	}
}

impl From<stack::Error> for Error {
	fn from(e: stack::Error) -> Error {
		Error(format!("Stack: {}", e))
	}
}

pub fn validate_module(module: &Module) -> Result<ValidatedModule, Error> {
	let context = prepare_context(module)?;

	let function_section_len = module
		.function_section()
		.map(|s| s.entries().len())
		.unwrap_or(0);
	let code_section_len = module.code_section().map(|s| s.bodies().len()).unwrap_or(0);
	if function_section_len != code_section_len {
		return Err(Error(format!(
			"length of function section is {}, while len of code section is {}",
			function_section_len,
			code_section_len
		)));
	}

	// validate every function body in user modules
	if function_section_len != 0 {
		// tests use invalid code
		let function_section = module
			.function_section()
			.expect("function_section_len != 0; qed");
		let code_section = module
			.code_section()
			.expect("function_section_len != 0; function_section_len == code_section_len; qed");
		// check every function body
		for (index, function) in function_section.entries().iter().enumerate() {
			let function_body = code_section
				.bodies()
				.get(index as usize)
				.ok_or(Error(format!("Missing body for function {}", index)))?;
			Validator::validate_function(&context, function, function_body).map_err(|e| {
				let Error(ref msg) = e;
				Error(format!("Function #{} validation error: {}", index, msg))
			})?;
		}
	}

	// validate start section
	if let Some(start_function) = module.start_section() {
		let (params, return_ty) = context.require_function(start_function)?;
		if return_ty != BlockType::NoResult || params.len() != 0 {
			return Err(Error(
				"start function expected to have type [] -> []".into(),
			));
		}
	}

	// validate export section
	if let Some(export_section) = module.export_section() {
		for export in export_section.entries() {
			match export.internal() {
				&Internal::Function(function_index) => {
					context.require_function(function_index)?;
				}
				&Internal::Global(global_index) => {
					context.require_global(global_index, Some(false))?;
				}
				&Internal::Memory(memory_index) => {
					context.require_memory(memory_index)?;
				}
				&Internal::Table(table_index) => {
					context.require_table(table_index)?;
				}
			}
		}
	}

	// validate import section
	if let Some(import_section) = module.import_section() {
		for import in import_section.entries() {
			match import.external() {
				&External::Function(function_type_index) => {
					context.require_function(function_type_index)?;
				},
				&External::Global(ref global_type) => {
					if global_type.is_mutable() {
						return Err(Error(format!("trying to import mutable global {}", import.field())));
					}
				},
				&External::Memory(ref memory_type) => {
					memory_type.validate()?;
				},
				&External::Table(ref table_type) => {
					table_type.validate()?;
				},
			}
		}
	}

	// there must be no greater than 1 table in tables index space
	if context.tables().len() > 1 {
		return Err(Error(format!("too many tables in index space: {}", context.tables().len())));
	}

	// there must be no greater than 1 linear memory in memory index space
	if context.memories().len() > 1 {
		return Err(Error(format!("too many memory regions in index space: {}", context.memories().len())));
	}

	// use data section to initialize linear memory regions
	if let Some(data_section) = module.data_section() {
		for data_segment in data_section.entries() {
			context.require_memory(data_segment.index())?;
			let init_ty = data_segment.offset().expr_const_type(context.globals())?;
			if init_ty != ValueType::I32 {
				return Err(Error(format!("segment offset should return I32")));
			}
		}
	}

	// TODO: element section

	let ModuleContext {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	} = context;

	Ok(ValidatedModule {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	})
}

fn prepare_context(module: &Module) -> Result<ModuleContext, Error> {
	// Copy types from module as is.
	let types = module
		.type_section()
		.map(|ts| ts.types().into_iter().cloned().collect())
		.unwrap_or_default();

	// Fill elements with imported values.

	// TODO: Use Func::type_ref?
	let mut func_type_indexes = Vec::new();
	let mut tables = Vec::new();
	let mut memories = Vec::new();
	let mut globals = Vec::new();

	for import_entry in module
		.import_section()
		.map(|i| i.entries())
		.unwrap_or_default()
	{
		match import_entry.external() {
			&External::Function(idx) => func_type_indexes.push(idx),
			&External::Table(ref table) => tables.push(table.clone()),
			&External::Memory(ref memory) => memories.push(memory.clone()),
			&External::Global(ref global) => globals.push(global.clone()),
		}
	}

	// Concatenate elements with defined in the module.
	if let Some(function_section) = module.function_section() {
		for func_entry in function_section.entries() {
			func_type_indexes.push(func_entry.type_ref());
		}
	}
	if let Some(table_section) = module.table_section() {
		for table_entry in table_section.entries() {
			table_entry.validate()?;
			tables.push(table_entry.clone());
		}
	}
	if let Some(mem_section) = module.memory_section() {
		for mem_entry in mem_section.entries() {
			mem_entry.validate()?;
			memories.push(mem_entry.clone());
		}
	}
	if let Some(global_section) = module.global_section() {
		// Validation of globals is defined over modified context C', which
		// contains only imported globals. So we do globals validation
		// in two passes, in first we validate globals and after all globals are validated
		// add them in globals list.
		for global_entry in global_section.entries() {
			global_entry.validate(&globals)?;
		}

		for global_entry in global_section.entries() {
			globals.push(global_entry.global_type().clone());
		}
	}

	Ok(ModuleContext {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	})
}

impl ResizableLimits {
	fn validate(&self) -> Result<(), Error> {
		if let Some(maximum) = self.maximum() {
			if self.initial() > maximum {
				return Err(Error(format!(
					"maximum limit {} is lesser than minimum {}",
					maximum,
					self.initial()
				)));
			}
		}
		Ok(())
	}
}

impl MemoryType {
	fn validate(&self) -> Result<(), Error> {
		self.limits().validate()
	}
}

impl TableType {
	fn validate(&self) -> Result<(), Error> {
		self.limits().validate()
	}
}

impl GlobalEntry {
	fn validate(&self, globals: &[GlobalType]) -> Result<(), Error> {
		let init = self.init_expr();
		let init_expr_ty = init.expr_const_type(globals)?;
		if init_expr_ty != self.global_type().content_type() {
			return Err(Error(format!(
				"Trying to initialize variable of type {:?} with value of type {:?}",
				self.global_type().content_type(),
				init_expr_ty
			)));
		}
		Ok(())
	}
}

impl InitExpr {
	/// Returns type of this constant expression.
	fn expr_const_type(&self, globals: &[GlobalType]) -> Result<ValueType, Error> {
		let code = self.code();
		if code.len() != 2 {
			return Err(Error(
				format!("Init expression should always be with length 2")
			));
		}
		let expr_ty: ValueType = match code[0] {
			Opcode::I32Const(_) => ValueType::I32,
			Opcode::I64Const(_) => ValueType::I64,
			Opcode::F32Const(_) => ValueType::F32,
			Opcode::F64Const(_) => ValueType::F64,
			Opcode::GetGlobal(idx) => match globals.get(idx as usize) {
				Some(target_global) => {
					if target_global.is_mutable() {
						return Err(Error(format!("Global {} is mutable", idx)));
					}
					target_global.content_type()
				}
				None => {
					return Err(Error(
						format!("Global {} doesn't exists or not yet defined", idx),
					))
				}
			},
			_ => return Err(Error(format!("Non constant opcode in init expr"))),
		};
		if code[1] != Opcode::End {
			return Err(Error(format!("Expression doesn't ends with `end` opcode")));
		}
		Ok(expr_ty)
	}
}
<commit_msg>validate element section<commit_after>#![allow(unused, missing_docs)]

use std::fmt;
use std::iter::repeat;
use elements::{BlockType, External, FunctionType, GlobalEntry, GlobalType, Internal, MemoryType,
               Module, Opcode, ResizableLimits, TableType, Type, ValueType, InitExpr};
use common::stack;
use self::context::ModuleContext;
use self::func::Validator;

pub use self::module::ValidatedModule;

mod context;
mod module;
mod func;

#[cfg(test)]
mod tests;

pub struct Error(String);

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{}", self.0)
	}
}

impl From<stack::Error> for Error {
	fn from(e: stack::Error) -> Error {
		Error(format!("Stack: {}", e))
	}
}

pub fn validate_module(module: &Module) -> Result<ValidatedModule, Error> {
	let context = prepare_context(module)?;

	let function_section_len = module
		.function_section()
		.map(|s| s.entries().len())
		.unwrap_or(0);
	let code_section_len = module.code_section().map(|s| s.bodies().len()).unwrap_or(0);
	if function_section_len != code_section_len {
		return Err(Error(format!(
			"length of function section is {}, while len of code section is {}",
			function_section_len,
			code_section_len
		)));
	}

	// validate every function body in user modules
	if function_section_len != 0 {
		// tests use invalid code
		let function_section = module
			.function_section()
			.expect("function_section_len != 0; qed");
		let code_section = module
			.code_section()
			.expect("function_section_len != 0; function_section_len == code_section_len; qed");
		// check every function body
		for (index, function) in function_section.entries().iter().enumerate() {
			let function_body = code_section
				.bodies()
				.get(index as usize)
				.ok_or(Error(format!("Missing body for function {}", index)))?;
			Validator::validate_function(&context, function, function_body).map_err(|e| {
				let Error(ref msg) = e;
				Error(format!("Function #{} validation error: {}", index, msg))
			})?;
		}
	}

	// validate start section
	if let Some(start_function) = module.start_section() {
		let (params, return_ty) = context.require_function(start_function)?;
		if return_ty != BlockType::NoResult || params.len() != 0 {
			return Err(Error(
				"start function expected to have type [] -> []".into(),
			));
		}
	}

	// validate export section
	if let Some(export_section) = module.export_section() {
		for export in export_section.entries() {
			match export.internal() {
				&Internal::Function(function_index) => {
					context.require_function(function_index)?;
				}
				&Internal::Global(global_index) => {
					context.require_global(global_index, Some(false))?;
				}
				&Internal::Memory(memory_index) => {
					context.require_memory(memory_index)?;
				}
				&Internal::Table(table_index) => {
					context.require_table(table_index)?;
				}
			}
		}
	}

	// validate import section
	if let Some(import_section) = module.import_section() {
		for import in import_section.entries() {
			match import.external() {
				&External::Function(function_type_index) => {
					context.require_function(function_type_index)?;
				},
				&External::Global(ref global_type) => {
					if global_type.is_mutable() {
						return Err(Error(format!("trying to import mutable global {}", import.field())));
					}
				},
				&External::Memory(ref memory_type) => {
					memory_type.validate()?;
				},
				&External::Table(ref table_type) => {
					table_type.validate()?;
				},
			}
		}
	}

	// there must be no greater than 1 table in tables index space
	if context.tables().len() > 1 {
		return Err(Error(format!("too many tables in index space: {}", context.tables().len())));
	}

	// there must be no greater than 1 linear memory in memory index space
	if context.memories().len() > 1 {
		return Err(Error(format!("too many memory regions in index space: {}", context.memories().len())));
	}

	// use data section to initialize linear memory regions
	if let Some(data_section) = module.data_section() {
		for data_segment in data_section.entries() {
			context.require_memory(data_segment.index())?;
			let init_ty = data_segment.offset().expr_const_type(context.globals())?;
			if init_ty != ValueType::I32 {
				return Err(Error(format!("segment offset should return I32")));
			}
		}
	}

	// use element section to fill tables
	if let Some(element_section) = module.elements_section() {
		for element_segment in element_section.entries() {
			context.require_table(element_segment.index())?;

			let init_ty = element_segment.offset().expr_const_type(context.globals())?;
			if init_ty != ValueType::I32 {
				return Err(Error(format!("segment offset should return I32")));
			}

			for function_index in element_segment.members() {
				context.require_function(*function_index)?;
			}
		}
	}

	let ModuleContext {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	} = context;

	Ok(ValidatedModule {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	})
}

fn prepare_context(module: &Module) -> Result<ModuleContext, Error> {
	// Copy types from module as is.
	let types = module
		.type_section()
		.map(|ts| ts.types().into_iter().cloned().collect())
		.unwrap_or_default();

	// Fill elements with imported values.

	// TODO: Use Func::type_ref?
	let mut func_type_indexes = Vec::new();
	let mut tables = Vec::new();
	let mut memories = Vec::new();
	let mut globals = Vec::new();

	for import_entry in module
		.import_section()
		.map(|i| i.entries())
		.unwrap_or_default()
	{
		match import_entry.external() {
			&External::Function(idx) => func_type_indexes.push(idx),
			&External::Table(ref table) => tables.push(table.clone()),
			&External::Memory(ref memory) => memories.push(memory.clone()),
			&External::Global(ref global) => globals.push(global.clone()),
		}
	}

	// Concatenate elements with defined in the module.
	if let Some(function_section) = module.function_section() {
		for func_entry in function_section.entries() {
			func_type_indexes.push(func_entry.type_ref());
		}
	}
	if let Some(table_section) = module.table_section() {
		for table_entry in table_section.entries() {
			table_entry.validate()?;
			tables.push(table_entry.clone());
		}
	}
	if let Some(mem_section) = module.memory_section() {
		for mem_entry in mem_section.entries() {
			mem_entry.validate()?;
			memories.push(mem_entry.clone());
		}
	}
	if let Some(global_section) = module.global_section() {
		// Validation of globals is defined over modified context C', which
		// contains only imported globals. So we do globals validation
		// in two passes, in first we validate globals and after all globals are validated
		// add them in globals list.
		for global_entry in global_section.entries() {
			global_entry.validate(&globals)?;
		}

		for global_entry in global_section.entries() {
			globals.push(global_entry.global_type().clone());
		}
	}

	Ok(ModuleContext {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	})
}

impl ResizableLimits {
	fn validate(&self) -> Result<(), Error> {
		if let Some(maximum) = self.maximum() {
			if self.initial() > maximum {
				return Err(Error(format!(
					"maximum limit {} is lesser than minimum {}",
					maximum,
					self.initial()
				)));
			}
		}
		Ok(())
	}
}

impl MemoryType {
	fn validate(&self) -> Result<(), Error> {
		self.limits().validate()
	}
}

impl TableType {
	fn validate(&self) -> Result<(), Error> {
		self.limits().validate()
	}
}

impl GlobalEntry {
	fn validate(&self, globals: &[GlobalType]) -> Result<(), Error> {
		let init = self.init_expr();
		let init_expr_ty = init.expr_const_type(globals)?;
		if init_expr_ty != self.global_type().content_type() {
			return Err(Error(format!(
				"Trying to initialize variable of type {:?} with value of type {:?}",
				self.global_type().content_type(),
				init_expr_ty
			)));
		}
		Ok(())
	}
}

impl InitExpr {
	/// Returns type of this constant expression.
	fn expr_const_type(&self, globals: &[GlobalType]) -> Result<ValueType, Error> {
		let code = self.code();
		if code.len() != 2 {
			return Err(Error(
				format!("Init expression should always be with length 2")
			));
		}
		let expr_ty: ValueType = match code[0] {
			Opcode::I32Const(_) => ValueType::I32,
			Opcode::I64Const(_) => ValueType::I64,
			Opcode::F32Const(_) => ValueType::F32,
			Opcode::F64Const(_) => ValueType::F64,
			Opcode::GetGlobal(idx) => match globals.get(idx as usize) {
				Some(target_global) => {
					if target_global.is_mutable() {
						return Err(Error(format!("Global {} is mutable", idx)));
					}
					target_global.content_type()
				}
				None => {
					return Err(Error(
						format!("Global {} doesn't exists or not yet defined", idx),
					))
				}
			},
			_ => return Err(Error(format!("Non constant opcode in init expr"))),
		};
		if code[1] != Opcode::End {
			return Err(Error(format!("Expression doesn't ends with `end` opcode")));
		}
		Ok(expr_ty)
	}
}
<|endoftext|>


<commit_before>// This module implements configuration related stuff.
// Copyright (c) 2014 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use std::collections::TreeMap;
use serialize::json::Json;

/// Currently we are using `JsonObject` as config type.  Works like
/// a JSON Object but provides ways to fill it from JSON files:
///
/// ```rust
/// app.config.from_jsonfile("yourconfig.json")
/// ```
///
/// You can also load configurations from an environment variable
/// pointing to a file:
///
/// ```rust
/// app.config.from_envvar("YOURAPPLICATION_SETTINGS")
/// ```
///
/// In this case, you have to set this environment variable to the file
/// you want to use.  On Linux and OS X you can use the export statement:
///
/// ```bash
/// export YOURAPPLICATION_SETTINGS="/path/to/config/file"
/// ```
///
pub type Config = TreeMap<String, Json>;

impl Config {
    pub fn from_jsonfile(&mut self, filepath: Path) {
        ()
    }
}
<commit_msg>Fixed config<commit_after>// This module implements configuration related stuff.
// Copyright (c) 2014 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use serialize::json::JsonObject;

pub trait ConfigTrait {
    fn from_jsonfile(&mut self, filepath: Path) -> Path {
        filepath
    }
}

/// Currently we are using `JsonObject` as config type.  Works like
/// a JSON Object but provides ways to fill it from JSON files:
///
/// ```rust
/// app.config.from_jsonfile("yourconfig.json")
/// ```
///
/// You can also load configurations from an environment variable
/// pointing to a file:
///
/// ```rust
/// app.config.from_envvar("YOURAPPLICATION_SETTINGS")
/// ```
///
/// In this case, you have to set this environment variable to the file
/// you want to use.  On Linux and OS X you can use the export statement:
///
/// ```bash
/// export YOURAPPLICATION_SETTINGS="/path/to/config/file"
/// ```
///
pub type Config = JsonObject;

impl ConfigTrait for Config {
}
<|endoftext|>


<commit_before>//! Provides a type for the task state segment structure.

use crate::VirtAddr;

/// In 64-bit mode the TSS holds information that is not
/// directly related to the task-switch mechanism,
/// but is used for finding kernel level stack
/// if interrupts arrive while in kernel mode.
#[derive(Debug, Clone, Copy)]
#[repr(C, packed)]
pub struct TaskStateSegment {
    reserved_1: u32,
    /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
    pub privilege_stack_table: [VirtAddr; 3],
    reserved_2: u64,
    /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
    pub interrupt_stack_table: [VirtAddr; 7],
    reserved_3: u64,
    reserved_4: u16,
    /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base.
    pub iomap_base: u16,
}

impl TaskStateSegment {
    /// Creates a new TSS with zeroed privilege and interrupt stack table and a zero
    /// `iomap_base`.
    #[inline]
    pub const fn new() -> TaskStateSegment {
        TaskStateSegment {
            privilege_stack_table: [VirtAddr::zero(); 3],
            interrupt_stack_table: [VirtAddr::zero(); 7],
            iomap_base: 0,
            reserved_1: 0,
            reserved_2: 0,
            reserved_3: 0,
            reserved_4: 0,
        }
    }
}
<commit_msg>tss: Initialize iopb to be empty instead of zero<commit_after>//! Provides a type for the task state segment structure.

use crate::VirtAddr;
use core::mem::size_of;

/// In 64-bit mode the TSS holds information that is not
/// directly related to the task-switch mechanism,
/// but is used for finding kernel level stack
/// if interrupts arrive while in kernel mode.
#[derive(Debug, Clone, Copy)]
#[repr(C, packed)]
pub struct TaskStateSegment {
    reserved_1: u32,
    /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
    pub privilege_stack_table: [VirtAddr; 3],
    reserved_2: u64,
    /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
    pub interrupt_stack_table: [VirtAddr; 7],
    reserved_3: u64,
    reserved_4: u16,
    /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base.
    pub iomap_base: u16,
}

impl TaskStateSegment {
    /// Creates a new TSS with zeroed privilege and interrupt stack table and an
    /// empty I/O-Permission Bitmap.
    ///
    /// As we always set the TSS segment limit to
    /// `size_of::<TaskStateSegment>() - 1`, this means that `iomap_base` is
    /// initialized to `size_of::<TaskStateSegment>()`.
    #[inline]
    pub const fn new() -> TaskStateSegment {
        TaskStateSegment {
            privilege_stack_table: [VirtAddr::zero(); 3],
            interrupt_stack_table: [VirtAddr::zero(); 7],
            iomap_base: size_of::<TaskStateSegment>() as u16,
            reserved_1: 0,
            reserved_2: 0,
            reserved_3: 0,
            reserved_4: 0,
        }
    }
}

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

    #[test]
    pub fn check_tss_size() {
        // Per the SDM, the minimum size of a TSS is 0x68 bytes, giving a
        // minimum limit of 0x67.
        assert_eq!(size_of::<TaskStateSegment>(), 0x68);
    }
}
<|endoftext|>