Async Ser/Deserialization from disk w/ async-bincode and async-std

For this subroutine, I am using async-bincode as well as async-std.

    pub async fn load(self, location: &str) -> Result<Self, AccountError<String>> {
        async_std::fs::File::open(location)
            .map_err(|err| AccountError::IoError(err.to_string()))
            .and_then(|file| async {
                async_bincode::AsyncBincodeReader::from(async_std::io::BufReader::new(file).await)
                    .map_err(|err| AccountError::IoError(err.to_string()))
            }).map_err(|err| err)
    }

Here is the error:

 no method named `map_err` found for type `async_bincode::reader::AsyncBincodeReader<async_std::io::buf_reader::BufReader<async_std::fs::file::File>, _>` in the current scope
  --> hyxe_user\src\client_account.rs:57:22
   |
57 |                     .map_err(|err| AccountError::IoError(err.to_string()))
   |                      ^^^^^^^
   |
   = note: the method `map_err` exists but the following trait bounds were not satisfied:
           `&async_bincode::reader::AsyncBincodeReader<async_std::io::buf_reader::BufReader<async_std::fs::file::File>, _> : futures_util::try_future::TryFutureExt`
           `&mut async_bincode::reader::AsyncBincodeReader<async_std::io::buf_reader::BufReader<async_std::fs::file::File>, _> : futures_util::try_future::TryFutureExt`
           `async_bincode::reader::AsyncBincodeReader<async_std::io::buf_reader::BufReader<async_std::fs::file::File>, _> : futures_util::try_future::TryFutureExt`


My goal is to have load asynchronously write serialized bytes to the local disk

And, for the serialization-half:

    pub async fn save(self, location: &str) -> Result<(), AccountError<String>> {
        async_bincode::serialize_into(async_std::fs::File::open(location), self.inner.deref())
            .map_err(|err| AccountError::IoError(err.to_string()))
    }

Error:

the trait bound `impl core::future::future::Future: std::io::Write` is not satisfied
  --> hyxe_user\src\client_account.rs:53:9
   |
53 |         async_bincode::serialize_into(async_std::fs::File::open(location), self.inner.deref())
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `impl core::future::future::Future`
   |
   = note: required by `async_bincode::serialize_into`

I haven't tried compiling, but how about the following?

pub async fn load(self, location: &str) -> Result<Self, AccountError<String>> {
    match async_std::fs::File::open(location).await {
        Err(err) => AccountError::IoError(err.to_string()),
        Ok(file) => {
            async_bincode::AsyncBincodeReader::from(async_std::io::BufReader::new(file))
                .map_err(|err| AccountError::IoError(err.to_string()))
        }
    }
}

pub async fn save(self, location: &str) -> Result<(), AccountError<String>> {
    async_bincode::serialize_into(async_std::fs::File::open(location).await, self.inner.deref())
        .await
        .map_err(|err| AccountError::IoError(err.to_string()))
}

Thank for your reply. This is the new compiler-output:

error[E0599]: no method named `map_err` found for type `async_bincode::reader::AsyncBincodeReader<async_std::io::buf_reader::BufReader<async_std::fs::file::File>, _>` in the current scope
  --> hyxe_user\src\client_account.rs:61:22
   |
61 |                     .map_err(|err| AccountError::IoError(err.to_string()))
   |                      ^^^^^^^
   |
   = note: the method `map_err` exists but the following trait bounds were not satisfied:
           `&async_bincode::reader::AsyncBincodeReader<async_std::io::buf_reader::BufReader<async_std::fs::file::File>, _> : futures_util::try_future::TryFutureExt`
           `&async_bincode::reader::AsyncBincodeReader<async_std::io::buf_reader::BufReader<async_std::fs::file::File>, _> : futures_util::try_stream::TryStreamExt`
           `&mut async_bincode::reader::AsyncBincodeReader<async_std::io::buf_reader::BufReader<async_std::fs::file::File>, _> : futures_util::try_future::TryFutureExt`
           `&mut async_bincode::reader::AsyncBincodeReader<async_std::io::buf_reader::BufReader<async_std::fs::file::File>, _> : futures_util::try_stream::TryStreamExt`
           `async_bincode::reader::AsyncBincodeReader<async_std::io::buf_reader::BufReader<async_std::fs::file::File>, _> : futures_util::try_future::TryFutureExt`
           `async_bincode::reader::AsyncBincodeReader<async_std::io::buf_reader::BufReader<async_std::fs::file::File>, _> : futures_util::try_stream::TryStreamExt`

