//! This file has been automatically generated by `objc2`'s `header-translator`.
//! DO NOT EDIT
use core::ffi::*;
use core::ptr::NonNull;
use objc2::__framework_prelude::*;
use objc2_foundation::*;

use crate::*;

/// Controls the acceleration structure refit operation
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructurerefitoptions?language=objc)
// NS_OPTIONS
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MTLAccelerationStructureRefitOptions(pub NSUInteger);
bitflags::bitflags! {
    impl MTLAccelerationStructureRefitOptions: NSUInteger {
/// Refitting shall result in updated vertex data from the provided geometry descriptor.
/// If not set, vertex buffers shall be ignored on the geometry descriptor and vertex data previously
/// encoded shall be copied.
        #[doc(alias = "MTLAccelerationStructureRefitOptionVertexData")]
        const VertexData = 1<<0;
/// Refitting shall result in updated per primitive data from the provided geometry descriptor.
/// If not set, per primitive data buffers shall be ignored on the geometry descriptor and per primitive
/// data previously encoded shall be copied.
        #[doc(alias = "MTLAccelerationStructureRefitOptionPerPrimitiveData")]
        const PerPrimitiveData = 1<<1;
    }
}

unsafe impl Encode for MTLAccelerationStructureRefitOptions {
    const ENCODING: Encoding = NSUInteger::ENCODING;
}

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

/// [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructureusage?language=objc)
// NS_OPTIONS
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MTLAccelerationStructureUsage(pub NSUInteger);
bitflags::bitflags! {
    impl MTLAccelerationStructureUsage: NSUInteger {
/// Default usage
        #[doc(alias = "MTLAccelerationStructureUsageNone")]
        const None = 0;
/// Enable refitting for this acceleration structure. Note that this may reduce
/// acceleration structure quality.
        #[doc(alias = "MTLAccelerationStructureUsageRefit")]
        const Refit = 1<<0;
/// Prefer building this acceleration structure quickly at the cost of reduced ray
/// tracing performance.
        #[doc(alias = "MTLAccelerationStructureUsagePreferFastBuild")]
        const PreferFastBuild = 1<<1;
/// Enable extended limits for this acceleration structure, possibly at the cost of
/// reduced ray tracing performance.
        #[doc(alias = "MTLAccelerationStructureUsageExtendedLimits")]
        const ExtendedLimits = 1<<2;
/// Prioritize intersection performance over acceleration structure build time
        #[doc(alias = "MTLAccelerationStructureUsagePreferFastIntersection")]
        const PreferFastIntersection = 1<<4;
/// Minimize the size of the acceleration structure in memory, potentially at
/// the cost of increased build time or reduced intersection performance.
        #[doc(alias = "MTLAccelerationStructureUsageMinimizeMemory")]
        const MinimizeMemory = 1<<5;
    }
}

unsafe impl Encode for MTLAccelerationStructureUsage {
    const ENCODING: Encoding = NSUInteger::ENCODING;
}

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

/// [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructureinstanceoptions?language=objc)
// NS_OPTIONS
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MTLAccelerationStructureInstanceOptions(pub u32);
bitflags::bitflags! {
    impl MTLAccelerationStructureInstanceOptions: u32 {
/// No options
        #[doc(alias = "MTLAccelerationStructureInstanceOptionNone")]
        const None = 0;
/// Disable triangle back or front face culling
        #[doc(alias = "MTLAccelerationStructureInstanceOptionDisableTriangleCulling")]
        const DisableTriangleCulling = 1<<0;
/// Override triangle front-facing winding. By default, the winding is
/// assumed to be clockwise unless overridden by the intersector object. This overrides
/// the intersector's winding order.
        #[doc(alias = "MTLAccelerationStructureInstanceOptionTriangleFrontFacingWindingCounterClockwise")]
        const TriangleFrontFacingWindingCounterClockwise = 1<<1;
/// Geometry is opaque
        #[doc(alias = "MTLAccelerationStructureInstanceOptionOpaque")]
        const Opaque = 1<<2;
/// Geometry is non-opaque
        #[doc(alias = "MTLAccelerationStructureInstanceOptionNonOpaque")]
        const NonOpaque = 1<<3;
    }
}

unsafe impl Encode for MTLAccelerationStructureInstanceOptions {
    const ENCODING: Encoding = u32::ENCODING;
}

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

/// [Apple's documentation](https://developer.apple.com/documentation/metal/mtlmatrixlayout?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MTLMatrixLayout(pub NSInteger);
impl MTLMatrixLayout {
    /// Column-major order
    #[doc(alias = "MTLMatrixLayoutColumnMajor")]
    pub const ColumnMajor: Self = Self(0);
    /// Row-major order
    #[doc(alias = "MTLMatrixLayoutRowMajor")]
    pub const RowMajor: Self = Self(1);
}

unsafe impl Encode for MTLMatrixLayout {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

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

extern_class!(
    /// Base class for acceleration structure descriptors. Do not use this class directly. Use
    /// one of the derived classes instead.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructuredescriptor?language=objc)
    #[unsafe(super(NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTLAccelerationStructureDescriptor;
);

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

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

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

impl MTLAccelerationStructureDescriptor {
    extern_methods!(
        #[unsafe(method(usage))]
        #[unsafe(method_family = none)]
        pub fn usage(&self) -> MTLAccelerationStructureUsage;

        /// Setter for [`usage`][Self::usage].
        #[unsafe(method(setUsage:))]
        #[unsafe(method_family = none)]
        pub fn setUsage(&self, usage: MTLAccelerationStructureUsage);
    );
}

/// Methods declared on superclass `NSObject`.
impl MTLAccelerationStructureDescriptor {
    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>;
    );
}

impl DefaultRetained for MTLAccelerationStructureDescriptor {
    #[inline]
    fn default_retained() -> Retained<Self> {
        Self::new()
    }
}

extern_class!(
    /// Base class for all geometry descriptors. Do not use this class directly. Use one of the derived
    /// classes instead.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructuregeometrydescriptor?language=objc)
    #[unsafe(super(NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTLAccelerationStructureGeometryDescriptor;
);

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

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

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

impl MTLAccelerationStructureGeometryDescriptor {
    extern_methods!(
        #[unsafe(method(intersectionFunctionTableOffset))]
        #[unsafe(method_family = none)]
        pub fn intersectionFunctionTableOffset(&self) -> NSUInteger;

        /// Setter for [`intersectionFunctionTableOffset`][Self::intersectionFunctionTableOffset].
        #[unsafe(method(setIntersectionFunctionTableOffset:))]
        #[unsafe(method_family = none)]
        pub fn setIntersectionFunctionTableOffset(
            &self,
            intersection_function_table_offset: NSUInteger,
        );

        /// Whether the geometry is opaque
        #[unsafe(method(opaque))]
        #[unsafe(method_family = none)]
        pub fn opaque(&self) -> bool;

        /// Setter for [`opaque`][Self::opaque].
        #[unsafe(method(setOpaque:))]
        #[unsafe(method_family = none)]
        pub fn setOpaque(&self, opaque: bool);

        /// Whether intersection functions may be invoked more than once per ray/primitive
        /// intersection. Defaults to YES.
        #[unsafe(method(allowDuplicateIntersectionFunctionInvocation))]
        #[unsafe(method_family = none)]
        pub fn allowDuplicateIntersectionFunctionInvocation(&self) -> bool;

        /// Setter for [`allowDuplicateIntersectionFunctionInvocation`][Self::allowDuplicateIntersectionFunctionInvocation].
        #[unsafe(method(setAllowDuplicateIntersectionFunctionInvocation:))]
        #[unsafe(method_family = none)]
        pub fn setAllowDuplicateIntersectionFunctionInvocation(
            &self,
            allow_duplicate_intersection_function_invocation: bool,
        );

        /// Label
        #[unsafe(method(label))]
        #[unsafe(method_family = none)]
        pub fn label(&self) -> Option<Retained<NSString>>;

        /// Setter for [`label`][Self::label].
        ///
        /// This is [copied][objc2_foundation::NSCopying::copy] when set.
        #[unsafe(method(setLabel:))]
        #[unsafe(method_family = none)]
        pub fn setLabel(&self, label: Option<&NSString>);

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Data buffer containing per-primitive data. May be nil.
        #[unsafe(method(primitiveDataBuffer))]
        #[unsafe(method_family = none)]
        pub fn primitiveDataBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`primitiveDataBuffer`][Self::primitiveDataBuffer].
        #[unsafe(method(setPrimitiveDataBuffer:))]
        #[unsafe(method_family = none)]
        pub fn setPrimitiveDataBuffer(
            &self,
            primitive_data_buffer: Option<&ProtocolObject<dyn MTLBuffer>>,
        );

        /// Primitive data buffer offset in bytes. Must be aligned to the platform's buffer offset alignment. Defaults to 0 bytes.
        #[unsafe(method(primitiveDataBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn primitiveDataBufferOffset(&self) -> NSUInteger;

        /// Setter for [`primitiveDataBufferOffset`][Self::primitiveDataBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setPrimitiveDataBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setPrimitiveDataBufferOffset(&self, primitive_data_buffer_offset: NSUInteger);

        /// Stride, in bytes, between per-primitive data in the primitive data buffer. Must be at least primitiveDataElementSize and must be a
        /// multiple of 4 bytes. Defaults to 0 bytes. Assumed to be equal to primitiveDataElementSize if zero.
        #[unsafe(method(primitiveDataStride))]
        #[unsafe(method_family = none)]
        pub fn primitiveDataStride(&self) -> NSUInteger;

        /// Setter for [`primitiveDataStride`][Self::primitiveDataStride].
        #[unsafe(method(setPrimitiveDataStride:))]
        #[unsafe(method_family = none)]
        pub fn setPrimitiveDataStride(&self, primitive_data_stride: NSUInteger);

        /// Size, in bytes, of the data for each primitive in the primitive data buffer. Must be at most primitiveDataStride and must be a
        /// multiple of 4 bytes. Defaults to 0 bytes.
        #[unsafe(method(primitiveDataElementSize))]
        #[unsafe(method_family = none)]
        pub fn primitiveDataElementSize(&self) -> NSUInteger;

        /// Setter for [`primitiveDataElementSize`][Self::primitiveDataElementSize].
        #[unsafe(method(setPrimitiveDataElementSize:))]
        #[unsafe(method_family = none)]
        pub fn setPrimitiveDataElementSize(&self, primitive_data_element_size: NSUInteger);
    );
}

