Majored / rs-async-zip

An asynchronous ZIP archive reading/writing crate.
MIT License
123 stars 40 forks source link

Tokio file doesn't satisfy `tokio::fs::File: futures_lite::AsyncWrite` #107

Closed AdamJSoftware closed 10 months ago

AdamJSoftware commented 10 months ago

I was trying to replicate one of the examples (here is my code, basically copy/paste). And I keep getting the following error.


use async_zip::base::write::ZipFileWriter;
use async_zip::{Compression, ZipEntryBuilder};

use std::path::{Path, PathBuf};

use anyhow::{anyhow, bail, Result};
use tokio::io::AsyncReadExt;
use tokio::fs::File;

pub async fn handle_directory(input_path: &Path, writer: &mut ZipFileWriter<File>) -> Result<()> {
        let entries = walk_dir(input_path.into()).await?;
        let input_dir_str = input_path.as_os_str().to_str().ok_or(anyhow!("Input path not valid UTF-8."))?;

        for entry_path_buf in entries {
            let entry_path = entry_path_buf.as_path();
            let entry_str = entry_path.as_os_str().to_str().ok_or(anyhow!("Directory file path not valid UTF-8."))?;

            if !entry_str.starts_with(input_dir_str) {
                bail!("Directory file path does not start with base input directory path.");
            }

            let entry_str = &entry_str[input_dir_str.len() + 1..];
            write_entry(entry_str, entry_path, writer).await?;
        }

        Ok(())
    }

pub async fn write_entry(filename: &str, input_path: &Path, writer: &mut ZipFileWriter<File>) -> Result<()> {
    let mut input_file = File::open(input_path).await?;
    let input_file_size = input_file.metadata().await?.len() as usize;

    let mut buffer = Vec::with_capacity(input_file_size);
    input_file.read_to_end(&mut buffer).await?;

    let builder = ZipEntryBuilder::new(filename.into(), Compression::Deflate);
    writer.write_entry_whole(builder, &buffer).await?;

    Ok(())
}

pub async fn walk_dir(dir: PathBuf) -> Result<Vec<PathBuf>> {
    let mut dirs = vec![dir];
    let mut files = vec![];

    while !dirs.is_empty() {
        let mut dir_iter = tokio::fs::read_dir(dirs.remove(0)).await?;

        while let Some(entry) = dir_iter.next_entry().await? {
            let entry_path_buf = entry.path();

            if entry_path_buf.is_dir() {
                dirs.push(entry_path_buf);
            } else {
                files.push(entry_path_buf);
            }
        }
    }

    Ok(files)
}

Error:

error[E0599]: the method `write_entry_whole` exists for mutable reference `&mut ZipFileWriter<File>`, but its trait bounds were not satisfied
  --> src/utils/zip.rs:40:12
   |
40 |     writer.write_entry_whole(builder, &buffer).await?;
   |            ^^^^^^^^^^^^^^^^^ method cannot be called on `&mut ZipFileWriter<File>` due to unsatisfied trait bounds
   |
  ::: /home/adam/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.32.0/src/fs/file.rs:93:1
   |
93 | pub struct File {
   | --------------- doesn't satisfy `tokio::fs::File: futures_lite::AsyncWrite`
   |
   = note: the following trait bounds were not satisfied:
           `tokio::fs::File: futures_lite::AsyncWrite`

Any idea what is going on? I've also listed my cargo.toml

async-trait = "0.1.68"
derivative = "2.2.0"
md5 = "0.7.0"
sea-query = {version = "0.28.4", features=["backend-sqlite"]}
serde = {version = "1.0.160", features=["derive"]}
serde_json = "1.0.96"
serde_yaml = "0.9.21"
yaml-rust = "0.4.5"
paste = "1.0.12"
convert_case = "0.6.0"
dotenv = "0.15.0"
fs_extra = "1.3.0"
kube = {version = "0.74.0", features=["runtime", "derive", "client", "admission"]}
k8s-openapi = {version = "0.15.0", features=["v1_23"], default-features = false}
tokio = {version = "1.28.0", features = ["full"]}
reqwest = {version = "0.11.17", features = ["json"]}
tracing = "0.1.37"
deadpool-postgres = "0.10.5"
tokio-postgres = "0.7.8"
diff-struct = "0.5.1"
sea-orm = { version = "0.12.1", features = ["postgres-array", "with-json", "sqlx-postgres", "runtime-tokio-native-tls", "sea-query-binder"]}
strum = { version = "0.24", features = ["derive"] }
anyhow = {version = "1.0.71", features = ["backtrace"]}
lapin = "2.2.1"
futures-lite = "1.13.0"
find_all = "2.0.0"
thiserror = "1.0.43"
chrono = "0.4.26"
csv-async = {version = "1.2.6", features=["tokio"]}
clap = { version = "4.3.23", features = ["derive"] }
async-compression = {version = "0.4.2", features = ["all"]}
async-tar = "0.4.2"
async_zip = {version = "0.0.15", features=["full"]}
futures-util = "0.3.28"
tokio-util = { version = "0.7", features = ["compat"] }
Majored commented 10 months ago

Apologies for the delayed response. This crate currently has a base implementation using futures and then a tokio compatibility module.

https://docs.rs/async_zip/latest/async_zip/tokio/index.html

If you simply switch the following, this should compile:

use async_zip::base::write::ZipFileWriter; to use async_zip::tokio::write::ZipFileWriter;