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}