<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};

/// 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), ()>;
<commit_msg>Some comments cleanup<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.
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>use std::fmt;
use std::str::FromStr;
use std::slice;
use nom::IResult;
use expression::Expression;
use term::Term;
use parsers;
use error::Error;

/// A Production is comprised of any number of Expressions
#[derive(PartialEq, Debug, Clone)]
pub struct Production {
    pub lhs: Term,
    rhs: Vec<Expression>,
}

impl Production {
    /// Construct a new `Production`
    pub fn new() -> Production {
        Production {
            lhs: Term::Nonterminal(String::new()),
            rhs: vec![],
        }
    }

    /// Construct an `Production` from `Expression`s
    pub fn from_parts(t: Term, e: Vec<Expression>) -> Production {
        Production { lhs: t, rhs: e }
    }

    // Get `Production` by parsing a string
    pub fn from_str(s: &str) -> Result<Self, Error> {
        match parsers::production_complete(s.as_bytes()) {
            IResult::Done(_, o) => Ok(o),
            IResult::Incomplete(n) => Err(Error::from(n)),
            IResult::Error(e) => Err(Error::from(e)),
        }
    }

    /// Add `Expression` to the `Production`'s right hand side
    pub fn add_to_rhs(&mut self, expr: Expression) {
        self.rhs.push(expr)
    }

    /// Remove `Expression` from the `Production`'s right hand side
    ///
    /// If interested if `Expression` was removed, then inspect the returned `Option`.
    pub fn remove_from_rhs(&mut self, expr: &Expression) -> Option<Expression> {
        if let Some(pos) = self.rhs.iter().position(|x| *x == *expr) {
            Some(self.rhs.remove(pos))
        } else {
            None
        }
    }

    /// Get iterator of the `Production`'s right hand side `Expression`s
    pub fn rhs_iter(&self) -> Iter {
        Iter { iterator: self.rhs.iter() }
    }

    /// Get mutable iterator of the `Production`'s right hand side `Expression`s
    pub fn rhs_iter_mut(&mut self) -> IterMut {
        IterMut { iterator: self.rhs.iter_mut() }
    }
}

impl fmt::Display for Production {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{} ::= {}",
            self.lhs.to_string(),
            self.rhs
                .iter()
                .map(|s| s.to_string())
                .collect::<Vec<_>>()
                .join(" | ")
        )
    }
}

impl FromStr for Production {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::from_str(s)
    }
}

pub struct Iter<'a> {
    iterator: slice::Iter<'a, Expression>,
}

impl<'a> Iterator for Iter<'a> {
    type Item = &'a Expression;

    fn next(&mut self) -> Option<Self::Item> {
        self.iterator.next()
    }
}

pub struct IterMut<'a> {
    iterator: slice::IterMut<'a, Expression>,
}

impl<'a> Iterator for IterMut<'a> {
    type Item = &'a mut Expression;

    fn next(&mut self) -> Option<Self::Item> {
        self.iterator.next()
    }
}

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

    #[test]
    fn new_productions() {
        let lhs1: Term = Term::Nonterminal(String::from("STRING A"));
        let rhs1: Expression = Expression::from_parts(vec![
            Term::Terminal(String::from("STRING B")),
            Term::Nonterminal(String::from("STRING C")),
        ]);
        let p1: Production = Production::from_parts(lhs1, vec![rhs1]);

        let lhs2: Term = Term::Nonterminal(String::from("STRING A"));
        let rhs2: Expression = Expression::from_parts(vec![
            Term::Terminal(String::from("STRING B")),
            Term::Nonterminal(String::from("STRING C")),
        ]);
        let mut p2: Production = Production::new();
        p2.lhs = lhs2;
        p2.add_to_rhs(rhs2);

        assert_eq!(p1, p2);
    }

    #[test]
    fn remove_from_rhs() {
        let lhs = Term::Nonterminal(String::from("dna"));
        let last = Expression::from_parts(vec![Term::Nonterminal(String::from("base"))]);
        let one_more = Expression::from_parts(vec![
            Term::Nonterminal(String::from("base")),
            Term::Nonterminal(String::from("dna")),
        ]);
        // unnecessary expression to be removed from production
        let two_more = Expression::from_parts(vec![
            Term::Nonterminal(String::from("base")),
            Term::Nonterminal(String::from("base")),
            Term::Nonterminal(String::from("dna")),
        ]);
        let expression_list = vec![last, one_more, two_more.clone()];
        let mut production = Production::from_parts(lhs, expression_list.clone());
        let removed = production.remove_from_rhs(&two_more);

        // the removed element should be the accident
        assert_eq!(Some(two_more.clone()), removed);
        // number of productions should have decreased
        assert_eq!(production.rhs_iter().count(), expression_list.len() - 1);
        // the unnecessary should no longer be found
        assert_eq!(
            production.rhs_iter().find(
                |&expression| *expression == two_more,
            ),
            None
        );
    }

    #[test]
    fn remove_nonexistent_from_rhs() {
        let lhs = Term::Nonterminal(String::from("dna"));
        let last = Expression::from_parts(vec![Term::Nonterminal(String::from("base"))]);
        let one_more = Expression::from_parts(vec![
            Term::Terminal(String::from("base")),
            Term::Nonterminal(String::from("dna")),
        ]);
        let expression_list = vec![last, one_more];
        let mut production = Production::from_parts(lhs, expression_list.clone());

        // unused expression to fail being removed from production
        let two_more = Expression::from_parts(vec![
            Term::Nonterminal(String::from("base")),
            Term::Nonterminal(String::from("base")),
            Term::Nonterminal(String::from("dna")),
        ]);
        let removed = production.remove_from_rhs(&two_more);

        // the unused term should not be found in the terms
        assert_eq!(production.rhs_iter().find(|&expr| *expr == two_more), None);
        // no term should have been removed
        assert_eq!(None, removed);
        // number of terms should not have decreased
        assert_eq!(production.rhs_iter().count(), expression_list.len());
    }

    #[test]
    fn parse_complete() {
        let lhs = Term::Nonterminal(String::from("dna"));
        let last = Expression::from_parts(vec![Term::Nonterminal(String::from("base"))]);
        let one_more = Expression::from_parts(vec![
            Term::Nonterminal(String::from("base")),
            Term::Nonterminal(String::from("dna")),
        ]);
        let production = Production::from_parts(lhs, vec![last, one_more]);
        assert_eq!(
            Ok(production),
            Production::from_str("<dna> ::= <base> | <base> <dna>")
        );
    }

    #[test]
    fn parse_error() {
        let result = Production::from_str("<base> ::= \"A\" | \"C\" | \"G\" |");
        assert!(
            result.is_err(),
            "production result should be error {:?}",
            result
        );

        let production = result.unwrap_err();
        match production {
            Error::ParseError(_) => (),
            e => panic!("production error should be error: {:?}", e),
        }
    }

    #[test]
    fn parse_incomplete() {
        let result = Production::from_str("");
        assert!(result.is_err(), "{:?} should be err", result);
        match result {
            Err(e) => {
                match e {
                    Error::ParseIncomplete(_) => (),
                    e => panic!("should should be Error::ParseIncomplete: {:?}", e),
                }
            }
            Ok(s) => panic!("should should be Error::ParseIncomplete: {}", s),
        }
    }

    #[test]
    fn parse_semicolon_separated() {
        let result = Production::from_str("<base> ::= \"A\" ; \"C\" ; \"G\" ; \"T\"");
        assert!(result.is_err(), "{:?} should be error", result);

        let production = result.unwrap_err();
        match production {
            Error::ParseError(_) => (),
            e => panic!("invalid production should be parsing error: {:?}", e),
        }
    }
}
<commit_msg>Test Production to_string and from_str property<commit_after>use std::fmt;
use std::str::FromStr;
use std::slice;
use nom::IResult;
use expression::Expression;
use term::Term;
use parsers;
use error::Error;