/// Methods declared on superclass `NSObject`.
impl MTLAccelerationStructureGeometryDescriptor {
    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>;
    );
}

impl DefaultRetained for MTLAccelerationStructureGeometryDescriptor {
    #[inline]
    fn default_retained() -> Retained<Self> {
        Self::new()
    }
}

/// Describes what happens to the object before the first motion key and after the last
/// motion key.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlmotionbordermode?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MTLMotionBorderMode(pub u32);
impl MTLMotionBorderMode {
    /// Motion is stopped. (default)
    #[doc(alias = "MTLMotionBorderModeClamp")]
    pub const Clamp: Self = Self(0);
    /// Object disappears
    #[doc(alias = "MTLMotionBorderModeVanish")]
    pub const Vanish: Self = Self(1);
}

unsafe impl Encode for MTLMotionBorderMode {
    const ENCODING: Encoding = u32::ENCODING;
}

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

extern_class!(
    /// Descriptor for a primitive acceleration structure
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlprimitiveaccelerationstructuredescriptor?language=objc)
    #[unsafe(super(MTLAccelerationStructureDescriptor, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTLPrimitiveAccelerationStructureDescriptor;
);

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

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

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

impl MTLPrimitiveAccelerationStructureDescriptor {
    extern_methods!(
        /// Array of geometry descriptors. If motionKeyframeCount is greater than one all geometryDescriptors
        /// must be motion versions and have motionKeyframeCount of primitive buffers.
        #[unsafe(method(geometryDescriptors))]
        #[unsafe(method_family = none)]
        pub fn geometryDescriptors(
            &self,
        ) -> Option<Retained<NSArray<MTLAccelerationStructureGeometryDescriptor>>>;

        /// Setter for [`geometryDescriptors`][Self::geometryDescriptors].
        #[unsafe(method(setGeometryDescriptors:))]
        #[unsafe(method_family = none)]
        pub fn setGeometryDescriptors(
            &self,
            geometry_descriptors: Option<&NSArray<MTLAccelerationStructureGeometryDescriptor>>,
        );

        /// Motion border mode describing what happens if acceleration structure is sampled before
        /// motionStartTime. If not set defaults to MTLMotionBorderModeClamp.
        #[unsafe(method(motionStartBorderMode))]
        #[unsafe(method_family = none)]
        pub fn motionStartBorderMode(&self) -> MTLMotionBorderMode;

        /// Setter for [`motionStartBorderMode`][Self::motionStartBorderMode].
        #[unsafe(method(setMotionStartBorderMode:))]
        #[unsafe(method_family = none)]
        pub fn setMotionStartBorderMode(&self, motion_start_border_mode: MTLMotionBorderMode);

        /// Motion border mode describing what happens if acceleration structure is sampled after
        /// motionEndTime. If not set defaults to MTLMotionBorderModeClamp.
        #[unsafe(method(motionEndBorderMode))]
        #[unsafe(method_family = none)]
        pub fn motionEndBorderMode(&self) -> MTLMotionBorderMode;

        /// Setter for [`motionEndBorderMode`][Self::motionEndBorderMode].
        #[unsafe(method(setMotionEndBorderMode:))]
        #[unsafe(method_family = none)]
        pub fn setMotionEndBorderMode(&self, motion_end_border_mode: MTLMotionBorderMode);

        /// Motion start time of this geometry. If not set defaults to 0.0f.
        #[unsafe(method(motionStartTime))]
        #[unsafe(method_family = none)]
        pub fn motionStartTime(&self) -> c_float;

        /// Setter for [`motionStartTime`][Self::motionStartTime].
        #[unsafe(method(setMotionStartTime:))]
        #[unsafe(method_family = none)]
        pub fn setMotionStartTime(&self, motion_start_time: c_float);

        /// Motion end time of this geometry. If not set defaults to 1.0f.
        #[unsafe(method(motionEndTime))]
        #[unsafe(method_family = none)]
        pub fn motionEndTime(&self) -> c_float;

        /// Setter for [`motionEndTime`][Self::motionEndTime].
        #[unsafe(method(setMotionEndTime:))]
        #[unsafe(method_family = none)]
        pub fn setMotionEndTime(&self, motion_end_time: c_float);

        /// Motion keyframe count. Is 1 by default which means no motion.
        #[unsafe(method(motionKeyframeCount))]
        #[unsafe(method_family = none)]
        pub fn motionKeyframeCount(&self) -> NSUInteger;

        /// Setter for [`motionKeyframeCount`][Self::motionKeyframeCount].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setMotionKeyframeCount:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMotionKeyframeCount(&self, motion_keyframe_count: NSUInteger);

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

/// Methods declared on superclass `NSObject`.
impl MTLPrimitiveAccelerationStructureDescriptor {
    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>;
    );
}

impl DefaultRetained for MTLPrimitiveAccelerationStructureDescriptor {
    #[inline]
    fn default_retained() -> Retained<Self> {
        Self::new()
    }
}

extern_class!(
    /// Descriptor for triangle geometry
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructuretrianglegeometrydescriptor?language=objc)
    #[unsafe(super(MTLAccelerationStructureGeometryDescriptor, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTLAccelerationStructureTriangleGeometryDescriptor;
);

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

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

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

impl MTLAccelerationStructureTriangleGeometryDescriptor {
    extern_methods!(
        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Vertex buffer containing triangle vertices. Each vertex position must be formatted
        /// according to the vertex format. Must not be nil.
        #[unsafe(method(vertexBuffer))]
        #[unsafe(method_family = none)]
        pub fn vertexBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`vertexBuffer`][Self::vertexBuffer].
        #[unsafe(method(setVertexBuffer:))]
        #[unsafe(method_family = none)]
        pub fn setVertexBuffer(&self, vertex_buffer: Option<&ProtocolObject<dyn MTLBuffer>>);

        /// Vertex buffer offset. Must be a multiple of the vertex stride and must be aligned to the
        /// platform's buffer offset alignment.
        #[unsafe(method(vertexBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn vertexBufferOffset(&self) -> NSUInteger;

        /// Setter for [`vertexBufferOffset`][Self::vertexBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setVertexBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setVertexBufferOffset(&self, vertex_buffer_offset: NSUInteger);

        #[cfg(feature = "MTLStageInputOutputDescriptor")]
        /// Format type of the vertex buffer.
        /// Defaults to MTLAttributeFormatFloat3 (packed).
        #[unsafe(method(vertexFormat))]
        #[unsafe(method_family = none)]
        pub fn vertexFormat(&self) -> MTLAttributeFormat;

        #[cfg(feature = "MTLStageInputOutputDescriptor")]
        /// Setter for [`vertexFormat`][Self::vertexFormat].
        #[unsafe(method(setVertexFormat:))]
        #[unsafe(method_family = none)]
        pub fn setVertexFormat(&self, vertex_format: MTLAttributeFormat);

        /// Stride, in bytes, between vertices in the vertex buffer. Must be a multiple of the vertex format data type size and must be aligned to
        /// the vertex format data type's alignment. Defaults to 0, which will result in a stride of the vertex format data size.
        #[unsafe(method(vertexStride))]
        #[unsafe(method_family = none)]
        pub fn vertexStride(&self) -> NSUInteger;

        /// Setter for [`vertexStride`][Self::vertexStride].
        #[unsafe(method(setVertexStride:))]
        #[unsafe(method_family = none)]
        pub fn setVertexStride(&self, vertex_stride: NSUInteger);

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Optional index buffer containing references to vertices in the vertex buffer. May be nil.
        #[unsafe(method(indexBuffer))]
        #[unsafe(method_family = none)]
        pub fn indexBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`indexBuffer`][Self::indexBuffer].
        #[unsafe(method(setIndexBuffer:))]
        #[unsafe(method_family = none)]
        pub fn setIndexBuffer(&self, index_buffer: Option<&ProtocolObject<dyn MTLBuffer>>);

        /// Index buffer offset. Must be a multiple of the index data type size and must be aligned to both
        /// the index data type's alignment and the platform's buffer offset alignment.
        #[unsafe(method(indexBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn indexBufferOffset(&self) -> NSUInteger;

        /// Setter for [`indexBufferOffset`][Self::indexBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setIndexBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setIndexBufferOffset(&self, index_buffer_offset: NSUInteger);

        #[cfg(feature = "MTLArgument")]
        /// Index type
        #[unsafe(method(indexType))]
        #[unsafe(method_family = none)]
        pub fn indexType(&self) -> MTLIndexType;

        #[cfg(feature = "MTLArgument")]
        /// Setter for [`indexType`][Self::indexType].
        #[unsafe(method(setIndexType:))]
        #[unsafe(method_family = none)]
        pub fn setIndexType(&self, index_type: MTLIndexType);

        /// Number of triangles
        #[unsafe(method(triangleCount))]
        #[unsafe(method_family = none)]
        pub fn triangleCount(&self) -> NSUInteger;

        /// Setter for [`triangleCount`][Self::triangleCount].
        #[unsafe(method(setTriangleCount:))]
        #[unsafe(method_family = none)]
        pub fn setTriangleCount(&self, triangle_count: NSUInteger);

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Buffer containing packed float4x3 transformation matrix. Transform is applied to the vertex data when building the acceleration structure. Input vertex buffers are not modified.
        /// When set to nil, transformation matrix is not applied to vertex data.
        #[unsafe(method(transformationMatrixBuffer))]
        #[unsafe(method_family = none)]
        pub fn transformationMatrixBuffer(&self)
            -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`transformationMatrixBuffer`][Self::transformationMatrixBuffer].
        ///
        /// # Safety
        ///
        /// - `transformation_matrix_buffer` may need to be synchronized.
        /// - `transformation_matrix_buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `transformation_matrix_buffer` contents should be of the correct type.
        #[unsafe(method(setTransformationMatrixBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setTransformationMatrixBuffer(
            &self,
            transformation_matrix_buffer: Option<&ProtocolObject<dyn MTLBuffer>>,
        );

        /// Transformation matrix buffer offset. Must be a multiple of 4 bytes. Defaults to 0.
        #[unsafe(method(transformationMatrixBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn transformationMatrixBufferOffset(&self) -> NSUInteger;

        /// Setter for [`transformationMatrixBufferOffset`][Self::transformationMatrixBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setTransformationMatrixBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setTransformationMatrixBufferOffset(
            &self,
            transformation_matrix_buffer_offset: NSUInteger,
        );

        /// Matrix layout for the transformation matrix in the transformation
        /// matrix buffer. Defaults to MTLMatrixLayoutColumnMajor.
        #[unsafe(method(transformationMatrixLayout))]
        #[unsafe(method_family = none)]
        pub fn transformationMatrixLayout(&self) -> MTLMatrixLayout;

        /// Setter for [`transformationMatrixLayout`][Self::transformationMatrixLayout].
        #[unsafe(method(setTransformationMatrixLayout:))]
        #[unsafe(method_family = none)]
        pub fn setTransformationMatrixLayout(&self, transformation_matrix_layout: MTLMatrixLayout);

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

