Rust 与 Objective-C 互操作

2,251 阅读1分钟

项目地址:github.com/gfx-rs/meta…

Rust 表达 Objective-C new操作

pub enum MTLHeapDescriptor {}

foreign_obj_type! {
    type CType = MTLHeapDescriptor;
    pub struct HeapDescriptor;
    pub struct HeapDescriptorRef;
}

impl HeapDescriptor {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLHeapDescriptor);
            msg_send![class, new]
        }
    }
}

impl HeapDescriptorRef {
    pub fn cpu_cache_mode(&self) -> MTLCPUCacheMode {
        unsafe { msg_send![self, cpuCacheMode] }
    }

    pub fn set_cpu_cache_mode(&self, mode: MTLCPUCacheMode) {
        unsafe { msg_send![self, setCpuCacheMode: mode] }
    }

    pub fn storage_mode(&self) -> MTLStorageMode {
        unsafe { msg_send![self, storageMode] }
    }

    pub fn set_storage_mode(&self, mode: MTLStorageMode) {
        unsafe { msg_send![self, setStorageMode: mode] }
    }

    pub fn size(&self) -> NSUInteger {
        unsafe { msg_send![self, size] }
    }

    pub fn set_size(&self, size: NSUInteger) {
        unsafe {
            msg_send![self, setSize: size];
        }
    }
}

Rust 表达 Objective-C 继承关系

父类CAMetalDrawable继承自NSObject,用Rust表达如下。

pub enum MTLDrawable {}

foreign_obj_type! {
    type CType = MTLDrawable;
    pub struct Drawable;
    pub struct DrawableRef;
}


impl DrawableRef {
    pub fn present(&self) {
        unsafe {
            msg_send![self, present]
        }
    }
}

子类CAMetalDrawable用Rust表达如下。

pub enum CAMetalDrawable {}

foreign_obj_type! {
    type CType = CAMetalDrawable;
    pub struct CoreAnimationDrawable;
    pub struct CoreAnimationDrawableRef;
    type ParentType = DrawableRef;
}

impl CoreAnimationDrawableRef {
    pub fn texture(&self) -> &TextureRef {
        unsafe { msg_send![self, texture] }
    }
}

工具宏

macro_rules! foreign_obj_type {
    {type CType = $raw_ident:ident;
    pub struct $owned_ident:ident;
    pub struct $ref_ident:ident;
    type ParentType = $parent_ref:ident;
    } => {
        foreign_obj_type! {
            type CType = $raw_ident;
            pub struct $owned_ident;
            pub struct $ref_ident;
        }

        impl ::std::ops::Deref for $ref_ident {
            type Target = $parent_ref;

            fn deref(&self) -> &$parent_ref {
                unsafe { &*(self as *const $ref_ident as *const $parent_ref)  }
            }
        }
    };
    {type CType = $raw_ident:ident;
    pub struct $owned_ident:ident;
    pub struct $ref_ident:ident;
    } => {
        foreign_type! {
            type CType = $raw_ident;
            fn drop = ::obj_drop;
            fn clone = ::obj_clone;
            pub struct $owned_ident;
            pub struct $ref_ident;
        }

        unsafe impl ::objc::Message for $raw_ident {
        }
        unsafe impl ::objc::Message for $ref_ident {
        }

        impl ::std::fmt::Debug for $ref_ident {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                unsafe {
                    use ::objc_foundation::INSString;
                    // TODO: might leak, not 100% sure...
                    let string: &::objc_foundation::NSString = msg_send![self, debugDescription];
                    write!(f, "{}", string.as_str())
                }
            }
        }

        impl ::std::fmt::Debug for $owned_ident {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                ::std::ops::Deref::deref(self).fmt(f)
            }
        }
    };
}

辅助项目

上述操作依赖如下项目: