mtl-rs 0.1.10

Rust bindings for Apple's Metal API
use std::path::Path;

use objc2::{
    Message,
    encode::{Encode, Encoding, RefEncode},
    extern_class, extern_conformance, extern_methods, extern_protocol, msg_send,
    rc::{Allocated, Retained},
};
use objc2_foundation::{CopyingHelper, NSCopying, NSData, NSError, NSObject, NSObjectProtocol, NSURL};

/// Configuration options for pipeline dataset serializer objects.
///
/// Use these options to enable different functionality in instances of ``MTL4PipelineDataSetSerializer``.
///
/// You can combine these values via a logical `OR` and set it to ``MTL4PipelineDataSetSerializerDescriptor/configuration``
/// to specify desired level of serialization support for instances of ``MTL4PipelineDataSetSerializer``.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtl4pipelinedatasetserializerconfiguration?language=objc)
// NS_OPTIONS
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MTL4PipelineDataSetSerializerConfiguration(pub usize);
bitflags::bitflags! {
    impl MTL4PipelineDataSetSerializerConfiguration: usize {
/// Enables serializing pipeline scripts.
///
/// Set this mask to use ``MTL4PipelineDataSetSerializer.serializeAsPipelinesScriptWithError``.
///
/// This for the default behavior.
        #[doc(alias = "MTL4PipelineDataSetSerializerConfigurationCaptureDescriptors")]
        const CaptureDescriptors = 1<<0;
/// Enables serializing pipeline binary functions.
///
/// Set this mask to use ``MTL4PipelineDataSetSerializer.serializeAsArchiveAndFlush(toURL:error:)``.
        #[doc(alias = "MTL4PipelineDataSetSerializerConfigurationCaptureBinaries")]
        const CaptureBinaries = 1<<1;
    }
}

unsafe impl Encode for MTL4PipelineDataSetSerializerConfiguration {
    const ENCODING: Encoding = usize::ENCODING;
}

unsafe impl RefEncode for MTL4PipelineDataSetSerializerConfiguration {
    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}

extern_class!(
    /// Groups together properties to create a pipeline data set serializer.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtl4pipelinedatasetserializerdescriptor?language=objc)
    #[unsafe(super(NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTL4PipelineDataSetSerializerDescriptor;
);

extern_conformance!(
    unsafe impl NSCopying for MTL4PipelineDataSetSerializerDescriptor {}
);

unsafe impl CopyingHelper for MTL4PipelineDataSetSerializerDescriptor {
    type Result = Self;
}

extern_conformance!(
    unsafe impl NSObjectProtocol for MTL4PipelineDataSetSerializerDescriptor {}
);

impl MTL4PipelineDataSetSerializerDescriptor {
    extern_methods!(
        /// Specifies the configuration of the serialization process.
        ///
        /// The configuration of the serialization process determines the mechanisms you use to serialize pipeline data sets.
        ///
        /// When this configuration contains ``MTL4PipelineDataSetSerializerConfigurationCaptureDescriptors``, use
        /// ``serializeAsPipelinesScriptWithError:`` to serialize pipeline scripts.
        ///
        /// If this option contains ``MTL4PipelineDataSetSerializerConfigurationCaptureBinaries``, the serializer can additionally
        /// serialize to a binary archive by calling ``serializeAsArchiveAndFlushToURL:error::``.
        #[unsafe(method(configuration))]
        #[unsafe(method_family = none)]
        pub fn configuration(&self) -> MTL4PipelineDataSetSerializerConfiguration;

        /// Setter for [`configuration`][Self::configuration].
        #[unsafe(method(setConfiguration:))]
        #[unsafe(method_family = none)]
        pub fn set_configuration(
            &self,
            configuration: MTL4PipelineDataSetSerializerConfiguration,
        );
    );
}

/// Methods declared on superclass `NSObject`.
impl MTL4PipelineDataSetSerializerDescriptor {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub fn new() -> Retained<Self>;
    );
}

extern_protocol!(
    /// A fast-addition container for collecting data during pipeline state creation.
    ///
    /// Pipeline data serializer instances allow you to create binary archives and serialize pipeline scripts to use with
    /// the offline Metal binary generator (`metal-tt`)
    /// <doc
    /// :compiling-binary-archives-from-a-custom-configuration-script.md>.
    ///
    /// You capture and retain all relevant data for all pipelines a compiler instance creates by providing an instance of
    /// this object to its ``MTL4CompilerDescriptor``.
    ///
    /// After capturing data, you can serialize it to a binary archive to persist its contents offline by calling
    /// ``serializeAsArchiveAndFlushToURL:error:``. You can also serialize a pipeline script suitable for the offline binary
    /// generator (`metal-tt`) by calling ``serializeAsPipelinesScriptWithError:``
    ///
    /// - Note: The objects ``MTL4PipelineDataSetSerializer`` contains are opaque and can't accelerate compilation for
    /// compilers they are not attached to. Additionally, your program can't read data out of data set serializer instances.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtl4pipelinedatasetserializer?language=objc)
    pub unsafe trait MTL4PipelineDataSetSerializer: NSObjectProtocol {}
);

pub trait MTL4PipelineDataSetSerializerExt: MTL4PipelineDataSetSerializer + Message {
    /// Serializes a pipeline data set to an archive at a filesystem path.
    fn serialize_as_archive_and_flush_to_path(
        &self,
        path: &Path,
    ) -> Result<(), Retained<NSError>>
    where
        Self: Sized,
    {
        let url = NSURL::from_file_path(path).expect("path must be a valid file URL path");
        unsafe { msg_send![self, serializeAsArchiveAndFlushToURL: &*url, error: _] }
    }

    /// Serializes a serializer data set to a pipeline script as bytes.
    fn serialize_as_pipelines_script(&self) -> Result<Box<[u8]>, Retained<NSError>>
    where
        Self: Sized,
    {
        let mut error: *mut NSError = std::ptr::null_mut();
        let data: Option<Retained<NSData>> =
            unsafe { msg_send![self, serializeAsPipelinesScriptWithError: &mut error] };
        match data {
            Some(data) => Ok(data.to_vec().into_boxed_slice()),
            None => Err(unsafe { Retained::retain(error).unwrap() }),
        }
    }
}

impl<T: MTL4PipelineDataSetSerializer + Message> MTL4PipelineDataSetSerializerExt for T {}