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

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    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]
    }

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    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>Fix definition of MTLNewLibraryCompletionHandler<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;

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    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]
    }

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    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 cocoa::base::id;
use std::mem;
use std::ops::{Deref, DerefMut};
use {CommandEncoder, StoreAction, RenderCommandEncoder};

#[derive(Debug)]
pub struct ParallelRenderCommandEncoder(id);

unsafe impl Send for ParallelRenderCommandEncoder {}

impl Deref for ParallelRenderCommandEncoder {
    type Target = CommandEncoder;
    fn deref(&self) -> &Self::Target {
        unsafe { mem::transmute(&self.0) }
    }
}

impl DerefMut for ParallelRenderCommandEncoder {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { mem::transmute(&mut self.0) }
    }
}

impl ParallelRenderCommandEncoder {
    pub fn render_command_encoder(&self) -> RenderCommandEncoder {
        unimplemented!()
    }

    pub fn set_color_store_action_at(&self, store_action: StoreAction, index: usize) {
        unimplemented!()
    }

    pub fn set_depth_store_action(self, store_action: StoreAction) {
        unimplemented!()
    }

    pub fn set_stencil_store_action(self, store_action: StoreAction) {
        unimplemented!()
    }
}

impl_from_into_raw!(ParallelRenderCommandEncoder, of protocol "MTLRenderCommandEncoder");
<commit_msg>Rename `render_command_encoder` to `create_render_command_encoder` to emphasise that it creates a `RenderCommandEncoder`<commit_after>use cocoa::base::id;
use std::mem;
use std::ops::{Deref, DerefMut};
use {CommandEncoder, StoreAction, RenderCommandEncoder};

#[derive(Debug)]
pub struct ParallelRenderCommandEncoder(id);

unsafe impl Send for ParallelRenderCommandEncoder {}

impl Deref for ParallelRenderCommandEncoder {
    type Target = CommandEncoder;
    fn deref(&self) -> &Self::Target {
        unsafe { mem::transmute(&self.0) }
    }
}

impl DerefMut for ParallelRenderCommandEncoder {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { mem::transmute(&mut self.0) }
    }
}

impl ParallelRenderCommandEncoder {
    pub fn create_render_command_encoder(&self) -> RenderCommandEncoder {
        unimplemented!()
    }

    pub fn set_color_store_action_at(&self, store_action: StoreAction, index: usize) {
        unimplemented!()
    }

    pub fn set_depth_store_action(self, store_action: StoreAction) {
        unimplemented!()
    }

    pub fn set_stencil_store_action(self, store_action: StoreAction) {
        unimplemented!()
    }
}

impl_from_into_raw!(ParallelRenderCommandEncoder, of protocol "MTLRenderCommandEncoder");
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

/// Implements inherent methods for a float vector `$name` containing multiple
/// `$lanes` of float `$type`, which uses `$bits_ty` as its binary
/// representation. Called from `define_float_vector!`.
macro_rules! impl_float_vector {
    { $name:ident, $type:ty, $bits_ty:ident, $mask_ty:ident, $mask_impl_ty:ident } => {
        impl_vector! { $name, $type }

        impl<const LANES: usize> $name<LANES>
        where
            Self: crate::LanesAtMost64,
            crate::$bits_ty<LANES>: crate::LanesAtMost64,
        {
            /// Raw transmutation to an unsigned integer vector type with the
            /// same size and number of lanes.
            #[inline]
            pub fn to_bits(self) -> crate::$bits_ty<LANES> {
                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<crate::$bits_ty<LANES>>());
                unsafe { core::mem::transmute_copy(&self) }
            }

            /// Raw transmutation from an unsigned integer vector type with the
            /// same size and number of lanes.
            #[inline]
            pub fn from_bits(bits: crate::$bits_ty<LANES>) -> Self {
                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<crate::$bits_ty<LANES>>());
                unsafe { core::mem::transmute_copy(&bits) }
            }

            /// Produces a vector where every lane has the absolute value of the
            /// equivalently-indexed lane in `self`.
            #[inline]
            pub fn abs(self) -> Self {
                let no_sign = crate::$bits_ty::splat(!0 >> 1);
                Self::from_bits(self.to_bits() & no_sign)
            }
        }

        impl<const LANES: usize> $name<LANES>
        where
            Self: crate::LanesAtMost64,
            crate::$bits_ty<LANES>: crate::LanesAtMost64,
            crate::$mask_impl_ty<LANES>: crate::LanesAtMost64,
        {
            /// Returns true for each lane if it has a positive sign, including
            /// `+0.0`, `NaN`s with positive sign bit and positive infinity.
            #[inline]
            pub fn is_sign_positive(self) -> crate::$mask_ty<LANES> {
                !self.is_sign_negative()
            }

            /// Returns true for each lane if it has a negative sign, including
            /// `-0.0`, `NaN`s with negative sign bit and negative infinity.
            #[inline]
            pub fn is_sign_negative(self) -> crate::$mask_ty<LANES> {
                let sign_bits = self.to_bits() & crate::$bits_ty::splat((!0 >> 1) + 1);
                sign_bits.lanes_gt(crate::$bits_ty::splat(0))
            }

            /// Returns true for each lane if its value is `NaN`.
            #[inline]
            pub fn is_nan(self) -> crate::$mask_ty<LANES> {
                self.lanes_ne(self)
            }

            /// Returns true for each lane if its value is positive infinity or negative infinity.
            #[inline]
            pub fn is_infinite(self) -> crate::$mask_ty<LANES> {
                self.abs().lanes_eq(Self::splat(<$type>::INFINITY))
            }

            /// Returns true for each lane if its value is neither infinite nor `NaN`.
            #[inline]
            pub fn is_finite(self) -> crate::$mask_ty<LANES> {
                self.abs().lanes_lt(Self::splat(<$type>::INFINITY))
            }

            /// Returns true for each lane if its value is subnormal.
            #[inline]
            pub fn is_subnormal(self) -> crate::$mask_ty<LANES> {
                let exponent_mask = crate::$bits_ty::splat(!0 << <$type>::MANTISSA_DIGITS);
                self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & exponent_mask).lanes_eq(crate::$bits_ty::splat(0))
            }

            /// Returns true for each lane if its value is neither neither zero, infinite,
            /// subnormal, or `NaN`.
            #[inline]
            pub fn is_normal(self) -> crate::$mask_ty<LANES> {
                !(self.abs().lanes_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal())
            }
        }
    };
}

