lib3mf_async/
archive.rs

1//! Async archive reader abstraction layer.
2//!
3//! This module provides the [`AsyncArchiveReader`] trait, which defines the interface for
4//! asynchronously reading entries from archive containers (ZIP files). It mirrors the synchronous
5//! [`lib3mf_core::archive::ArchiveReader`] trait but with async methods.
6//!
7//! ## Design
8//!
9//! The trait abstracts over different async archive implementations, allowing the 3MF loader
10//! to work with any async archive backend. Currently, [`AsyncZipArchive`] is the primary
11//! implementation using the async-zip crate.
12//!
13//! ## Examples
14//!
15//! ```no_run
16//! use lib3mf_async::archive::AsyncArchiveReader;
17//! use lib3mf_async::zip::AsyncZipArchive;
18//! use tokio::fs::File;
19//!
20//! #[tokio::main]
21//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
22//!     let file = File::open("model.3mf").await?;
23//!     let mut archive = AsyncZipArchive::new(file).await?;
24//!
25//!     // Check if an entry exists
26//!     if archive.entry_exists("_rels/.rels").await {
27//!         // Read the entry
28//!         let data = archive.read_entry("_rels/.rels").await?;
29//!         println!("Read {} bytes", data.len());
30//!     }
31//!
32//!     // List all entries
33//!     let entries = archive.list_entries().await?;
34//!     println!("Archive contains {} entries", entries.len());
35//!
36//!     Ok(())
37//! }
38//! ```
39//!
40//! [`AsyncZipArchive`]: crate::zip::AsyncZipArchive
41
42use async_trait::async_trait;
43use lib3mf_core::error::Result;
44
45/// Trait for reading entries from an archive asynchronously.
46///
47/// This trait provides async methods for reading archive contents without blocking the executor.
48/// It is analogous to [`lib3mf_core::archive::ArchiveReader`] but with async/await semantics.
49///
50/// # Trait Bounds
51///
52/// Implementors must be `Send + Sync` to allow the archive reader to be used across async task
53/// boundaries. This is required because async functions may be sent between threads in the tokio
54/// runtime.
55///
56/// # Implementors
57///
58/// - [`AsyncZipArchive`]: ZIP archive reader using async-zip
59///
60/// [`AsyncZipArchive`]: crate::zip::AsyncZipArchive
61#[async_trait]
62pub trait AsyncArchiveReader: Send + Sync {
63    /// Reads the content of an archive entry by name.
64    ///
65    /// # Arguments
66    ///
67    /// * `name` - The entry path within the archive (e.g., "_rels/.rels", "3D/3dmodel.model")
68    ///
69    /// # Returns
70    ///
71    /// The full content of the entry as a `Vec<u8>`.
72    ///
73    /// # Errors
74    ///
75    /// Returns [`Lib3mfError::ResourceNotFound`] if the entry does not exist.
76    ///
77    /// Returns [`Lib3mfError::Io`] if reading fails.
78    ///
79    /// [`Lib3mfError::ResourceNotFound`]: lib3mf_core::error::Lib3mfError::ResourceNotFound
80    /// [`Lib3mfError::Io`]: lib3mf_core::error::Lib3mfError::Io
81    async fn read_entry(&mut self, name: &str) -> Result<Vec<u8>>;
82
83    /// Checks if an archive entry exists.
84    ///
85    /// # Arguments
86    ///
87    /// * `name` - The entry path within the archive
88    ///
89    /// # Returns
90    ///
91    /// `true` if the entry exists, `false` otherwise.
92    async fn entry_exists(&mut self, name: &str) -> bool;
93
94    /// Lists all entry names in the archive.
95    ///
96    /// # Returns
97    ///
98    /// A vector of all entry path names in the archive.
99    ///
100    /// # Errors
101    ///
102    /// Returns [`Lib3mfError::Io`] if the archive cannot be read.
103    ///
104    /// [`Lib3mfError::Io`]: lib3mf_core::error::Lib3mfError::Io
105    async fn list_entries(&mut self) -> Result<Vec<String>>;
106}