質問編集履歴
7
GitHubのリポジトリを特定のコミットを指定
test
CHANGED
File without changes
|
test
CHANGED
@@ -57,10 +57,10 @@
|
|
57
57
|
### 本題
|
58
58
|
|
59
59
|
創作したマクロのGitHubはこちらになります。
|
60
|
-
[https://github.com/kano1101/perform-wasm](https://github.com/kano1101/perform-wasm)
|
60
|
+
[https://github.com/kano1101/perform-wasm/tree/3e4a68f0135baa8b5873826685ee810a314c993b](https://github.com/kano1101/perform-wasm/tree/3e4a68f0135baa8b5873826685ee810a314c993b)
|
61
61
|
|
62
62
|
また、創作したマクロを使うコードもGitHubに保存しました。
|
63
|
-
[https://github.com/kano1101/reexport](https://github.com/kano1101/reexport)
|
63
|
+
[https://github.com/kano1101/reexport/tree/1d1cb4651e92393a78235301f3c2acf3a436384f](https://github.com/kano1101/reexport/tree/1d1cb4651e92393a78235301f3c2acf3a436384f)
|
64
64
|
|
65
65
|
今回は、これらのコードを使いたい場合に設定する「依存関係」についてが解決したい問題です。
|
66
66
|
|
6
文面を訂正
test
CHANGED
File without changes
|
test
CHANGED
@@ -54,7 +54,9 @@
|
|
54
54
|
|
55
55
|
これを解決しようとしてみています。
|
56
56
|
|
57
|
+
### 本題
|
58
|
+
|
57
|
-
|
59
|
+
創作したマクロのGitHubはこちらになります。
|
58
60
|
[https://github.com/kano1101/perform-wasm](https://github.com/kano1101/perform-wasm)
|
59
61
|
|
60
62
|
また、創作したマクロを使うコードもGitHubに保存しました。
|
@@ -73,7 +75,7 @@
|
|
73
75
|
|
74
76
|
今の状況では、新たなプロジェクトでこのマクロを使用したい場合、上にリストした3つのクレートをそのプロジェクトでふたたび同じように`Cargo.toml`に追加する必要があります。これが問題です!
|
75
77
|
|
76
|
-
`perform_wasm`を使うたびに毎回、同じ依存関係を記述しなければならないのが不便なのでこれをしなくてもコンパイルできるようにというのが今回実現したいことです。
|
78
|
+
`perform_wasm`を新たなプロジェクトが使うたびに毎回、同じ依存関係を記述しなければならないのが不便なのでこれをしなくてもコンパイルできるようにというのが今回実現したいことです。
|
77
79
|
|
78
80
|
GitHubでも確認いただけますが参考までにマクロのコードを掲載します。
|
79
81
|
|
5
タイトル修正
test
CHANGED
@@ -1 +1 @@
|
|
1
|
-
[Rust]自作マクロ定義の中で外部クレートを使う場合、別のプロジェクトからそのマクロを使っても再度同じ外部クレートの依存関係をCargo.tomlにしなくて済むような方法がわからない
|
1
|
+
[Rust]自作マクロ定義の中で外部クレートを使う場合、別のプロジェクトからそのマクロを使っても、再度同じ外部クレートの依存関係をCargo.tomlに記述しなくて済むような方法がわからない
|
test
CHANGED
File without changes
|
4
タイトル修正
test
CHANGED
@@ -1 +1 @@
|
|
1
|
-
[Rust]自作マクロ定義の中で外部クレートを使
|
1
|
+
[Rust]自作マクロ定義の中で外部クレートを使う場合、別のプロジェクトからそのマクロを使っても再度同じ外部クレートの依存関係をCargo.tomlにしなくて済むような方法がわからない
|
test
CHANGED
File without changes
|
3
文面をわかりやすいよう修正
test
CHANGED
File without changes
|
test
CHANGED
@@ -1,18 +1,66 @@
|
|
1
1
|
### 前提
|
2
2
|
|
3
|
+
Rustでの質問で、前提の話になります。
|
4
|
+
|
3
|
-
|
5
|
+
ブラウザ上で動作する`wasm`に、`wasm_bindgen_futures`クレートの関数`spawn_local`を使っています。
|
6
|
+
|
7
|
+
非同期処理(`async`、`await`)を要求するメソッドを`async`ブロックに仕込んでこの関数に引数で与えたいとした場合に起きた話です。
|
8
|
+
|
9
|
+
ライフタイムの短い参照は`async`ブロック内に入れられません。
|
10
|
+
|
11
|
+
例えば`egui`クレートの頻出のパラメータ`ui: &mut Ui`を`async`ブロック内部に入れようと思って`ui.label()`などを使って`reqwest::get()`の結果の値を非同期にスクリーンに表示したいと考えた場合など、そういうときにライフタイムの問題が言われ、コンパイルできません。
|
12
|
+
|
13
|
+
`wasm`で典型的なパターンの問題と思われます。
|
14
|
+
|
15
|
+
```rust
|
16
|
+
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
17
|
+
egui::TopBottomPanel::top("select_tab").show(ctx, |ui| {
|
18
|
+
wasm_bindgen_futures::spawn_local(async {
|
19
|
+
let ip = reqwest::get("http://httpbin.org/ip")
|
20
|
+
.await
|
21
|
+
.unwrap()
|
22
|
+
.text()
|
23
|
+
.await
|
24
|
+
.unwrap();
|
25
|
+
// ui.label(ip); // 'staticなFuture内部にライフタイムの短い参照uiを入れられない
|
26
|
+
});
|
27
|
+
});
|
28
|
+
}
|
29
|
+
```
|
30
|
+
|
31
|
+
解決策として次のように考えました。
|
32
|
+
|
33
|
+
```rust
|
34
|
+
build_perform!(ip, i32, String);
|
35
|
+
|
36
|
+
fn display(&self, ui: &mut Ui) -> Option<()> {
|
37
|
+
let f = async {
|
38
|
+
reqwest::get("http://httpbin.org/ip")
|
39
|
+
.await
|
40
|
+
.unwrap()
|
41
|
+
.text()
|
42
|
+
.await
|
43
|
+
.unwrap()
|
44
|
+
};
|
45
|
+
ip::perform::set_begin(1, f);
|
46
|
+
let ip = ip::perform::try_fetch(1)?;
|
47
|
+
ui.label(ip);
|
48
|
+
Some(())
|
49
|
+
}
|
50
|
+
```
|
51
|
+
`Future`トレイト内で非同期処理を行なった結果の値を外に出そうと考えました。
|
4
52
|
|
5
53
|
この関数は普通に使うには、与えられる引数のトレイト境界条件が`Future<Output = ()> + 'static`であることにより戻り値が`()`であることもあって、簡単に`async`ブロックから外に値を取り出せないところあるためが使いづらいです。
|
6
54
|
|
7
55
|
これを解決しようとしてみています。
|
8
56
|
|
9
|
-
創作したマクロのGitHubはこちらになります。
|
57
|
+
この創作したマクロのGitHubはこちらになります。
|
10
58
|
[https://github.com/kano1101/perform-wasm](https://github.com/kano1101/perform-wasm)
|
11
59
|
|
12
60
|
また、創作したマクロを使うコードもGitHubに保存しました。
|
13
61
|
[https://github.com/kano1101/reexport](https://github.com/kano1101/reexport)
|
14
62
|
|
15
|
-
今回は、これらのコードを使
|
63
|
+
今回は、これらのコードを使いたい場合に設定する「依存関係」についてが解決したい問題です。
|
16
64
|
|
17
65
|
### 実現したいこと
|
18
66
|
|
@@ -23,7 +71,7 @@
|
|
23
71
|
- `tokio`
|
24
72
|
- `wasm_bindgen_futures`
|
25
73
|
|
26
|
-
今の状況では、新たな
|
74
|
+
今の状況では、新たなプロジェクトでこのマクロを使用したい場合、上にリストした3つのクレートをそのプロジェクトでふたたび同じように`Cargo.toml`に追加する必要があります。これが問題です!
|
27
75
|
|
28
76
|
`perform_wasm`を使うたびに毎回、同じ依存関係を記述しなければならないのが不便なのでこれをしなくてもコンパイルできるようにというのが今回実現したいことです。
|
29
77
|
|
@@ -122,8 +170,6 @@
|
|
122
170
|
|
123
171
|
`perform_wasm`を利用する側の別の新たなプロジェクトにも`Cargo.toml`の依存関係に前述でリストした3つの依存クレートを含めなければコンパイルが通りません。
|
124
172
|
|
125
|
-
逆に、含めればコンパイルは通ります。
|
126
|
-
|
127
173
|
```console
|
128
174
|
error[E0433]: failed to resolve: use of undeclared crate or module `once_cell`
|
129
175
|
--> src/main.rs:11:5
|
@@ -154,6 +200,8 @@
|
|
154
200
|
error: could not compile `reexport` due to 3 previous errors
|
155
201
|
Serving HTTP on :: port 8080 (http://[::]:8080/) ...
|
156
202
|
```
|
203
|
+
|
204
|
+
逆に、含めればコンパイルは通ります。
|
157
205
|
|
158
206
|
### 該当のソースコード
|
159
207
|
|
2
ファイル名の追記
test
CHANGED
File without changes
|
test
CHANGED
@@ -29,6 +29,7 @@
|
|
29
29
|
|
30
30
|
GitHubでも確認いただけますが参考までにマクロのコードを掲載します。
|
31
31
|
|
32
|
+
##### perform_wasm/src/lib.rs
|
32
33
|
```rust
|
33
34
|
#[macro_export]
|
34
35
|
macro_rules! build_perform {
|
@@ -156,6 +157,7 @@
|
|
156
157
|
|
157
158
|
### 該当のソースコード
|
158
159
|
|
160
|
+
##### reexport/Cargo.toml
|
159
161
|
```toml
|
160
162
|
[package]
|
161
163
|
name = "reexport"
|
@@ -177,6 +179,7 @@
|
|
177
179
|
# wasm-bindgen-futures = "0.4.33"
|
178
180
|
```
|
179
181
|
|
182
|
+
##### reexport/src/main.rs
|
180
183
|
```rust
|
181
184
|
fn main() {
|
182
185
|
console_error_panic_hook::set_once();
|
@@ -194,7 +197,7 @@
|
|
194
197
|
|
195
198
|
### 試したこと
|
196
199
|
|
197
|
-
##### run.sh
|
200
|
+
##### reexport/run.sh
|
198
201
|
```bash
|
199
202
|
(
|
200
203
|
cd `dirname $0`
|
@@ -206,6 +209,8 @@
|
|
206
209
|
|
207
210
|
##### 実行したコマンド
|
208
211
|
```console
|
212
|
+
% pwd
|
213
|
+
/Users/a.kano/development/temp/reexport
|
209
214
|
% ./run.sh
|
210
215
|
```
|
211
216
|
|
1
reexportのGitHubを追加と文面がわかりにくいところを修正
test
CHANGED
@@ -1 +1 @@
|
|
1
|
-
[Rust]自作マクロ定義の中で外部クレートを使ったら、別のプロジェクトからそのマクロを使いたい際に再度同じ外部クレートの依存関係をCargo.tomlに記述
|
1
|
+
[Rust]自作マクロ定義の中で外部クレートを使ったら、別のプロジェクトからそのマクロを使いたい際に再度同じ外部クレートの依存関係をCargo.tomlに記述しなくて良い方法がないかわからない
|
test
CHANGED
@@ -1,29 +1,127 @@
|
|
1
1
|
### 前提
|
2
2
|
|
3
|
-
Rustで`wasm_bindgen_futures`クレートを使う際
|
3
|
+
Rustで`wasm_bindgen_futures`クレートの関数`spawn_local`を使う際、与える引数`Future`の問題を解消して使いやすくするマクロを作っています。
|
4
|
-
|
4
|
+
|
5
|
-
この
|
5
|
+
この関数は普通に使うには、与えられる引数のトレイト境界条件が`Future<Output = ()> + 'static`であることにより戻り値が`()`であることもあって、簡単に`async`ブロックから外に値を取り出せないところあるためが使いづらいです。
|
6
|
+
|
6
|
-
|
7
|
+
これを解決しようとしてみています。
|
8
|
+
|
7
|
-
GitHubはこちらになります。
|
9
|
+
創作したマクロのGitHubはこちらになります。
|
8
10
|
[https://github.com/kano1101/perform-wasm](https://github.com/kano1101/perform-wasm)
|
9
11
|
|
12
|
+
また、創作したマクロを使うコードもGitHubに保存しました。
|
13
|
+
[https://github.com/kano1101/reexport](https://github.com/kano1101/reexport)
|
14
|
+
|
10
|
-
これを使う際に発生する依存関係に関することが問題です。
|
15
|
+
今回は、これらのコードを使う際に発生する依存関係に関することが解決したい問題です。
|
11
16
|
|
12
17
|
### 実現したいこと
|
13
18
|
|
19
|
+
創作したマクロのプロジェクトは`perform_wasm`と名付けました。
|
20
|
+
|
14
|
-
|
21
|
+
`perform_wasm`中のマクロ内では、以下のクレートのモジュールをuseしています。
|
15
|
-
|
22
|
+
- `once_cell`
|
23
|
+
- `tokio`
|
24
|
+
- `wasm_bindgen_futures`
|
25
|
+
|
16
|
-
|
26
|
+
今の状況では、新たなのプロジェクトでこのマクロを使用したい場合、上にリストした3つのクレートをそのプロジェクトでふたたび同じように`Cargo.toml`に追加する必要があります。
|
17
|
-
|
27
|
+
|
18
|
-
|
28
|
+
`perform_wasm`を使うたびに毎回、同じ依存関係を記述しなければならないのが不便なのでこれをしなくてもコンパイルできるようにというのが今回実現したいことです。
|
29
|
+
|
19
|
-
|
30
|
+
GitHubでも確認いただけますが参考までにマクロのコードを掲載します。
|
31
|
+
|
32
|
+
```rust
|
33
|
+
#[macro_export]
|
34
|
+
macro_rules! build_perform {
|
35
|
+
($space:ident, $key:ty, $value:ty) => {
|
36
|
+
mod $space {
|
37
|
+
pub mod perform {
|
38
|
+
use once_cell::sync::OnceCell;
|
39
|
+
use std::collections::HashMap;
|
40
|
+
use std::future::Future;
|
41
|
+
use std::hash::Hash;
|
42
|
+
use tokio::sync::Mutex;
|
43
|
+
use wasm_bindgen_futures::spawn_local;
|
44
|
+
static STORE: OnceCell<Mutex<HashMap<$key, $value>>> = OnceCell::new();
|
45
|
+
|
46
|
+
fn global_data() -> &'static Mutex<HashMap<$key, $value>>
|
47
|
+
where
|
48
|
+
$key: Hash,
|
49
|
+
$value: Default,
|
50
|
+
{
|
51
|
+
STORE.get_or_init(|| {
|
52
|
+
let hash_map = HashMap::new();
|
53
|
+
Mutex::new(hash_map)
|
54
|
+
})
|
55
|
+
}
|
56
|
+
|
57
|
+
async fn lock_and_do_mut<F>(f: F) -> Option<$value>
|
58
|
+
where
|
59
|
+
F: FnOnce(&mut HashMap<$key, $value>) -> Option<$value>,
|
60
|
+
$key: Hash,
|
61
|
+
{
|
62
|
+
let mut hash_map = global_data().lock().await;
|
63
|
+
f(&mut *hash_map)
|
64
|
+
}
|
65
|
+
|
66
|
+
async fn lock_and_do<F>(f: F) -> Option<$value>
|
67
|
+
where
|
68
|
+
F: Fn(&HashMap<$key, $value>) -> Option<$value>,
|
69
|
+
{
|
70
|
+
let hash_map = global_data().lock().await;
|
71
|
+
f(&*hash_map)
|
72
|
+
}
|
73
|
+
#[allow(dead_code)]
|
74
|
+
fn try_lock_and_do<F>(f: F) -> Option<$value>
|
75
|
+
where
|
76
|
+
F: Fn(&HashMap<$key, $value>) -> Option<$value>,
|
77
|
+
{
|
78
|
+
let hash_map = global_data().try_lock().ok()?;
|
79
|
+
f(&*hash_map)
|
80
|
+
}
|
81
|
+
|
82
|
+
fn get_and_clone(key: $key, hash_map: &HashMap<$key, $value>) -> Option<$value>
|
83
|
+
where
|
84
|
+
$value: Clone,
|
85
|
+
{
|
86
|
+
hash_map.get(&key).map(|v| v.clone())
|
87
|
+
}
|
88
|
+
|
89
|
+
pub async fn set_async<Fut>(key: $key, f: Fut)
|
90
|
+
where
|
91
|
+
Fut: Future<Output = $value> + 'static,
|
92
|
+
{
|
93
|
+
let value = f.await;
|
94
|
+
lock_and_do_mut(|hash_map| hash_map.insert(key, value)).await;
|
95
|
+
}
|
96
|
+
#[allow(dead_code)]
|
97
|
+
= pub fn set_begin<Fut>(key: $key, f: Fut)
|
98
|
+
where
|
99
|
+
Fut: Future<Output = $value> + 'static,
|
100
|
+
{
|
101
|
+
spawn_local(async move {
|
102
|
+
let value = f.await;
|
103
|
+
lock_and_do_mut(|hash_map| hash_map.insert(key, value)).await;
|
104
|
+
});
|
105
|
+
}
|
20
|
-
|
106
|
+
pub async fn fetch_async(key: $key) -> Option<$value> {
|
107
|
+
lock_and_do(|hash_map| get_and_clone(key, hash_map)).await
|
108
|
+
}
|
109
|
+
#[allow(dead_code)]
|
110
|
+
pub fn try_fetch(key: $key) -> Option<$value> {
|
111
|
+
let value = try_lock_and_do(|hash_map| get_and_clone(key, hash_map))?;
|
112
|
+
Some(value)
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
};
|
117
|
+
}
|
118
|
+
```
|
21
119
|
|
22
120
|
### 発生している問題・エラーメッセージ
|
23
121
|
|
24
|
-
再度記載しますが、GitHubのソースコードも提示させていただいた自作のクレート`perform_wasm`の中では`once_cell`、`tokio`、`wasm_bindgen_futures`を使っています。
|
25
|
-
|
26
|
-
|
122
|
+
`perform_wasm`を利用する側の別の新たなプロジェクトにも`Cargo.toml`の依存関係に前述でリストした3つの依存クレートを含めなければコンパイルが通りません。
|
123
|
+
|
124
|
+
逆に、含めればコンパイルは通ります。
|
27
125
|
|
28
126
|
```console
|
29
127
|
error[E0433]: failed to resolve: use of undeclared crate or module `once_cell`
|
@@ -125,7 +223,10 @@
|
|
125
223
|
cargo 1.65.0 (4bc8f24d3 2022-10-20)
|
126
224
|
```
|
127
225
|
|
128
|
-
プロジェクトを作るたびに
|
226
|
+
論点を戻すと、毎回依存クレートをdependenciesに記述すれば動作はしますので、それで解決ということにもしても良いところかもしれませんが、プロジェクトを作るたびに余分なクレートを依存関係に含めなければならないとなると、せっかく良い機能をクレートとしてブラックボックス化しているのに意味がないと思います。
|
227
|
+
|
228
|
+
`perform_wasm`に修正を入れなければならないのか、`reexport`の修正で済むのか、どう修正すると解決できるのかがわかりません。
|
229
|
+
|
129
230
|
|
130
231
|
この現象の解決方法をご存知の方、もしいらっしゃいましたらご教示願えますと幸いです。
|
131
232
|
|