/// A Production is comprised of any number of Expressions
#[derive(PartialEq, Debug, Clone)]
pub struct Production {
    pub lhs: Term,
    rhs: Vec<Expression>,
}

impl Production {
    /// Construct a new `Production`
    pub fn new() -> Production {
        Production {
            lhs: Term::Nonterminal(String::new()),
            rhs: vec![],
        }
    }

    /// Construct an `Production` from `Expression`s
    pub fn from_parts(t: Term, e: Vec<Expression>) -> Production {
        Production { lhs: t, rhs: e }
    }

    // Get `Production` by parsing a string
    pub fn from_str(s: &str) -> Result<Self, Error> {
        match parsers::production_complete(s.as_bytes()) {
            IResult::Done(_, o) => Ok(o),
            IResult::Incomplete(n) => Err(Error::from(n)),
            IResult::Error(e) => Err(Error::from(e)),
        }
    }

    /// Add `Expression` to the `Production`'s right hand side
    pub fn add_to_rhs(&mut self, expr: Expression) {
        self.rhs.push(expr)
    }

    /// Remove `Expression` from the `Production`'s right hand side
    ///
    /// If interested if `Expression` was removed, then inspect the returned `Option`.
    pub fn remove_from_rhs(&mut self, expr: &Expression) -> Option<Expression> {
        if let Some(pos) = self.rhs.iter().position(|x| *x == *expr) {
            Some(self.rhs.remove(pos))
        } else {
            None
        }
    }

    /// Get iterator of the `Production`'s right hand side `Expression`s
    pub fn rhs_iter(&self) -> Iter {
        Iter { iterator: self.rhs.iter() }
    }

    /// Get mutable iterator of the `Production`'s right hand side `Expression`s
    pub fn rhs_iter_mut(&mut self) -> IterMut {
        IterMut { iterator: self.rhs.iter_mut() }
    }
}

impl fmt::Display for Production {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{} ::= {}",
            self.lhs.to_string(),
            self.rhs
                .iter()
                .map(|s| s.to_string())
                .collect::<Vec<_>>()
                .join(" | ")
        )
    }
}

impl FromStr for Production {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::from_str(s)
    }
}

pub struct Iter<'a> {
    iterator: slice::Iter<'a, Expression>,
}

impl<'a> Iterator for Iter<'a> {
    type Item = &'a Expression;

    fn next(&mut self) -> Option<Self::Item> {
        self.iterator.next()
    }
}

pub struct IterMut<'a> {
    iterator: slice::IterMut<'a, Expression>,
}

impl<'a> Iterator for IterMut<'a> {
    type Item = &'a mut Expression;

    fn next(&mut self) -> Option<Self::Item> {
        self.iterator.next()
    }
}

#[cfg(test)]
mod tests {
    extern crate quickcheck;
    extern crate rand;

    use self::quickcheck::{Arbitrary, Gen, QuickCheck, StdGen, TestResult};
    use super::*;

    impl Arbitrary for Production {
        fn arbitrary<G: Gen>(g: &mut G) -> Self {
            let lhs_str = String::arbitrary(g)
                .chars()
                .filter(|&c| (c != '>'))
                .collect();

            let lhs = Term::Nonterminal(lhs_str);

            let mut rhs = Vec::<Expression>::arbitrary(g);
            if rhs.len() < 1 {
                rhs.push(Expression::arbitrary(g));
            }
            Production { lhs: lhs, rhs: rhs }
        }
    }

    fn prop_to_string_and_back(prop: Production) -> TestResult {
        let to_string = prop.to_string();
        let from_str = Production::from_str(&to_string);
        match from_str {
            Ok(from_prod) => TestResult::from_bool(from_prod == prop),
            _ => TestResult::error(format!("{} to string and back should be safe", prop)),
        }
    }