/// Methods declared on superclass `NSObject`.
impl MTLAccelerationStructureTriangleGeometryDescriptor {
    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>;
    );
}

impl DefaultRetained for MTLAccelerationStructureTriangleGeometryDescriptor {
    #[inline]
    fn default_retained() -> Retained<Self> {
        Self::new()
    }
}

extern_class!(
    /// Descriptor for bounding box geometry
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructureboundingboxgeometrydescriptor?language=objc)
    #[unsafe(super(MTLAccelerationStructureGeometryDescriptor, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTLAccelerationStructureBoundingBoxGeometryDescriptor;
);

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

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

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

impl MTLAccelerationStructureBoundingBoxGeometryDescriptor {
    extern_methods!(
        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Bounding box buffer containing MTLAxisAlignedBoundingBoxes. Must not be nil.
        #[unsafe(method(boundingBoxBuffer))]
        #[unsafe(method_family = none)]
        pub fn boundingBoxBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`boundingBoxBuffer`][Self::boundingBoxBuffer].
        #[unsafe(method(setBoundingBoxBuffer:))]
        #[unsafe(method_family = none)]
        pub fn setBoundingBoxBuffer(
            &self,
            bounding_box_buffer: Option<&ProtocolObject<dyn MTLBuffer>>,
        );

        /// Bounding box buffer offset. Must be a multiple of the bounding box stride and must be
        /// aligned to the platform's buffer offset alignment.
        #[unsafe(method(boundingBoxBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn boundingBoxBufferOffset(&self) -> NSUInteger;

        /// Setter for [`boundingBoxBufferOffset`][Self::boundingBoxBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setBoundingBoxBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setBoundingBoxBufferOffset(&self, bounding_box_buffer_offset: NSUInteger);

        /// Stride, in bytes, between bounding boxes in the bounding box buffer. Must be at least 24
        /// bytes and must be a multiple of 4 bytes. Defaults to 24 bytes.
        #[unsafe(method(boundingBoxStride))]
        #[unsafe(method_family = none)]
        pub fn boundingBoxStride(&self) -> NSUInteger;

        /// Setter for [`boundingBoxStride`][Self::boundingBoxStride].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setBoundingBoxStride:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setBoundingBoxStride(&self, bounding_box_stride: NSUInteger);

        /// Number of bounding boxes
        #[unsafe(method(boundingBoxCount))]
        #[unsafe(method_family = none)]
        pub fn boundingBoxCount(&self) -> NSUInteger;

        /// Setter for [`boundingBoxCount`][Self::boundingBoxCount].
        #[unsafe(method(setBoundingBoxCount:))]
        #[unsafe(method_family = none)]
        pub fn setBoundingBoxCount(&self, bounding_box_count: NSUInteger);

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

/// Methods declared on superclass `NSObject`.
impl MTLAccelerationStructureBoundingBoxGeometryDescriptor {
    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>;
    );
}

impl DefaultRetained for MTLAccelerationStructureBoundingBoxGeometryDescriptor {
    #[inline]
    fn default_retained() -> Retained<Self> {
        Self::new()
    }
}

extern_class!(
    /// MTLbuffer and description how the data is stored in it.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlmotionkeyframedata?language=objc)
    #[unsafe(super(NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTLMotionKeyframeData;
);

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

impl MTLMotionKeyframeData {
    extern_methods!(
        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Buffer containing the data of a single keyframe. Multiple keyframes can be interleaved in one MTLBuffer.
        #[unsafe(method(buffer))]
        #[unsafe(method_family = none)]
        pub fn buffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`buffer`][Self::buffer].
        ///
        /// # Safety
        ///
        /// - `buffer` may need to be synchronized.
        /// - `buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `buffer` contents should be of the correct type.
        #[unsafe(method(setBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setBuffer(&self, buffer: Option<&ProtocolObject<dyn MTLBuffer>>);

        /// Buffer offset. Must be a multiple of 4 bytes.
        #[unsafe(method(offset))]
        #[unsafe(method_family = none)]
        pub fn offset(&self) -> NSUInteger;

        /// Setter for [`offset`][Self::offset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setOffset(&self, offset: NSUInteger);

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

/// Methods declared on superclass `NSObject`.
impl MTLMotionKeyframeData {
    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>;
    );
}

impl DefaultRetained for MTLMotionKeyframeData {
    #[inline]
    fn default_retained() -> Retained<Self> {
        Self::new()
    }
}

extern_class!(
    /// Descriptor for motion triangle geometry
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructuremotiontrianglegeometrydescriptor?language=objc)
    #[unsafe(super(MTLAccelerationStructureGeometryDescriptor, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTLAccelerationStructureMotionTriangleGeometryDescriptor;
);

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

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

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

impl MTLAccelerationStructureMotionTriangleGeometryDescriptor {
    extern_methods!(
        /// Vertex buffer containing triangle vertices similar to what MTLAccelerationStructureTriangleGeometryDescriptor has but array of the values.
        #[unsafe(method(vertexBuffers))]
        #[unsafe(method_family = none)]
        pub fn vertexBuffers(&self) -> Retained<NSArray<MTLMotionKeyframeData>>;

        /// Setter for [`vertexBuffers`][Self::vertexBuffers].
        ///
        /// This is [copied][objc2_foundation::NSCopying::copy] when set.
        #[unsafe(method(setVertexBuffers:))]
        #[unsafe(method_family = none)]
        pub fn setVertexBuffers(&self, vertex_buffers: &NSArray<MTLMotionKeyframeData>);

        #[cfg(feature = "MTLStageInputOutputDescriptor")]
        /// Format type of the vertex buffers across all keyframes.
        /// Defaults to MTLAttributeFormatFloat3 (packed).
        #[unsafe(method(vertexFormat))]
        #[unsafe(method_family = none)]
        pub fn vertexFormat(&self) -> MTLAttributeFormat;

        #[cfg(feature = "MTLStageInputOutputDescriptor")]
        /// Setter for [`vertexFormat`][Self::vertexFormat].
        #[unsafe(method(setVertexFormat:))]
        #[unsafe(method_family = none)]
        pub fn setVertexFormat(&self, vertex_format: MTLAttributeFormat);

        /// Stride, in bytes, between vertices in each keyframe's vertex buffer. Must be a multiple of the vertex format data type size and must be aligned to
        /// the vertex format data type's alignment. Defaults to 0, which will result in a stride of the vertex format data size.
        #[unsafe(method(vertexStride))]
        #[unsafe(method_family = none)]
        pub fn vertexStride(&self) -> NSUInteger;

        /// Setter for [`vertexStride`][Self::vertexStride].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setVertexStride:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setVertexStride(&self, vertex_stride: NSUInteger);

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Optional index buffer containing references to vertices in the vertex buffer. May be nil.
        #[unsafe(method(indexBuffer))]
        #[unsafe(method_family = none)]
        pub fn indexBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`indexBuffer`][Self::indexBuffer].
        ///
        /// # Safety
        ///
        /// - `index_buffer` may need to be synchronized.
        /// - `index_buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `index_buffer` contents should be of the correct type.
        #[unsafe(method(setIndexBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setIndexBuffer(&self, index_buffer: Option<&ProtocolObject<dyn MTLBuffer>>);

        /// Index buffer offset. Must be a multiple of the index data type size and must be aligned to both
        /// the index data type's alignment and the platform's buffer offset alignment.
        #[unsafe(method(indexBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn indexBufferOffset(&self) -> NSUInteger;

        /// Setter for [`indexBufferOffset`][Self::indexBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setIndexBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setIndexBufferOffset(&self, index_buffer_offset: NSUInteger);

        #[cfg(feature = "MTLArgument")]
        /// Index type
        #[unsafe(method(indexType))]
        #[unsafe(method_family = none)]
        pub fn indexType(&self) -> MTLIndexType;

        #[cfg(feature = "MTLArgument")]
        /// Setter for [`indexType`][Self::indexType].
        #[unsafe(method(setIndexType:))]
        #[unsafe(method_family = none)]
        pub fn setIndexType(&self, index_type: MTLIndexType);

        /// Number of triangles
        #[unsafe(method(triangleCount))]
        #[unsafe(method_family = none)]
        pub fn triangleCount(&self) -> NSUInteger;

        /// Setter for [`triangleCount`][Self::triangleCount].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setTriangleCount:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setTriangleCount(&self, triangle_count: NSUInteger);

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Buffer containing packed float4x3 transformation matrix. Transform is applied to the vertex data when building the acceleration structure. Input vertex buffers are not modified.
        /// The transformation matrix is applied to all keyframes' vertex data.
        /// When set to nil, transformation matrix is not applied to vertex data.
        #[unsafe(method(transformationMatrixBuffer))]
        #[unsafe(method_family = none)]
        pub fn transformationMatrixBuffer(&self)
            -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`transformationMatrixBuffer`][Self::transformationMatrixBuffer].
        ///
        /// # Safety
        ///
        /// - `transformation_matrix_buffer` may need to be synchronized.
        /// - `transformation_matrix_buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `transformation_matrix_buffer` contents should be of the correct type.
        #[unsafe(method(setTransformationMatrixBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setTransformationMatrixBuffer(
            &self,
            transformation_matrix_buffer: Option<&ProtocolObject<dyn MTLBuffer>>,
        );

        /// Transformation matrix buffer offset. Must be a multiple of 4 bytes. Defaults to 0.
        #[unsafe(method(transformationMatrixBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn transformationMatrixBufferOffset(&self) -> NSUInteger;

        /// Setter for [`transformationMatrixBufferOffset`][Self::transformationMatrixBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setTransformationMatrixBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setTransformationMatrixBufferOffset(
            &self,
            transformation_matrix_buffer_offset: NSUInteger,
        );

        /// Matrix layout for the transformation matrix in the transformation
        /// matrix buffer. Defaults to MTLMatrixLayoutColumnMajor.
        #[unsafe(method(transformationMatrixLayout))]
        #[unsafe(method_family = none)]
        pub fn transformationMatrixLayout(&self) -> MTLMatrixLayout;

        /// Setter for [`transformationMatrixLayout`][Self::transformationMatrixLayout].
        #[unsafe(method(setTransformationMatrixLayout:))]
        #[unsafe(method_family = none)]
        pub fn setTransformationMatrixLayout(&self, transformation_matrix_layout: MTLMatrixLayout);

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

