Minimal Reproducible example:
use std::pin::Pin;
use std::rc::Rc;
use yew::prelude::*;
// pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
pub struct UseSignTxHandle {
api_call: Rc<dyn Fn() -> Pin<Box<dyn std::future::Future<Output = Option<String>>>>>,
}
impl UseSignTxHandle {
pub fn api_call(&self) {
(self.api_call)();
}
}
impl Clone for UseSignTxHandle {
fn clone(&self) -> Self {
Self {
api_call: self.api_call.clone(),
}
}
}
#[hook]
pub fn use_sign_tx_handle() -> UseSignTxHandle
{
let state: UseStateHandle<Option<String>> = use_state(|| None);
let phrase_option = state.clone();
let api_call = {
let phrase_option = phrase_option.clone();
Rc::new(move || {
let phrase_option = phrase_option.clone();
let pin = Box::pin( async {
if let Some(seed) = *phrase_option {
let events = "Hello World".to_string();
Some(events)
} else {
None
}
});
pin
})
};
UseSignTxHandle { api_call }
}
Error:
UseSignTxHandle { api_call }
| ^^^^^^^^ expected trait object `dyn std::future::Future`, found opaque type
|
::: /home/amiya/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/mod.rs:72:43
|
72 | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
| ------------------------------- the found opaque type
|
= note: expected struct `Pin<Box<(dyn std::future::Future<Output = std::option::Option<std::string::String>> + 'static)>>`
found struct `Pin<Box<impl std::future::Future<Output = std::option::Option<std::string::String>>>>`
= note: required for the cast from `[closure@src/components/accounts/hooks/sign_tx_handle.rs:35:17: 35:24]` to the object type `dyn Fn() -> Pin<Box<(dyn std::future::Future<Output = std::option::Option<std::string::String>> + 'static)>>`
Trying to build async function as hook in yew:
use crate::components::accounts::account_store::PhraseStore;
use crate::components::accounts::functions::get_from_seed_sr;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use subxt::{tx::PairSigner, PolkadotConfig};
use yew::prelude::*;
use yewdux::prelude::*;
use subxt::blocks::ExtrinsicEvents;
use subxt::config::WithExtrinsicParams;
use subxt::tx::BaseExtrinsicParams;
use subxt::tx::PlainTip;
use subxt::SubstrateConfig;
// pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
pub struct UseSignTxHandle {
api_call: Rc<dyn Fn() -> Pin<Box<dyn std::future::Future<Output = std::option::Option<ExtrinsicEvents<WithExtrinsicParams<SubstrateConfig, BaseExtrinsicParams<SubstrateConfig, PlainTip>>>>>>>>,
}
impl UseSignTxHandle {
pub fn api_call(&self) {
(self.api_call)();
}
}
impl Clone for UseSignTxHandle {
fn clone(&self) -> Self {
Self {
api_call: self.api_call.clone(),
}
}
}
#[hook]
pub fn use_sign_tx_handle<T>(tx: T) -> UseSignTxHandle
where
T: subxt::tx::TxPayload + 'static,
{
let (store, _) = use_store::<PhraseStore>();
let phrase_option = store.mnemonic_phrase.clone();
let api_call = {
let phrase_option = phrase_option.clone();
Rc::new(move || {
let phrase_option = phrase_option.clone();
let pin = Box::pin(async {
let client =
subxt::client::OnlineClient::<PolkadotConfig>::from_url("ws://127.0.0.1:9944")
.await
.unwrap();
if let Some(seed) = phrase_option {
let pair = get_from_seed_sr(&seed);
let signer = PairSigner::new(pair);
let result = client
.tx()
.sign_and_submit_then_watch_default(&tx, &signer)
.await
.unwrap()
.wait_for_finalized()
.await
.unwrap();
let events = result.fetch_events().await.unwrap();
Some(events)
} else {
None
}
});
pin
})
};
UseSignTxHandle { api_call }
}
Gives error:
UseSignTxHandle { api_call }
| ^^^^^^^^ expected trait object `dyn std::future::Future`, found opaque type
note: expected struct `Pin<Box<(dyn std::future::Future<Output = std::option::Option<ExtrinsicEvents<WithExtrinsicParams<SubstrateConfig, BaseExtrinsicParams<SubstrateConfig, PlainTip>>>>> + 'static)>>`
found struct `Pin<Box<impl std::future::Future<Output = std::option::Option<ExtrinsicEvents<WithExtrinsicParams<SubstrateConfig, BaseExtrinsicParams<SubstrateConfig, PlainTip>>>>>>>`
As I suspected the as _
works. It is needed to convert the concrete Pin<Box<impl Future<…>>>
into a trait object Pin<Box<dyn Future<…>>>
expected by UseSignTxHandle
:
#[hook]
pub fn use_sign_tx_handle<T>(tx: T) -> UseSignTxHandle
where
T: subxt::tx::TxPayload + 'static,
{
let state: UseStateHandle<Option<String>> = use_state(|| None);
let api_call = {
Rc::new(move || {
let state = state.clone();
Box::pin(async move { state.as_ref().map(|_| "Hello World".to_string()) }) as _
})
};
UseSignTxHandle { api_call }
}