lib3mf_core/lib.rs
1//! # lib3mf-core
2//!
3//! Pure Rust implementation of the 3D Manufacturing Format (3MF) specification.
4//!
5//! ## Overview
6//!
7//! 3MF is an XML-based file format for additive manufacturing (3D printing), developed by the 3MF Consortium.
8//! It stores geometry, materials, colors, textures, and metadata in an OPC (Open Packaging Conventions) ZIP container.
9//!
10//! This crate provides a complete, memory-safe implementation of the 3MF Core Specification v1.4.0 and all major
11//! extensions, including:
12//!
13//! - **Beam Lattice Extension**: Structural lattices with cylindrical beams
14//! - **Boolean Operations Extension**: CSG operations on meshes
15//! - **Displacement Extension**: Texture-driven surface modification
16//! - **Materials and Properties Extension**: Base materials, color groups, textures, and composites
17//! - **Production Extension**: UUIDs, part numbers, manufacturing metadata
18//! - **Secure Content Extension**: Digital signatures and encryption (behind `crypto` feature)
19//! - **Slice Extension**: 2D layer-based geometry for DLP/SLA printing
20//! - **Volumetric Extension**: Voxel data representation
21//!
22//! ## Quick Start
23//!
24//! ```no_run
25//! use lib3mf_core::archive::{ZipArchiver, ArchiveReader, find_model_path};
26//! use lib3mf_core::parser::parse_model;
27//! use lib3mf_core::validation::ValidationLevel;
28//! use std::fs::File;
29//!
30//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
31//! // Open the 3MF file (ZIP archive)
32//! let file = File::open("model.3mf")?;
33//! let mut archiver = ZipArchiver::new(file)?;
34//!
35//! // Locate the main model XML via OPC relationships
36//! let model_path = find_model_path(&mut archiver)?;
37//!
38//! // Read and parse the model
39//! let model_data = archiver.read_entry(&model_path)?;
40//! let model = parse_model(std::io::Cursor::new(model_data))?;
41//!
42//! // Validate the model
43//! let report = model.validate(ValidationLevel::Standard);
44//! if report.has_errors() {
45//! for item in &report.items {
46//! eprintln!("Validation issue: {}", item.message);
47//! }
48//! }
49//!
50//! // Access model data
51//! println!("Unit: {:?}", model.unit);
52//! println!("Build items: {}", model.build.items.len());
53//! println!("Objects: {}", model.resources.iter_objects().count());
54//! # Ok(())
55//! # }
56//! ```
57//!
58//! ## Feature Flags
59//!
60//! By default, `lib3mf-core` is built with minimal dependencies (`default = []`). Optional features can be enabled
61//! to add functionality at the cost of additional dependencies:
62//!
63//! | Feature | Description | Dependency Impact |
64//! |---------|-------------|-------------------|
65//! | `crypto` | Enables Secure Content Extension (digital signatures, encryption) | ~300 crates (rsa, aes-gcm, sha1, sha2, x509-parser, base64) |
66//! | `parallel` | Enables multi-threaded mesh processing using Rayon | +1 crate |
67//! | `png-validation` | Enables PNG texture validation | +1 crate |
68//! | `full` | Enables all features: `crypto`, `parallel`, `png-validation` | All of the above |
69//!
70//! **Minimal build** (no features): ~154 crates
71//! **Full build** (`--all-features`): ~300 crates
72//!
73//! ```toml
74//! # Cargo.toml - minimal build (no crypto, no parallel)
75//! [dependencies]
76//! lib3mf-core = "0.1"
77//!
78//! # Cargo.toml - with crypto support
79//! [dependencies]
80//! lib3mf-core = { version = "0.1", features = ["crypto"] }
81//!
82//! # Cargo.toml - full-featured build
83//! [dependencies]
84//! lib3mf-core = { version = "0.1", features = ["full"] }
85//! ```
86//!
87//! ## Modules
88//!
89//! - [`archive`]: OPC (Open Packaging Conventions) container and ZIP archive handling. Provides the [`ArchiveReader`]
90//! trait for abstracting over archive backends and [`find_model_path`] for discovering the main model XML.
91//! - [`parser`]: XML-to-Model parsing pipeline. The primary entry point is [`parse_model`], which converts XML to an
92//! in-memory [`Model`] structure. For large files (>100MB), see [`parser::streaming`] for event-based parsing.
93//! - [`model`]: Core data model structures: [`Model`], [`Object`], [`Mesh`], [`ResourceCollection`], [`Build`], [`BuildItem`].
94//! Follows an immutable-by-default design philosophy for thread safety and predictability.
95//! - [`validation`]: Progressive validation system with four levels ([`ValidationLevel`]): Minimal (structure),
96//! Standard (reference integrity), Strict (spec compliance), and Paranoid (geometry analysis with BVH acceleration).
97//! - [`writer`]: Model-to-XML-to-ZIP serialization pipeline. Mirrors the parser module structure but in reverse.
98//! - [`crypto`] (feature gated): Secure Content Extension support for digital signatures and encryption. Requires
99//! `features = ["crypto"]` to enable.
100//! - [`error`]: Error handling types. All library functions return [`Result<T>`][`crate::Result`] with [`Lib3mfError`]
101//! for failures. The library never panics on user input.
102//!
103//! ## Architecture
104//!
105//! The library follows a layered architecture:
106//!
107//! ```text
108//! Archive Layer (ZIP/OPC) → Parser Layer (XML) → Model Layer (Immutable) → Validation → Writer Layer
109//! ```
110//!
111//! 1. **Archive layer** ([`ZipArchiver`]) opens the 3MF file (ZIP container)
112//! 2. **OPC parser** reads `_rels/.rels` to locate the main model XML via [`find_model_path`]
113//! 3. **XML parser** ([`parse_model`]) converts XML to an in-memory [`Model`] structure
114//! 4. **Model** contains resources (objects, materials, textures) and build instructions
115//! 5. **Validation** applies progressive checks at different levels
116//! 6. **Writer** serializes the model back to XML and ZIP
117//!
118//! ## Design Principles
119//!
120//! - **Immutable-by-default**: Model structures use Clone semantics. Mutation happens via explicit repair operations.
121//! - **No panics**: All errors are returned as `Result<T, Lib3mfError>`. Invalid input never panics.
122//! - **Trait-based abstraction**: [`ArchiveReader`], [`ArchiveWriter`], and other traits decouple implementation
123//! from interface.
124//! - **Progressive validation**: Choose the validation level that matches your performance/correctness tradeoff.
125//! - **Extension-first**: Extensions like Beam Lattice, Slice, and Boolean Operations are first-class citizens
126//! integrated into core structures.
127//!
128//! [`archive`]: crate::archive
129//! [`parser`]: crate::parser
130//! [`model`]: crate::model
131//! [`validation`]: crate::validation
132//! [`writer`]: crate::writer
133//! [`crypto`]: crate::crypto
134//! [`error`]: crate::error
135//! [`ArchiveReader`]: crate::archive::ArchiveReader
136//! [`ArchiveWriter`]: crate::archive::ArchiveWriter
137//! [`find_model_path`]: crate::archive::find_model_path
138//! [`parse_model`]: crate::parser::parse_model
139//! [`Model`]: crate::model::Model
140//! [`Object`]: crate::model::Object
141//! [`Mesh`]: crate::model::Mesh
142//! [`ResourceCollection`]: crate::model::ResourceCollection
143//! [`Build`]: crate::model::Build
144//! [`BuildItem`]: crate::model::BuildItem
145//! [`ValidationLevel`]: crate::validation::ValidationLevel
146//! [`Lib3mfError`]: crate::error::Lib3mfError
147//! [`ZipArchiver`]: crate::archive::ZipArchiver
148
149pub mod archive;
150#[cfg(feature = "crypto")]
151pub mod crypto;
152pub mod error;
153pub mod model;
154pub mod parser;
155pub mod utils;
156pub mod validation;
157pub mod writer;
158
159pub use error::{Lib3mfError, Result};
160pub use model::*;
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165 // use glam::Vec3; // Removed unused import
166
167 #[test]
168 fn test_model_default() {
169 let model = Model::default();
170 assert_eq!(model.unit, Unit::Millimeter);
171 assert!(model.metadata.is_empty());
172 }
173
174 #[test]
175 fn test_mesh_construction() {
176 let mut mesh = Mesh::new();
177 let v1 = mesh.add_vertex(0.0, 0.0, 0.0);
178 let v2 = mesh.add_vertex(1.0, 0.0, 0.0);
179 let v3 = mesh.add_vertex(0.0, 1.0, 0.0);
180
181 mesh.add_triangle(v1, v2, v3);
182
183 assert_eq!(mesh.vertices.len(), 3);
184 assert_eq!(mesh.triangles.len(), 1);
185
186 let t = &mesh.triangles[0];
187 assert_eq!(t.v1, 0);
188 assert_eq!(t.v2, 1);
189 assert_eq!(t.v3, 2);
190 }
191
192 #[test]
193 fn test_resource_collection() {
194 let mut resources = ResourceCollection::new();
195 let mesh = Mesh::new();
196 let object = Object {
197 id: ResourceId(1),
198 object_type: ObjectType::Model,
199 name: Some("Test Object".to_string()),
200 part_number: None,
201 uuid: None,
202 pid: None,
203 thumbnail: None,
204 pindex: None,
205 geometry: Geometry::Mesh(mesh),
206 };
207
208 assert!(resources.add_object(object.clone()).is_ok());
209 assert!(resources.add_object(object).is_err()); // Duplicate ID
210
211 assert!(resources.get_object(ResourceId(1)).is_some());
212 assert!(resources.get_object(ResourceId(2)).is_none());
213 }
214}