/// Methods declared on superclass `NSObject`.
impl MTLAccelerationStructureMotionTriangleGeometryDescriptor {
    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>;
    );
}

impl DefaultRetained for MTLAccelerationStructureMotionTriangleGeometryDescriptor {
    #[inline]
    fn default_retained() -> Retained<Self> {
        Self::new()
    }
}

extern_class!(
    /// Descriptor for motion bounding box geometry
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructuremotionboundingboxgeometrydescriptor?language=objc)
    #[unsafe(super(MTLAccelerationStructureGeometryDescriptor, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor;
);

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

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

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

impl MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor {
    extern_methods!(
        /// Bounding box buffer containing MTLAxisAlignedBoundingBoxes similar to what MTLAccelerationStructureBoundingBoxGeometryDescriptor has but array of the values.
        #[unsafe(method(boundingBoxBuffers))]
        #[unsafe(method_family = none)]
        pub fn boundingBoxBuffers(&self) -> Retained<NSArray<MTLMotionKeyframeData>>;

        /// Setter for [`boundingBoxBuffers`][Self::boundingBoxBuffers].
        ///
        /// This is [copied][objc2_foundation::NSCopying::copy] when set.
        #[unsafe(method(setBoundingBoxBuffers:))]
        #[unsafe(method_family = none)]
        pub fn setBoundingBoxBuffers(&self, bounding_box_buffers: &NSArray<MTLMotionKeyframeData>);

        /// Stride, in bytes, between bounding boxes in the bounding box buffer. Must be at least 24
        /// bytes and must be a multiple of 4 bytes. Defaults to 24 bytes.
        #[unsafe(method(boundingBoxStride))]
        #[unsafe(method_family = none)]
        pub fn boundingBoxStride(&self) -> NSUInteger;

        /// Setter for [`boundingBoxStride`][Self::boundingBoxStride].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setBoundingBoxStride:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setBoundingBoxStride(&self, bounding_box_stride: NSUInteger);

        /// Number of bounding boxes
        #[unsafe(method(boundingBoxCount))]
        #[unsafe(method_family = none)]
        pub fn boundingBoxCount(&self) -> NSUInteger;

        /// Setter for [`boundingBoxCount`][Self::boundingBoxCount].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setBoundingBoxCount:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setBoundingBoxCount(&self, bounding_box_count: NSUInteger);

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

/// Methods declared on superclass `NSObject`.
impl MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor {
    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>;
    );
}

impl DefaultRetained for MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor {
    #[inline]
    fn default_retained() -> Retained<Self> {
        Self::new()
    }
}

/// Curve types
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlcurvetype?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MTLCurveType(pub NSInteger);
impl MTLCurveType {
    /// Curve with a circular cross-section. These curves have the
    /// advantage of having a real 3D shape consistent across different ray
    /// directions, well-defined surface normals, etc. However, they may be
    /// slower to intersect. These curves are ideal for viewing close-up.
    #[doc(alias = "MTLCurveTypeRound")]
    pub const Round: Self = Self(0);
    /// Curve with a flat cross-section aligned with the ray direction.
    /// These curves may be faster to intersect but do not have a consistent
    /// 3D structure across different rays. These curves are ideal for viewing
    /// at a distance or curves with a small radius such as hair and fur.
    #[doc(alias = "MTLCurveTypeFlat")]
    pub const Flat: Self = Self(1);
}

unsafe impl Encode for MTLCurveType {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

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

/// Basis function to use to interpolate curve control points
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlcurvebasis?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MTLCurveBasis(pub NSInteger);
impl MTLCurveBasis {
    /// B-Spline basis. Each curve segment must have 3 or 4 control
    /// points. Curve segments join with C^(N - 2) continuity, where N is
    /// the number of control points. The curve does not necessarily pass
    /// through the control points without additional control points at the
    /// beginning and end of the curve. Each curve segment can overlap
    /// N-1 control points.
    #[doc(alias = "MTLCurveBasisBSpline")]
    pub const BSpline: Self = Self(0);
    /// Catmull-Rom basis. Curves represented in this basis can also be
    /// easily converted to and from the Bézier basis. Each curve segment must
    /// have 4 control points. Each index in the control point index buffer
    /// points to the first of 4 consecutive control points in the control point
    /// buffer.
    ///
    /// The tangent at each control point is given by
    /// (P_(i+1) - P_(i-1)) / 2. Therefore, the curve does not pass through the
    /// first and last control point of each connected sequence of curve
    /// segments. Instead, the first and last control point are used to control
    /// the tangent vector at the beginning and end of the curve.
    ///
    /// Curve segments join with C^1 continuity and the
    /// curve passes through the control points. Each curve segment can overlap
    /// 3 control points.
    #[doc(alias = "MTLCurveBasisCatmullRom")]
    pub const CatmullRom: Self = Self(1);
    /// Linear basis. The curve is made of a sequence of connected line
    /// segments each with 2 control points.
    #[doc(alias = "MTLCurveBasisLinear")]
    pub const Linear: Self = Self(2);
    /// Bezier basis
    #[doc(alias = "MTLCurveBasisBezier")]
    pub const Bezier: Self = Self(3);
}

unsafe impl Encode for MTLCurveBasis {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

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

/// Type of end cap to insert at the beginning and end of each connected
/// sequence of curve segments.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlcurveendcaps?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MTLCurveEndCaps(pub NSInteger);
impl MTLCurveEndCaps {
    /// No end caps
    #[doc(alias = "MTLCurveEndCapsNone")]
    pub const None: Self = Self(0);
    /// Disk end caps
    #[doc(alias = "MTLCurveEndCapsDisk")]
    pub const Disk: Self = Self(1);
    /// Spherical end caps
    #[doc(alias = "MTLCurveEndCapsSphere")]
    pub const Sphere: Self = Self(2);
}

unsafe impl Encode for MTLCurveEndCaps {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

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

extern_class!(
    /// Acceleration structure geometry descriptor describing geometry
    /// made of curve primitives
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructurecurvegeometrydescriptor?language=objc)
    #[unsafe(super(MTLAccelerationStructureGeometryDescriptor, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTLAccelerationStructureCurveGeometryDescriptor;
);

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

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

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

impl MTLAccelerationStructureCurveGeometryDescriptor {
    extern_methods!(
        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Buffer containing curve control points. Each control point must
        /// be of the format specified by the control point format. Must not be
        /// nil when the acceleration structure is built.
        #[unsafe(method(controlPointBuffer))]
        #[unsafe(method_family = none)]
        pub fn controlPointBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`controlPointBuffer`][Self::controlPointBuffer].
        ///
        /// # Safety
        ///
        /// - `control_point_buffer` may need to be synchronized.
        /// - `control_point_buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `control_point_buffer` contents should be of the correct type.
        #[unsafe(method(setControlPointBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setControlPointBuffer(
            &self,
            control_point_buffer: Option<&ProtocolObject<dyn MTLBuffer>>,
        );

        /// Control point buffer offset. Must be a multiple of the control
        /// point format's element size and must be aligned to the platform's
        /// buffer offset alignment.
        #[unsafe(method(controlPointBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn controlPointBufferOffset(&self) -> NSUInteger;

        /// Setter for [`controlPointBufferOffset`][Self::controlPointBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setControlPointBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setControlPointBufferOffset(&self, control_point_buffer_offset: NSUInteger);

        /// Number of control points in the control point buffer
        #[unsafe(method(controlPointCount))]
        #[unsafe(method_family = none)]
        pub fn controlPointCount(&self) -> NSUInteger;

        /// Setter for [`controlPointCount`][Self::controlPointCount].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setControlPointCount:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setControlPointCount(&self, control_point_count: NSUInteger);

        /// Stride, in bytes, between control points in the control point
        /// buffer. Must be a multiple of the control point format's element size
        /// and must be at least the control point format's size. Defaults to 0
        /// bytes, indicating that the control points are tightly packed.
        #[unsafe(method(controlPointStride))]
        #[unsafe(method_family = none)]
        pub fn controlPointStride(&self) -> NSUInteger;

        /// Setter for [`controlPointStride`][Self::controlPointStride].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setControlPointStride:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setControlPointStride(&self, control_point_stride: NSUInteger);

        #[cfg(feature = "MTLStageInputOutputDescriptor")]
        /// Format of the control points in the control point buffer.
        /// Defaults to MTLAttributeFormatFloat3 (packed).
        #[unsafe(method(controlPointFormat))]
        #[unsafe(method_family = none)]
        pub fn controlPointFormat(&self) -> MTLAttributeFormat;

        #[cfg(feature = "MTLStageInputOutputDescriptor")]
        /// Setter for [`controlPointFormat`][Self::controlPointFormat].
        #[unsafe(method(setControlPointFormat:))]
        #[unsafe(method_family = none)]
        pub fn setControlPointFormat(&self, control_point_format: MTLAttributeFormat);

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Buffer containing the curve radius for each control point. Each
        /// radius must be of the type specified by the radius format. Each radius
        /// must be at least zero. Must not be nil when the acceleration structure
        /// is built.
        #[unsafe(method(radiusBuffer))]
        #[unsafe(method_family = none)]
        pub fn radiusBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`radiusBuffer`][Self::radiusBuffer].
        ///
        /// # Safety
        ///
        /// - `radius_buffer` may need to be synchronized.
        /// - `radius_buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `radius_buffer` contents should be of the correct type.
        #[unsafe(method(setRadiusBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setRadiusBuffer(&self, radius_buffer: Option<&ProtocolObject<dyn MTLBuffer>>);

        /// Radius buffer offset. Must be a multiple of the radius format
        /// size and must be aligned to the platform's buffer offset alignment.
        #[unsafe(method(radiusBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn radiusBufferOffset(&self) -> NSUInteger;

        /// Setter for [`radiusBufferOffset`][Self::radiusBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setRadiusBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setRadiusBufferOffset(&self, radius_buffer_offset: NSUInteger);