/// A SIMD vector of containing `LANES` `f32` values.
#[repr(simd)]
pub struct SimdF32<const LANES: usize>([f32; LANES])
where
    Self: crate::LanesAtMost64;

impl_float_vector! { SimdF32, f32, SimdU32, Mask32, SimdI32 }

from_transmute_x86! { unsafe f32x4 => __m128 }
from_transmute_x86! { unsafe f32x8 => __m256 }
//from_transmute_x86! { unsafe f32x16 => __m512 }

/// A SIMD vector of containing `LANES` `f64` values.
#[repr(simd)]
pub struct SimdF64<const LANES: usize>([f64; LANES])
where
    Self: crate::LanesAtMost64;

impl_float_vector! { SimdF64, f64, SimdU64, Mask64, SimdI64 }

from_transmute_x86! { unsafe f64x2 => __m128d }
from_transmute_x86! { unsafe f64x4 => __m256d }
//from_transmute_x86! { unsafe f64x8 => __m512d }

/// Vector of two `f32` values
pub type f32x2 = SimdF32<2>;

/// Vector of four `f32` values
pub type f32x4 = SimdF32<4>;

/// Vector of eight `f32` values
pub type f32x8 = SimdF32<8>;

/// Vector of 16 `f32` values
pub type f32x16 = SimdF32<16>;

/// Vector of two `f64` values
pub type f64x2 = SimdF64<2>;

/// Vector of four `f64` values
pub type f64x4 = SimdF64<4>;

/// Vector of eight `f64` values
pub type f64x8 = SimdF64<8>;
<commit_msg>Fix normal and subnormal classification<commit_after>#![allow(non_camel_case_types)]

/// Implements inherent methods for a float vector `$name` containing multiple
/// `$lanes` of float `$type`, which uses `$bits_ty` as its binary
/// representation. Called from `define_float_vector!`.
macro_rules! impl_float_vector {
    { $name:ident, $type:ty, $bits_ty:ident, $mask_ty:ident, $mask_impl_ty:ident } => {
        impl_vector! { $name, $type }

        impl<const LANES: usize> $name<LANES>
        where
            Self: crate::LanesAtMost64,
            crate::$bits_ty<LANES>: crate::LanesAtMost64,
        {
            /// Raw transmutation to an unsigned integer vector type with the
            /// same size and number of lanes.
            #[inline]
            pub fn to_bits(self) -> crate::$bits_ty<LANES> {
                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<crate::$bits_ty<LANES>>());
                unsafe { core::mem::transmute_copy(&self) }
            }

            /// Raw transmutation from an unsigned integer vector type with the
            /// same size and number of lanes.
            #[inline]
            pub fn from_bits(bits: crate::$bits_ty<LANES>) -> Self {
                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<crate::$bits_ty<LANES>>());
                unsafe { core::mem::transmute_copy(&bits) }
            }

            /// Produces a vector where every lane has the absolute value of the
            /// equivalently-indexed lane in `self`.
            #[inline]
            pub fn abs(self) -> Self {
                let no_sign = crate::$bits_ty::splat(!0 >> 1);
                Self::from_bits(self.to_bits() & no_sign)
            }
        }

        impl<const LANES: usize> $name<LANES>
        where
            Self: crate::LanesAtMost64,
            crate::$bits_ty<LANES>: crate::LanesAtMost64,
            crate::$mask_impl_ty<LANES>: crate::LanesAtMost64,
        {
            /// Returns true for each lane if it has a positive sign, including
            /// `+0.0`, `NaN`s with positive sign bit and positive infinity.
            #[inline]
            pub fn is_sign_positive(self) -> crate::$mask_ty<LANES> {
                !self.is_sign_negative()
            }

            /// Returns true for each lane if it has a negative sign, including
            /// `-0.0`, `NaN`s with negative sign bit and negative infinity.
            #[inline]
            pub fn is_sign_negative(self) -> crate::$mask_ty<LANES> {
                let sign_bits = self.to_bits() & crate::$bits_ty::splat((!0 >> 1) + 1);
                sign_bits.lanes_gt(crate::$bits_ty::splat(0))
            }

            /// Returns true for each lane if its value is `NaN`.
            #[inline]
            pub fn is_nan(self) -> crate::$mask_ty<LANES> {
                self.lanes_ne(self)
            }

            /// Returns true for each lane if its value is positive infinity or negative infinity.
            #[inline]
            pub fn is_infinite(self) -> crate::$mask_ty<LANES> {
                self.abs().lanes_eq(Self::splat(<$type>::INFINITY))
            }

            /// Returns true for each lane if its value is neither infinite nor `NaN`.
            #[inline]
            pub fn is_finite(self) -> crate::$mask_ty<LANES> {
                self.abs().lanes_lt(Self::splat(<$type>::INFINITY))
            }

            /// Returns true for each lane if its value is subnormal.
            #[inline]
            pub fn is_subnormal(self) -> crate::$mask_ty<LANES> {
                self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(<$type>::INFINITY).to_bits()).lanes_eq(crate::$bits_ty::splat(0))
            }

            /// Returns true for each lane if its value is neither neither zero, infinite,
            /// subnormal, or `NaN`.
            #[inline]
            pub fn is_normal(self) -> crate::$mask_ty<LANES> {
                !(self.abs().lanes_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite())
            }
        }
    };
}