    #[test]
    fn to_string_and_back() {
        QuickCheck::new()
            .tests(1000)
            .gen(StdGen::new(rand::thread_rng(), 25usize))
            .quickcheck(prop_to_string_and_back as fn(Production) -> TestResult)
    }

    #[test]
    fn new_productions() {
        let lhs1: Term = Term::Nonterminal(String::from("STRING A"));
        let rhs1: Expression = Expression::from_parts(vec![
            Term::Terminal(String::from("STRING B")),
            Term::Nonterminal(String::from("STRING C")),
        ]);
        let p1: Production = Production::from_parts(lhs1, vec![rhs1]);

        let lhs2: Term = Term::Nonterminal(String::from("STRING A"));
        let rhs2: Expression = Expression::from_parts(vec![
            Term::Terminal(String::from("STRING B")),
            Term::Nonterminal(String::from("STRING C")),
        ]);
        let mut p2: Production = Production::new();
        p2.lhs = lhs2;
        p2.add_to_rhs(rhs2);

        assert_eq!(p1, p2);
    }

    #[test]
    fn remove_from_rhs() {
        let lhs = Term::Nonterminal(String::from("dna"));
        let last = Expression::from_parts(vec![Term::Nonterminal(String::from("base"))]);
        let one_more = Expression::from_parts(vec![
            Term::Nonterminal(String::from("base")),
            Term::Nonterminal(String::from("dna")),
        ]);
        // unnecessary expression to be removed from production
        let two_more = Expression::from_parts(vec![
            Term::Nonterminal(String::from("base")),
            Term::Nonterminal(String::from("base")),
            Term::Nonterminal(String::from("dna")),
        ]);
        let expression_list = vec![last, one_more, two_more.clone()];
        let mut production = Production::from_parts(lhs, expression_list.clone());
        let removed = production.remove_from_rhs(&two_more);

        // the removed element should be the accident
        assert_eq!(Some(two_more.clone()), removed);
        // number of productions should have decreased
        assert_eq!(production.rhs_iter().count(), expression_list.len() - 1);
        // the unnecessary should no longer be found
        assert_eq!(
            production.rhs_iter().find(
                |&expression| *expression == two_more,
            ),
            None
        );
    }

    #[test]
    fn remove_nonexistent_from_rhs() {
        let lhs = Term::Nonterminal(String::from("dna"));
        let last = Expression::from_parts(vec![Term::Nonterminal(String::from("base"))]);
        let one_more = Expression::from_parts(vec![
            Term::Terminal(String::from("base")),
            Term::Nonterminal(String::from("dna")),
        ]);
        let expression_list = vec![last, one_more];
        let mut production = Production::from_parts(lhs, expression_list.clone());

        // unused expression to fail being removed from production
        let two_more = Expression::from_parts(vec![
            Term::Nonterminal(String::from("base")),
            Term::Nonterminal(String::from("base")),
            Term::Nonterminal(String::from("dna")),
        ]);
        let removed = production.remove_from_rhs(&two_more);

        // the unused term should not be found in the terms
        assert_eq!(production.rhs_iter().find(|&expr| *expr == two_more), None);
        // no term should have been removed
        assert_eq!(None, removed);
        // number of terms should not have decreased
        assert_eq!(production.rhs_iter().count(), expression_list.len());
    }

    #[test]
    fn parse_complete() {
        let lhs = Term::Nonterminal(String::from("dna"));
        let last = Expression::from_parts(vec![Term::Nonterminal(String::from("base"))]);
        let one_more = Expression::from_parts(vec![
            Term::Nonterminal(String::from("base")),
            Term::Nonterminal(String::from("dna")),
        ]);
        let production = Production::from_parts(lhs, vec![last, one_more]);
        assert_eq!(
            Ok(production),
            Production::from_str("<dna> ::= <base> | <base> <dna>")
        );
    }

    #[test]
    fn parse_error() {
        let result = Production::from_str("<base> ::= \"A\" | \"C\" | \"G\" |");
        assert!(
            result.is_err(),
            "production result should be error {:?}",
            result
        );

        let production = result.unwrap_err();
        match production {
            Error::ParseError(_) => (),
            e => panic!("production error should be error: {:?}", e),
        }
    }

    #[test]
    fn parse_incomplete() {
        let result = Production::from_str("");
        assert!(result.is_err(), "{:?} should be err", result);
        match result {
            Err(e) => {
                match e {
                    Error::ParseIncomplete(_) => (),
                    e => panic!("should should be Error::ParseIncomplete: {:?}", e),
                }
            }
            Ok(s) => panic!("should should be Error::ParseIncomplete: {}", s),
        }
    }

    #[test]
    fn parse_semicolon_separated() {
        let result = Production::from_str("<base> ::= \"A\" ; \"C\" ; \"G\" ; \"T\"");
        assert!(result.is_err(), "{:?} should be error", result);

        let production = result.unwrap_err();
        match production {
            Error::ParseError(_) => (),
            e => panic!("invalid production should be parsing error: {:?}", e),
        }
    }
}
<|endoftext|>


<commit_before>use cast::transmute;
use cmp::Eq;
use num::from_int;
use ptr::to_unsafe_ptr;
use vec::raw::buf_as_slice;
use std::cmp::FuzzyEq;

use funs::exp::*;
use funs::trig::*;
use funs::common::*;
use math::*;
use matrix::{Mat3, Mat4};
use ncast::*;
use vector::Vec3;

// These quaternion type aliases are not actually specified in the GLSL spec
// but they follow the same nomenclature

pub type quat4  = Quat<f32>;         /// a single-precision floating-point quaternion
pub type dquat4 = Quat<f64>;         /// a double-precision floating-point quaternion

//
//  Quaternion
//
pub trait Quaternion<T> {
    pure fn dim() -> uint;

    pure fn mul_t(value: T) -> self;
    pure fn div_t(value: T) -> self;