        #[cfg(feature = "MTLStageInputOutputDescriptor")]
        /// Format of the radii in the radius buffer. Defaults to
        /// MTLAttributeFormatFloat.
        #[unsafe(method(radiusFormat))]
        #[unsafe(method_family = none)]
        pub fn radiusFormat(&self) -> MTLAttributeFormat;

        #[cfg(feature = "MTLStageInputOutputDescriptor")]
        /// Setter for [`radiusFormat`][Self::radiusFormat].
        #[unsafe(method(setRadiusFormat:))]
        #[unsafe(method_family = none)]
        pub fn setRadiusFormat(&self, radius_format: MTLAttributeFormat);

        /// Stride, in bytes, between radii in the radius buffer. Must be
        /// a multiple of the radius format size. Defaults to 0 bytes, indicating
        /// that the radii are tightly packed.
        #[unsafe(method(radiusStride))]
        #[unsafe(method_family = none)]
        pub fn radiusStride(&self) -> NSUInteger;

        /// Setter for [`radiusStride`][Self::radiusStride].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setRadiusStride:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setRadiusStride(&self, radius_stride: NSUInteger);

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Index buffer containing references to control points in the control
        /// point buffer. Must not be nil when the acceleration structure is built.
        #[unsafe(method(indexBuffer))]
        #[unsafe(method_family = none)]
        pub fn indexBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`indexBuffer`][Self::indexBuffer].
        ///
        /// # Safety
        ///
        /// - `index_buffer` may need to be synchronized.
        /// - `index_buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `index_buffer` contents should be of the correct type.
        #[unsafe(method(setIndexBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setIndexBuffer(&self, index_buffer: Option<&ProtocolObject<dyn MTLBuffer>>);

        /// Index buffer offset. Must be a multiple of the index data type
        /// size and must be aligned to both the index data type's alignment and
        /// the platform's buffer offset alignment.
        #[unsafe(method(indexBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn indexBufferOffset(&self) -> NSUInteger;

        /// Setter for [`indexBufferOffset`][Self::indexBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setIndexBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setIndexBufferOffset(&self, index_buffer_offset: NSUInteger);

        #[cfg(feature = "MTLArgument")]
        /// Index type
        #[unsafe(method(indexType))]
        #[unsafe(method_family = none)]
        pub fn indexType(&self) -> MTLIndexType;

        #[cfg(feature = "MTLArgument")]
        /// Setter for [`indexType`][Self::indexType].
        #[unsafe(method(setIndexType:))]
        #[unsafe(method_family = none)]
        pub fn setIndexType(&self, index_type: MTLIndexType);

        /// Number of curve segments
        #[unsafe(method(segmentCount))]
        #[unsafe(method_family = none)]
        pub fn segmentCount(&self) -> NSUInteger;

        /// Setter for [`segmentCount`][Self::segmentCount].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setSegmentCount:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setSegmentCount(&self, segment_count: NSUInteger);

        /// Number of control points per curve segment. Must be 2, 3, or 4.
        #[unsafe(method(segmentControlPointCount))]
        #[unsafe(method_family = none)]
        pub fn segmentControlPointCount(&self) -> NSUInteger;

        /// Setter for [`segmentControlPointCount`][Self::segmentControlPointCount].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setSegmentControlPointCount:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setSegmentControlPointCount(&self, segment_control_point_count: NSUInteger);

        /// Curve type. Defaults to MTLCurveTypeRound.
        #[unsafe(method(curveType))]
        #[unsafe(method_family = none)]
        pub fn curveType(&self) -> MTLCurveType;

        /// Setter for [`curveType`][Self::curveType].
        #[unsafe(method(setCurveType:))]
        #[unsafe(method_family = none)]
        pub fn setCurveType(&self, curve_type: MTLCurveType);

        /// Curve basis. Defaults to MTLCurveBasisBSpline.
        #[unsafe(method(curveBasis))]
        #[unsafe(method_family = none)]
        pub fn curveBasis(&self) -> MTLCurveBasis;

        /// Setter for [`curveBasis`][Self::curveBasis].
        #[unsafe(method(setCurveBasis:))]
        #[unsafe(method_family = none)]
        pub fn setCurveBasis(&self, curve_basis: MTLCurveBasis);

        /// Type of curve end caps. Defaults to MTLCurveEndCapsNone.
        #[unsafe(method(curveEndCaps))]
        #[unsafe(method_family = none)]
        pub fn curveEndCaps(&self) -> MTLCurveEndCaps;

        /// Setter for [`curveEndCaps`][Self::curveEndCaps].
        #[unsafe(method(setCurveEndCaps:))]
        #[unsafe(method_family = none)]
        pub fn setCurveEndCaps(&self, curve_end_caps: MTLCurveEndCaps);

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

/// Methods declared on superclass `NSObject`.
impl MTLAccelerationStructureCurveGeometryDescriptor {
    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>;
    );
}

impl DefaultRetained for MTLAccelerationStructureCurveGeometryDescriptor {
    #[inline]
    fn default_retained() -> Retained<Self> {
        Self::new()
    }
}

extern_class!(
    /// Acceleration structure motion geometry descriptor describing
    /// geometry made of curve primitives
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructuremotioncurvegeometrydescriptor?language=objc)
    #[unsafe(super(MTLAccelerationStructureGeometryDescriptor, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTLAccelerationStructureMotionCurveGeometryDescriptor;
);

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

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

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

impl MTLAccelerationStructureMotionCurveGeometryDescriptor {
    extern_methods!(
        /// Buffers containing curve control points for each keyframe.
        /// Each control point must be of the format specified by the control
        /// point format. Buffer offsets musts be multiples of the control
        /// point format's element size and must be aligned to the platform's
        /// buffer offset alignment. Must not be nil when the acceleration
        /// structure is built.
        #[unsafe(method(controlPointBuffers))]
        #[unsafe(method_family = none)]
        pub fn controlPointBuffers(&self) -> Retained<NSArray<MTLMotionKeyframeData>>;

        /// Setter for [`controlPointBuffers`][Self::controlPointBuffers].
        ///
        /// This is [copied][objc2_foundation::NSCopying::copy] when set.
        #[unsafe(method(setControlPointBuffers:))]
        #[unsafe(method_family = none)]
        pub fn setControlPointBuffers(
            &self,
            control_point_buffers: &NSArray<MTLMotionKeyframeData>,
        );

        /// Number of control points in the control point buffers
        #[unsafe(method(controlPointCount))]
        #[unsafe(method_family = none)]
        pub fn controlPointCount(&self) -> NSUInteger;

        /// Setter for [`controlPointCount`][Self::controlPointCount].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setControlPointCount:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setControlPointCount(&self, control_point_count: NSUInteger);

        /// Stride, in bytes, between control points in the control point
        /// buffer. Must be a multiple of the control point format's element size
        /// and must be at least the control point format's size. Defaults to 0
        /// bytes, indicating that the control points are tightly packed.
        #[unsafe(method(controlPointStride))]
        #[unsafe(method_family = none)]
        pub fn controlPointStride(&self) -> NSUInteger;

        /// Setter for [`controlPointStride`][Self::controlPointStride].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setControlPointStride:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setControlPointStride(&self, control_point_stride: NSUInteger);

        #[cfg(feature = "MTLStageInputOutputDescriptor")]
        /// Format of the control points in the control point buffer.
        /// Defaults to MTLAttributeFormatFloat3 (packed).
        #[unsafe(method(controlPointFormat))]
        #[unsafe(method_family = none)]
        pub fn controlPointFormat(&self) -> MTLAttributeFormat;

        #[cfg(feature = "MTLStageInputOutputDescriptor")]
        /// Setter for [`controlPointFormat`][Self::controlPointFormat].
        #[unsafe(method(setControlPointFormat:))]
        #[unsafe(method_family = none)]
        pub fn setControlPointFormat(&self, control_point_format: MTLAttributeFormat);

        /// Buffers containing the curve radius for each control point for
        /// each keyframe. Each radius must be of the type specified by the radius
        /// format. Buffer offsets must be multiples of the radius format size
        /// and must be aligned to the platform's buffer offset alignment. Each radius
        /// must be at least zero. Must not be nil when the acceleration structure
        /// is built.
        #[unsafe(method(radiusBuffers))]
        #[unsafe(method_family = none)]
        pub fn radiusBuffers(&self) -> Retained<NSArray<MTLMotionKeyframeData>>;

        /// Setter for [`radiusBuffers`][Self::radiusBuffers].
        ///
        /// This is [copied][objc2_foundation::NSCopying::copy] when set.
        #[unsafe(method(setRadiusBuffers:))]
        #[unsafe(method_family = none)]
        pub fn setRadiusBuffers(&self, radius_buffers: &NSArray<MTLMotionKeyframeData>);

        #[cfg(feature = "MTLStageInputOutputDescriptor")]
        /// Format of the radii in the radius buffer. Defaults to
        /// MTLAttributeFormatFloat.
        #[unsafe(method(radiusFormat))]
        #[unsafe(method_family = none)]
        pub fn radiusFormat(&self) -> MTLAttributeFormat;

        #[cfg(feature = "MTLStageInputOutputDescriptor")]
        /// Setter for [`radiusFormat`][Self::radiusFormat].
        #[unsafe(method(setRadiusFormat:))]
        #[unsafe(method_family = none)]
        pub fn setRadiusFormat(&self, radius_format: MTLAttributeFormat);

        /// Stride, in bytes, between radii in the radius buffer. Must be
        /// a multiple of 4 bytes. Defaults to 4 bytes.
        #[unsafe(method(radiusStride))]
        #[unsafe(method_family = none)]
        pub fn radiusStride(&self) -> NSUInteger;

        /// Setter for [`radiusStride`][Self::radiusStride].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setRadiusStride:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setRadiusStride(&self, radius_stride: NSUInteger);

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Index buffer containing references to control points in the control
        /// point buffer. Must not be nil.
        #[unsafe(method(indexBuffer))]
        #[unsafe(method_family = none)]
        pub fn indexBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`indexBuffer`][Self::indexBuffer].
        ///
        /// # Safety
        ///
        /// - `index_buffer` may need to be synchronized.
        /// - `index_buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `index_buffer` contents should be of the correct type.
        #[unsafe(method(setIndexBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setIndexBuffer(&self, index_buffer: Option<&ProtocolObject<dyn MTLBuffer>>);

        /// Index buffer offset. Must be a multiple of the index data type
        /// size and must be aligned to both the index data type's alignment and
        /// the platform's buffer offset alignment.
        #[unsafe(method(indexBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn indexBufferOffset(&self) -> NSUInteger;

