Rust から NSLog を呼びたい

Mac OS においてデバッグするときには、NSLog を呼ばないととにかくやりづらい、というときがあります(InputMethodKit を使った開発をするときなどが特にそうです)。 そんなときには、以下の様にすると良いでしょう。

use cocoa::base::{id, nil};
use cocoa::foundation::NSString;


#[link(name = "Foundation", kind = "framework")]
extern {
    pub fn NSLog(fmt: id, ...);
}

fn main() {
    unsafe {
        NSLog(NSString::alloc(nil).init_str("Hello, %@"), NSString::alloc(nil).init_str("world"));
    }
}

Dependency は以下のように Cargo.toml に記述します。

[package]
name = "rust-nslog-sample"
version = "0.1.0"
edition = "2021"

[dependencies]
cocoa = "0.24.0"

さて、とはいえ毎回 NSString だなんだと書くのはめんどくさい、というのはあるかも。 せめて最初の引数はマクロ化したいですよね。

↓マクロ化するならこんな感じかな?

use cocoa::base::{id, nil};
use cocoa::foundation::NSString;


#[link(name = "Foundation", kind = "framework")]
extern {
    pub fn NSLog(fmt: id, ...);
}

macro_rules! NSLog {
    ( $fmt:expr ) => {
        unsafe {
            NSLog(NSString::alloc(nil).init_str($fmt))
        }
    };
    ( $fmt:expr, $( $x:expr ),* ) => {
        unsafe {
            NSLog(NSString::alloc(nil).init_str($fmt), $($x, )*)
        }
    };
}

fn main() {
    unsafe {
        NSLog!("Hello, %@ %d", NSString::alloc(nil).init_str("world"), 5963);
    }
}