Implementation of Send is missing when calling FutureExt::boxed() - async-await

I'm experimenting with futures with WASM, using wasm-bindgen-futures and the rust-webpack-template; the full working code and problem code is available.
My experiment is to call an async fn run(), wrapped by a fn run_js() -> js_sys::Promise, from JavaScript. The following is working:
pub async fn run() -> Result<(), JsValue> {
Ok(())
}
// Called by our JS entry point to run the example.
#[wasm_bindgen(js_name = run)]
pub fn run_js() -> js_sys::Promise {
use crate::compat::future_to_promise;
use futures::future::FutureExt;
future_to_promise(async move {
run().await?;
Ok(JsValue::UNDEFINED)
}.boxed())
}
The next step was to add a sleep function and call it from run():
// in run:
sleep(500).await?;
pub async fn sleep(millis: i32) -> Result<(), JsValue> {
use crate::compat::promise_to_future;
let promise = js_sys::Promise::new(&mut move |resolve, _| {
let window = web_sys::window().expect("should have a Window");
window.set_timeout_with_callback_and_timeout_and_arguments_0(
&resolve, millis
).expect("don't expect error on setTimeout()");
});
promise_to_future(promise).await?;
Ok(())
}
crate::compat converts Future 0.3 -> Future 0.1 -> Promise, and back. For completeness, here is promise_to_future:
pub fn promise_to_future(promise: Promise) -> impl Future<Output=Result<JsValue, JsValue>> {
// promise to 0.1
let future01 = JsFuture::from(promise);
// 0.1 to 0.3
Compat01As03::new(future01)
}
Adding this, I get a compilation error here:
error[E0277]: `*mut u8` cannot be sent between threads safely
--> src/lib.rs:45:7
|
42 | future_to_promise(async move {
43 | run().await?;
44 | Ok(JsValue::UNDEFINED)
45 | }.boxed())
| ^^^^^ `*mut u8` cannot be sent between threads safely
|
= help: within `impl core::future::future::Future`, the trait `std::marker::Send` is not implemented for `*mut u8`
error[E0277]: `(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)` cannot be sent between threads safely
--> src/lib.rs:45:7
|
42 | future_to_promise(async move {
43 | run().await?;
44 | Ok(JsValue::UNDEFINED)
45 | }.boxed())
| ^^^^^ `(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)`
(more source code context added, and abridged; full version below)
I can't make out what the error is; something here is not Send, but that's about as much as I understand from this.
Shouldn't this be possible in principle? Or how should I write my sleep function to work correctly?
Full Compiler output:
Compiling rust-webpack v0.1.0 (/data/Documents/Programmieren/rust/hello-web/crate)
error[E0277]: `*mut u8` cannot be sent between threads safely
--> src/lib.rs:45:7
|
45 | }.boxed())
| ^^^^^ `*mut u8` cannot be sent between threads safely
|
= help: within `impl core::future::future::Future`, the trait `std::marker::Send` is not implemented for `*mut u8`
= note: required because it appears within the type `std::marker::PhantomData<*mut u8>`
= note: required because it appears within the type `wasm_bindgen::JsValue`
= note: required because it appears within the type `js_sys::Object`
= note: required because it appears within the type `js_sys::Promise`
= note: required because it appears within the type `{i32, js_sys::Promise, fn(std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}`
= note: required because it appears within the type `[static generator#src/sleep.rs:4:56: 16:2 millis:i32 {i32, js_sys::Promise, fn(std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]`
= note: required because it appears within the type `std::future::GenFuture<[static generator#src/sleep.rs:4:56: 16:2 millis:i32 {i32, js_sys::Promise, fn(std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]>`
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because it appears within the type `{fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}`
= note: required because it appears within the type `[static generator#src/lib.rs:16:43: 34:2 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]`
= note: required because it appears within the type `std::future::GenFuture<[static generator#src/lib.rs:16:43: 34:2 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]>`
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because it appears within the type `{fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}`
= note: required because it appears within the type `[static generator#src/lib.rs:42:34: 45:6 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]`
= note: required because it appears within the type `std::future::GenFuture<[static generator#src/lib.rs:42:34: 45:6 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]>`
= note: required because it appears within the type `impl core::future::future::Future`
error[E0277]: `(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)` cannot be sent between threads safely
--> src/lib.rs:45:7
|
45 | }.boxed())
| ^^^^^ `(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>`
= note: required because it appears within the type `std::boxed::Box<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>`
= note: required because it appears within the type `std::mem::ManuallyDrop<std::boxed::Box<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>>`
= note: required because it appears within the type `wasm_bindgen::closure::Closure<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>`
= note: required because it appears within the type `(wasm_bindgen::closure::Closure<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>, wasm_bindgen::closure::Closure<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>)`
= note: required because it appears within the type `std::option::Option<(wasm_bindgen::closure::Closure<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>, wasm_bindgen::closure::Closure<(dyn std::ops::FnMut(wasm_bindgen::JsValue) + 'static)>)>`
= note: required because it appears within the type `wasm_bindgen_futures::JsFuture`
= note: required because it appears within the type `futures::task_impl::Spawn<wasm_bindgen_futures::JsFuture>`
= note: required because it appears within the type `futures_util::compat::compat01as03::Compat01As03<wasm_bindgen_futures::JsFuture>`
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because it appears within the type `{i32, js_sys::Promise, fn(std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}`
= note: required because it appears within the type `[static generator#src/sleep.rs:4:56: 16:2 millis:i32 {i32, js_sys::Promise, fn(std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]`
= note: required because it appears within the type `std::future::GenFuture<[static generator#src/sleep.rs:4:56: 16:2 millis:i32 {i32, js_sys::Promise, fn(std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]>`
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because it appears within the type `{fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}`
= note: required because it appears within the type `[static generator#src/lib.rs:16:43: 34:2 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]`
= note: required because it appears within the type `std::future::GenFuture<[static generator#src/lib.rs:16:43: 34:2 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]>`
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because it appears within the type `{fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}`
= note: required because it appears within the type `[static generator#src/lib.rs:42:34: 45:6 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]`
= note: required because it appears within the type `std::future::GenFuture<[static generator#src/lib.rs:42:34: 45:6 {fn(std::result::Result<(), wasm_bindgen::JsValue>) -> std::result::Result<<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Ok, <std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::Error> {<std::result::Result<(), wasm_bindgen::JsValue> as std::ops::Try>::into_result}, impl core::future::future::Future, ()}]>`
= note: required because it appears within the type `impl core::future::future::Future`

