#objective-c #api-bindings

nightly no-std objrs

Objective-Rust:Rust 与 Objective-C 的不神圣结合

3 个版本

使用旧的 Rust 2015

0.0.2 2018 年 12 月 2 日
0.0.1 2018 年 8 月 23 日
0.0.0 2018 年 5 月 14 日

macOS 和 iOS API 中排名 #53

Download history 24/week @ 2024-03-25 100/week @ 2024-04-01 9/week @ 2024-04-08 7/week @ 2024-04-15 14/week @ 2024-04-22 10/week @ 2024-04-29 18/week @ 2024-05-06 13/week @ 2024-05-13 19/week @ 2024-05-20 14/week @ 2024-05-27 10/week @ 2024-06-03 13/week @ 2024-06-10 14/week @ 2024-06-17 18/week @ 2024-06-24 32/week @ 2024-07-01 9/week @ 2024-07-08

每月下载量 76
用于 6 crate

Apache-2.0 OR MIT OR MPL-2.0

72KB
1.5K SLoC

objrs

Objective-Rust:Rust 与 Objective-C 的不神圣结合。

objrs 是一个库,可以轻松编写与 Objective-C 代码交互的 Rust 代码。其主要目的是帮助 Rust 应用程序使用 Apple 的原生 Objective-C 框架。

除非你的代码是一堆垃圾,你想要助燃火焰,否则请不要在生产环境中使用 objrs! 项目处于起步阶段,处于一个非常实验性的阶段。API 不稳定,存在许多(已知和未知的)错误,故意引发未定义行为等。

话虽如此,试试 objrs 吧!玩玩它。非常欢迎反馈,尤其是如果你有任何关于如何更好地与 Objective-C 交互的聪明想法(例如,Objective-C 协议在 Rust 中的映射非常差,objrs 中的实现也是... 有缺陷)。

TL;DR:objrs 是什么,它做什么?

编写需要与 Objective-C 代码交互的 Rust 程序是一种痛苦的经历。不是创建 FFI 桥接(用 C 编写)(对于每一个小细节),就是要使用像 objc-rsrust-objc 这样的东西来执行所有与 Objective-C 运行时的交互(在运行时!这增加了开销并减少了编译器的安全检查)。

objrs 与之不同。它提供了一组宏,这些宏在编译时对您的代码应用一系列(有问题的)转换,以便它编译成(大约)与纯 Objective-C 相同的机器代码。objrs 将您的纯 Rust 代码转换为与 Objective-C 兼容的 ABI。以下是一个示例

Objective-C

#import <Foundation/Foundation.h>

int main() {
  NSObject *object = [NSObject new];
  [object hash];
  return 0;
}

以下 Objective-C 程序可以使用 objrs 在 Rust 中实现如下

Rust

extern crate objrs;
use objrs::objrs;

#[objrs(class, root_class)]
#[link(name = "Foundation", kind = "framework")]
struct NSObject;

#[objrs(impl)]
#[link(name = "Foundation", kind = "framework")]
impl NSObject {
  // In practice you probably wouldn't want to use #[inline(always)] unless you knew what you were
  // doing. Omitting it just results in an extra extern "C" wrapper fn being used, which introduces
  // an extra jmp indirection.
  #[objrs(selector = "new")]
  #[inline(always)]
  fn new() -> objrs::Strong<NSObject> {}

  #[objrs(selector = "hash")]
  #[inline(always)]
  fn hash(&self) -> usize {}
}

fn main() {
  let object = NSObject::new();
  object.hash();
}

Objective-C 和 Rust 代码都将编译成相同的汇编代码(除了一些小的外观差异之外,请参阅 HOW_IT_WORKS.md 以获取更详细的说明)。

请查看demo目录中的完整演示应用程序(完全用Rust编写)。

如何使用objrs

  1. 在macOS上使用最新的nightly版本的Rust。
  2. 在您的Cargo.toml[dependencies]部分中放入objrs = "0.0.2"
  3. 在您的crate的主Rust文件中放入#![feature(rust_2018_preview)]以启用objrs所需的nightly功能。
  4. 在您的代码中放入use objrs::objrs,以将objrs宏属性引入作用域。
  5. 开始编写代码!

objrs还为Apple的框架提供了框架绑定。以下Apple框架有(不完整的)Rust绑定:

有关更多详细信息,包括属性宏的实际语法,请参阅完整文档。这里的文档旨在简单易懂。

示例

使用现有的框架绑定

如果您不打算实现自己的Objective-C绑定或类,则不需要依赖于核心的objrscrate。

extern crate objrs_frameworks_foundation;
use objrs_frameworks_foundation::NSObject;

fn main() {
  // Create a new NSObject instance that is released when it goes out of scope.
  let object = NSObject::new();
}

创建自己的类

您可以创建自己的类类型。实例变量受支持,但只能通过self直接访问(例如,self.ivar将工作,而some_other_ident.ivar将不会工作)。

extern crate objrs;
extern crate objrs_frameworks_foundation;

use objrs::objrs;
use objrs_frameworks_foundation::NSObject;

// objrs supports instance variables, even if they have non-trivial constructors and destructors.
#[objrs(class, super = NSObject)]
pub struct StringCollection {
  strings: Vec<String>,
}

#[objrs(impl)]
impl StringCollection {
  // Using `no_impl` will tell objrs to just let the super class handle the message. Don't populate
  // the method body; objrs will do that automatically.
  #[objrs(selector = "new", no_impl)]
  pub fn new() -> objrs::Strong<StringCollection> {}

  // You can still use normal Rust methods. These methods are callable from Rust but not
  // Objective-C.
  pub fn add_string(&mut self, string: String) {
    self.strings.push(string);
  }

  // This method is callable from Objective-C because it has been given a selector.
  #[objrs(selector = "printStrings")]
  pub fn print_strings(&self) {
    for string in self.strings.iter() {
      println!("String: {}", string);
    }
  }
}

fn main() {
  let mut string_collection = StringCollection::new();
  string_collection.add_string(String::from("Hello, world!"));
  string_collection.print_strings();
}

待办事项列表

  • 完全重写项目。这个版本是一个非常原始的原型。
  • 找出更好的所有权和借用模型。我认为Rust的引用是澄清Objective-C API中所有权和可变性的好方法,但结果证明Objective-C中存在太多的可变别名。
  • 找出如何正确支持协议。当前的实现既非常粗糙又难以使用。
  • 正确支持自动释放和弱值。我有点忽略了它们。
  • 自动将单元测试注入到使用objrs宏的代码中。单元测试将比较类名、继承结构、选择器、方法参数和返回值、协议一致性等。这一切都可以在今天自动完成。
  • 块。目前完全不支持。

要求

  • Nightly Rust。
  • macOS。iOS和tvOS应该可以工作(希望如此),但尚未经过测试。watchOS支持取决于armv7支持。
  • 最近的操作系统版本。只有macOS 10.14.1已经过测试。最低要求将在以后确定。
  • 适用于x86_64或arm64(aarch64)的计算机。可能会添加armv7支持,但我没有armv7的Apple设备。可能会添加i386(32位x86)支持,但鉴于其过时,目前没有计划这么做。

许可证

请参阅COPYRIGHT文件。objrs根据Apache License 2.0、MIT License和Mozilla Public License 2.0的条款进行三重许可。

依赖关系

约2MB
约48K SLoC