        /// Setter for [`indexBufferOffset`][Self::indexBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setIndexBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setIndexBufferOffset(&self, index_buffer_offset: NSUInteger);

        #[cfg(feature = "MTLArgument")]
        /// Index type
        #[unsafe(method(indexType))]
        #[unsafe(method_family = none)]
        pub fn indexType(&self) -> MTLIndexType;

        #[cfg(feature = "MTLArgument")]
        /// Setter for [`indexType`][Self::indexType].
        #[unsafe(method(setIndexType:))]
        #[unsafe(method_family = none)]
        pub fn setIndexType(&self, index_type: MTLIndexType);

        /// Number of curve segments
        #[unsafe(method(segmentCount))]
        #[unsafe(method_family = none)]
        pub fn segmentCount(&self) -> NSUInteger;

        /// Setter for [`segmentCount`][Self::segmentCount].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setSegmentCount:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setSegmentCount(&self, segment_count: NSUInteger);

        /// Number of control points per curve segment. Must be 2, 3, or 4.
        #[unsafe(method(segmentControlPointCount))]
        #[unsafe(method_family = none)]
        pub fn segmentControlPointCount(&self) -> NSUInteger;

        /// Setter for [`segmentControlPointCount`][Self::segmentControlPointCount].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setSegmentControlPointCount:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setSegmentControlPointCount(&self, segment_control_point_count: NSUInteger);

        /// Curve type. Defaults to MTLCurveTypeRound.
        #[unsafe(method(curveType))]
        #[unsafe(method_family = none)]
        pub fn curveType(&self) -> MTLCurveType;

        /// Setter for [`curveType`][Self::curveType].
        #[unsafe(method(setCurveType:))]
        #[unsafe(method_family = none)]
        pub fn setCurveType(&self, curve_type: MTLCurveType);

        /// Curve basis. Defaults to MTLCurveBasisBSpline.
        #[unsafe(method(curveBasis))]
        #[unsafe(method_family = none)]
        pub fn curveBasis(&self) -> MTLCurveBasis;

        /// Setter for [`curveBasis`][Self::curveBasis].
        #[unsafe(method(setCurveBasis:))]
        #[unsafe(method_family = none)]
        pub fn setCurveBasis(&self, curve_basis: MTLCurveBasis);

        /// Type of curve end caps. Defaults to MTLCurveEndCapsNone.
        #[unsafe(method(curveEndCaps))]
        #[unsafe(method_family = none)]
        pub fn curveEndCaps(&self) -> MTLCurveEndCaps;

        /// Setter for [`curveEndCaps`][Self::curveEndCaps].
        #[unsafe(method(setCurveEndCaps:))]
        #[unsafe(method_family = none)]
        pub fn setCurveEndCaps(&self, curve_end_caps: MTLCurveEndCaps);

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

/// Methods declared on superclass `NSObject`.
impl MTLAccelerationStructureMotionCurveGeometryDescriptor {
    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>;
    );
}

impl DefaultRetained for MTLAccelerationStructureMotionCurveGeometryDescriptor {
    #[inline]
    fn default_retained() -> Retained<Self> {
        Self::new()
    }
}

/// [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructureinstancedescriptor?language=objc)
#[cfg(feature = "MTLAccelerationStructureTypes")]
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct MTLAccelerationStructureInstanceDescriptor {
    /// Transformation matrix describing how to transform the bottom-level acceleration structure.
    pub transformationMatrix: MTLPackedFloat4x3,
    /// Instance options
    pub options: MTLAccelerationStructureInstanceOptions,
    /// Instance mask used to ignore geometry during ray tracing
    pub mask: u32,
    /// Used to index into intersection function tables
    pub intersectionFunctionTableOffset: u32,
    /// Acceleration structure index to use for this instance
    pub accelerationStructureIndex: u32,
}

#[cfg(feature = "MTLAccelerationStructureTypes")]
unsafe impl Encode for MTLAccelerationStructureInstanceDescriptor {
    const ENCODING: Encoding = Encoding::Struct(
        "?",
        &[
            <MTLPackedFloat4x3>::ENCODING,
            <MTLAccelerationStructureInstanceOptions>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
        ],
    );
}

#[cfg(feature = "MTLAccelerationStructureTypes")]
unsafe impl RefEncode for MTLAccelerationStructureInstanceDescriptor {
    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}

/// [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructureuseridinstancedescriptor?language=objc)
#[cfg(feature = "MTLAccelerationStructureTypes")]
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct MTLAccelerationStructureUserIDInstanceDescriptor {
    /// Transformation matrix describing how to transform the bottom-level acceleration structure.
    pub transformationMatrix: MTLPackedFloat4x3,
    /// Instance options
    pub options: MTLAccelerationStructureInstanceOptions,
    /// Instance mask used to ignore geometry during ray tracing
    pub mask: u32,
    /// Used to index into intersection function tables
    pub intersectionFunctionTableOffset: u32,
    /// Acceleration structure index to use for this instance
    pub accelerationStructureIndex: u32,
    /// User-assigned instance ID to help identify this instance in an
    /// application-defined way
    pub userID: u32,
}

#[cfg(feature = "MTLAccelerationStructureTypes")]
unsafe impl Encode for MTLAccelerationStructureUserIDInstanceDescriptor {
    const ENCODING: Encoding = Encoding::Struct(
        "?",
        &[
            <MTLPackedFloat4x3>::ENCODING,
            <MTLAccelerationStructureInstanceOptions>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
        ],
    );
}

#[cfg(feature = "MTLAccelerationStructureTypes")]
unsafe impl RefEncode for MTLAccelerationStructureUserIDInstanceDescriptor {
    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}

/// [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructureinstancedescriptortype?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MTLAccelerationStructureInstanceDescriptorType(pub NSUInteger);
impl MTLAccelerationStructureInstanceDescriptorType {
    /// Default instance descriptor: MTLAccelerationStructureInstanceDescriptor
    #[doc(alias = "MTLAccelerationStructureInstanceDescriptorTypeDefault")]
    pub const Default: Self = Self(0);
    /// Instance descriptor with an added user-ID
    #[doc(alias = "MTLAccelerationStructureInstanceDescriptorTypeUserID")]
    pub const UserID: Self = Self(1);
    /// Instance descriptor with support for motion
    #[doc(alias = "MTLAccelerationStructureInstanceDescriptorTypeMotion")]
    pub const Motion: Self = Self(2);
    /// Instance descriptor with a resource handle for the instanced acceleration structure
    #[doc(alias = "MTLAccelerationStructureInstanceDescriptorTypeIndirect")]
    pub const Indirect: Self = Self(3);
    /// Motion instance descriptor with a resource handle for the instanced acceleration structure.
    #[doc(alias = "MTLAccelerationStructureInstanceDescriptorTypeIndirectMotion")]
    pub const IndirectMotion: Self = Self(4);
}

unsafe impl Encode for MTLAccelerationStructureInstanceDescriptorType {
    const ENCODING: Encoding = NSUInteger::ENCODING;
}

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

/// [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructuremotioninstancedescriptor?language=objc)
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct MTLAccelerationStructureMotionInstanceDescriptor {
    /// Instance options
    pub options: MTLAccelerationStructureInstanceOptions,
    /// Instance mask used to ignore geometry during ray tracing
    pub mask: u32,
    /// Used to index into intersection function tables
    pub intersectionFunctionTableOffset: u32,
    /// Acceleration structure index to use for this instance
    pub accelerationStructureIndex: u32,
    /// User-assigned instance ID to help identify this instance in an
    /// application-defined way
    pub userID: u32,
    /// The index of the first set of transforms describing one keyframe of the animation.
    /// These transforms are stored in a separate buffer and they are uniformly distributed over
    /// time time span of the motion.
    pub motionTransformsStartIndex: u32,
    /// The count of motion transforms belonging to this motion which are stored in consecutive
    /// memory addresses at the separate motionTransforms buffer.
    pub motionTransformsCount: u32,
    /// Motion border mode describing what happens if acceleration structure is sampled
    /// before motionStartTime
    pub motionStartBorderMode: MTLMotionBorderMode,
    /// Motion border mode describing what happens if acceleration structure is sampled
    /// after motionEndTime
    pub motionEndBorderMode: MTLMotionBorderMode,
    /// Motion start time of this instance
    pub motionStartTime: c_float,
    /// Motion end time of this instance
    pub motionEndTime: c_float,
}

unsafe impl Encode for MTLAccelerationStructureMotionInstanceDescriptor {
    const ENCODING: Encoding = Encoding::Struct(
        "?",
        &[
            <MTLAccelerationStructureInstanceOptions>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <MTLMotionBorderMode>::ENCODING,
            <MTLMotionBorderMode>::ENCODING,
            <c_float>::ENCODING,
            <c_float>::ENCODING,
        ],
    );
}

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

/// [Apple's documentation](https://developer.apple.com/documentation/metal/mtlindirectaccelerationstructureinstancedescriptor?language=objc)
#[cfg(all(feature = "MTLAccelerationStructureTypes", feature = "MTLTypes"))]
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct MTLIndirectAccelerationStructureInstanceDescriptor {
    /// Transformation matrix describing how to transform the bottom-level acceleration structure.
    pub transformationMatrix: MTLPackedFloat4x3,
    /// Instance options
    pub options: MTLAccelerationStructureInstanceOptions,
    /// Instance mask used to ignore geometry during ray tracing
    pub mask: u32,
    /// Used to index into intersection function tables
    pub intersectionFunctionTableOffset: u32,
    /// User-assigned instance ID to help identify this instance in an
    /// application-defined way
    pub userID: u32,
    /// Acceleration structure resource handle to use for this instance
    pub accelerationStructureID: MTLResourceID,
}

#[cfg(all(feature = "MTLAccelerationStructureTypes", feature = "MTLTypes"))]
unsafe impl Encode for MTLIndirectAccelerationStructureInstanceDescriptor {
    const ENCODING: Encoding = Encoding::Struct(
        "?",
        &[
            <MTLPackedFloat4x3>::ENCODING,
            <MTLAccelerationStructureInstanceOptions>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <MTLResourceID>::ENCODING,
        ],
    );
}

#[cfg(all(feature = "MTLAccelerationStructureTypes", feature = "MTLTypes"))]
unsafe impl RefEncode for MTLIndirectAccelerationStructureInstanceDescriptor {
    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}

/// [Apple's documentation](https://developer.apple.com/documentation/metal/mtlindirectaccelerationstructuremotioninstancedescriptor?language=objc)
#[cfg(feature = "MTLTypes")]
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct MTLIndirectAccelerationStructureMotionInstanceDescriptor {
    /// Instance options
    pub options: MTLAccelerationStructureInstanceOptions,
    /// Instance mask used to ignore geometry during ray tracing
    pub mask: u32,
    /// Used to index into intersection function tables
    pub intersectionFunctionTableOffset: u32,
    /// User-assigned instance ID to help identify this instance in an
    /// application-defined way
    pub userID: u32,
    /// Acceleration structure resource handle to use for this instance
    pub accelerationStructureID: MTLResourceID,
    /// The index of the first set of transforms describing one keyframe of the animation.
    /// These transforms are stored in a separate buffer and they are uniformly distributed over
    /// time time span of the motion.
    pub motionTransformsStartIndex: u32,
    /// The count of motion transforms belonging to this motion which are stored in consecutive
    /// memory addresses at the separate motionTransforms buffer.
    pub motionTransformsCount: u32,
    /// Motion border mode describing what happens if acceleration structure is sampled
    /// before motionStartTime
    pub motionStartBorderMode: MTLMotionBorderMode,
    /// Motion border mode describing what happens if acceleration structure is sampled
    /// after motionEndTime
    pub motionEndBorderMode: MTLMotionBorderMode,
    /// Motion start time of this instance
    pub motionStartTime: c_float,
    /// Motion end time of this instance
    pub motionEndTime: c_float,
}

#[cfg(feature = "MTLTypes")]
unsafe impl Encode for MTLIndirectAccelerationStructureMotionInstanceDescriptor {
    const ENCODING: Encoding = Encoding::Struct(
        "?",
        &[
            <MTLAccelerationStructureInstanceOptions>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <MTLResourceID>::ENCODING,
            <u32>::ENCODING,
            <u32>::ENCODING,
            <MTLMotionBorderMode>::ENCODING,
            <MTLMotionBorderMode>::ENCODING,
            <c_float>::ENCODING,
            <c_float>::ENCODING,
        ],
    );
}

#[cfg(feature = "MTLTypes")]
unsafe impl RefEncode for MTLIndirectAccelerationStructureMotionInstanceDescriptor {
    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}

/// [Apple's documentation](https://developer.apple.com/documentation/metal/mtltransformtype?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MTLTransformType(pub NSInteger);
impl MTLTransformType {
    /// A tightly packed matrix with 4 columns and 3 rows. The full transform is assumed
    /// to be a 4x4 matrix with the last row being (0, 0, 0, 1).
    #[doc(alias = "MTLTransformTypePackedFloat4x3")]
    pub const PackedFloat4x3: Self = Self(0);
    /// A transformation represented by individual components such as translation and
    /// rotation. The rotation is represented by a quaternion, allowing for correct motion
    /// interpolation.
    #[doc(alias = "MTLTransformTypeComponent")]
    pub const Component: Self = Self(1);
}

unsafe impl Encode for MTLTransformType {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

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

extern_class!(
    /// Descriptor for an instance acceleration structure
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlinstanceaccelerationstructuredescriptor?language=objc)
    #[unsafe(super(MTLAccelerationStructureDescriptor, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTLInstanceAccelerationStructureDescriptor;
);

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

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

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

impl MTLInstanceAccelerationStructureDescriptor {
    extern_methods!(
        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Buffer containing instance descriptors of the type specified by the instanceDescriptorType property
        #[unsafe(method(instanceDescriptorBuffer))]
        #[unsafe(method_family = none)]
        pub fn instanceDescriptorBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`instanceDescriptorBuffer`][Self::instanceDescriptorBuffer].
        #[unsafe(method(setInstanceDescriptorBuffer:))]
        #[unsafe(method_family = none)]
        pub fn setInstanceDescriptorBuffer(
            &self,
            instance_descriptor_buffer: Option<&ProtocolObject<dyn MTLBuffer>>,
        );

        /// Offset into the instance descriptor buffer. Must be a multiple of 64 bytes and must be
        /// aligned to the platform's buffer offset alignment.
        #[unsafe(method(instanceDescriptorBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn instanceDescriptorBufferOffset(&self) -> NSUInteger;

        /// Setter for [`instanceDescriptorBufferOffset`][Self::instanceDescriptorBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setInstanceDescriptorBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setInstanceDescriptorBufferOffset(
            &self,
            instance_descriptor_buffer_offset: NSUInteger,
        );

        /// Stride, in bytes, between instance descriptors in the instance descriptor buffer. Must
        /// be at least the size of the instance descriptor type and must be a multiple of 4 bytes.
        /// Defaults to the size of the instance descriptor type.
        #[unsafe(method(instanceDescriptorStride))]
        #[unsafe(method_family = none)]
        pub fn instanceDescriptorStride(&self) -> NSUInteger;

        /// Setter for [`instanceDescriptorStride`][Self::instanceDescriptorStride].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setInstanceDescriptorStride:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setInstanceDescriptorStride(&self, instance_descriptor_stride: NSUInteger);

        /// Number of instance descriptors
        #[unsafe(method(instanceCount))]
        #[unsafe(method_family = none)]
        pub fn instanceCount(&self) -> NSUInteger;

        /// Setter for [`instanceCount`][Self::instanceCount].
        #[unsafe(method(setInstanceCount:))]
        #[unsafe(method_family = none)]
        pub fn setInstanceCount(&self, instance_count: NSUInteger);

        #[cfg(all(feature = "MTLAllocation", feature = "MTLResource"))]
        /// Acceleration structures to be instanced
        #[unsafe(method(instancedAccelerationStructures))]
        #[unsafe(method_family = none)]
        pub fn instancedAccelerationStructures(
            &self,
        ) -> Option<Retained<NSArray<ProtocolObject<dyn MTLAccelerationStructure>>>>;

        #[cfg(all(feature = "MTLAllocation", feature = "MTLResource"))]
        /// Setter for [`instancedAccelerationStructures`][Self::instancedAccelerationStructures].
        #[unsafe(method(setInstancedAccelerationStructures:))]
        #[unsafe(method_family = none)]
        pub fn setInstancedAccelerationStructures(
            &self,
            instanced_acceleration_structures: Option<
                &NSArray<ProtocolObject<dyn MTLAccelerationStructure>>,
            >,
        );

        /// Type of instance descriptor in the instance descriptor buffer. Defaults to
        /// MTLAccelerationStructureInstanceDescriptorTypeDefault.
        #[unsafe(method(instanceDescriptorType))]
        #[unsafe(method_family = none)]
        pub fn instanceDescriptorType(&self) -> MTLAccelerationStructureInstanceDescriptorType;

        /// Setter for [`instanceDescriptorType`][Self::instanceDescriptorType].
        #[unsafe(method(setInstanceDescriptorType:))]
        #[unsafe(method_family = none)]
        pub fn setInstanceDescriptorType(
            &self,
            instance_descriptor_type: MTLAccelerationStructureInstanceDescriptorType,
        );

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Buffer containing transformation information for motion
        #[unsafe(method(motionTransformBuffer))]
        #[unsafe(method_family = none)]
        pub fn motionTransformBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`motionTransformBuffer`][Self::motionTransformBuffer].
        ///
        /// # Safety
        ///
        /// - `motion_transform_buffer` may need to be synchronized.
        /// - `motion_transform_buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `motion_transform_buffer` contents should be of the correct type.
        #[unsafe(method(setMotionTransformBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMotionTransformBuffer(
            &self,
            motion_transform_buffer: Option<&ProtocolObject<dyn MTLBuffer>>,
        );

        /// Offset into the instance motion descriptor buffer. Must be a multiple of 64 bytes and
        /// must be aligned to the platform's buffer offset alignment.
        #[unsafe(method(motionTransformBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn motionTransformBufferOffset(&self) -> NSUInteger;

        /// Setter for [`motionTransformBufferOffset`][Self::motionTransformBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setMotionTransformBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMotionTransformBufferOffset(
            &self,
            motion_transform_buffer_offset: NSUInteger,
        );

        /// Number of motion transforms
        #[unsafe(method(motionTransformCount))]
        #[unsafe(method_family = none)]
        pub fn motionTransformCount(&self) -> NSUInteger;

        /// Setter for [`motionTransformCount`][Self::motionTransformCount].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setMotionTransformCount:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMotionTransformCount(&self, motion_transform_count: NSUInteger);

        /// Matrix layout of the transformation matrices in the instance descriptors
        /// in the instance descriptor buffer and the transformation matrices in the
        /// transformation matrix buffer. Defaults to MTLMatrixLayoutColumnMajor.
        #[unsafe(method(instanceTransformationMatrixLayout))]
        #[unsafe(method_family = none)]
        pub fn instanceTransformationMatrixLayout(&self) -> MTLMatrixLayout;

        /// Setter for [`instanceTransformationMatrixLayout`][Self::instanceTransformationMatrixLayout].
        #[unsafe(method(setInstanceTransformationMatrixLayout:))]
        #[unsafe(method_family = none)]
        pub fn setInstanceTransformationMatrixLayout(
            &self,
            instance_transformation_matrix_layout: MTLMatrixLayout,
        );

        /// Type of motion transforms. Defaults to MTLTransformTypePackedFloat4x3.
        #[unsafe(method(motionTransformType))]
        #[unsafe(method_family = none)]
        pub fn motionTransformType(&self) -> MTLTransformType;

        /// Setter for [`motionTransformType`][Self::motionTransformType].
        #[unsafe(method(setMotionTransformType:))]
        #[unsafe(method_family = none)]
        pub fn setMotionTransformType(&self, motion_transform_type: MTLTransformType);

        /// Motion transform stride. Defaults to 0, indicating that transforms are tightly packed according to the
        /// motion transform type.
        #[unsafe(method(motionTransformStride))]
        #[unsafe(method_family = none)]
        pub fn motionTransformStride(&self) -> NSUInteger;

        /// Setter for [`motionTransformStride`][Self::motionTransformStride].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setMotionTransformStride:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMotionTransformStride(&self, motion_transform_stride: NSUInteger);

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

/// Methods declared on superclass `NSObject`.
impl MTLInstanceAccelerationStructureDescriptor {
    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>;
    );
}

impl DefaultRetained for MTLInstanceAccelerationStructureDescriptor {
    #[inline]
    fn default_retained() -> Retained<Self> {
        Self::new()
    }
}

