1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
//! High-level async 3MF model loading.
//!
//! This module provides the [`load_model_async`] function, which orchestrates the complete
//! async loading pipeline from file path to parsed [`Model`].
//!
//! ## Loading Pipeline
//!
//! The function performs these steps:
//!
//! 1. **Async file open**: Opens the 3MF file using `tokio::fs::File::open()`
//! 2. **ZIP initialization**: Creates an [`AsyncZipArchive`] and reads the central directory
//! 3. **OPC relationship parsing**: Reads `_rels/.rels` to find the main model part
//! 4. **Async entry reading**: Reads the model XML data from the archive
//! 5. **Spawn-blocked parsing**: Offloads CPU-bound XML parsing to a blocking thread pool
//!
//! ## Performance Characteristics
//!
//! - **I/O operations**: Non-blocking, multiple files can be loaded concurrently
//! - **XML parsing**: Runs on blocking thread pool via `tokio::task::spawn_blocking`
//! - **Memory**: Entire model XML is loaded into memory before parsing
//!
//! ## Examples
//!
//! ### Basic Usage
//!
//! ```no_run
//! use lib3mf_async::loader::load_model_async;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let model = load_model_async("cube.3mf").await?;
//! println!("Loaded {} build items", model.build.items.len());
//! Ok(())
//! }
//! ```
//!
//! ### Concurrent Loading
//!
//! ```no_run
//! use lib3mf_async::loader::load_model_async;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Load multiple files concurrently
//! let (model1, model2, model3) = tokio::try_join!(
//! load_model_async("file1.3mf"),
//! load_model_async("file2.3mf"),
//! load_model_async("file3.3mf"),
//! )?;
//!
//! println!("Loaded {} models concurrently", 3);
//! Ok(())
//! }
//! ```
//!
//! [`Model`]: lib3mf_core::model::Model
//! [`AsyncZipArchive`]: crate::zip::AsyncZipArchive
use crateAsyncArchiveReader;
use crateAsyncZipArchive;
use ;
use ;
use Model;
use parse_model;
use Cursor;
use Path;
use File;
/// Asynchronously loads a 3MF model from a file path.
///
/// This is the primary entry point for async 3MF loading. It handles all aspects of
/// loading: file I/O, ZIP archive access, OPC relationship parsing, and XML model parsing.
///
/// # Arguments
///
/// * `path` - Path to the 3MF file (any type implementing `AsRef<Path>`)
///
/// # Returns
///
/// A fully parsed [`Model`] containing all resources, build items, and metadata.
///
/// # Errors
///
/// Returns [`Lib3mfError::Io`] if:
/// - File cannot be opened
/// - ZIP archive cannot be read
/// - Archive entries cannot be read
///
/// Returns [`Lib3mfError::InvalidStructure`] if:
/// - `_rels/.rels` file is missing or malformed
/// - No 3D model relationship is found (must have type `http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel`)
/// - Model part path is invalid
///
/// Returns parsing errors from [`parse_model`] if the model XML is malformed.
///
/// # Implementation Details
///
/// ## Async vs Blocking
///
/// - **Async operations**: File open, ZIP directory reading, entry reading
/// - **Blocking operations**: XML parsing (offloaded to `tokio::task::spawn_blocking`)
///
/// The function uses `spawn_blocking` for XML parsing because it's CPU-bound work that would
/// otherwise block the tokio executor. This allows other async tasks to progress while
/// parsing happens on a dedicated thread pool.
///
/// ## OPC Discovery
///
/// The function follows the Open Packaging Conventions (OPC) standard to discover the
/// main model part:
///
/// 1. Reads `_rels/.rels` (package-level relationships)
/// 2. Finds relationship with type ending in `/3dmodel`
/// 3. Reads the target model part (typically `/3D/3dmodel.model`)
///
/// # Examples
///
/// ```no_run
/// use lib3mf_async::loader::load_model_async;
/// use lib3mf_core::validation::ValidationLevel;
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// // Load a 3MF file
/// let model = load_model_async("complex_model.3mf").await?;
///
/// // Validate the loaded model
/// let report = model.validate(ValidationLevel::Standard);
/// if report.has_errors() {
/// eprintln!("Model has validation errors:");
/// for item in &report.items {
/// eprintln!(" - {}", item.message);
/// }
/// }
///
/// // Process the model
/// println!("Objects: {}", model.resources.iter_objects().count());
/// println!("Build items: {}", model.build.items.len());
///
/// Ok(())
/// }
/// ```
///
/// [`Model`]: lib3mf_core::model::Model
/// [`Lib3mfError::Io`]: lib3mf_core::error::Lib3mfError::Io
/// [`Lib3mfError::InvalidStructure`]: lib3mf_core::error::Lib3mfError::InvalidStructure
/// [`parse_model`]: lib3mf_core::parser::model_parser::parse_model
pub async