/// A SIMD vector of containing `LANES` `f32` values.
#[repr(simd)]
pub struct SimdF32<const LANES: usize>([f32; LANES])
where
    Self: crate::LanesAtMost64;

impl_float_vector! { SimdF32, f32, SimdU32, Mask32, SimdI32 }

from_transmute_x86! { unsafe f32x4 => __m128 }
from_transmute_x86! { unsafe f32x8 => __m256 }
//from_transmute_x86! { unsafe f32x16 => __m512 }

/// A SIMD vector of containing `LANES` `f64` values.
#[repr(simd)]
pub struct SimdF64<const LANES: usize>([f64; LANES])
where
    Self: crate::LanesAtMost64;

impl_float_vector! { SimdF64, f64, SimdU64, Mask64, SimdI64 }

from_transmute_x86! { unsafe f64x2 => __m128d }
from_transmute_x86! { unsafe f64x4 => __m256d }
//from_transmute_x86! { unsafe f64x8 => __m512d }

/// Vector of two `f32` values
pub type f32x2 = SimdF32<2>;

/// Vector of four `f32` values
pub type f32x4 = SimdF32<4>;

/// Vector of eight `f32` values
pub type f32x8 = SimdF32<8>;

/// Vector of 16 `f32` values
pub type f32x16 = SimdF32<16>;

/// Vector of two `f64` values
pub type f64x2 = SimdF64<2>;

/// Vector of four `f64` values
pub type f64x4 = SimdF64<4>;

/// Vector of eight `f64` values
pub type f64x8 = SimdF64<8>;
<|endoftext|>


<commit_before>//! Command like parsing for rust-analyzer.
//!
//! If run started args, we run the LSP server loop. With a subcommand, we do a
//! one-time batch processing.

use std::{env, fmt::Write, path::PathBuf};

use anyhow::{bail, Result};
use pico_args::Arguments;
use rust_analyzer::cli::{AnalysisStatsCmd, BenchCmd, BenchWhat, Position, Verbosity};
use ssr::{SsrPattern, SsrRule};
use vfs::AbsPathBuf;

pub(crate) struct Args {
    pub(crate) verbosity: Verbosity,
    pub(crate) log_file: Option<PathBuf>,
    pub(crate) command: Command,
}

pub(crate) enum Command {
    Parse { no_dump: bool },
    Symbols,
    Highlight { rainbow: bool },
    AnalysisStats(AnalysisStatsCmd),
    Bench(BenchCmd),
    Diagnostics { path: PathBuf, load_output_dirs: bool, with_proc_macro: bool },
    Ssr { rules: Vec<SsrRule> },
    StructuredSearch { debug_snippet: Option<String>, patterns: Vec<SsrPattern> },
    ProcMacro,
    RunServer,
    Version,
    Help,
}

const HELP: &str = "\
rust-analyzer

USAGE:
    rust-analyzer [FLAGS] [COMMAND] [COMMAND_OPTIONS]

FLAGS:
    --version         Print version
    -h, --help        Print this help

    -v,  --verbose
    -vv, --spammy
    -q,  --quiet      Set verbosity

    --log-file <PATH> Log to the specified filed instead of stderr

ENVIRONMENTAL VARIABLES:
    RA_LOG            Set log filter in env_logger format
    RA_PROFILE        Enable hierarchical profiler

COMMANDS:

not specified         Launch LSP server

parse < main.rs       Parse tree
    --no-dump         Suppress printing

symbols < main.rs     Parse input an print the list of symbols

highlight < main.rs   Highlight input as html
    --rainbow         Enable rainbow highlighting of identifiers

analysis-stats <PATH> Batch typecheck project and print summary statistics
    <PATH>            Directory with Cargo.toml
    --randomize       Randomize order in which crates, modules, and items are processed
    --parallel        Run type inference in parallel
    --memory-usage    Collect memory usage statistics
    -o, --only <PATH> Only analyze items matching this path
    --with-deps       Also analyze all dependencies
    --load-output-dirs
                      Load OUT_DIR values by running `cargo check` before analysis
    --with-proc-macro Use proc-macro-srv for proc-macro expanding

analysis-bench <PATH> Benchmark specific analysis operation
    <PATH>            Directory with Cargo.toml
    --highlight <PATH>
                      Compute syntax highlighting for this file
    --complete <PATH:LINE:COLUMN>
                      Compute completions at this location
    --goto-def <PATH:LINE:COLUMN>
                      Compute goto definition at this location
    --memory-usage    Collect memory usage statistics
    --load-output-dirs
                      Load OUT_DIR values by running `cargo check` before analysis
    --with-proc-macro Use proc-macro-srv for proc-macro expanding

diagnostics <PATH>
    <PATH>            Directory with Cargo.toml
    --load-output-dirs
                      Load OUT_DIR values by running `cargo check` before analysis
    --with-proc-macro Use proc-macro-srv for proc-macro expanding

ssr [RULE...]
    <RULE>            A structured search replace rule (`$a.foo($b) ==> bar($a, $b)`)
    --debug <snippet> Prints debug information for any nodes with source exactly
                      equal to <snippet>