The .boxed() extension function requires the Future to be Send since a recent change in futures. Apparently your future doesn't fulfill that constraint - likely because JS futures are only valid on the main JS thread.
If .boxed() happens inside the scope of your library you can use Box::pin(future) instead of future.boxed() in order to get a type erased boxed future without the Send requirement.

Related

Hi I am new to rust And I tried to setup a matrix rust server... and it always throws me a issue in error.rs

error[E0599]: no method named `map_err` found for type parameter `Self` in the current scope
--> src\server\error.rs:40:24
|
34 | pub trait ResultExt<T>: Sized {
| ----------------------------- method `map_err` not found for this type parameter
...
40 | let res = self.map_err(|_| MatrixError::internal_err());
| ^^^^^^^ method not found in `Self`
|
= help: items from traits can only be used if the type parameter is bounded by the trait
help: the following traits define an item `map_err`, perhaps you need to add another supertrait for one of them:
|
34 | pub trait ResultExt<T>: Sized + ServiceFactory {
| ++++++++++++++++
34 | pub trait ResultExt<T>: Sized + TryFutureExt {
| ++++++++++++++
34 | pub trait ResultExt<T>: Sized + TryStreamExt {
| ++++++++++++++
34 | pub trait ResultExt<T>: Sized + actix_service::Service {
| ++++++++++++++++++++++++
For more information about this error, try `rustc --explain E0599`.
warning: `maelstrom` (bin "maelstrom") generated 12 warnings
error: could not compile `maelstrom` due to previous error; 12 warnings emitted
It runs into an error where it says that self.map_err is not defined
I tried to completely delete the error.rs out of the code (it didn't work)
here is the code to mess around with
(oh and yes the matrix server uses actix web)
use actix_web::{http::StatusCode, Error, HttpResponse};
#[derive(Clone, Debug, serde::Serialize)]
pub struct MatrixError {
#[serde(skip)]
pub status: StatusCode,
pub errcode: ErrorCode,
pub error: String,
}
impl MatrixError {
pub fn new(status: StatusCode, errcode: ErrorCode, error: &str) -> Self {
MatrixError {
status,
errcode,
error: error.to_string(),
}
}
pub fn internal_err() -> Self {
Self::new(
StatusCode::INTERNAL_SERVER_ERROR,
ErrorCode::UNKNOWN,
"Internal server error.",
)
}
}
impl From<MatrixError> for Error {
fn from(e: MatrixError) -> Self {
HttpResponse::build(e.status).json(e).into()
}
}
pub trait ResultExt<T>: Sized {
fn with_codes(self, status: StatusCode, code: ErrorCode) -> Result<T, MatrixError>;
fn unknown(self) -> Result<T, MatrixError> {
#[cfg(debug_assertions)] // don't leak ISE info in release mode
let res = self.with_codes(StatusCode::INTERNAL_SERVER_ERROR, ErrorCode::UNKNOWN);
#[cfg(not(debug_assertions))]
let res = self.map_err(|_| MatrixError::internal_err());
res
}
}
impl<T, E> ResultExt<T> for Result<T, E>
where
E: std::fmt::Display,
{
fn with_codes(self, status: StatusCode, code: ErrorCode) -> Result<T, MatrixError> {
self.map_err(|e| MatrixError {
status,
errcode: code,
error: format!("{}", e),
})
}
}

Should I try to access self in a PointerPressed event handler for a CoreApp in the Rust Crate for Windows?

E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement. E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement. E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement. E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement.
#![windows_subsystem = "windows"]
use windows::{
core::*,
Foundation::*,
ApplicationModel::Core::*,
Foundation::Numerics::*,
Foundation::TypedEventHandler,
Win32::System::Com::*,
UI::{
Core::*,
Composition::*,
},
};
use windows as Windows;
#[implement(Windows::ApplicationModel::Core::IFrameworkViewSource)]
struct App();
#[allow(non_snake_case)]
impl App {
fn CreateView(&self) -> Result<IFrameworkView> {
// TODO: need self query `self.into()` to support implementing both IFrameworkViewSource and IFrameworkView on the same object.
Ok(AppView::new().into())
}
}
#[implement(Windows::ApplicationModel::Core::IFrameworkView)]
struct AppView {
m_target: Option<CompositionTarget>,
m_visuals: Option<VisualCollection>,
m_selected: Option<Visual>,
m_offset: Option<Vector2>,
}
#[allow(non_snake_case)]
impl AppView {
fn new() -> Self {
Self {
m_target: None,
m_visuals: None,
m_selected: None,
m_offset: None,
}
}
fn Initialize(&self, _: &Option<CoreApplicationView>) -> Result<()> {
Ok(())
}
fn Load(&self, _: &HSTRING) -> Result<()> {
Ok(())
}
fn Uninitialize(&self) -> Result<()> {
Ok(())
}
fn Run(&self) -> Result<()> {
let window = CoreWindow::GetForCurrentThread()?;
window.Activate()?;
let dispatcher = window.Dispatcher()?;
dispatcher.ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit)?;
Ok(())
}
fn SetWindow(&mut self, window: &Option<CoreWindow>) -> Result<()> {
let compositor = Compositor::new()?;
let root = compositor.CreateContainerVisual()?;
self.m_target = Some(compositor.CreateTargetForCurrentView()?);
let target = self.m_target.as_ref().unwrap();
target.SetRoot(&root)?;
self.m_visuals = Some(root.Children()?);
let visuals = self.m_visuals.as_ref().unwrap(); // extra line for test is ok
window.as_ref().unwrap().PointerPressed(TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, args|
{
let args = args.as_ref().unwrap();
let currentpoint = args.CurrentPoint().unwrap();
let point = currentpoint.Position().unwrap(); // Point not Vector2
//let visuals: &VisualCollection = self.m_visuals.as_ref().unwrap();
let visuals = self.m_visuals.as_ref().unwrap(); // E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement
Ok(())
}
))?;
window.as_ref().unwrap().PointerMoved(TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, _args|
{
Ok(())
}
))?;
window.as_ref().unwrap().PointerReleased(TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, _args|
{
Ok(())
}
))?;
Ok(())
}
fn AddVisual(_point: Point) {
//...
}
}
fn main() -> Result<()> {
unsafe {
CoInitializeEx(std::ptr::null_mut(), COINIT_MULTITHREADED)?;
}
let app: IFrameworkViewSource = App().into();
CoreApplication::Run(app)?;
Ok(())
}
Capturing AppView's instance self reference in v0.30 doesn't seem to be possible, because TypedEventHandler::new has a + 'static requirement for the callback (see), so any reference it captures must be 'static (a global variable basically).
Please raise an issue here if you want this. Your code looks like a reasonable way to use this API.
Until then, as a workaround you could make a level of indirection, where instead of storing the state directly in AppView, you store it in a shared helper object, for example:
struct AppView {
m_state: Rc<RefCell<AppViewState>>,
}
struct AppViewState {
m_target: Option<CompositionTarget>,
m_visuals: Option<VisualCollection>,
m_selected: Option<Visual>,
m_offset: Option<Vector2>,
}
You can clone it move into the callback for modification:
let pointer_pressed_state = Rc::clone(self.m_state);
let pointer_pressed_handler = TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, args| {
let state_ref = pointer_pressed_state.borrow(); // or .borrow_mut()
...
});
let pointer_moved_state = Rc::clone(self.m_state);
let pointer_moved_handler = TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, args| {
let state_ref = pointer_moved_state.borrow(); // or .borrow_mut()
...
});
This should work, because now the closure doesn't capture any references (everything gets moved).
If you want, you can add methods to AppViewState, and call them from the closures like state_ref.OnPointerPressed(...).
Another option that I don't recommend is to use unsafe and cast self to 'static.
Rc<RefCell> gives a thread related compiler error but changing to Arc<Mutex> resolves this.
struct AppView {
m_state: Arc<Mutex<AppViewState>>,
}
struct AppViewState {
m_target: Option<CompositionTarget>,
m_visuals: Option<VisualCollection>,
m_selected: Option<Visual>,
m_offset: Option<Vector2>,
}