    // pure fn mul_v(other: &Vec3) -> Vec3;

    pure fn add_q(other: &self) -> self;
    pure fn sub_q(other: &self) -> self;
    pure fn mul_q(other: &self) -> self;

    pure fn dot(other: &self) -> T;

    pure fn conjugate() -> self;
    pure fn inverse() -> self;
    pure fn length2() -> T;
    pure fn length() -> T;
    pure fn normalize() -> self;

    pure fn nlerp(other: &self, amount: T) -> self;
    pure fn slerp(other: &self, amount: T) -> self;

    pure fn to_Mat3() -> Mat3<T>;
    pure fn to_Mat4() -> Mat4<T>;
}

pub trait ToQuat<T> {
    pure fn to_Quat() -> Quat<T>;
}

pub struct Quat<T> { w: T, x: T, y: T, z: T }

pub mod Quat {

    #[inline(always)]
    pub pure fn new<T>(w: T, x: T, y: T, z: T) -> Quat<T> {
        Quat { w: move w, x: move x, y: move y, z: move z }
    }

    #[inline(always)]
    pub pure fn from_sv<T:Copy>(s: T, v: Vec3<T>) -> Quat<T> {
        Quat::new(s, v.x, v.y, v.z)
    }

    #[inline(always)]
    pub pure fn zero<T:Copy NumCast>() -> Quat<T> {
        let _0 = cast(0);
        Quat::new(_0, _0, _0, _0)
    }

    #[inline(always)]
    pub pure fn identity<T:Copy NumCast>() -> Quat<T> {
        let _0 = cast(0);
        Quat::new(cast(1), _0, _0, _0)
    }
}

pub impl<T:Copy Num NumCast Trig Exp Extent Ord FuzzyEq> Quat<T>: Quaternion<T> {
    #[inline(always)]
    pure fn dim() -> uint { 4 }

    #[inline(always)]
    pure fn mul_t(value: T) -> Quat<T> {
        Quat::new(self[0] * value,
                  self[1] * value,
                  self[2] * value,
                  self[3] * value)
    }

    #[inline(always)]
    pure fn div_t(value: T) -> Quat<T> {
        Quat::new(self[0] / value,
                  self[1] / value,
                  self[2] / value,
                  self[3] / value)
    }

    #[inline(always)]
    pure fn add_q(other: &Quat<T>) -> Quat<T> {
        Quat::new(self[0] + other[0],
                  self[1] + other[1],
                  self[2] + other[2],
                  self[3] + other[3])
    }

    #[inline(always)]
    pure fn sub_q(other: &Quat<T>) -> Quat<T> {
        Quat::new(self[0] - other[0],
                  self[1] - other[1],
                  self[2] - other[2],
                  self[3] - other[3])
    }

    #[inline(always)]
    pure fn mul_q(other: &Quat<T>) -> Quat<T> {
        Quat::new(self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z,
                  self.w * other.x + self.x * other.w + self.y * other.z - self.z * other.y,
                  self.w * other.y + self.y * other.w + self.z * other.x - self.x * other.z,
                  self.w * other.z + self.z * other.w + self.x * other.y - self.y * other.x)
    }

    #[inline(always)]
    pure fn dot(other: &Quat<T>) -> T {
        self.w * other.w +
        self.x * other.x +
        self.y * other.y +
        self.z * other.z
    }

    #[inline(always)]
    pure fn conjugate() -> Quat<T> {
        Quat::new(self.w, -self.x, -self.y, -self.z)
    }

    #[inline(always)]
    pure fn inverse() -> Quat<T> {
        let mut n: T = from_int(1);
        n /= self.length2();
        self.conjugate().mul_t(n)
    }

    #[inline(always)]
    pure fn length2() -> T {
        self.w * self.w +
        self.x * self.x +
        self.y * self.y +
        self.z * self.z
    }

    #[inline(always)]
    pure fn length() -> T {
        self.length2().sqrt()
    }

    #[inline(always)]
    pure fn normalize() -> Quat<T> {
        let mut n: T = cast(1);
        n /= self.length();
        return self.mul_t(n);
    }

    #[inline(always)]
    pure fn nlerp(other: &Quat<T>, amount: T) -> Quat<T> {
        let _1: T = cast(1);
        self.mul_t(_1 - amount).add_q(&other.mul_t(amount)).normalize()
    }

    /**
     * Spherical Linear Intoperlation
     *
     * Both quaternions should be normalized first, or else strange things will
     * will happen...
     *
     * Note: The `acos` used in `slerp` is an expensive operation, so unless your
     * quarternions a far away from each other it's generally more advisable to
     * use nlerp when you know your rotations are going to be small.
     *
     * See *[Understanding Slerp, Then Not Using It]
     * (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/)*
     * for more information. The [Arcsynthesis OpenGL tutorial]
     * (http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Interpolation.html)
     * also provides a good explanation.
     */
    #[inline(always)]
    pure fn slerp(other: &Quat<T>, amount: T) -> Quat<T> {
        let dot: T = cast(self.dot(other));

        // if quaternions are close together use `nlerp`
        let dot_threshold = cast(0.9995);
        if dot > dot_threshold { return self.nlerp(other, amount) }

        let robust_dot = dot.clamp(&-cast(1), &cast(1));    // stay within the domain of acos()
        let theta_0 = acos(&robust_dot);                    // the angle between the quaternions
        let theta = theta_0 * amount;                       // the fraction of theta specified by `amount`

        let q = other.sub_q(&self.mul_t(robust_dot))
                     .normalize();

        self.mul_t(cos(&theta)).add_q(&q.mul_t(sin(&theta)))
    }