search [PATTERN..]
    <PATTERN>         A structured search replace pattern (`$a.foo($b)`)
    --debug <snippet> Prints debug information for any nodes with source exactly
                      equal to <snippet>
";

impl Args {
    pub(crate) fn parse() -> Result<Args> {
        let mut matches = Arguments::from_env();

        if matches.contains("--version") {
            matches.finish().or_else(handle_extra_flags)?;
            return Ok(Args {
                verbosity: Verbosity::Normal,
                log_file: None,
                command: Command::Version,
            });
        }

        let verbosity = match (
            matches.contains(["-vv", "--spammy"]),
            matches.contains(["-v", "--verbose"]),
            matches.contains(["-q", "--quiet"]),
        ) {
            (true, _, true) => bail!("Invalid flags: -q conflicts with -vv"),
            (true, _, false) => Verbosity::Spammy,
            (false, false, false) => Verbosity::Normal,
            (false, false, true) => Verbosity::Quiet,
            (false, true, false) => Verbosity::Verbose,
            (false, true, true) => bail!("Invalid flags: -q conflicts with -v"),
        };
        let log_file = matches.opt_value_from_str("--log-file")?;

        if matches.contains(["-h", "--help"]) {
            eprintln!("{}", HELP);
            return Ok(Args { verbosity, log_file: None, command: Command::Help });
        }

        let subcommand = match matches.subcommand()? {
            Some(it) => it,
            None => {
                matches.finish().or_else(handle_extra_flags)?;
                return Ok(Args { verbosity, log_file, command: Command::RunServer });
            }
        };
        let command = match subcommand.as_str() {
            "parse" => {
                let no_dump = matches.contains("--no-dump");
                matches.finish().or_else(handle_extra_flags)?;
                Command::Parse { no_dump }
            }
            "symbols" => {
                matches.finish().or_else(handle_extra_flags)?;
                Command::Symbols
            }
            "highlight" => {
                let rainbow = matches.contains("--rainbow");
                matches.finish().or_else(handle_extra_flags)?;
                Command::Highlight { rainbow }
            }
            "analysis-stats" => {
                let randomize = matches.contains("--randomize");
                let parallel = matches.contains("--parallel");
                let memory_usage = matches.contains("--memory-usage");
                let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
                let with_deps: bool = matches.contains("--with-deps");
                let load_output_dirs = matches.contains("--load-output-dirs");
                let with_proc_macro = matches.contains("--with-proc-macro");
                let path = {
                    let mut trailing = matches.free()?;
                    if trailing.len() != 1 {
                        bail!("Invalid flags");
                    }
                    trailing.pop().unwrap().into()
                };

                Command::AnalysisStats(AnalysisStatsCmd {
                    randomize,
                    parallel,
                    memory_usage,
                    only,
                    with_deps,
                    path,
                    load_output_dirs,
                    with_proc_macro,
                })
            }
            "analysis-bench" => {
                let highlight_path: Option<String> = matches.opt_value_from_str("--highlight")?;
                let complete_path: Option<Position> = matches.opt_value_from_str("--complete")?;
                let goto_def_path: Option<Position> = matches.opt_value_from_str("--goto-def")?;
                let what = match (highlight_path, complete_path, goto_def_path) {
                    (Some(path), None, None) => {
                        let path = env::current_dir().unwrap().join(path);
                        BenchWhat::Highlight { path: AbsPathBuf::assert(path) }
                    }
                    (None, Some(position), None) => BenchWhat::Complete(position),
                    (None, None, Some(position)) => BenchWhat::GotoDef(position),
                    _ => panic!(
                        "exactly one of  `--highlight`, `--complete` or `--goto-def` must be set"
                    ),
                };
                let memory_usage = matches.contains("--memory-usage");
                let load_output_dirs = matches.contains("--load-output-dirs");
                let with_proc_macro = matches.contains("--with-proc-macro");

                let path = {
                    let mut trailing = matches.free()?;
                    if trailing.len() != 1 {
                        bail!("Invalid flags");
                    }
                    trailing.pop().unwrap().into()
                };

                Command::Bench(BenchCmd {
                    memory_usage,
                    path,
                    what,
                    load_output_dirs,
                    with_proc_macro,
                })
            }
            "diagnostics" => {
                let load_output_dirs = matches.contains("--load-output-dirs");
                let with_proc_macro = matches.contains("--with-proc-macro");
                let path = {
                    let mut trailing = matches.free()?;
                    if trailing.len() != 1 {
                        bail!("Invalid flags");
                    }
                    trailing.pop().unwrap().into()
                };

                Command::Diagnostics { path, load_output_dirs, with_proc_macro }
            }
            "proc-macro" => Command::ProcMacro,
            "ssr" => {
                let mut rules = Vec::new();
                while let Some(rule) = matches.free_from_str()? {
                    rules.push(rule);
                }
                Command::Ssr { rules }
            }
            "search" => {
                let debug_snippet = matches.opt_value_from_str("--debug")?;
                let mut patterns = Vec::new();
                while let Some(rule) = matches.free_from_str()? {
                    patterns.push(rule);
                }
                Command::StructuredSearch { patterns, debug_snippet }
            }
            _ => {
                eprintln!("{}", HELP);
                return Ok(Args { verbosity, log_file: None, command: Command::Help });
            }
        };
        Ok(Args { verbosity, log_file, command })
    }
}

fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
    if let pico_args::Error::UnusedArgsLeft(flags) = e {
        let mut invalid_flags = String::new();
        for flag in flags {
            write!(&mut invalid_flags, "{}, ", flag)?;
        }
        let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
        bail!("Invalid flags: {}", invalid_flags);
    } else {
        bail!(e);
    }
}
<commit_msg>Simplify<commit_after>//! Command like parsing for rust-analyzer.
//!
//! If run started args, we run the LSP server loop. With a subcommand, we do a
//! one-time batch processing.

use std::{env, fmt::Write, path::PathBuf};

use anyhow::{bail, format_err, Result};
use pico_args::Arguments;
use rust_analyzer::cli::{AnalysisStatsCmd, BenchCmd, BenchWhat, Position, Verbosity};
use ssr::{SsrPattern, SsrRule};
use vfs::AbsPathBuf;

pub(crate) struct Args {
    pub(crate) verbosity: Verbosity,
    pub(crate) log_file: Option<PathBuf>,
    pub(crate) command: Command,
}

pub(crate) enum Command {
    Parse { no_dump: bool },
    Symbols,
    Highlight { rainbow: bool },
    AnalysisStats(AnalysisStatsCmd),
    Bench(BenchCmd),
    Diagnostics { path: PathBuf, load_output_dirs: bool, with_proc_macro: bool },
    Ssr { rules: Vec<SsrRule> },
    StructuredSearch { debug_snippet: Option<String>, patterns: Vec<SsrPattern> },
    ProcMacro,
    RunServer,
    Version,
    Help,
}

const HELP: &str = "\
rust-analyzer

USAGE:
    rust-analyzer [FLAGS] [COMMAND] [COMMAND_OPTIONS]

FLAGS:
    --version         Print version
    -h, --help        Print this help

    -v,  --verbose
    -vv, --spammy
    -q,  --quiet      Set verbosity

    --log-file <PATH> Log to the specified filed instead of stderr

ENVIRONMENTAL VARIABLES:
    RA_LOG            Set log filter in env_logger format
    RA_PROFILE        Enable hierarchical profiler

COMMANDS:

not specified         Launch LSP server

parse < main.rs       Parse tree
    --no-dump         Suppress printing

symbols < main.rs     Parse input an print the list of symbols

highlight < main.rs   Highlight input as html
    --rainbow         Enable rainbow highlighting of identifiers

analysis-stats <PATH> Batch typecheck project and print summary statistics
    <PATH>            Directory with Cargo.toml
    --randomize       Randomize order in which crates, modules, and items are processed
    --parallel        Run type inference in parallel
    --memory-usage    Collect memory usage statistics
    -o, --only <PATH> Only analyze items matching this path
    --with-deps       Also analyze all dependencies
    --load-output-dirs
                      Load OUT_DIR values by running `cargo check` before analysis
    --with-proc-macro Use proc-macro-srv for proc-macro expanding

analysis-bench <PATH> Benchmark specific analysis operation
    <PATH>            Directory with Cargo.toml
    --highlight <PATH>
                      Compute syntax highlighting for this file
    --complete <PATH:LINE:COLUMN>
                      Compute completions at this location
    --goto-def <PATH:LINE:COLUMN>
                      Compute goto definition at this location
    --memory-usage    Collect memory usage statistics
    --load-output-dirs
                      Load OUT_DIR values by running `cargo check` before analysis
    --with-proc-macro Use proc-macro-srv for proc-macro expanding

diagnostics <PATH>
    <PATH>            Directory with Cargo.toml
    --load-output-dirs
                      Load OUT_DIR values by running `cargo check` before analysis
    --with-proc-macro Use proc-macro-srv for proc-macro expanding

ssr [RULE...]
    <RULE>            A structured search replace rule (`$a.foo($b) ==> bar($a, $b)`)

search [PATTERN..]
    <PATTERN>         A structured search replace pattern (`$a.foo($b)`)
    --debug <snippet> Prints debug information for any nodes with source exactly
                      equal to <snippet>
";

