libuv を使ったEcho Server を移植するのをネタにSwift / Cブリッジについて入門する

Swift から C言語のライブラリを直接扱えることが出来るのは知っていたのですが、今までやったことがなかったため [libuv](https://github.com/libuv/libuv) のチュートリアルである [uvbook](https://github.com/nikhilm/uvbook) に載っている [tcp-echo-server](https://github.com/nikhilm/uvbook/tree/master/code/tcp-echo-server) をSwift に移植して、C言語ブリッジについて入門してみたいと思います。

# 環境構築
今回はMac上でXcodeを使いtcp-echo-server を移植することにします。
ソースコードはここにあります https://github.com/yokochie/EchoServer-Sample

Xcodeのバージョンは7.2、Swiftのバージョンは2.1.1になります。

## libuv のインストール
libuv の tcp-echo-server を移植するため libuv が必要です。インストールは Homebrew と使えば簡単にできます。

```shell-session
$ brew install --HEAD libuv
```

インストールすると /usr/local/{include,lib} 以下に必要なファイルが入ります。

```shell-session
$ ls /usr/local/include/uv*.h
/usr/local/include/uv-darwin.h		/usr/local/include/uv-threadpool.h	/usr/local/include/uv-version.h
/usr/local/include/uv-errno.h		/usr/local/include/uv-unix.h		/usr/local/include/uv.h
$ ls /usr/local/lib/libuv*
/usr/local/lib/libuv.1.dylib	/usr/local/lib/libuv.a		/usr/local/lib/libuv.dylib
```

## Xcode プロジェクトの作成
[SwiftとLibpcapによるパケットモニターの作成 ｜ Developers.IO](http://dev.classmethod.jp/client-side/swift-libpcap/) の記事を参考に Command Line Toolのプロジェクトを作ります。

libuv を使うため、まずはプロジェクトの設定から libuv.dylib の追加と Search Path の Header Search Path, Library Search Path に /usr/local/include/, /usr/local/lib を追加します。
<img width="703" alt="LibrarySetting.png" src="https://qiita-image-store.s3.amazonaws.com/0/36234/2558a007-84c6-3814-d314-a325ff7965d4.png">
<img width="489" alt="SearchPath.png" src="https://qiita-image-store.s3.amazonaws.com/0/36234/c9d182e0-4358-93d2-de91-78550df4d404.png">

## libuv が呼び出せるようにする
Bridging-Header.h を何らかの方法で作り（Objective-C のファイルを新規作成して削除する方法が楽）、

```c
#include <uv.h>
```

を追加します。

すると下の図のようにlibuv のメソッドがサジェストされるようになります。
<img width="417" alt="suggest.png" src="https://qiita-image-store.s3.amazonaws.com/0/36234/6c023baf-1430-ad87-30eb-cc5e6fbac697.png">

# Swift/C ブリッジ入門
https://github.com/yokochie/EchoServer-Sample/blob/master/EchoServer/main.swift にあえてC言語での実装( https://github.com/nikhilm/uvbook/blob/master/code/tcp-echo-server/main.c )と似せて書いたものを載せました。環境構築の最後に載せた図のように関数はそのまま呼べるため、変数の型をちゃんと合わせてしまえばすんなり移植できました。この記事を読みつつ見比べてみると理解しやすいかと思います。

## 変数の型について
[Using Swift with Cocoa and Objective-C (Swift 2.1): Interacting with C APIs](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-ID17)に載っているように `CChar`, `CInt`のような頭文字Cで始まる型に変換されます。（ただし、XCode 上でサジェストされる型は `Int8` や `Int32` のようにビット数が明示された型になっています。）

また、ポインタについては `Type *` が `UnsafeMutablePointer<Type>` に、 `const Type *` が `UnsafePointer<Type>` になります。また、`NULL` は `nil` に変わります。

通常の型の変換とポインタの型の変換を踏まえると

```c
int * hoge = NULL
```

が

```swift
var hoge: UnsafeMutablePointer<CInt> = nil
```

になります。

## ポインタの扱いについて
[Cの構造体はそのままSwiftの構造体として使える](http://qiita.com/dankogai/items/2d19b8352183cca3461f#2-1)にも書いてありますが、変数のポインタを要求する関数である場合は `&` を頭につければOKです(メソッドの定義に inout をつけたものと同じ扱い）。今回のソースコードだと main.swift:66 で行なっています。

```swift
uv_ip4_addr("0.0.0.0", CInt(DEFAULT_PORT), &addr)
```

ただし、この手法はキャストが発生する場合はダメなようです。
https://github.com/nikhilm/uvbook/blob/master/code/tcp-echo-server/main.c#L64 の

```c
uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);
```
をそのまま、`&`を付けて移植は型が合わずコンパイルエラーとなりました。
そのため、[`withUnsafePointer` 関数](https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_StandardLibrary_Functions/index.html#//apple_ref/swift/func/s:FSs17withUnsafePointeru0_rFzTRq_FzGVSs13UnsafePointerq__q0__q0_)と `UnsafePointer` のイニシャライザを使ってキャストを行なっています。

```swift
withUnsafePointer(&addr) {
    uv_tcp_bind(&server, UnsafePointer<sockaddr>($0), 0)
}
```
（[UnsafePointer Structure Reference](https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_UnsafePointer_Structure/index.html)の Initializers にポインタ内部の変数の型を直接取れるものがない点にご注意ください）

また、libuv ではコールバック関数を多用するのですが、グローバルで宣言された関数についてはそのまま指定することが出来ました。
例えば、`uv_listen` 関数では引数の最後に `void (*uv_connection_cb)(uv_stream_t* server, int status)`を取ります。Swift で実装された https://github.com/yokochie/EchoServer-Sample/blob/master/EchoServer/main.swift#L73 では `func on_new_connect(server: UnsafeMutablePointer<uv_stream_t>, status: CInt)` をそのまま受け渡すことができています。

## ポインタ内部の扱い
C言語では `*` 演算子や `->` 演算子を使ってポインタ内の変数を参照できましたが、Swift では `memory` プロパティを使います（https://github.com/yokochie/EchoServer-Sample/blob/master/EchoServer/main.swift#L13 で使っています）
メモリの確保は `UnsafeMutablePointer<CChar>.alloc(size)`、解放は `destory` メソッドを使用します。

## その他
Swift Standard Library に標準エラー出力に出力するといった関数がないようですので今回は標準出力にエラー文を出しています。
http://ericasadun.com/2015/06/09/swift-2-0-how-to-print/ に書いてあるように OutputStream を開いて出力すればできるようです。

# 実装確認
Xcode 上で ⌘R を押し実行します。その後、Terminal で

```shell-session
$ telnet localhost 7000
```

を実行します。 `hoge` といった何らかの文字を入力し、同じ文字列が表示されたらOKです。

実行確認例

```shell-session
$ telnet localhost 7000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hoge
hoge
```

コマンドラインからビルドしたい場合は

```shell-session
$ swiftc main.swift -import-objc-header ../EchoServer-Bridging-Header.h -I/usr/local/include -L/usr/local/lib -luv
```

のようにすれば、同じディレクトリに `main` ファイルが増えているためそれを実行すればOKです。

## グローバル関数の代わりにクロージャを使用
[Swift2で作るコマンドラインツール - クックパッド開発者ブログ](http://techlife.cookpad.com/entry/2015/11/09/150248)の「signalをフックする」の項に書いてあるようにクロージャを関数ポインタとして渡すことが可能です。
https://github.com/yokochie/EchoServer-Sample/blob/use_closure/EchoServer/main.swift にクロージャに変えて実装したものを用意しました。

ほとんど変わらないと思いますが、通常のクロージャ型の前に `@convention(c)` が付いています。（以下、一例）

```swift
let alloc_buffer: @convention(c) (UnsafeMutablePointer<uv_handle_t>, size_t, UnsafeMutablePointer<uv_buf_t>) -> Void = { (handle, suggested_size, buf) in
    buf.memory.base = UnsafeMutablePointer<CChar>.alloc(suggested_size)
    buf.memory.len = suggested_size
}
```

# 終わりに（感想）
今回初めて Swift から C言語のライブラリを触りましたが、思いのほか簡単に扱え驚きました。ソースコードを見比べると 変数、関数の定義の仕方の違いはありますが、よく似ていると思います。

iOS アプリ実装言語としてSwift が注目されていると思いますが、Swift でサーバープログラムなどが実装されてくるとより面白くなってくると思います。

この記事はいろいろな方々の記事の寄せ集めになってしまいましたが、同じようなことにチャレンジする方が増えてくだされば幸いです。

# 参考文献
* [libuv](https://github.com/libuv/libuv) 
* [uvbook](https://github.com/nikhilm/uvbook)
* [SwiftとLibpcapによるパケットモニターの作成 ｜ Developers.IO](http://dev.classmethod.jp/client-side/swift-libpcap/) 
* [Using Swift with Cocoa and Objective-C (Swift 2.1): Interacting with C APIs](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html)
* [Swift - UnsafePointerと上手に付き合う - Qiita](http://qiita.com/dankogai/items/2d19b8352183cca3461f)
* [Swift Standard Library Reference](https://developer.apple.com/library/ios/documentation/General/Reference/SwiftStandardLibraryReference/index.html#//apple_ref/doc/uid/TP40014608)
* [Swift2で作るコマンドラインツール - クックパッド開発者ブログ](http://techlife.cookpad.com/entry/2015/11/09/150248)