    #[inline(always)]
    pure fn to_Mat3() -> Mat3<T> {
        let x2 = self.x + self.x;
        let y2 = self.y + self.y;
        let z2 = self.z + self.z;

        let xx2 = x2 * self.x;
        let xy2 = x2 * self.y;
        let xz2 = x2 * self.z;

        let yy2 = y2 * self.y;
        let yz2 = y2 * self.z;
        let zz2 = z2 * self.z;

        let wy2 = y2 * self.w;
        let wz2 = z2 * self.w;
        let wx2 = x2 * self.w;

        let _1: T = from_int(1);

        Mat3::new(_1 - yy2 - zz2,      xy2 - wz2,      xz2 + wy2,
                       xy2 + wz2, _1 - xx2 - zz2,      yz2 - wx2,
                       xz2 - wy2,      yz2 + wx2, _1 - xx2 - yy2)
    }

    #[inline(always)]
    pure fn to_Mat4() -> Mat4<T> {
        self.to_Mat3().to_Mat4()
    }
}

pub impl<T:Copy> Quat<T>: Index<uint, T> {
    #[inline(always)]
    pure fn index(i: uint) -> T {
        unsafe { do buf_as_slice(
            transmute::<*Quat<T>, *T>(
                to_unsafe_ptr(&self)), 4) |slice| { slice[i] }
        }
    }
}

pub impl<T:Copy Neg<T>> Quat<T>: Neg<Quat<T>> {
    #[inline(always)]
    pure fn neg() -> Quat<T> {
        Quat::new(-self[0], -self[1], -self[2], -self[3])
    }
}

// TODO: make work for T:Integer
pub impl<T:Copy FuzzyEq> Quat<T>: Eq {
    #[inline(always)]
    pure fn eq(other: &Quat<T>) -> bool {
        self.fuzzy_eq(other)
    }

    #[inline(always)]
    pure fn ne(other: &Quat<T>) -> bool {
        !(self == *other)
    }
}

pub impl<T:Copy Eq> Quat<T>: ExactEq {
    #[inline(always)]
    pure fn exact_eq(other: &Quat<T>) -> bool {
        self[0] == other[0] &&
        self[1] == other[1] &&
        self[2] == other[2] &&
        self[3] == other[3]
    }
}

pub impl<T:Copy FuzzyEq> Quat<T>: FuzzyEq {
    #[inline(always)]
    pure fn fuzzy_eq(other: &Quat<T>) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1]) &&
        self[2].fuzzy_eq(&other[2]) &&
        self[3].fuzzy_eq(&other[3])
    }
}

pub impl<T:Copy> Quat<T>: ToPtr<T> {
    #[inline(always)]
    pure fn to_ptr() -> *T {
        to_unsafe_ptr(&self[0])
    }
}<commit_msg>Add mul_v method and from_axis_angle function (thanks Dzmitry)<commit_after>use cast::transmute;
use cmp::Eq;
use num::from_int;
use ptr::to_unsafe_ptr;
use vec::raw::buf_as_slice;
use std::cmp::FuzzyEq;

use funs::exp::*;
use funs::trig::*;
use funs::common::*;
use math::*;
use matrix::{Mat3, Mat4};
use ncast::*;
use vector::Vec3;

// These quaternion type aliases are not actually specified in the GLSL spec
// but they follow the same nomenclature

pub type quat4  = Quat<f32>;         /// a single-precision floating-point quaternion
pub type dquat4 = Quat<f64>;         /// a double-precision floating-point quaternion

//
//  Quaternion
//
pub trait Quaternion<T> {
    pure fn dim() -> uint;

    pure fn mul_t(value: T) -> self;
    pure fn div_t(value: T) -> self;

    pure fn mul_v(vec: &Vec3<T>) -> Vec3<T>;

    pure fn add_q(other: &self) -> self;
    pure fn sub_q(other: &self) -> self;
    pure fn mul_q(other: &self) -> self;

    pure fn dot(other: &self) -> T;

    pure fn conjugate() -> self;
    pure fn inverse() -> self;
    pure fn length2() -> T;
    pure fn length() -> T;
    pure fn normalize() -> self;

    pure fn nlerp(other: &self, amount: T) -> self;
    pure fn slerp(other: &self, amount: T) -> self;

    pure fn to_Mat3() -> Mat3<T>;
    pure fn to_Mat4() -> Mat4<T>;
}

pub trait ToQuat<T> {
    pure fn to_Quat() -> Quat<T>;
}

pub struct Quat<T> { w: T, x: T, y: T, z: T }

pub mod Quat {
    #[inline(always)]
    pub pure fn new<T>(w: T, x: T, y: T, z: T) -> Quat<T> {
        Quat { w: move w, x: move x, y: move y, z: move z }
    }

    #[inline(always)]
    pub pure fn from_sv<T:Copy>(s: T, v: Vec3<T>) -> Quat<T> {
        Quat::new(s, v.x, v.y, v.z)
    }

    #[inline(always)]
    pub pure fn from_axis_angle<T:Copy Num NumCast Trig AngleConv>(axis: Vec3<T>, theta: T) -> Quat<T> {
        let half = radians(&theta) / cast(2);
        from_sv(cos(&half), axis.mul_t(sin(&half)))
    }

    #[inline(always)]
    pub pure fn zero<T:Copy NumCast>() -> Quat<T> {
        let _0 = cast(0);
        Quat::new(_0, _0, _0, _0)
    }

    #[inline(always)]
    pub pure fn identity<T:Copy NumCast>() -> Quat<T> {
        let _0 = cast(0);
        Quat::new(cast(1), _0, _0, _0)
    }
}

pub impl<T:Copy Num NumCast Trig Exp Extent Ord FuzzyEq> Quat<T>: Quaternion<T> {
    #[inline(always)]
    pure fn dim() -> uint { 4 }

    #[inline(always)]
    pure fn mul_t(value: T) -> Quat<T> {
        Quat::new(self[0] * value,
                  self[1] * value,
                  self[2] * value,
                  self[3] * value)
    }

    #[inline(always)]
    pure fn div_t(value: T) -> Quat<T> {
        Quat::new(self[0] / value,
                  self[1] / value,
                  self[2] / value,
                  self[3] / value)
    }