Oh, I see. So we need to delete that line since AsyncBincodeReader::from() cannot fail:

pub fn load(self, location: &str) -> Result<Self, AccountError<String>> {
    match async_std::fs::File::open(location).await {
        Err(err) => Err(AccountError::IoError(err.to_string())),
        Ok(file) => Ok(async_bincode::AsyncBincodeReader::from(
            async_std::io::BufReader::new(file),
        )),
    }
}
1 Like

Looks like it's getting closer. It doesn't appear that AsyncBincodeReader is auto-converting to the type representing Self?

error[E0271]: type mismatch resolving `<impl core::future::future::Future as core::future::future::Future>::Output == std::result::Result<client_account::ClientNetworkAccount<'static>, misc::AccountError<std::string::String>>`
  --> hyxe_user\src\client_account.rs:56:48
   |
56 |     pub async fn load(self, location: &str) -> Result<Self, AccountError<String>> {
   |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `async_bincode::reader::AsyncBincodeReader`, found struct `client_account::ClientNetworkAccount`
   |
   = note: expected type `std::result::Result<async_bincode::reader::AsyncBincodeReader<async_std::io::buf_reader::BufReader<async_std::fs::file::File>, _>, _>`
              found type `std::result::Result<client_account::ClientNetworkAccount<'static>, _>`
   = note: the return type of a function must have a statically known size

It seems the load function is creating an AsyncBincodeReader rather than ClientNetworkAccount. I don't know how to construct that type though -- that depends on your codebase :slight_smile:

#[derive(Serialize, Deserialize)]
/// Inner device
pub struct ClientNetworkAccountInner<'cna> {
    cid: u64,
    full_name: &'cna str,
    password: SecVec<u8>
}

/// A thread-safe handle for sharing data across threads and applications
pub struct ClientNetworkAccount<'cna> {
    /// The inner thread-safe device
    inner: Arc<RwLock<ClientNetworkAccountInner<'cna>>>
}

This is (currently) all there is to it. Are the bytes inside the AsyncBincodeReader?

There seems to be a misunderstanding as to what it means to mark a function as async.

pub async fn load(self, location: &str) -> Result<Self, AccountError<String>> {
    async_std::fs::File::open(location)
        .map_err(|err| AccountError::IoError(err.to_string()))
        .and_then(|file| async {
            async_bincode::AsyncBincodeReader::from(async_std::io::BufReader::new(file).await)
                .map_err(|err| AccountError::IoError(err.to_string()))
        }).map_err(|err| err)
}

Since there is no await inside this function body, this is syntax sugar for a future that immediately returns the value in the body. Therefore it turns into this:

pub fn load(self, location: &str) -> impl Future<Item = Result<Self, AccountError<String>>> {
    futures::future::ready(
        async_std::fs::File::open(location)
            .map_err(|err| AccountError::IoError(err.to_string()))
            .and_then(|file| async {
                async_bincode::AsyncBincodeReader::from(async_std::io::BufReader::new(file).await)
                    .map_err(|err| AccountError::IoError(err.to_string()))
            }).map_err(|err| err)
    )
}

The problem here is that the body of this function is something of the kind Future<Item=Future<Item=Result<Self, AccountError<String>>>>. There is an extra future here.

The same problem appears in your async block inside the and_then.

You should not return futures from async functions or blocks, instead you should await them and return the result.

1 Like