In Substrate is there a way to use storage and functions from one custom module in another?

I have seen the Substrate Tutorial on creating crates of individual Substrate Runtime modules here in order to re-use the functionality, but I wondered if there is a way for one custom module to access the storage or functions from another custom module?
Something along these lines:
/// In ModuleA
pub type IndexType = u64;
decl_storage! {
trait Store for Module<T: Trait> as ModuleA {
pub MyIndexCount get(my_index_count): Option<IndexType>;
}
}
And then inside ModuleB - what do I need to do to use/include the functionality of ModuleA, and how do I call it?
/// In ModuleB
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn deposit_event<T>() = default;
pub fn edit_index(origin) -> Result {
let sender = ensure_signed(origin)?;
// --->>>> I want to read some storage from ModuleA whilst inside ModuleB
let c: IndexType = ReadStorageFromModuleA >>> my_index_count().ok_or("Storage Read Error: cannot get index")?;
// change storage in ModuleA from ModuleB
WriteToStorageInModuleA <MyIndexCount<T>>::put(&c + 1);
Ok(())
}
}
}
If you are building a module (module2) which has a direct dependency on another module (module1), you must inherit module1's trait in module2's trait definition:
pub trait Trait: module1::Trait {
...
}
To access public storage items from module1 in module2, you need to do the following:
Import the appropriate storage trait to access the storage API: StorageValue, StorageMap, etc...
Access the public storage through module1's storage type
<module1::Something<T>>::get()
<module1::Something<T>>::put()
etc...
To access other public functions from module 1 in module 2, you need to use the Module type:
<module1::Module<T>>::public_function();
Here is a simple example of two modules interacting in this way:
module1.rs
Note that all the things in this module are marked public (pub)
use support::{decl_module, decl_storage, StorageValue};
pub trait Trait: system::Trait {}
decl_storage! {
trait Store for Module<T: Trait> as TemplateModule {
pub Something: u32;
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
}
}
impl<T: Trait> Module<T> {
pub fn get_value() -> u32 {
<Something<T>>::get()
}
}
module2.rs
use support::{decl_module, decl_event, StorageValue, dispatch::Result};
use system::ensure_signed;
use crate::module1;
pub trait Trait: module1::Trait {
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
decl_module! {
/// The module declaration.
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn deposit_event<T>() = default;
pub fn get_value_directly(origin) -> Result {
let who = ensure_signed(origin)?;
let value = <module1::Something<T>>::get();
Self::deposit_event(RawEvent::ValueIs(value, who));
Ok(())
}
pub fn set_value_directly(origin, value: u32) -> Result {
let _ = ensure_signed(origin)?;
<module1::Something<T>>::put(value);
Ok(())
}
pub fn get_value_public_function(origin) -> Result {
let who = ensure_signed(origin)?;
let value = <module1::Module<T>>::get_value();
Self::deposit_event(RawEvent::ValueIs(value, who));
Ok(())
}
}
}
decl_event!(
pub enum Event<T> where <T as system::Trait>::AccountId {
ValueIs(u32, AccountId),
}
);