    #[inline(always)]
    pure fn mul_v(vec: &Vec3<T>) -> Vec3<T>  {
        let base = Vec3{ x:self.x, y:self.y, z:self.z };
        let tmp = base.cross(vec).add_v(&vec.mul_t(self.w));
        base.cross(&tmp).mul_t(cast(2)).add_v(vec)
    }

    #[inline(always)]
    pure fn add_q(other: &Quat<T>) -> Quat<T> {
        Quat::new(self[0] + other[0],
                  self[1] + other[1],
                  self[2] + other[2],
                  self[3] + other[3])
    }

    #[inline(always)]
    pure fn sub_q(other: &Quat<T>) -> Quat<T> {
        Quat::new(self[0] - other[0],
                  self[1] - other[1],
                  self[2] - other[2],
                  self[3] - other[3])
    }

    #[inline(always)]
    pure fn mul_q(other: &Quat<T>) -> Quat<T> {
        Quat::new(self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z,
                  self.w * other.x + self.x * other.w + self.y * other.z - self.z * other.y,
                  self.w * other.y + self.y * other.w + self.z * other.x - self.x * other.z,
                  self.w * other.z + self.z * other.w + self.x * other.y - self.y * other.x)
    }

    #[inline(always)]
    pure fn dot(other: &Quat<T>) -> T {
        self.w * other.w +
        self.x * other.x +
        self.y * other.y +
        self.z * other.z
    }

    #[inline(always)]
    pure fn conjugate() -> Quat<T> {
        Quat::new(self.w, -self.x, -self.y, -self.z)
    }

    #[inline(always)]
    pure fn inverse() -> Quat<T> {
        let mut n: T = from_int(1);
        n /= self.length2();
        self.conjugate().mul_t(n)
    }

    #[inline(always)]
    pure fn length2() -> T {
        self.w * self.w +
        self.x * self.x +
        self.y * self.y +
        self.z * self.z
    }

    #[inline(always)]
    pure fn length() -> T {
        self.length2().sqrt()
    }

    #[inline(always)]
    pure fn normalize() -> Quat<T> {
        let mut n: T = cast(1);
        n /= self.length();
        return self.mul_t(n);
    }

    #[inline(always)]
    pure fn nlerp(other: &Quat<T>, amount: T) -> Quat<T> {
        let _1: T = cast(1);
        self.mul_t(_1 - amount).add_q(&other.mul_t(amount)).normalize()
    }

    /**
     * Spherical Linear Intoperlation
     *
     * Both quaternions should be normalized first, or else strange things will
     * will happen...
     *
     * Note: The `acos` used in `slerp` is an expensive operation, so unless your
     * quarternions a far away from each other it's generally more advisable to
     * use nlerp when you know your rotations are going to be small.
     *
     * See *[Understanding Slerp, Then Not Using It]
     * (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/)*
     * for more information. The [Arcsynthesis OpenGL tutorial]
     * (http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Interpolation.html)
     * also provides a good explanation.
     */
    #[inline(always)]
    pure fn slerp(other: &Quat<T>, amount: T) -> Quat<T> {
        let dot: T = cast(self.dot(other));

        // if quaternions are close together use `nlerp`
        let dot_threshold = cast(0.9995);
        if dot > dot_threshold { return self.nlerp(other, amount) }

        let robust_dot = dot.clamp(&-cast(1), &cast(1));    // stay within the domain of acos()
        let theta_0 = acos(&robust_dot);                    // the angle between the quaternions
        let theta = theta_0 * amount;                       // the fraction of theta specified by `amount`

        let q = other.sub_q(&self.mul_t(robust_dot))
                     .normalize();

        self.mul_t(cos(&theta)).add_q(&q.mul_t(sin(&theta)))
    }

    #[inline(always)]
    pure fn to_Mat3() -> Mat3<T> {
        let x2 = self.x + self.x;
        let y2 = self.y + self.y;
        let z2 = self.z + self.z;

        let xx2 = x2 * self.x;
        let xy2 = x2 * self.y;
        let xz2 = x2 * self.z;

        let yy2 = y2 * self.y;
        let yz2 = y2 * self.z;
        let zz2 = z2 * self.z;

        let wy2 = y2 * self.w;
        let wz2 = z2 * self.w;
        let wx2 = x2 * self.w;

        let _1: T = from_int(1);

        Mat3::new(_1 - yy2 - zz2,      xy2 - wz2,      xz2 + wy2,
                       xy2 + wz2, _1 - xx2 - zz2,      yz2 - wx2,
                       xz2 - wy2,      yz2 + wx2, _1 - xx2 - yy2)
    }

    #[inline(always)]
    pure fn to_Mat4() -> Mat4<T> {
        self.to_Mat3().to_Mat4()
    }
}

pub impl<T:Copy> Quat<T>: Index<uint, T> {
    #[inline(always)]
    pure fn index(i: uint) -> T {
        unsafe { do buf_as_slice(
            transmute::<*Quat<T>, *T>(
                to_unsafe_ptr(&self)), 4) |slice| { slice[i] }
        }
    }
}

pub impl<T:Copy Neg<T>> Quat<T>: Neg<Quat<T>> {
    #[inline(always)]
    pure fn neg() -> Quat<T> {
        Quat::new(-self[0], -self[1], -self[2], -self[3])
    }
}

// TODO: make work for T:Integer
pub impl<T:Copy FuzzyEq> Quat<T>: Eq {
    #[inline(always)]
    pure fn eq(other: &Quat<T>) -> bool {
        self.fuzzy_eq(other)
    }

    #[inline(always)]
    pure fn ne(other: &Quat<T>) -> bool {
        !(self == *other)
    }
}

