Skip to main content

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