UbuntuにOBS Studioをインストールする

screenshot

https://obsproject.com/ja

コマンドでインストールが可能です。

sudo add-apt-repository ppa:obsproject/obs-studio
sudo apt update
sudo apt install obs-studio

まさかUbuntuにもOBS入るとは。これなら私もゲーム実況が可能になりますね。

なお、Switchなどの映像を取り込むにはキャプチャーボードが必要になります。しかし、PCでできるゲームをキャプチャする分には別に必要ないです。PCゲームを愛する孤独な私には必要ありません。ボイスロイドでみんなでプレイしている気持ちになりたいと思います。

Rustで`T` cannot be sent between threads safelyと言われたら

こんなコードを書いて

fn get(key: String) -> Pin<Box<dyn Future<Output = Result<String, ()>>>> {
    Box::pin((async move || {
      key
    })()
}

得られた値をboxedする段階でエラーが出てしまった

error[E0277]: `dyn core::future::future::Future<Output = std::result::Result<String>, ()>>` cannot be sent between threads safely
   --> src/main.rs:431:25
    |
431 |         Box::new(result.boxed().compat())
    |                         ^^^^^ `dyn core::future::future::Future<Output = std::result::Result<String>, ()>>` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `dyn core::future::future::Future<Output = std::result::Result<String>, ()>>`
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<dyn core::future::future::Future<Output = std::result::Result<String>, ()>>>`
    = note: required because it appears within the type `std::boxed::Box<dyn core::future::future::Future<Output = std::result::Result<String>, ()>>>`
    = note: required because it appears within the type `std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = std::result::Result<String>, ()>>>>`
    = note: required because it appears within the type `for<'r> {std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<String>, ()>> + 'r)>>, ()}`
    = note: required because it appears within the type `[static generator@src/main.rs:425:66: 429:10 key:std::string::String for<'r> {std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<String>, ()>> + 'r)>>, ()}]`
    = note: required because it appears within the type `std::future::GenFuture<[static generator@src/main.rs:425:66: 429:10 key:std::string::String for<'r> {std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<String>, ()>> + 'r)>>, ()}]>`
    = note: required because it appears within the type `impl core::future::future::Future`

スレッド間で安全に送信できないために出たエラーです。親切なことに Send を実装すると良いと教えてくれています。Send とはこちらが参考になります。

最初に取り上げるトレイトは Send です。 型 T が Send を実装していた場合、 この型のものはスレッド間で安全に受け渡しされる所有権を持てることを意味します。

これはある種の制約を強制させる際に重要です。 例えば、もし2つのスレッドをつなぐチャネルがあり、そのチャネルを通じてデータを別のスレッドに送れるようにしたいとします。 このときには、その型について Send が実装されているかを確かめます。

というわけで Send を実装してあげれば完了します。

fn get(key: String) -> Pin<Box<dyn Future<Output = Result<String, ()>> + Send>> {
    Box::pin((async move || {
      key
    })()
}

RustのFuture 0.3のOutputにはResult型以外も定義できる

RustのFutureではResult型しか返せなかったですよね。今いじってたら0.3からResult以外でも返せるんですね。

https://docs.rs/futures-preview/0.3.0-alpha.18/futures/prelude/trait.Future.html

したがって、Futureのバージョン0.3Result型を返す時は逆にこうなるというわけですね

fn hoge(text: String) -> Box<dyn Future<Output = Result<String>, ()>> + Send> {
  Box::new((async move || {
      Ok(Cursor::new(text))
  })())
}

忘れそうになるからメモ

RustのFuture 0.3でstd::marker::Unpin制約が実装されていないと言われたら

下記のコードはコンパイルが通りますが

fn get(key: String) -> Box<dyn Future<Output = Result<String, ()>>> {
    Box::new((async move || {
      key
    })()
}

get("text").await などのように await をコールしてコンパイルすると下記のエラーが発生しました

the trait `std::marker::Unpin` is not implemented for `Box<dyn Future<Output = Result<String, ()>>>`

これは下記のように Box::pin を使うことで解決します。

use std::pin::Pin;

fn get(key: String) -> Pin<Box<dyn Future<Output = Result<String, ()>>>> {
    Box::pin((async move || {
      key
    })()
}

これについては下記かな

  • フィーチャ pin がすでに実装されている。このフィーチャを有効化すると Pin と Unpin が使用可能になる。
  • futures のリポジトリ内に futures-stable という名前のクレートが作成されている。このクレートでは &mut self の代わりに Pin を用いた StableFuture などを提供している。元の Future の定義を変えないのは,おそらく互換性のためだと思われる(0.3 で切り替わる?)

https://qiita.com/ubnt_intrepid/items/df70da960b21b222d0ad

参考

Rustの関連関数を定義する

self を定義しないことで関連関数を定義することができ、これらは Struct{}.fun ではなく Struct::fn のようにコールします。Javaで言うところのStaticメソッドに似ています。

struct Example;

impl Example {
    fn foo() -> std::string::String {
        "hoge".to_string()
    }
    fn bar(self) -> std::string::String {
        "fuga".to_string()
    }
}

fn main() {
    assert_eq!(Example::foo(), "hoge");
    assert_eq!(Example{}.bar(), "fuga");
}

Google Cloud Storageでcurlを使ってオブジェクトを移動する

公式のドキュメント見てみると、基本的にはコピーしかないっぽですね。

https://cloud.google.com/storage/docs/renaming-copying-moving-objects?hl=ja

rewriteTo はこんな風に一度コピーしてから、削除をするって手順が示されていて

curl -X POST \
    -H "Authorization: Bearer [OAUTH2_TOKEN]" \
    -H "Content-Length: 0" \
    "https://www.googleapis.com/storage/v1/b/[BUCKET_NAME]/o/[OLD_OBJECT_NAME]/rewriteTo/b/[BUCKET_NAME]/o/[NEW_OBJECT_NAME]"

curl -X DELETE \
    -H "Authorization: Bearer [OAUTH2_TOKEN]" \
    "https://www.googleapis.com/storage/v1/b/[BUCKET_NAME]/o/[OLD_OBJECT_NAME]"

コピーはこの手順

curl -X POST \
    -H "Authorization: Bearer [OAUTH2_TOKEN]" \
    -H "Content-Length: 0" \
    "https://www.googleapis.com/storage/v1/b/[BUCKET_NAME]/o/[OKD_OBJECT_NAME]/rewriteTo/b/[BUCKET_NAME]/o/[NEW_OBJECT_NAME]"

Rustで文字列の先頭または末尾を削除する

pop() は末尾を1文字取り出す。remove() は任意の位置の文字を取り出します。どちらも元の場所から除去されます。

fn main() {

    let mut hello: String = "hello world!".to_string();
    hello.pop();
    assert_eq!("hello world", hello);

    hello.remove(0);
    assert_eq!("ello world", hello);
}