pub impl<T:Copy Eq> Quat<T>: ExactEq {
    #[inline(always)]
    pure fn exact_eq(other: &Quat<T>) -> bool {
        self[0] == other[0] &&
        self[1] == other[1] &&
        self[2] == other[2] &&
        self[3] == other[3]
    }
}

pub impl<T:Copy FuzzyEq> Quat<T>: FuzzyEq {
    #[inline(always)]
    pure fn fuzzy_eq(other: &Quat<T>) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1]) &&
        self[2].fuzzy_eq(&other[2]) &&
        self[3].fuzzy_eq(&other[3])
    }
}

pub impl<T:Copy> Quat<T>: ToPtr<T> {
    #[inline(always)]
    pure fn to_ptr() -> *T {
        to_unsafe_ptr(&self[0])
    }
}<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::path::Path;
use toml::Value as Toml;

use error::PackageError;
use package::Package;

/// The struct which represents the repos.
#[derive(Deserialize)]
pub struct Repository {
    url: String,
    packages: Vec<Package>,
}

/// Struct which represents a list of Repositories.
#[derive(Deserialize)]
struct RepositoryList(Vec<Repository>);

impl Repository {
    /// Returns the URL of the Repository.
    pub fn url(&self) -> &str {
        &self.url
    }

    /// Returns the packages which are provided by the Repository.
    pub fn packages(&self) -> &[Package] {
        self.packages.as_slice()
    }

    // Attempts to find the package which satifies the predicate.
    // If there are no packages that match the predicate, a `None` is returned.
    pub fn find_by_predicate<F>(&self, predicate: F) -> Option<&Package>
        where F: Fn(&Package) -> bool {
        for pkg in &self.packages {
            if predicate(&pkg) {
                return Some(&pkg)
            }
        };

        None
    }
}

impl RepositoryList {
    fn read_from(path: &Path) -> Result<Self, PackageError> {
        let mut list = File::open(path)?;
        let mut content = String::new();
        list.read_to_string(&mut content)?;
        let list = content.parse::<Toml>()?;
        let list = list.try_into::<Self>()?;
        Ok(list)
    }
}<commit_msg>Make RepositoryList and its field public<commit_after>use std::fs::File;
use std::io::Read;
use std::path::Path;
use toml::Value as Toml;

use error::PackageError;
use package::Package;

/// The struct which represents the repos.
#[derive(Deserialize)]
pub struct Repository {
    url: String,
    packages: Vec<Package>,
}

/// Struct which represents a list of Repositories.
#[derive(Deserialize)]
pub struct RepositoryList(pub Vec<Repository>);

impl Repository {
    /// Returns the URL of the Repository.
    pub fn url(&self) -> &str {
        &self.url
    }

    /// Returns the packages which are provided by the Repository.
    pub fn packages(&self) -> &[Package] {
        self.packages.as_slice()
    }

    // Attempts to find the package which satifies the predicate.
    // If there are no packages that match the predicate, a `None` is returned.
    pub fn find_by_predicate<F>(&self, predicate: F) -> Option<&Package>
        where F: Fn(&Package) -> bool {
        for pkg in &self.packages {
            if predicate(&pkg) {
                return Some(&pkg)
            }
        };

        None
    }
}

impl RepositoryList {
    fn read_from(path: &Path) -> Result<Self, PackageError> {
        let mut list = File::open(path)?;
        let mut content = String::new();
        list.read_to_string(&mut content)?;
        let list = content.parse::<Toml>()?;
        let list = list.try_into::<Self>()?;
        Ok(list)
    }
}<|endoftext|>


<commit_before>//! Common Subexpression Elimination (CSE)
//!
//! This module implements methods and structs to perform CSE.
//! However, this implement doesn't consider much about commutative
//! opcodes. One the other hand, considering too much will cause
//! a huge memory consume. Thus, a balanced solution should be
//! improved.

use std::collections::HashMap;
use std::marker::PhantomData;

use middle::ssa::ssa_traits::{NodeType, SSA, SSAMod, SSAWalk};
use middle::ir::MOpcode;
use super::ssasort::Sorter;

#[derive(Debug)]
pub struct CSE<'a, I, S>
    where I: Iterator<Item = S::ValueRef>,
          S: 'a + SSAMod + SSA + SSAWalk<I>
{
    exprs: HashMap<String, Vec<S::ValueRef>>,
    hashed: HashMap<S::ValueRef, String>,
    ssa: &'a mut S,
    foo: PhantomData<I>,
}