extern_class!(
    /// Descriptor for an instance acceleration structure built with an indirected buffer of instances.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/metal/mtlindirectinstanceaccelerationstructuredescriptor?language=objc)
    #[unsafe(super(MTLAccelerationStructureDescriptor, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MTLIndirectInstanceAccelerationStructureDescriptor;
);

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

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

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

impl MTLIndirectInstanceAccelerationStructureDescriptor {
    extern_methods!(
        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Buffer containing instance descriptors of the type specified by the instanceDescriptorType property
        #[unsafe(method(instanceDescriptorBuffer))]
        #[unsafe(method_family = none)]
        pub fn instanceDescriptorBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`instanceDescriptorBuffer`][Self::instanceDescriptorBuffer].
        ///
        /// # Safety
        ///
        /// - `instance_descriptor_buffer` may need to be synchronized.
        /// - `instance_descriptor_buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `instance_descriptor_buffer` contents should be of the correct type.
        #[unsafe(method(setInstanceDescriptorBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setInstanceDescriptorBuffer(
            &self,
            instance_descriptor_buffer: Option<&ProtocolObject<dyn MTLBuffer>>,
        );

        /// Offset into the instance descriptor buffer. Must be a multiple of 64 bytes and must be
        /// aligned to the platform's buffer offset alignment.
        #[unsafe(method(instanceDescriptorBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn instanceDescriptorBufferOffset(&self) -> NSUInteger;

        /// Setter for [`instanceDescriptorBufferOffset`][Self::instanceDescriptorBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setInstanceDescriptorBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setInstanceDescriptorBufferOffset(
            &self,
            instance_descriptor_buffer_offset: NSUInteger,
        );

        /// Stride, in bytes, between instance descriptors in the instance descriptor buffer. Must
        /// be at least the size of the instance descriptor type and must be a multiple of 4 bytes.
        /// Defaults to the size of the instance descriptor type.
        #[unsafe(method(instanceDescriptorStride))]
        #[unsafe(method_family = none)]
        pub fn instanceDescriptorStride(&self) -> NSUInteger;

        /// Setter for [`instanceDescriptorStride`][Self::instanceDescriptorStride].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setInstanceDescriptorStride:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setInstanceDescriptorStride(&self, instance_descriptor_stride: NSUInteger);

        /// Maximum number of instance descriptors
        #[unsafe(method(maxInstanceCount))]
        #[unsafe(method_family = none)]
        pub fn maxInstanceCount(&self) -> NSUInteger;

        /// Setter for [`maxInstanceCount`][Self::maxInstanceCount].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setMaxInstanceCount:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMaxInstanceCount(&self, max_instance_count: NSUInteger);

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Buffer containing the instance count as a uint32_t value. Value at build time
        /// must be less than or equal to maxInstanceCount.
        #[unsafe(method(instanceCountBuffer))]
        #[unsafe(method_family = none)]
        pub fn instanceCountBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`instanceCountBuffer`][Self::instanceCountBuffer].
        ///
        /// # Safety
        ///
        /// - `instance_count_buffer` may need to be synchronized.
        /// - `instance_count_buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `instance_count_buffer` contents should be of the correct type.
        #[unsafe(method(setInstanceCountBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setInstanceCountBuffer(
            &self,
            instance_count_buffer: Option<&ProtocolObject<dyn MTLBuffer>>,
        );

        /// Offset into the instance count buffer. Must be a multiple of 4 bytes and must be
        /// aligned to the platform's buffer offset alignment.
        #[unsafe(method(instanceCountBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn instanceCountBufferOffset(&self) -> NSUInteger;

        /// Setter for [`instanceCountBufferOffset`][Self::instanceCountBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setInstanceCountBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setInstanceCountBufferOffset(&self, instance_count_buffer_offset: NSUInteger);

        /// Type of instance descriptor in the instance descriptor buffer. Defaults to
        /// MTLAccelerationStructureInstanceDescriptorTypeIndirect. Must be
        /// MTLAccelerationStructureInstanceDescriptorTypeIndirect or
        /// MTLAccelerationStructureInstanceDescriptorTypeIndirectMotion.
        #[unsafe(method(instanceDescriptorType))]
        #[unsafe(method_family = none)]
        pub fn instanceDescriptorType(&self) -> MTLAccelerationStructureInstanceDescriptorType;

        /// Setter for [`instanceDescriptorType`][Self::instanceDescriptorType].
        #[unsafe(method(setInstanceDescriptorType:))]
        #[unsafe(method_family = none)]
        pub fn setInstanceDescriptorType(
            &self,
            instance_descriptor_type: MTLAccelerationStructureInstanceDescriptorType,
        );

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Buffer containing transformation information for motion
        #[unsafe(method(motionTransformBuffer))]
        #[unsafe(method_family = none)]
        pub fn motionTransformBuffer(&self) -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`motionTransformBuffer`][Self::motionTransformBuffer].
        ///
        /// # Safety
        ///
        /// - `motion_transform_buffer` may need to be synchronized.
        /// - `motion_transform_buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `motion_transform_buffer` contents should be of the correct type.
        #[unsafe(method(setMotionTransformBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMotionTransformBuffer(
            &self,
            motion_transform_buffer: Option<&ProtocolObject<dyn MTLBuffer>>,
        );

        /// Offset into the instance motion descriptor buffer. Must be a multiple of 64 bytes and
        /// must be aligned to the platform's buffer offset alignment.
        #[unsafe(method(motionTransformBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn motionTransformBufferOffset(&self) -> NSUInteger;

        /// Setter for [`motionTransformBufferOffset`][Self::motionTransformBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setMotionTransformBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMotionTransformBufferOffset(
            &self,
            motion_transform_buffer_offset: NSUInteger,
        );

        /// Maximum number of motion transforms
        #[unsafe(method(maxMotionTransformCount))]
        #[unsafe(method_family = none)]
        pub fn maxMotionTransformCount(&self) -> NSUInteger;

        /// Setter for [`maxMotionTransformCount`][Self::maxMotionTransformCount].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setMaxMotionTransformCount:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMaxMotionTransformCount(&self, max_motion_transform_count: NSUInteger);

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Buffer containing the motion transform count as a uint32_t value. Value at build time
        /// must be less than or equal to maxMotionTransformCount.
        #[unsafe(method(motionTransformCountBuffer))]
        #[unsafe(method_family = none)]
        pub fn motionTransformCountBuffer(&self)
            -> Option<Retained<ProtocolObject<dyn MTLBuffer>>>;

        #[cfg(all(
            feature = "MTLAllocation",
            feature = "MTLBuffer",
            feature = "MTLResource"
        ))]
        /// Setter for [`motionTransformCountBuffer`][Self::motionTransformCountBuffer].
        ///
        /// # Safety
        ///
        /// - `motion_transform_count_buffer` may need to be synchronized.
        /// - `motion_transform_count_buffer` may be unretained, you must ensure it is kept alive while in use.
        /// - `motion_transform_count_buffer` contents should be of the correct type.
        #[unsafe(method(setMotionTransformCountBuffer:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMotionTransformCountBuffer(
            &self,
            motion_transform_count_buffer: Option<&ProtocolObject<dyn MTLBuffer>>,
        );

        /// Offset into the motion transform count buffer. Must be a multiple of 4 bytes and must be
        /// aligned to the platform's buffer offset alignment.
        #[unsafe(method(motionTransformCountBufferOffset))]
        #[unsafe(method_family = none)]
        pub fn motionTransformCountBufferOffset(&self) -> NSUInteger;

        /// Setter for [`motionTransformCountBufferOffset`][Self::motionTransformCountBufferOffset].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setMotionTransformCountBufferOffset:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMotionTransformCountBufferOffset(
            &self,
            motion_transform_count_buffer_offset: NSUInteger,
        );

        /// Matrix layout of the transformation matrices in the instance descriptors
        /// in the instance descriptor buffer and the transformation matrices in the
        /// transformation matrix buffer. Defaults to MTLMatrixLayoutColumnMajor.
        #[unsafe(method(instanceTransformationMatrixLayout))]
        #[unsafe(method_family = none)]
        pub fn instanceTransformationMatrixLayout(&self) -> MTLMatrixLayout;

        /// Setter for [`instanceTransformationMatrixLayout`][Self::instanceTransformationMatrixLayout].
        #[unsafe(method(setInstanceTransformationMatrixLayout:))]
        #[unsafe(method_family = none)]
        pub fn setInstanceTransformationMatrixLayout(
            &self,
            instance_transformation_matrix_layout: MTLMatrixLayout,
        );

        /// Type of motion transforms. Defaults to MTLTransformTypePackedFloat4x3.
        #[unsafe(method(motionTransformType))]
        #[unsafe(method_family = none)]
        pub fn motionTransformType(&self) -> MTLTransformType;

        /// Setter for [`motionTransformType`][Self::motionTransformType].
        #[unsafe(method(setMotionTransformType:))]
        #[unsafe(method_family = none)]
        pub fn setMotionTransformType(&self, motion_transform_type: MTLTransformType);

        /// Motion transform stride. Defaults to 0, indicating that transforms are tightly packed according to the
        /// motion transform type.
        #[unsafe(method(motionTransformStride))]
        #[unsafe(method_family = none)]
        pub fn motionTransformStride(&self) -> NSUInteger;

        /// Setter for [`motionTransformStride`][Self::motionTransformStride].
        ///
        /// # Safety
        ///
        /// This might not be bounds-checked.
        #[unsafe(method(setMotionTransformStride:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMotionTransformStride(&self, motion_transform_stride: NSUInteger);

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

/// Methods declared on superclass `NSObject`.
impl MTLIndirectInstanceAccelerationStructureDescriptor {
    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>;
    );
}

impl DefaultRetained for MTLIndirectInstanceAccelerationStructureDescriptor {
    #[inline]
    fn default_retained() -> Retained<Self> {
        Self::new()
    }
}

extern_protocol!(
    /// [Apple's documentation](https://developer.apple.com/documentation/metal/mtlaccelerationstructure?language=objc)
    #[cfg(all(feature = "MTLAllocation", feature = "MTLResource"))]
    pub unsafe trait MTLAccelerationStructure: MTLResource {
        #[unsafe(method(size))]
        #[unsafe(method_family = none)]
        fn size(&self) -> NSUInteger;

        #[cfg(feature = "MTLTypes")]
        /// Handle of the GPU resource suitable for storing in an Argument Buffer
        #[unsafe(method(gpuResourceID))]
        #[unsafe(method_family = none)]
        fn gpuResourceID(&self) -> MTLResourceID;
    }
);