impl Args {
    pub(crate) fn parse() -> Result<Args> {
        let mut matches = Arguments::from_env();

        if matches.contains("--version") {
            matches.finish().or_else(handle_extra_flags)?;
            return Ok(Args {
                verbosity: Verbosity::Normal,
                log_file: None,
                command: Command::Version,
            });
        }

        let verbosity = match (
            matches.contains(["-vv", "--spammy"]),
            matches.contains(["-v", "--verbose"]),
            matches.contains(["-q", "--quiet"]),
        ) {
            (true, _, true) => bail!("Invalid flags: -q conflicts with -vv"),
            (true, _, false) => Verbosity::Spammy,
            (false, false, false) => Verbosity::Normal,
            (false, false, true) => Verbosity::Quiet,
            (false, true, false) => Verbosity::Verbose,
            (false, true, true) => bail!("Invalid flags: -q conflicts with -v"),
        };
        let log_file = matches.opt_value_from_str("--log-file")?;

        if matches.contains(["-h", "--help"]) {
            eprintln!("{}", HELP);
            return Ok(Args { verbosity, log_file: None, command: Command::Help });
        }

        let subcommand = match matches.subcommand()? {
            Some(it) => it,
            None => {
                matches.finish().or_else(handle_extra_flags)?;
                return Ok(Args { verbosity, log_file, command: Command::RunServer });
            }
        };
        let command = match subcommand.as_str() {
            "parse" => Command::Parse { no_dump: matches.contains("--no-dump") },
            "symbols" => Command::Symbols,
            "highlight" => Command::Highlight { rainbow: matches.contains("--rainbow") },
            "analysis-stats" => Command::AnalysisStats(AnalysisStatsCmd {
                randomize: matches.contains("--randomize"),
                parallel: matches.contains("--parallel"),
                memory_usage: matches.contains("--memory-usage"),
                only: matches.opt_value_from_str(["-o", "--only"])?,
                with_deps: matches.contains("--with-deps"),
                load_output_dirs: matches.contains("--load-output-dirs"),
                with_proc_macro: matches.contains("--with-proc-macro"),
                path: matches
                    .free_from_str()?
                    .ok_or_else(|| format_err!("expected positional argument"))?,
            }),
            "analysis-bench" => Command::Bench(BenchCmd {
                what: {
                    let highlight_path: Option<String> =
                        matches.opt_value_from_str("--highlight")?;
                    let complete_path: Option<Position> =
                        matches.opt_value_from_str("--complete")?;
                    let goto_def_path: Option<Position> =
                        matches.opt_value_from_str("--goto-def")?;
                    match (highlight_path, complete_path, goto_def_path) {
                            (Some(path), None, None) => {
                                let path = env::current_dir().unwrap().join(path);
                                BenchWhat::Highlight { path: AbsPathBuf::assert(path) }
                            }
                            (None, Some(position), None) => BenchWhat::Complete(position),
                            (None, None, Some(position)) => BenchWhat::GotoDef(position),
                            _ => panic!(
                                "exactly one of  `--highlight`, `--complete` or `--goto-def` must be set"
                            ),
                        }
                },
                memory_usage: matches.contains("--memory-usage"),
                load_output_dirs: matches.contains("--load-output-dirs"),
                with_proc_macro: matches.contains("--with-proc-macro"),
                path: matches
                    .free_from_str()?
                    .ok_or_else(|| format_err!("expected positional argument"))?,
            }),
            "diagnostics" => Command::Diagnostics {
                load_output_dirs: matches.contains("--load-output-dirs"),
                with_proc_macro: matches.contains("--with-proc-macro"),
                path: matches
                    .free_from_str()?
                    .ok_or_else(|| format_err!("expected positional argument"))?,
            },
            "proc-macro" => Command::ProcMacro,
            "ssr" => Command::Ssr {
                rules: {
                    let mut acc = Vec::new();
                    while let Some(rule) = matches.free_from_str()? {
                        acc.push(rule);
                    }
                    acc
                },
            },
            "search" => Command::StructuredSearch {
                debug_snippet: matches.opt_value_from_str("--debug")?,
                patterns: {
                    let mut acc = Vec::new();
                    while let Some(rule) = matches.free_from_str()? {
                        acc.push(rule);
                    }
                    acc
                },
            },
            _ => {
                eprintln!("{}", HELP);
                return Ok(Args { verbosity, log_file: None, command: Command::Help });
            }
        };
        matches.finish().or_else(handle_extra_flags)?;
        Ok(Args { verbosity, log_file, command })
    }
}

fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
    if let pico_args::Error::UnusedArgsLeft(flags) = e {
        let mut invalid_flags = String::new();
        for flag in flags {
            write!(&mut invalid_flags, "{}, ", flag)?;
        }
        let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
        bail!("Invalid flags: {}", invalid_flags);
    } else {
        bail!(e);
    }
}
<|endoftext|>


<commit_before>export Msg, Prefetch, GetImage, Exit;
export ImageResponseMsg, ImageReady, ImageNotReady;
export ImageCacheTask;
export image_cache_task;

import image::base::{Image, load_from_memory, test_image_bin};
import std::net::url::url;
import util::url::{make_url, UrlMap, url_map};
import comm::{chan, port};
import task::spawn_listener;
import resource::resource_task;
import resource_task::ResourceTask;
import core::arc::arc;
import clone_arc = core::arc::clone;

enum Msg {
    Prefetch(url),
    GetImage(url, chan<ImageResponseMsg>),
    Exit
}

enum ImageResponseMsg {
    ImageReady(arc<~Image>),
    ImageNotReady
}

type ImageCacheTask = chan<Msg>;

fn image_cache_task(resource_task: ResourceTask) -> ImageCacheTask {
    do spawn_listener |from_client| {
        ImageCache {
            resource_task: resource_task,
            from_client: from_client,
            prefetch_map: url_map(),
            image_map: url_map()
        }.run();
    }
}

struct ImageCache {
    resource_task: ResourceTask;
    from_client: port<Msg>;
    prefetch_map: UrlMap<@PrefetchData>;
    image_map: UrlMap<@arc<~Image>>;
}

struct PrefetchData {
    response_port: port<resource_task::ProgressMsg>;
    mut data: ~[u8];
}

impl ImageCache {

    fn run() {

        loop {
            match self.from_client.recv() {
              Prefetch(url) => self.prefetch(url),
              GetImage(url, response) => self.get_image(url, response),
              Exit => break
            }
        }
    }

    /*priv*/ fn prefetch(url: url) {
        if self.prefetch_map.contains_key(url) {
            // We're already waiting for this image
            return
        }
        let response_port = port();
        self.resource_task.send(resource_task::Load(url, response_port.chan()));

        let prefetch_data = @PrefetchData {
            response_port: response_port,
            data: ~[]
        };

        self.prefetch_map.insert(url, prefetch_data);
    }