impl<'a, I, S> CSE<'a, I, S>
where I: Iterator<Item = S::ValueRef>,
      S: 'a + SSAMod + SSA + SSAWalk<I>
{
    pub fn new(ssa: &'a mut S) -> CSE<'a, I, S> {
        CSE {
            exprs: HashMap::new(),
            hashed: HashMap::new(),
            ssa: ssa,
            foo: PhantomData,
        }
    }

    fn hash_args(&self, args: &[S::ValueRef]) -> String {
        let mut result = String::new();
        for arg in args {
            if let Ok(node_data) = self.ssa.node_data(*arg) {
                match node_data.nt {
                    NodeType::Op(opc) => {
                        match opc {
                            MOpcode::OpConst(val) => result.push_str(&format!("{}", val)),
                            _ => result.push_str(self.hashed.get(arg).expect("Hash value not found!")),
                        }
                    }
                    _ => {
                        // NOTE: Phi functions and Comment node should be considered, otherwise,
                        // CSE will replace different op nodes, which only use phi/comment as
                        // operands, causing wrong analysis. Meanwhile, we take Invalid node
                        // into account, for it may not influence the answer. Actually, till
                        // now, there is no possibility to have an Invalid node.
                        // Attantion: any call node will cause a lot of Comment nodes as it return,
                        // to symbolize every register.
                        result.push_str(&format!("{:?}", arg));
                    }
                }
            }
        }
        result
    }

    // NOTE: Because we have sorted the operands, it's unnecessary to consider commutative opcodes.
    fn hash_string(&self, idx: &S::ValueRef) -> Option<String> {
        if let Ok(node_data) = self.ssa.node_data(*idx) {
            if let NodeType::Op(opc) = node_data.nt {
                let args = self.ssa.operands_of(*idx);
                let hashed_args = self.hash_args(&args);
                let hs = format!("{}{}", opc, hashed_args);
                return Some(hs);
            }
        }
        None
    }

    pub fn run(&mut self) {
        {
            let mut sorter = Sorter::new(self.ssa);
            sorter.run();
        }
        // Sort the operands for commutative opcode first;

        for expr in self.ssa.inorder_walk() {
            let hs_ = self.hash_string(&expr);
            let mut replaced = false;
            if hs_.is_none() {
                break;
            }
            let hs = hs_.as_ref().unwrap();
            if let Some(ex_idxs) = self.exprs.get(hs).cloned() {
                // NOTE: Though we can eliminate expression even if the two aren't in the same
                // block, we do not do so cause it requires that block b1 (block of the
                // replacer) must dominate block b2 (the replacee). Since we are currently not
                // using the dominator information, this replacement may not be safe. Hence we
                // restrict outselves to the case where both the expressions belong to the same
                // block.
                for ex_idx in &ex_idxs {
                    if self.ssa.block_for(*ex_idx) == self.ssa.block_for(expr) {
                        self.ssa.replace_value(expr, *ex_idx);
                        replaced = true;
                        break;
                    }
                }
            }

            if !replaced {
                if let Some(ref hs) = hs_ {
                    self.exprs.entry(hs.clone()).or_insert_with(Vec::new).push(expr);
                    self.hashed.insert(expr, hs.clone());
                }
            }
        }
    }
}
<commit_msg>fix typo?<commit_after>//! Common Subexpression Elimination (CSE)
//!
//! This module implements methods and structs to perform CSE.
//! However, this implement doesn't consider much about commutative
//! opcodes. On the other hand, considering too much will cause
//! a huge memory consume. Thus, a balanced solution should be
//! improved.

use std::collections::HashMap;
use std::marker::PhantomData;

use middle::ssa::ssa_traits::{NodeType, SSA, SSAMod, SSAWalk};
use middle::ir::MOpcode;
use super::ssasort::Sorter;

#[derive(Debug)]
pub struct CSE<'a, I, S>
    where I: Iterator<Item = S::ValueRef>,
          S: 'a + SSAMod + SSA + SSAWalk<I>
{
    exprs: HashMap<String, Vec<S::ValueRef>>,
    hashed: HashMap<S::ValueRef, String>,
    ssa: &'a mut S,
    foo: PhantomData<I>,
}

impl<'a, I, S> CSE<'a, I, S>
where I: Iterator<Item = S::ValueRef>,
      S: 'a + SSAMod + SSA + SSAWalk<I>
{
    pub fn new(ssa: &'a mut S) -> CSE<'a, I, S> {
        CSE {
            exprs: HashMap::new(),
            hashed: HashMap::new(),
            ssa: ssa,
            foo: PhantomData,
        }
    }

    fn hash_args(&self, args: &[S::ValueRef]) -> String {
        let mut result = String::new();
        for arg in args {
            if let Ok(node_data) = self.ssa.node_data(*arg) {
                match node_data.nt {
                    NodeType::Op(opc) => {
                        match opc {
                            MOpcode::OpConst(val) => result.push_str(&format!("{}", val)),
                            _ => result.push_str(self.hashed.get(arg).expect("Hash value not found!")),
                        }
                    }
                    _ => {
                        // NOTE: Phi functions and Comment node should be considered, otherwise,
                        // CSE will replace different op nodes, which only use phi/comment as
                        // operands, causing wrong analysis. Meanwhile, we take Invalid node
                        // into account, for it may not influence the answer. Actually, till
                        // now, there is no possibility to have an Invalid node.
                        // Attantion: any call node will cause a lot of Comment nodes as it return,
                        // to symbolize every register.
                        result.push_str(&format!("{:?}", arg));
                    }
                }
            }
        }
        result
    }

    // NOTE: Because we have sorted the operands, it's unnecessary to consider commutative opcodes.
    fn hash_string(&self, idx: &S::ValueRef) -> Option<String> {
        if let Ok(node_data) = self.ssa.node_data(*idx) {
            if let NodeType::Op(opc) = node_data.nt {
                let args = self.ssa.operands_of(*idx);
                let hashed_args = self.hash_args(&args);
                let hs = format!("{}{}", opc, hashed_args);
                return Some(hs);
            }
        }
        None
    }

    pub fn run(&mut self) {
        {
            let mut sorter = Sorter::new(self.ssa);
            sorter.run();
        }
        // Sort the operands for commutative opcode first;

        for expr in self.ssa.inorder_walk() {
            let hs_ = self.hash_string(&expr);
            let mut replaced = false;
            if hs_.is_none() {
                break;
            }
            let hs = hs_.as_ref().unwrap();
            if let Some(ex_idxs) = self.exprs.get(hs).cloned() {
                // NOTE: Though we can eliminate expression even if the two aren't in the same
                // block, we do not do so cause it requires that block b1 (block of the
                // replacer) must dominate block b2 (the replacee). Since we are currently not
                // using the dominator information, this replacement may not be safe. Hence we
                // restrict outselves to the case where both the expressions belong to the same
                // block.
                for ex_idx in &ex_idxs {
                    if self.ssa.block_for(*ex_idx) == self.ssa.block_for(expr) {
                        self.ssa.replace_value(expr, *ex_idx);
                        replaced = true;
                        break;
                    }
                }
            }

            if !replaced {
                if let Some(ref hs) = hs_ {
                    self.exprs.entry(hs.clone()).or_insert_with(Vec::new).push(expr);
                    self.hashed.insert(expr, hs.clone());
                }
            }
        }
    }
}
<|endoftext|>