How do I have a trait field in a struct?

I have some code that I want to turn into a crate. But it includes a structure that contains a field that I want to be provided by the user of the crate. But I need functionality from that field, so I want to specify it as a trait.
pub trait RoleTrait {
fn owner<T: RoleTrait>() -> T;
fn order<T: RoleTrait>(&self) -> usize;
}
pub struct RequestInfo<Role: RoleTrait + PartialEq> {
role: Option<Role>,
name: String,
}
impl<Role: RoleTrait> RequestInfo<Role>
where
Role: std::cmp::PartialEq,
{
fn name(&self) -> String {
self.name.to_string()
}
fn role(&self) -> &Option<Role> {
&self.role
}
fn is_owner(&self) -> bool {
if let Some(role) = self.role {
role == Role::owner()
} else {
false
}
}
fn order(&self) -> usize {
if let Some(role) = self.role {
role.order() + 1
} else {
0
}
}
fn from(name: String) -> RequestInfo<Role> {
RequestInfo::<Role> {
role: None,
name: name,
}
}
fn with_role(name: String, role: Role) -> RequestInfo<Role> {
RequestInfo::<Role> {
role: Some(role),
name: name,
}
}
}
With two implementations of RoleTrait:
#[derive(PartialEq)]
pub enum CourseRole {
Professor,
Marker,
Student,
}
impl RoleTrait for CourseRole {
fn owner<T: RoleTrait>() -> T {
CourseRole::Professor
}
fn order<T: RoleTrait>(&self) -> usize {
if *self == CourseRole::Professor {
0
} else {
1
}
}
}
#[derive(PartialEq)]
pub enum BlogRole {
Owner,
Blogger,
}
impl RoleTrait for BlogRole {
fn owner<T: RoleTrait>() -> T {
BlogRole::Owner
}
fn order<T: RoleTrait>(&self) -> usize {
if *self == BlogRole::Owner {
0
} else {
1
}
}
}
I get 3 errors with this.
error[E0282]: type annotations needed
--> src/main.rs:28:18
|
28 | role.order() + 1
| ^^^^^ cannot infer type for `T`
error[E0308]: mismatched types
--> src/main.rs:55:9
|
54 | fn owner<T: RoleTrait>() -> T {
| - expected `T` because of return type
55 | CourseRole::Professor
| ^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found enum `CourseRole`
|
= note: expected type `T`
found type `CourseRole`
error[E0308]: mismatched types
--> src/main.rs:72:9
|
71 | fn owner<T: RoleTrait>() -> T {
| - expected `T` because of return type
72 | BlogRole::Owner
| ^^^^^^^^^^^^^^^ expected type parameter, found enum `BlogRole`
|
= note: expected type `T`
found type `BlogRole`
(and the second error repeated for the other enum)
Frankly, I'm surprised (and pleased!) that some of my code is valid (like the references to owner in the trait). I had a lot more errors when I started writing this question, but I can't figure out these remaining ones since T looks so clear and rustc seems to have already figured out harder things. In the last 2 errors, it's almost like it doesn't realize that there is an implementation of the trait for the enum because it's in the middle of defining that implementation (but it obviously understands that in other places).
Something feels a little "off" with this trait:
pub trait RoleTrait {
fn owner<T: RoleTrait>() -> T;
fn order<T: RoleTrait>(&self) -> usize;
}
The owner method doesn't have a receiver (e.g. self), so it seems unnecessary to introduce a new type parameter; Self will do the same thing.
In order, having a separate T is not exactly the same thing as just using Self - it allows T and Self to be a completely different implementations of RoleTrait. But this feels like quite a strange and unusual requirement, especially since T doesn't appear in the method signature.
Your code can be fixed quite simply by following the more typical pattern:
pub trait RoleTrait {
fn owner() -> Self;
fn order(&self) -> usize;
}
This small change leads to all the type errors being resolved, and just leaving a couple of small borrow errors (playground), which can be quite easily addressed (playground).

How do I erase the type of future in the new future API?

The following does not compile
#![feature(await_macro, async_await, futures_api)]
use core::future::Future;
async fn foo() {}
trait Bar {
type Output: Future<Output = ()>;
fn bar(&self) -> Self::Output;
}
impl Bar for () {
type Output = Box<dyn Future<Output = ()>>;
fn bar(&self) -> Self::Output {
Box::new(foo())
}
}
async fn buz() {
await!(().bar())
}
error[E0277]: the trait bound `(dyn std::future::Future<Output=()> + 'static): std::marker::Unpin` is not satisfied
--> src/lib.rs:19:15
|
19 | await!(().bar())
| ^^^ the trait `std::marker::Unpin` is not implemented for `(dyn std::future::Future<Output=()> + 'static)`
|
= note: required because of the requirements on the impl of `std::future::Future` for `std::boxed::Box<(dyn std::future::Future<Output=()> + 'static)>`
error[E0277]: the trait bound `dyn std::future::Future<Output=()>: std::marker::Unpin` is not satisfied
--> src/lib.rs:19:5
|
19 | await!(().bar())
| ^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future<Output=()>`
|
= note: required because of the requirements on the impl of `std::future::Future` for `std::boxed::Box<dyn std::future::Future<Output=()>>`
= note: required by `std::future::poll_with_tls_waker`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
How can I set the type Output? I want bar to return some Future by calling foo so I can await! in buz.
In the old days with Future<Item = (), Error = ()>, the above would compile without any problems as we don't have the Unpin constraint, but we also don't have await.
Wrap the Box in a Pin:
impl Bar for () {
type Output = Pin<Box<dyn Future<Output = ()>>>;
fn bar(&self) -> Self::Output {
Box::pin(foo())
}
}

Resources