    /*priv*/ fn get_image(url: url, response: chan<ImageResponseMsg>) {
        match self.prefetch_map.find(url) {
          some(prefetch_data) => {

            let mut image_sent = false;

            while prefetch_data.response_port.peek() {
                match prefetch_data.response_port.recv() {
                  resource_task::Payload(data) => {
                    prefetch_data.data += data;
                  }
                  resource_task::Done(result::ok(*)) => {
                    // We've got the entire image binary
                    let mut data = ~[];
                    data <-> prefetch_data.data;
                    // FIXME: Need to do this in parallel
                    let image = @arc(~load_from_memory(data));
                    response.send(ImageReady(clone_arc(image)));
                    self.prefetch_map.remove(url);
                    self.image_map.insert(url, image);
                    image_sent = true;
                    break;
                  }
                  resource_task::Done(result::err(*)) => {
                    fail ~"FIXME: what happens now?"
                  }
                }
            }

            if !image_sent {
                response.send(ImageNotReady);
            }
          }
          none => {
            // FIXME: Probably faster to hit this map before the prefetch map
            match self.image_map.find(url) {
              some(image) => response.send(ImageReady(clone_arc(image))),
              none => fail ~"got a request for image data without prefetch"
            }
          }
        }
    }
}

#[test]
fn should_exit_on_request() {

    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Exit => break,
              _ => ()
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);
}

#[test]
#[should_fail]
fn should_fail_if_unprefetched_image_is_requested() {

    let mock_resource_task = do spawn_listener |from_client| {
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    let request = port();
    image_cache_task.send(GetImage(url, request.chan()));
    request.recv();
}

#[test]
fn should_request_url_from_resource_task_on_prefetch() {
    let url_requested = port();
    let url_requested_chan = url_requested.chan();

    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Load(url, _) => url_requested_chan.send(()),
              resource_task::Exit => break
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Prefetch(url));
    url_requested.recv();
    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);
}

#[test]
fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
    let url_requested = port();
    let url_requested_chan = url_requested.chan();

    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Load(url, _) => url_requested_chan.send(()),
              resource_task::Exit => break
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Prefetch(url));
    image_cache_task.send(Prefetch(url));
    url_requested.recv();
    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);
    assert !url_requested.peek()
}

#[test]
fn should_return_image_not_ready_if_data_has_not_arrived() {
    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Exit => break,
              _ => ()
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Prefetch(url));
    let response_port = port();
    image_cache_task.send(GetImage(url, response_port.chan()));
    assert response_port.recv() == ImageNotReady;
    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);
}

#[test]
fn should_return_decoded_image_data_if_data_has_arrived() {

    let image_bin_sent = port();
    let image_bin_sent_chan = image_bin_sent.chan();

    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Load(_, response) => {
                response.send(resource_task::Payload(test_image_bin()));
                response.send(resource_task::Done(result::ok(())));
                image_bin_sent_chan.send(());
              }
              resource_task::Exit => break
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Prefetch(url));

    // Wait until our mock resource task has sent the image to the image cache
    image_bin_sent.recv();

    let response_port = port();
    image_cache_task.send(GetImage(url, response_port.chan()));
    match response_port.recv() {
      ImageReady(_) => (),
      _ => fail
    }

    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);
}

#[test]
fn should_return_decoded_image_data_for_multiple_requests() {

    let image_bin_sent = port();
    let image_bin_sent_chan = image_bin_sent.chan();

    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Load(_, response) => {
                response.send(resource_task::Payload(test_image_bin()));
                response.send(resource_task::Done(result::ok(())));
                image_bin_sent_chan.send(());
              }
              resource_task::Exit => break
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Prefetch(url));

    // Wait until our mock resource task has sent the image to the image cache
    image_bin_sent.recv();

    for iter::repeat(2) {
        let response_port = port();
        image_cache_task.send(GetImage(url, response_port.chan()));
        match response_port.recv() {
          ImageReady(_) => (),
          _ => fail
        }
    }

    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);
}
<commit_msg>Don't continue to fetch images after they are decoded and cached<commit_after>export Msg, Prefetch, GetImage, Exit;
export ImageResponseMsg, ImageReady, ImageNotReady;
export ImageCacheTask;
export image_cache_task;

import image::base::{Image, load_from_memory, test_image_bin};
import std::net::url::url;
import util::url::{make_url, UrlMap, url_map};
import comm::{chan, port};
import task::spawn_listener;
import resource::resource_task;
import resource_task::ResourceTask;
import core::arc::arc;
import clone_arc = core::arc::clone;

enum Msg {
    Prefetch(url),
    GetImage(url, chan<ImageResponseMsg>),
    Exit
}

enum ImageResponseMsg {
    ImageReady(arc<~Image>),
    ImageNotReady
}

type ImageCacheTask = chan<Msg>;

fn image_cache_task(resource_task: ResourceTask) -> ImageCacheTask {
    do spawn_listener |from_client| {
        ImageCache {
            resource_task: resource_task,
            from_client: from_client,
            prefetch_map: url_map(),
            image_map: url_map()
        }.run();
    }
}

struct ImageCache {
    resource_task: ResourceTask;
    from_client: port<Msg>;
    prefetch_map: UrlMap<@PrefetchData>;
    image_map: UrlMap<@arc<~Image>>;
}

struct PrefetchData {
    response_port: port<resource_task::ProgressMsg>;
    mut data: ~[u8];
}

impl ImageCache {

    fn run() {

        loop {
            match self.from_client.recv() {
              Prefetch(url) => self.prefetch(url),
              GetImage(url, response) => self.get_image(url, response),
              Exit => break
            }
        }
    }

    /*priv*/ fn prefetch(url: url) {
        if self.image_map.contains_key(url) {
            // We've already decoded this image
            return
        }

        if self.prefetch_map.contains_key(url) {
            // We're already waiting for this image
            return
        }
        let response_port = port();
        self.resource_task.send(resource_task::Load(url, response_port.chan()));

        let prefetch_data = @PrefetchData {
            response_port: response_port,
            data: ~[]
        };

        self.prefetch_map.insert(url, prefetch_data);
    }

