RustでGUI 〜iced編〜

プログラム全体はgithubの[ogata-k/GUI_cmp/example_iced](https://github.com/ogata-k/GUI_cmp/tree/master/example_iced)をご覧ください。

# iced
今回使用するバージョンは```0.1.0-beta```です。

# どんなクレートか
[iced](https://crates.io/crates/iced)はバージョンにbetaとあるようにまだまだ開発中のGUIライブラリです。[README](https://github.com/hecrj/iced)によるとElmにインスパイアされて作られたクロスプラットフォーム向けのライブラリです。Elmを参考にしているだけあってコードの見た目もElmに見えます。
珍しいことに[Webアプリ](https://iced.rs/)もサポートしてるとのことです。さらに各種基本的なレンダーライブラリの対応や非同期も対応しています。

# コード
```Rust:main.rs
use iced::{Sandbox, Element, Button, Column, Text, Settings, Container, Length, Align, HorizontalAlignment, Color, Background, button};
use iced::settings::Window;

pub fn main() {
    Counter::run(Settings {
        window: Window {
            size: (300, 300), // (x, y)
            resizable: false,
        }
    })
}

// state
struct Counter {
    // counter value
    value: i32,

    // state of the two buttons
    increment_button: button::State,
    reset_button: button::State,
}

// message
#[derive(Debug, Clone, Copy)]
pub enum Message {
    Increment,
    Reset,
}

impl Sandbox for Counter {
    type Message = Message;

    fn new() -> Self {
        Counter {
            value: 0,
            increment_button: button::State::default(),
            reset_button: button::State::default(),
        }
    }

    fn title(&self) -> String {
        String::from("count up")
    }

    // update
    fn update(&mut self, message: Message) {
        match message {
            Message::Increment => {
                self.value += 1;
            }
            Message::Reset => {
                self.value = 0;
            }
        }
    }

    // view logic
    fn view(&mut self) -> Element<Message> {
        Container::new(
            Column::new()
                .push(
                    Button::new(&mut self.increment_button, Text::new("+1"))
                        .on_press(Message::Increment)
                        .border_radius(5)
                        .background(Background::Color(Color{r: 0.8, g: 0.8, b: 0.8, a: 1.})),
                )
                .push(
                    Text::new(self.value.to_string()).size(50).horizontal_alignment(HorizontalAlignment::Center),
                )
                .push(
                    Button::new(&mut self.reset_button, Text::new("reset"))
                        .on_press(Message::Reset),
                )
                .align_items(Align::Center)
        )
            .width(Length::Fill)
            .center_x()
            .height(Length::Fill)
            .center_y()
            .into()
    }
}
```
![iced.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167385/735c2387-4ba8-051f-6e83-ba99b9cbdfd3.png)

# コードの説明
``main``関数ではGUIのおおもととなるWindowの設定を元にアプリを起動するところだけを請け負います。
次に状態のモデルとなる```Counter```モデルです。今回はカウント値、カウントアップボタン、リセットボタンの状態を表現しています。
次に状態の変更を通知するときに通知するイベントメッセージの```Message```列挙体です。今回は増加とリセットを表現しています。
そして```Sandbox```トレイトを実装することで描画と更新処理を実装します。```Application```というトレイトもあるのですが、こちらは非同期を扱うときのトレイトとなります。描画は```view```関数で定義します。少しレイアウトの定義関数に癖がある気がしますが、よくある記述で書くことができます。
更新処理の```update```関数は状態モデルを更新する処理だけを行います。

# 所感
まだまだ実用には向かず未成熟な感じが強いですが、触ってみた限り**完全にElm**ですね。モデルやメッセージが肥大化しそうな予感はありますが、慣れると[Elmアーキテクチャ](https://guide.elm-lang.org/architecture/)の方がGUIは表記しやすいかもしれませんね。

# まとめ
まだまだ未成熟なライブラリですが、実用的になればRustでGUIと言ったらこれ！といえるGUIライブラリの一つになりそうな予感がします。