lib3mf_core/writer/
mod.rs

1//! Model-to-XML-to-ZIP serialization pipeline for writing 3MF files.
2//!
3//! This module provides the inverse of the parser: it converts an in-memory [`Model`](crate::model::Model)
4//! structure back into a valid 3MF archive (ZIP container with XML and attachments).
5//!
6//! ## Architecture
7//!
8//! The writer mirrors the parser module structure but in reverse:
9//!
10//! ```text
11//! Model → XML Writer → OPC Writer → Package Writer → ZIP Archive
12//! ```
13//!
14//! 1. **Model writer** ([`model_writer`]): Serializes the [`Model`](crate::model::Model) to XML
15//! 2. **Mesh writer** ([`mesh_writer`]): Writes `<mesh>` elements with vertices and triangles
16//! 3. **OPC writer** ([`opc_writer`]): Generates `_rels/.rels` and `[Content_Types].xml`
17//! 4. **Package writer** ([`package_writer`]): Orchestrates full 3MF package creation
18//! 5. **ZIP archive**: Compresses and writes the final `.3mf` file
19//!
20//! ## Usage
21//!
22//! The primary entry point is the [`write`](crate::model::Model::write) method on [`Model`](crate::model::Model):
23//!
24//! ```no_run
25//! use lib3mf_core::Model;
26//! use std::fs::File;
27//!
28//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
29//! // Create or load a model
30//! let model = Model::default();
31//!
32//! // Write to a 3MF file
33//! let output = File::create("output.3mf")?;
34//! model.write(output)?;
35//!
36//! println!("Model written to output.3mf");
37//! # Ok(())
38//! # }
39//! ```
40//!
41//! ## Writer Modules
42//!
43//! ### Core Writers
44//!
45//! - [`model_writer`]: Writes the `<model>` root element and resources
46//! - [`mesh_writer`]: Writes `<mesh>` geometry (vertices, triangles, properties)
47//! - [`opc_writer`]: Writes OPC metadata (`_rels/.rels`, `[Content_Types].xml`)
48//! - [`package_writer`]: Orchestrates writing of complete 3MF package
49//! - [`xml_writer`]: Low-level XML writing utilities
50//!
51//! ### Extension Writers
52//!
53//! - [`displacement_writer`]: Writes Displacement Extension data
54//! - **Beam Lattice**: Not yet implemented (partial support)
55//! - **Slice**: Partial support (slicestackid attribute only)
56//! - **Boolean Operations**: Fully supported in `model_writer`
57//! - **Volumetric**: Fully supported in `model_writer`
58//!
59//! ## Known Limitations
60//!
61//! The writer has some gaps compared to the parser:
62//!
63//! - **Beam lattice writer**: Not implemented. Models with beam lattices can be read but not written back.
64//! - **Slice writer**: Only writes `slicestackid` attribute, doesn't serialize full slice geometry.
65//! - **Namespace optimization**: Always emits all namespace declarations rather than only needed ones.
66//!
67//! These limitations don't affect core 3MF functionality but prevent full roundtrip testing for these extensions.
68//!
69//! ## Roundtrip Testing
70//!
71//! For supported features, the writer produces output that can be parsed back to an equivalent model:
72//!
73//! ```no_run
74//! use lib3mf_core::Model;
75//! use std::io::Cursor;
76//!
77//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
78//! let original_model = Model::default();
79//!
80//! // Write to memory
81//! let mut buffer = Cursor::new(Vec::new());
82//! original_model.write(&mut buffer)?;
83//!
84//! // Read back (would need to extract XML from ZIP in practice)
85//! // let parsed_model = parse_model(buffer)?;
86//! // assert_eq!(original_model, parsed_model);
87//! # Ok(())
88//! # }
89//! ```
90//!
91//! ## Error Handling
92//!
93//! All writing functions return [`Result<(), Lib3mfError>`](crate::error::Result):
94//!
95//! - **Io**: File system errors, ZIP writing errors, out of disk space
96//! - **InvalidStructure**: Model contains invalid data that can't be serialized
97//!
98//! The writer never panics on invalid input, though it may produce a 3MF file that fails validation.
99
100pub mod displacement_writer;
101pub mod mesh_writer;
102pub mod model_write_zip;
103pub mod model_writer;
104pub mod opc_writer;
105pub mod package_writer;
106pub mod xml_writer;