draco_io/traits.rs
1//! Common traits for readers and writers.
2//!
3//! These traits define consistent interfaces for all format implementations.
4//!
5//! # Usage
6//!
7//! Import the trait to access its methods:
8//!
9//! ```ignore
10//! use draco_io::{Writer, ObjWriter};
11//!
12//! let mut writer = ObjWriter::new();
13//! writer.add_mesh(&mesh, Some("Name"))?; // Calls trait method
14//! writer.write("output.obj")?;
15//! ```
16//!
17//! This enables generic functions:
18//!
19//! ```ignore
20//! fn save<W: Writer>(mut w: W, mesh: &Mesh) -> io::Result<()> {
21//! w.add_mesh(mesh, Some("Model"))?;
22//! w.write("output.ext")
23//! }
24//! ```
25
26use std::io::{self, Write};
27use std::path::Path;
28
29use draco_core::mesh::Mesh;
30
31/// Common interface for mesh writers.
32///
33/// All format writers implement this trait, providing a consistent API:
34///
35/// ```ignore
36/// use draco_io::{Writer, ObjWriter};
37///
38/// fn write_mesh<W: Writer>(mut writer: W, mesh: &Mesh) -> io::Result<()> {
39/// writer.add_mesh(mesh, Some("MyMesh"))?;
40/// writer.write("output.ext")
41/// }
42/// ```
43pub trait Writer: Sized {
44 /// Create a new writer instance.
45 fn new() -> Self;
46
47 /// Add a mesh to be written.
48 ///
49 /// # Arguments
50 /// * `mesh` - The mesh to add
51 /// * `name` - Optional name for the mesh (if format supports naming)
52 ///
53 /// # Returns
54 /// * `Ok(())` on success
55 /// * `Err` if the format cannot handle this mesh (e.g., compression failure)
56 fn add_mesh(&mut self, mesh: &Mesh, name: Option<&str>) -> io::Result<()>;
57
58 /// Write all added meshes to a file.
59 ///
60 /// # Arguments
61 /// * `path` - Output file path
62 fn write<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
63
64 /// Get the number of meshes/vertices added.
65 fn vertex_count(&self) -> usize;
66
67 /// Get the number of faces added (if applicable).
68 fn face_count(&self) -> usize {
69 0
70 }
71}
72
73/// Common interface for mesh readers.
74///
75/// All format readers implement this trait, providing a consistent API:
76///
77/// ```ignore
78/// use draco_io::{Reader, ObjReader};
79///
80/// fn load_mesh<R: Reader>(path: &str) -> io::Result<Mesh> {
81/// let mut reader = R::open(path)?;
82/// reader.read_mesh()
83/// }
84/// ```
85pub trait Reader: Sized {
86 /// Open a file for reading.
87 ///
88 /// # Arguments
89 /// * `path` - Input file path
90 fn open<P: AsRef<Path>>(path: P) -> io::Result<Self>;
91
92 /// Read multiple meshes (a scene) from the file.
93 ///
94 /// Formats that represent scenes or multiple mesh primitives should implement
95 /// this method and return all meshes in the file or scene.
96 fn read_meshes(&mut self) -> io::Result<Vec<Mesh>>;
97
98 /// Read a single mesh from the file.
99 ///
100 /// Default implementation returns the first mesh from `read_meshes()`.
101 fn read_mesh(&mut self) -> io::Result<Mesh> {
102 let meshes = self.read_meshes()?;
103 if let Some(m) = meshes.into_iter().next() {
104 Ok(m)
105 } else {
106 Err(io::Error::new(io::ErrorKind::InvalidData, "No mesh found"))
107 }
108 }
109}
110
111/// Common interface for readers that can be constructed from in-memory bytes.
112///
113/// This complements [`Reader::open`] for callers that already have file bytes
114/// loaded, or that are working in browser/embedded environments without direct
115/// filesystem access.
116pub trait ReadFromBytes: Sized {
117 /// Create a reader from a complete file payload.
118 fn from_bytes(bytes: &[u8]) -> io::Result<Self>;
119}
120
121/// Common interface for writers that can emit a complete file payload.
122///
123/// This complements [`Writer::write`] for callers that need to send bytes over
124/// the network, store them in an archive, or run roundtrips without temporary
125/// files.
126pub trait WriteToBytes: Writer {
127 /// Write all added data into a byte vector.
128 fn write_to_vec(&self) -> io::Result<Vec<u8>>;
129
130 /// Write all added data into an arbitrary byte sink.
131 fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
132 writer.write_all(&self.write_to_vec()?)
133 }
134}
135
136/// Extended writer trait for point cloud support.
137///
138/// Writers that can output point clouds (without faces) implement this trait.
139pub trait PointCloudWriter: Writer {
140 /// Add raw point positions.
141 fn add_points(&mut self, points: &[[f32; 3]]);
142
143 /// Add a single point.
144 fn add_point(&mut self, point: [f32; 3]) {
145 self.add_points(&[point]);
146 }
147}
148
149/// Extended reader trait for point cloud support.
150///
151/// Readers that can read point clouds implement this trait.
152pub trait PointCloudReader: Reader {
153 /// Read point positions only (no faces or topology).
154 fn read_points(&mut self) -> io::Result<Vec<[f32; 3]>>;
155}