libpna 0.33.0

PNA(Portable-Network-Archive) decoding and encoding library
Documentation
#![cfg(not(target_family = "wasm"))]
use libpna::{Archive, EntryBuilder, ReadEntry, ReadOptions, WriteOptions};
use std::io;
use tokio_util::compat::{
    FuturesAsyncReadCompatExt, FuturesAsyncWriteCompatExt, TokioAsyncReadCompatExt,
};

#[tokio::main]
async fn main() -> io::Result<()> {
    let mut args = std::env::args();
    let _ = args.next();
    match (args.next().as_deref(), args.next()) {
        (Some("create"), Some(s)) => create(s, &args.collect::<Vec<_>>()).await,
        (Some("extract"), Some(s)) => extract(s).await,
        (f, s) => Err(io::Error::other(format!("{f:?}{s:?}"))),
    }
}

async fn create(path: String, file_names: &[String]) -> io::Result<()> {
    let file = tokio::fs::File::create(path).await?.compat();
    let mut archive = Archive::write_header_async(file).await?;
    for file_name in file_names {
        let mut file = tokio::fs::File::open(file_name).await?;
        let mut entry_builder =
            EntryBuilder::new_file(file_name.into(), WriteOptions::builder().build())?
                .compat_write();
        tokio::io::copy(&mut file, &mut entry_builder).await?;
        let entry = entry_builder.into_inner().build()?;
        archive.add_entry_async(entry).await?;
    }
    archive.finalize_async().await?;
    Ok(())
}

async fn extract(path: String) -> io::Result<()> {
    let file = tokio::fs::File::open(path).await?.compat();
    let mut archive = Archive::read_header_async(file).await?;
    while let Some(entry) = archive.read_entry_async().await? {
        match entry {
            ReadEntry::Solid(solid_entry) => {
                for entry in solid_entry.entries(None)? {
                    let entry = entry?;
                    let mut file = io::Cursor::new(Vec::new());
                    let mut reader = entry.reader(ReadOptions::builder().build())?.compat();
                    tokio::io::copy(&mut reader, &mut file).await?;
                }
            }
            ReadEntry::Normal(entry) => {
                let mut file = io::Cursor::new(Vec::new());
                let mut reader = entry.reader(ReadOptions::builder().build())?.compat();
                tokio::io::copy(&mut reader, &mut file).await?;
            }
        }
    }
    Ok(())
}