    /*priv*/ fn get_image(url: url, response: chan<ImageResponseMsg>) {
        match self.prefetch_map.find(url) {
          some(prefetch_data) => {

            let mut image_sent = false;

            while prefetch_data.response_port.peek() {
                match prefetch_data.response_port.recv() {
                  resource_task::Payload(data) => {
                    prefetch_data.data += data;
                  }
                  resource_task::Done(result::ok(*)) => {
                    // We've got the entire image binary
                    let mut data = ~[];
                    data <-> prefetch_data.data;
                    // FIXME: Need to do this in parallel
                    let image = @arc(~load_from_memory(data));
                    response.send(ImageReady(clone_arc(image)));
                    self.prefetch_map.remove(url);
                    self.image_map.insert(url, image);
                    image_sent = true;
                    break;
                  }
                  resource_task::Done(result::err(*)) => {
                    fail ~"FIXME: what happens now?"
                  }
                }
            }

            if !image_sent {
                response.send(ImageNotReady);
            }
          }
          none => {
            // FIXME: Probably faster to hit this map before the prefetch map
            match self.image_map.find(url) {
              some(image) => response.send(ImageReady(clone_arc(image))),
              none => fail ~"got a request for image data without prefetch"
            }
          }
        }
    }
}

#[test]
fn should_exit_on_request() {

    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Exit => break,
              _ => ()
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);
}

#[test]
#[should_fail]
fn should_fail_if_unprefetched_image_is_requested() {

    let mock_resource_task = do spawn_listener |from_client| {
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    let request = port();
    image_cache_task.send(GetImage(url, request.chan()));
    request.recv();
}

#[test]
fn should_request_url_from_resource_task_on_prefetch() {
    let url_requested = port();
    let url_requested_chan = url_requested.chan();

    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Load(url, _) => url_requested_chan.send(()),
              resource_task::Exit => break
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Prefetch(url));
    url_requested.recv();
    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);
}

#[test]
fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
    let url_requested = port();
    let url_requested_chan = url_requested.chan();

    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Load(url, _) => url_requested_chan.send(()),
              resource_task::Exit => break
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Prefetch(url));
    image_cache_task.send(Prefetch(url));
    url_requested.recv();
    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);
    assert !url_requested.peek()
}

#[test]
fn should_return_image_not_ready_if_data_has_not_arrived() {
    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Exit => break,
              _ => ()
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Prefetch(url));
    let response_port = port();
    image_cache_task.send(GetImage(url, response_port.chan()));
    assert response_port.recv() == ImageNotReady;
    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);
}

#[test]
fn should_return_decoded_image_data_if_data_has_arrived() {

    let image_bin_sent = port();
    let image_bin_sent_chan = image_bin_sent.chan();

    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Load(_, response) => {
                response.send(resource_task::Payload(test_image_bin()));
                response.send(resource_task::Done(result::ok(())));
                image_bin_sent_chan.send(());
              }
              resource_task::Exit => break
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Prefetch(url));

    // Wait until our mock resource task has sent the image to the image cache
    image_bin_sent.recv();

    let response_port = port();
    image_cache_task.send(GetImage(url, response_port.chan()));
    match response_port.recv() {
      ImageReady(_) => (),
      _ => fail
    }

    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);
}

#[test]
fn should_return_decoded_image_data_for_multiple_requests() {

    let image_bin_sent = port();
    let image_bin_sent_chan = image_bin_sent.chan();

    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Load(_, response) => {
                response.send(resource_task::Payload(test_image_bin()));
                response.send(resource_task::Done(result::ok(())));
                image_bin_sent_chan.send(());
              }
              resource_task::Exit => break
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Prefetch(url));

    // Wait until our mock resource task has sent the image to the image cache
    image_bin_sent.recv();

    for iter::repeat(2) {
        let response_port = port();
        image_cache_task.send(GetImage(url, response_port.chan()));
        match response_port.recv() {
          ImageReady(_) => (),
          _ => fail
        }
    }

    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);
}

#[test]
fn should_not_request_image_from_resource_task_if_image_is_already_available() {

    let image_bin_sent = port();
    let image_bin_sent_chan = image_bin_sent.chan();

    let resource_task_exited = port();
    let resource_task_exited_chan = resource_task_exited.chan();

    let mock_resource_task = do spawn_listener |from_client| {

        // infer me
        let from_client: port<resource_task::ControlMsg> = from_client;

        loop {
            match from_client.recv() {
              resource_task::Load(_, response) => {
                response.send(resource_task::Payload(test_image_bin()));
                response.send(resource_task::Done(result::ok(())));
                image_bin_sent_chan.send(());
              }
              resource_task::Exit => {
                resource_task_exited_chan.send(());
                break
              }
            }
        }
    };

    let image_cache_task = image_cache_task(mock_resource_task);
    let url = make_url(~"file", none);

    image_cache_task.send(Prefetch(url));

    // Wait until our mock resource task has sent the image to the image cache
    image_bin_sent.recv();

    let response_port = port();
    image_cache_task.send(GetImage(url, response_port.chan()));
    match response_port.recv() {
      ImageReady(_) => (),
      _ => fail
    }

    image_cache_task.send(Prefetch(url));

    let response_port = port();
    image_cache_task.send(GetImage(url, response_port.chan()));
    response_port.recv();

    image_cache_task.send(Exit);
    mock_resource_task.send(resource_task::Exit);

    resource_task_exited.recv();

    // Our resource task should not have received another request for the image
    // because it's already cached
    assert !image_bin_sent.peek();
}
<|endoftext|>